在线时间2 小时
UID366752
ST金币0
蝴蝶豆0
注册时间2012-6-26
新手上路
- 最后登录
- 2018-5-30
|
a0a.1 0b0c
一直都是用MCU裸奔程序,现在在STM32F429 discovery上试了下移植UCOSII,现在把自己的心得分享一下,有不正确的地方,请指出来!
先直接把程序贴出来,说明放在后面。关于移植前的准备工作以及UCOSII的源码,大家可以网上搜索,很多资料,现只贴出主函数部分,其中用到的其他函数都是很简单就能实现的,方法很多,就不赘述了。
#include
#include "delay.h"
#include "key.h"
#include "led.h"
#include "usart.h"
#include "includes.h"
//UCOSII任务设置
// 起始任务
#define START_TASK_PRIO 10 //设置任务优先级
#define START_STK_SIZE 64 //设置任务堆栈大小
OS_STK START_TASK_STK[START_STK_SIZE];//任务堆栈
void START_Task(void *pdata); //任务函数
//LED任务(红灯)
#define RLED_TASK_PRIO 7
#define RLED_STK_SIZE 64
OS_STK RLED_TASK_STK[RLED_STK_SIZE];
void RLED_Task(void *pdata);
//主任务
#define MAIN_TASK_PRIO 5
#define MAIN_STK_SIZE 128
OS_STK MAIN_TASK_STK[MAIN_STK_SIZE];
void MAIN_Task(void *pdata);
//按键任务
#define KEY_TASK_PRIO 4
#define KEY_STK_SIZE 64
OS_STK KEY_TASK_STK[KEY_STK_SIZE];
void KEY_Task(void *pdata);
OS_EVENT *msg_key; //邮箱事件块指针(按键用)
OS_TMR *tmr1; //软件定时器1
//软件定时器1的回调函数
void TMR1_Callback(OS_TMR *ptmr,void *p_arg)
{
static u16 cpuusage = 0;
static u8 tcnt = 0;
if(tcnt == 5)
{
printf("CPU使用率:%d%%\r\n",cpuusage/5);//每隔一段时间打印出CPU使用率
cpuusage = 0;
tcnt = 0;
}
cpuusage += OSCPUUsage;
tcnt++;
}
int main(void)
{
F4_Clock_Init(); //关于时钟复位,参照官方例程,基本是照抄的
Delay_Init(150); //延时初始化
MYUSART1_Init(75,115200); //串口初始化
LED_Init(); //LED端口初始化
KEY_Init(); //按键端口初始化
OSInit();
//创建起始任务
OSTaskCreate(START_Task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO);
OSStart();
}
//起始任务
void START_Task(void *pdata)
{
OS_CPU_SR cpu_sr = 0;
pdata = pdata;
msg_key = OSMboxCreate((void *)0);//创建消息邮箱
OSStatInit(); //初始化统计任务
OS_ENTER_CRITICAL();//进入临界区,系统不响应中断
//创建如下任务
OSTaskCreate(RLED_Task,(void *)0,(OS_STK *)&RLED_TASK_STK[RLED_STK_SIZE-1],RLED_TASK_PRIO);
OSTaskCreate(MAIN_Task,(void *)0,(OS_STK *)&MAIN_TASK_STK[MAIN_STK_SIZE]-1,MAIN_TASK_PRIO);
OSTaskCreate(KEY_Task,(void *)0,(OS_STK *)&KEY_TASK_STK[KEY_STK_SIZE-1],KEY_TASK_PRIO );
OSTaskSuspend(START_TASK_PRIO);//将起始任务挂起
OS_EXIT_CRITICAL(); //退出临界区,系统正常响应中断
}
//LED任务
void RLED_Task(void *pdata)
{
while(1)
{
LED_On(REDLED);
OSTimeDly(500);
LED_Off(REDLED);
OSTimeDly(500);
}
}
//主任务
void MAIN_Task(void *pdata)
{
u32 key = 0;
u8 state;
u8 err;
//创建软件定时器1
tmr1 = OSTmrCreate(10,5,OS_TMR_OPT_PERIODIC,(OS_TMR_CALLBACK)TMR1_Callback,0,"tmr1",&err);
OSTmrStart(tmr1,&err);//启动软件定时器1
while(1)
{
key = (u32)OSMboxPend(msg_key,10,&err);//获取(请求)按键消息
switch(key)
{
case 1:
LED_Toggle(GREENLED);//翻转LED状态
state = LED_State(GREENLED);//获取LED当前状态
if(state == 1)
printf("邮箱消息发送成功,绿灯点亮!\r\n");
else printf(" 邮箱消息发送成功,绿灯熄灭!\r\n");
break;
default:
break;
}
OSTimeDly(10);
}
}
//按键扫描任务
void KEY_Task(void *pdata)
{
u8 key;
while(1)
{
key = KEY_Scan(0);
if(key)
{
printf("key=%d,准备发送消息邮箱...\r\n",key);
OSMboxPost(msg_key,(void *)key);//发送消息
}
OSTimeDly(10);
}
}
说明:
1,以上代码仅包含几个基础的简单功能:1)创建任务,设置任务的优先级,堆栈和任务函数,达到多任务运行的效果。2)通过消息邮箱,达到任务间通信的目的。3)使用软件定时器,打印出CPU的使用率。
2,在官方源码中,最重要的也是需要我们经常修改的是os_cfg.h这个文件。当然其他地方也会有修改的,限于本人水平还请大家多百度。关于os_cfg.h中几个重要的参数(仅讲本代码中用到的功能)如下:
OS_MAX_TASKS 允许的任务的最大数量,最新版的UCOSII最大任务支持255个。一般调试使用10个基本够了。
OS_TICKS_PER_SEC 时间节拍,这个是很重要的参数,该参数决定整个UCOSII系统的时间基准,就是一秒钟的节拍数量,如果设置为10,那么时间基准就是1000/10=100ms,依次类推,一般设置为1~100ms。在cortex-m4内核有SYSTICK定时器,一般以此定时器在硬件上产生时间节拍。关于延时函数,最终都是要调用UCOSII的自带的延时函数OSTimeDly。
OS_TMR_EN 定时器使能,取1时使能,不然会出现无法使用数据类型OS_TMR等问题
OS_TMR_CFG_TICKS_PER_SEC 定时器的节拍,意义等同于STM32的定时器设置产生中断的时间,具体要看在软件定时器的相关函数中的用法,大家可以自己多研究下。
下一句是自己添加的,设置优先级。
#define OS_TASK_TMR_PRIO 0u //设置软件定时器1的优先级为最高
3,一些基础知识普及,比较简单基础:
1)UCOSII的任何任务都是通过任务控制块来控制,任务控制块包括:
任务函数指针,任务堆栈指针,任务优先级。
任务函数指针用于找到函数入口,去执行具体的操作;
任务堆栈指针,用于该任务释放了CPU使用权时,用于保护现场,即保存该任务的相关参数到堆栈中,等待下次改任务获取了CPU使用权了,再从堆栈中加载参数,继续执行函数;
优先级是识别每个任务的唯一标示,且优先级不能有相同的。
2)每个任务就是一个死循环,在循环中至少要有一个延时语句,这样才能在该延时语句处释放该任务的CPU使用权,转而去响应中断或者执行优先级更高的任务,且延时长短视具体程序而定,一般延时10ms。
3)关于创建任务的语句,其中一个参数与具体处理器的堆栈增长方式有关,向上增长和向下增长是不同的参数。
4)中断响应时间是体现系统实时性好不好的重要参数之一。
备注:很多代码参照了正点原子的战舰STM32F103开发板的资料,有什么不明白的,大家可以多看看相关资料,还有任哲和邵贝贝的关于UCOSII的讲解,非常详细和经典。
|
|