实验内容:
创建4个任务:
static void AppTaskStart(void *p_arg);
static void main_task(void *p_arg);
static void Keyprocess_task (void *p_arg);
static void msgdis_task (void *p_arg);
两个消息队列:
static OS_Q Key_Msg;
static OS_Q Data_Msg;
一个软件定时器:
static OS_TMR tmr1;
AppTaskStart用于创建其他三个任务。
main_task 负责按键检测,并将测得按键值传入消息队列Key_Msg,同时LED绿灯闪烁和检测消息队列Data_Msg的总容量和剩余容量。
Keyprocess_task 根据不同的按键值做出相应的处理内容,其中KEY1按键BLUE灯翻转,KEY2按键RED灯翻转。
msgdis_task 用于在LCD上显示回调函数执行的次数。回调函数执行的次数会发送到消息队列Data_Msg。
关键代码:
任务优先级:
#define APP_TASK_START_PRIO 3
#define APP_MAIN_TASK_PRIO 4
#define APP_KEYPROCESS_TASK_PRIO 5
#define APP_MSGDIS_TASK_PRIO 6
static void AppTaskStart (void *p_arg)
{
CPU_INT32U cpu_clk_freq;
CPU_INT32U cnts;
OS_ERR err;
CPU_SR_ALLOC();
(void)p_arg;
BSP_Init(); /* Initialize BSP functions */
CPU_Init();
cpu_clk_freq = BSP_CPU_ClkFreq(); /* Determine SysTick reference freq. 72000000Hz */
cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz; /* Determine nbr SysTick increments 72000 */
OS_CPU_SysTickInit(cnts); //默认时间节拍100ms /* Init uC/OS periodic time src (SysTick). */
// OSSchedRoundRobinCfg(DEF_ENABLED,10,&err);//设置一个时间片10ms
Mem_Init(); /* Initialize Memory Management Module */
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err); /* Compute CPU capacity with no task running */
#endif
CPU_IntDisMeasMaxCurReset();
#if (APP_CFG_SERIAL_EN == DEF_ENABLED)
BSP_Ser_Init(115200); /* Enable Serial Interface */
#endif
OS_CRITICAL_ENTER(); //进入临界区
//创建 Key_Msg 消息队列
OSQCreate (&Key_Msg, "Key Msg", KEY_MSG_MAX_SIZE, &err);
//创建 Key_Msg 消息队列
OSQCreate (&Data_Msg, "Data Msg", DATA_MSG_MAX_SIZE, &err);
//创建定时器任务1,周期模式
OSTmrCreate ( (OS_TMR *)&tmr1 ,
(CPU_CHAR *)"tmr1",
(OS_TICK )0,
(OS_TICK )5, /*定时器定时周期50ms*/
(OS_OPT )OS_OPT_TMR_PERIODIC,
(OS_TMR_CALLBACK_PTR )tmr1_callback,
(void *)0,
(OS_ERR *)&err);
//创建main_task
OSTaskCreate((OS_TCB *)&MainTaskTCB, /* Create the start task */
(CPU_CHAR *)"main task",
(OS_TASK_PTR ) main_task,
(void *) 0,
(OS_PRIO ) APP_MAIN_TASK_PRIO,
(CPU_STK *)&MainTaskStk[0],
(CPU_STK_SIZE) APP_MAIN_TASK_STK_SIZE / 10,
(CPU_STK_SIZE) APP_MAIN_TASK_STK_SIZE,
(OS_MSG_QTY ) 0u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_SAVE_FP),
(OS_ERR *)&err);
//创建Keyprocess_task
OSTaskCreate((OS_TCB *)&KeyProsessTCB, /* Create the start task */
(CPU_CHAR *)"Keyprocess task",
(OS_TASK_PTR ) Keyprocess_task,
(void *) 0,
(OS_PRIO ) APP_KEYPROCESS_TASK_PRIO,
(CPU_STK *)&KeyProsessStk[0],
(CPU_STK_SIZE) APP_KEYPROCESS_TASK_STK_SIZE / 10,
(CPU_STK_SIZE) APP_KEYPROCESS_TASK_STK_SIZE,
(OS_MSG_QTY ) 0u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_SAVE_FP),
(OS_ERR *)&err);
//创建msgdis_task
OSTaskCreate((OS_TCB *)&MsgDisTCB, /* Create the start task */
(CPU_CHAR *)"msgdis task",
(OS_TASK_PTR ) msgdis_task,
(void *) 0,
(OS_PRIO ) APP_MSGDIS_TASK_PRIO,
(CPU_STK *)&MsgDisStk[0],
(CPU_STK_SIZE) APP_MSGDIS_TASK_STK_SIZE / 10,
(CPU_STK_SIZE) APP_MSGDIS_TASK_STK_SIZE,
(OS_MSG_QTY ) 0u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_SAVE_FP),
(OS_ERR *)&err);
OS_CRITICAL_EXIT(); //退出临界区
OSTmrStart (&tmr1, &err); /*开启定时器,开始调试时忘记开启,找了好久*/
OSTaskDel(&AppTaskStartTCB, &err); //删除起始任务自身
}
static void main_task (void *p_arg)
{
uint8_t time0 =0, key_num ;
OS_ERR err;
(void)p_arg;
while(1)
{
key_num = 0; /***此处必须将按键值清零,因为发送到消息队列的值是用指针,不清零总会用上次循环的按键的值***/
if(Key_Scan(KEY1_GPIO_PORT ,KEY1_GPIO_PIN) == KEY_ON) /*检测按键值*/
{
key_num = 1;
printf("\nKEY%d按下\n",key_num);
}
else if(Key_Scan(KEY2_GPIO_PORT ,KEY2_GPIO_PIN) == KEY_ON)
{
key_num = 2;
printf("\nKEY%d按下\n",key_num);
}
if(key_num)
{
OSQPost ( &Key_Msg,(void *) &key_num,(OS_MSG_SIZE)1, OS_OPT_POST_FIFO, &err); /*发送按键值给消息队列*/
}
time0 ++;
if(time0 % 10 == 0)
Check_msg_q();
if(time0 == 100)
{
LED_GRE_TOGGLE;
time0 = 0;
}
OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_HMSM_STRICT,&err); //延时10ms,用来低优先级的任务调度
}
}
/*
*brief按键处理函数
*/
static void Keyprocess_task (void *p_arg)
{
OS_ERR err;
uint8_t *key_val;
OS_MSG_SIZE msg_size;
printf("进入按键处理任务\n");
while(1)
{
key_val = OSQPend (&Key_Msg, 0, OS_OPT_PEND_BLOCKING, &msg_size, 0,&err);
switch (*key_val)
{
case 1:
{
LED_BLU_TOGGLE;
break ;
}
case 2:
{
LED_RED_TOGGLE;
break ;
}
default :
{
printf("进入默认情况%d\n",*key_val);
break;
}
}
OSTimeDlyHMSM(0,0,0,100,OS_OPT_TIME_HMSM_STRICT,&err); //延时10ms
}
}
void tmr1_callback(void *p_tmr, void *p_arg)
{
static uint16_t exu_time; /******************次数必须用静态变量,静态变量申明时自动初始化为0,每再次执行回调函数时仍然可以保存上次的值*******************/
OS_ERR err;
exu_time ++;
printf("进入回调函数\n");
OSQPost (&Data_Msg, (uint16_t *)&exu_time , 2, OS_OPT_POST_FIFO, &err);/*当消息队列慢时则将定时器停止,由于向消息队列发送次数数据与请求消息队列的数据同时在进行,所以应该发送速度大于请求速度,定时器才会停止*/
if(err != OS_ERR_NONE)
{
OSTmrStop ((OS_TMR *)&tmr1,
(OS_OPT ) OS_OPT_TMR_NONE,
(void *)0,
(OS_ERR *)&err);
printf("定时器1停止\n");
}
}
static void msgdis_task (void *p_arg)
{
OS_ERR err;
uint8_t *receive_data;
OS_MSG_SIZE msg_size;
while(1)
{
receive_data = OSQPend (&Data_Msg, 0, OS_OPT_PEND_BLOCKING, &msg_size, 0,&err);
LCD_SetColors(RED,BLACK);
sprintf(dispBuff,"定时器1运行次数%d ",*receive_data);
LCD_ClearLine(LINE(1)); /* 清除单行文字 */
ILI9341_DispStringLine_EN_CH(LINE(1),dispBuff);
OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); /*延时1s,由于定时器周期50ms这里延时1s才能保证可以消息队列慢来停止定时器*/
}
}
oid Check_msg_q(void) /*检测消息队列剩余容量*/
{
uint8_t max_msg, remain_msg;
CPU_SR_ALLOC();
OS_CRITICAL_ENTER(); //进入临界区
max_msg = Data_Msg.MsgQ.NbrEntriesSize ;
sprintf(dispBuff,"max_msg = %d",max_msg);
LCD_SetColors(RED,BLACK);
LCD_ClearLine(LINE(2)); /* 清除单行文字 */
ILI9341_DispStringLine_EN_CH(LINE(2),dispBuff);
remain_msg = Data_Msg.MsgQ.NbrEntriesSize - Data_Msg.MsgQ.NbrEntries; /* 用总容量减去已经使用的容量 */
sprintf(dispBuff,"remain_msg = %d",remain_msg);
LCD_SetColors(RED,BLACK);
LCD_ClearLine(LINE(3)); /* 清除单行文字 */
ILI9341_DispStringLine_EN_CH(LINE(3),dispBuff);
OS_CRITICAL_EXIT(); //退出临界区
}