您的位置:首页 > 文旅 > 旅游 > FreeRTOS和UCOS操作系统使用笔记

FreeRTOS和UCOS操作系统使用笔记

2024/12/26 22:46:00 来源:https://blog.csdn.net/weixin_42107504/article/details/140158407  浏览:    关键词:FreeRTOS和UCOS操作系统使用笔记

FreeRTOS使用示例

任务创建与删除

#define START_TASK_PRIO       1     //任务优先级 (1)
#define START_STK_SIZE        128   //任务堆栈大小 (2)
TaskHandle_t StartTask_Handler;     //任务句柄 (3)
void start_task(void *pvParameters);//任务函数 (4)#define TASK1_TASK_PRIO       2     //任务优先级
#define TASK1_STK_SIZE        128   //任务堆栈大小
TaskHandle_t Task1Task_Handler;     //任务句柄
void task1_task(void *pvParameters);//任务函数#define TASK2_TASK_PRIO       3     //任务优先级
#define TASK2_STK_SIZE        128   //任务堆栈大小
TaskHandle_t Task2Task_Handler;     //任务句柄
void task2_task(void *pvParameters);//任务函数int main(void)
{//创建开始任务xTaskCreate((TaskFunction_t )start_task, //任务函数 (1)(const char* )"start_task",   //任务名称(uint16_t )START_STK_SIZE,    //任务堆栈大小(void* )NULL,                 //传递给任务函数的参数(UBaseType_t )START_TASK_PRIO,//任务优先级(TaskHandle_t* )&StartTask_Handler);//任务句柄 vTaskStartScheduler();        //开启任务调度 (2)
}//开始任务任务函数
void start_task(void *pvParameters)  
{taskENTER_CRITICAL(); //进入临界区//创建 TASK1 任务xTaskCreate((TaskFunction_t )task1_task, (const char* )"task1_task", (uint16_t )TASK1_STK_SIZE, (void* )NULL, (UBaseType_t )TASK1_TASK_PRIO, (TaskHandle_t* )&Task1Task_Handler); //创建 TASK2 任务xTaskCreate((TaskFunction_t )task2_task, (const char* )"task2_task", (uint16_t )TASK2_STK_SIZE,(void* )NULL,(UBaseType_t )TASK2_TASK_PRIO,(TaskHandle_t* )&Task2Task_Handler); vTaskDelete(StartTask_Handler); //删除开始任务 (2)taskEXIT_CRITICAL(); //退出临界区
}//task1 任务函数
void task1_task(void *pvParameters)  
{u8 task1_num=0;while(1){task1_num++; //任务执 1 行次数加 1 注意 task1_num1 加到 255 的时候会清零!!if(task1_num==5) {vTaskDelete(Task2Task_Handler);//任务 1 执行 5 次删除任务 2}vTaskDelay(1000); //延时 1s,也就是 1000 个时钟节拍}
}
//task2 任务函数
void task2_task(void *pvParameters)
{u8 task2_num=0;while(1){task2_num++; //任务 2 执行次数加 1 注意 task1_num2 加到 255 的时候会清零!!vTaskDelay(1000); //延时 1s,也就是 1000 个时钟节拍}
}

任务挂起与恢复

#define START_TASK_PRIO   1        //任务优先级
#define START_STK_SIZE    128      //任务堆栈大小
TaskHandle_t StartTask_Handler;    //任务句柄
void start_task(void *pvParameters); //任务函数#define KEY_TASK_PRIO     2        //任务优先级
#define KEY_STK_SIZE      128      //任务堆栈大小
TaskHandle_t KeyTask_Handler;      //任务句柄
void key_task(void *pvParameters); //任务函数#define TASK1_TASK_PRIO    3        //任务优先级
#define TASK1_STK_SIZE     128      //任务堆栈大小
TaskHandle_t Task1Task_Handler;     //任务句柄
void task1_task(void *pvParameters); //任务函数#define TASK2_TASK_PRIO     4       //任务优先级
#define TASK2_STK_SIZE      128     //任务堆栈大小
TaskHandle_t Task2Task_Handler;     //任务句柄
void task2_task(void *pvParameters);//任务函数int main(void)
{//创建开始任务xTaskCreate((TaskFunction_t )start_task, //任务函数 (1)(const char* )"start_task",   //任务名称(uint16_t )START_STK_SIZE,    //任务堆栈大小(void* )NULL,                 //传递给任务函数的参数(UBaseType_t )START_TASK_PRIO,//任务优先级(TaskHandle_t* )&StartTask_Handler);//任务句柄 vTaskStartScheduler();        //开启任务调度 (2)
}//开始任务任务函数
void start_task(void *pvParameters)  
{taskENTER_CRITICAL(); //进入临界区//创建 KEY 任务xTaskCreate((TaskFunction_t )key_task, (const char* )"key_task", (uint16_t )KEY_STK_SIZE, (void* )NULL, (UBaseType_t )KEY_TASK_PRIO, (TaskHandle_t* )&KeyTask_Handler); //创建 TASK1 任务xTaskCreate((TaskFunction_t )task1_task, (const char* )"task1_task", (uint16_t )TASK1_STK_SIZE, (void* )NULL, (UBaseType_t )TASK1_TASK_PRIO, (TaskHandle_t* )&Task1Task_Handler); //创建 TASK2 任务xTaskCreate((TaskFunction_t )task2_task, (const char* )"task2_task", (uint16_t )TASK2_STK_SIZE,(void* )NULL,(UBaseType_t )TASK2_TASK_PRIO,(TaskHandle_t* )&Task2Task_Handler); vTaskDelete(StartTask_Handler); //删除开始任务taskEXIT_CRITICAL(); //退出临界区
}void key_task(void *pvParameters)
{u8 key;while(1){key=KEY_Scan(0);switch(key){case WKUP_PRES:vTaskSuspend(Task1Task_Handler);//挂起任务 1break;case KEY1_PRES:vTaskResume(Task1Task_Handler);//恢复任务 1break;case KEY2_PRES:vTaskSuspend(Task2Task_Handler);//挂起任务 2 break;}vTaskDelay(10); //延时 10ms }
}//task1 任务函数
void task1_task(void *pvParameters)  
{u8 task1_num=0;while(1){task1_num++; //任务执 1 行次数加 1 注意 task1_num1 加到 255 的时候会清零!!printf("任务 1 已经执行:%d 次\r\n",task1_num);vTaskDelay(1000); //延时 1s,也就是 1000 个时钟节拍}
}
//task2 任务函数
void task2_task(void *pvParameters)
{u8 task2_num=0;while(1){task2_num++; //任务 2 执行次数加 1 注意 task1_num2 加到 255 的时候会清零!!printf("任务 2 已经执行:%d 次\r\n",task2_num);vTaskDelay(1000); //延时 1s,也就是 1000 个时钟节拍}
}

消息队列

  • 应用:类似二值或者计数型信号量(两种也是队列实现)。即一个任务或者中断连续往一个队列发送5包数据;另一个任务就可以延后处理数据按5次调用取出数据来用。

 

#define START_TASK_PRIO       1    //任务优先级
#define START_STK_SIZE        256  //任务堆栈大小
TaskHandle_t StartTask_Handler;    //任务句柄
void start_task(void *pvParameters); //任务函数#define TASK1_TASK_PRIO       2    //任务优先级
#define TASK1_STK_SIZE        256  //任务堆栈大小
TaskHandle_t Task1Task_Handler;    //任务句柄
void task1_task(void *pvParameters);//任务函数#define KEYPROCESS_TASK_PRIO  3    //任务优先级
#define KEYPROCESS_STK_SIZE   256  //任务堆栈大小
TaskHandle_t Keyprocess_Handler;   //任务句柄
void Keyprocess_task(void *pvParameters); //任务函数//按键消息队列的数量
#define KEYMSG_Q_NUM  1 //按键消息队列的数量 (1)
#define MESSAGE_Q_NUM 4 //发送数据的消息队列的数量 (2)
QueueHandle_t Key_Queue; //按键值消息队列句柄
QueueHandle_t Message_Queue; //信息队列句柄int main(void)
{//创建开始任务
}//开始任务任务函数
void start_task(void *pvParameters)  
{taskENTER_CRITICAL(); //进入临界区//创建消息 Key_QueueKey_Queue=xQueueCreate(KEYMSG_Q_NUM,sizeof(u8)); (1)//创建消息 Message_Queue,队列项长度是串口接收缓冲区长度Message_Queue=xQueueCreate(MESSAGE_Q_NUM,USART_REC_LEN); (2)//创建 TASK1 任务xTaskCreate((TaskFunction_t )task1_task, (const char* )"task1_task", (uint16_t )TASK1_STK_SIZE, (void* )NULL, (UBaseType_t )TASK1_TASK_PRIO, (TaskHandle_t* )&Task1Task_Handler); //创建 TASK2 任务xTaskCreate((TaskFunction_t )Keyprocess_task, (const char* )"keyprocess_task", (uint16_t )KEYPROCESS_STK_SIZE,(void* )NULL,(UBaseType_t )KEYPROCESS_TASK_PRIO,(TaskHandle_t* )&Keyprocess_Handler); vTaskDelete(StartTask_Handler); //删除开始任务taskEXIT_CRITICAL(); //退出临界区
}
void task1_task(void *pvParameters)
{BaseType_t err;while(1){u8 key=KEY_Scan(0);  if((Key_Queue!=0)&&(key)){ //消息队列 Key_Queue 创建成功,并且按键被按下err=xQueueSend(Key_Queue,&key,10);if(err==errQUEUE_FULL) {printf("队列 Key_Queue 已满,数据发送失败!\r\n");}}vTaskDelay(10); //延时 10ms,也就是 10 个时钟节拍}
}
//Keyprocess_task 函数
void Keyprocess_task(void *pvParameters)
{u8 num,key,beepsta=1;while(1){if(Key_Queue!=0){if(xQueueReceive(Key_Queue,&key,portMAX_DELAY)){//请求消息 Key_Queueswitch(key){case WKUP_PRES: //KEY_UP 控制 LED1break;case KEY2_PRES: //KEY2 控制蜂鸣器break;case KEY0_PRES: //KEY0 刷新 LCD 背景break;}}}vTaskDelay(10); //延时 10ms,也就是 10 个时钟节拍}
}
//串口 1 中断服务程序
void USART1_IRQHandler(void) 
{ ......if(USART_RX_STA&0x8000) {//向队列发送接收到的数据//向队列中发送数据xQueueSendFromISR(Message_Queue,USART_RX_BUF,&xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换portYIELD_FROM_ISR(xHigherPriorityTaskWoken); }
}
//回调函数,定时器中断服务函数调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{u8 *buffer;BaseType_t xTaskWokenByReceive=pdFALSE;BaseType_t err;if(Message_Queue!=0){.......//请求消息 Message_Queueerr=xQueueReceiveFromISR(Message_Queue,buffer,&xTaskWokenByReceive); if(err==pdTRUE){ //接收到消息disp_str(buffer); //在 LCD 上显示接收到的消息 (6)}}//如果需要的话进行一次任务切换portYIELD_FROM_ISR(xTaskWokenByReceive);  
}

二值信号量

  • 用途:【1】共享资源访问;【2】用于任务同步
//二值信号量句柄
SemaphoreHandle_t BinarySemaphore;//二值信号量句柄int main(void)
{//创建开始任务
}//开始任务任务函数
void start_task(void *pvParameters)  
{taskENTER_CRITICAL(); //进入临界区//创建二值信号量BinarySemaphore=xSemaphoreCreateBinary();//创建 TASK1 任务xTaskCreate((TaskFunction_t )task1_task, (const char* )"task1_task", (uint16_t )TASK1_STK_SIZE, (void* )NULL, (UBaseType_t )TASK1_TASK_PRIO, (TaskHandle_t* )&Task1Task_Handler); //创建 TASK2 任务xTaskCreate((TaskFunction_t )DataProcess_task, (const char* )"keyprocess_task", (uint16_t )DATAPROCESS_STK_SIZE,(void* )NULL,(UBaseType_t )DATAPROCESS_TASK_PRIO,(TaskHandle_t* )&DataProcess_Handler); vTaskDelete(StartTask_Handler); //删除开始任务taskEXIT_CRITICAL(); //退出临界区
}
void task1_task(void *pvParameters)
{BaseType_t err;while(1){vTaskDelay(500); //延时 500ms,也就是 500 个时钟节拍}
}
//DataProcess_task 函数
void DataProcess_task(void *pvParameters)
{while(1){if(BinarySemaphore!=NULL){err=xSemaphoreTake(BinarySemaphore,portMAX_DELAY);//获取信号量 (1)if(err==pdTRUE){ //获取信号量成功//处理数据}else if(err==pdFALSE){vTaskDelay(10); //延时 10ms,也就是 10 个时钟节拍}}}
}
//串口 1 中断服务程序
void USART1_IRQHandler(void) 
{ BaseType_t xHigherPriorityTaskWoken;//接收到数据,并且二值信号量有效if((USART_RX_STA&0x8000)&&(BinarySemaphore!=NULL)){xSemaphoreGiveFromISR(BinarySemaphore,&xHigherPriorityTaskWoken);//释放二值信号量portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换}
}

计数型信号量

  • 应用:类似按键连续按下5次,其它任务同步延后按5次逐个完成对应的工作(而不是指响应最后一次按下,每次按下都响应,只是响应时间往后延时完成)
//计数型信号量句柄
SemaphoreHandle_t CountSemaphore;//计数型信号量int main(void)
{//创建开始任务
}//开始任务任务函数
void start_task(void *pvParameters)  
{taskENTER_CRITICAL(); //进入临界区//创建计数型信号量,计数型信号量计数最大值设置为255,初始值设置为0。CountSemaphore=xSemaphoreCreateCounting(255,0); //创建释放信号量任务xTaskCreate((TaskFunction_t )SemapGive_task, (const char* )"semapgive_task", (uint16_t )SEMAPGIVE_STK_SIZE, (void* )NULL, (UBaseType_t )SEMAPGIVE_TASK_PRIO, (TaskHandle_t* )&SemapGiveTask_Handler);//创建获取信号量任务xTaskCreate((TaskFunction_t )SemapTake_task, (const char* )"semaptake_task", (uint16_t )SEMAPTAKE_STK_SIZE,(void* )NULL,(UBaseType_t )SEMAPTAKE_TASK_PRIO,(TaskHandle_t* )&SemapTakeTask_Handler); vTaskDelete(StartTask_Handler); //删除开始任务taskEXIT_CRITICAL();            //退出临界区
}
//释放计数型信号量任务函数
void SemapGive_task(void *pvParameters)
{u8 semavalue;BaseType_t err;while(1){key=KEY_Scan(0);if(CountSemaphore!=NULL) {//计数型信号量创建成功switch(key){case WKUP_PRES:err=xSemaphoreGive(CountSemaphore);//释放计数型信号量if(err==pdFALSE){//信号量释放失败}semavalue=uxSemaphoreGetCount(CountSemaphore);//获取计数型信号量值break;}}vTaskDelay(10);//延时 10ms,也就是 10 个时钟节拍}
}
//获取计数型信号量任务函数
void SemapTake_task(void *pvParameters)
{u8 semavalue;while(1){xSemaphoreTake(CountSemaphore,portMAX_DELAY); //等待数值信号量 (5)semavalue=uxSemaphoreGetCount(CountSemaphore); //获取数值信号量值 (6)//打印或者显示信号量的值semavalue    vTaskDelay(1000); //延时 1s,也就是 1000 个时钟节拍}
}

互斥信号量

  • 当一个低优先级任务和一个高优先级任务同时使用同一个信号量,且低优先级的任务延时阻塞比较久才释放信号量!
  • 而系统中还有其他中等优先级任务时。如果低优先级任务获得了信号量,那么高优先级的任务就会处于等待状态。
  • 但是,中等优先级的任务可以打断低优先级任务而先于高优先级任务运行(此时高优先级的任务在等待信号量 ,所以不能运行),这是就出现了优先级翻转的现象。
SemaphoreHandle_t MutexSemaphore;//创建互斥信号量int main(void)
{//创建开始任务
}//开始任务任务函数
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //进入临界区//创建互斥信号量MutexSemaphore=xSemaphoreCreateMutex(); (1)//创建高优先级任务xTaskCreate((TaskFunction_t )high_task, (const char* )"high_task", (uint16_t )HIGH_STK_SIZE, (void* )NULL, (UBaseType_t )HIGH_TASK_PRIO, (TaskHandle_t* )&HighTask_Handler); //创建中等优先级任务xTaskCreate((TaskFunction_t )middle_task, (const char* )"middle_task", (uint16_t )MIDDLE_STK_SIZE,(void* )NULL,(UBaseType_t )MIDDLE_TASK_PRIO,(TaskHandle_t* )&MiddleTask_Handler); //创建低优先级任务xTaskCreate((TaskFunction_t )low_task, (const char* )"low_task", (uint16_t )LOW_STK_SIZE,(void* )NULL,(UBaseType_t )LOW_TASK_PRIO,(TaskHandle_t* )&LowTask_Handler);vTaskDelete(StartTask_Handler); //删除开始任务taskEXIT_CRITICAL(); //退出临界区
}
//高优先级任务的任务函数
void high_task(void *pvParameters)
{while(1){vTaskDelay(500); //延时 500ms,也就是 500 个时钟节拍xSemaphoreTake(MutexSemaphore,portMAX_DELAY); //获取互斥信号量 printf("high task Running!\r\n");xSemaphoreGive(MutexSemaphore); //释放信号量 vTaskDelay(500); //延时 500ms,也就是 500 个时钟节拍 }
}//中等优先级任务的任务函数
void middle_task(void *pvParameters)
{while(1){printf("middle task Running!\r\n");vTaskDelay(1000); //延时 1s,也就是 1000 个时钟节拍}
}
//低优先级任务的任务函数
void low_task(void *pvParameters)
{static u32 times;while(1){xSemaphoreTake(MutexSemaphore,portMAX_DELAY); //获取互斥信号量printf("low task Running!\r\n");for(times=0;times<20000000;times++){ //模拟低优先级任务占用互斥信号量taskYIELD(); //发起任务调度}xSemaphoreGive(MutexSemaphore); //释放互斥信号量vTaskDelay(1000); //延时 1s,也就是 1000 个时钟节拍}
}

事件标志组

  • 类似裸跑时一个全局flag变量,对应的一个或者多个bit被置起来,就同步做另一个事情
  • 事件标志组是在不同任务间置起标志位(发送),由其中一个任务判断哪些标志位被置起来而同步做某个事件。
EventGroupHandle_t EventGroupHandler; //事件标志组句柄
#define EVENTBIT_0 (1<<0) //事件位
#define EVENTBIT_1 (1<<1)
#define EVENTBIT_2 (1<<2)
#define EVENTBIT_ALL (EVENTBIT_0|EVENTBIT_1|EVENTBIT_2)int main(void)
{//创建开始任务
}//开始任务任务函数
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //进入临界区//创建事件标志组EventGroupHandler=xEventGroupCreate(); //创建事件标志组 (1)//创建设置事件位的任务xTaskCreate((TaskFunction_t )eventsetbit_task, (const char* )"eventsetbit_task", (uint16_t )EVENTSETBIT_STK_SIZE, (void* )NULL, (UBaseType_t )EVENTSETBIT_TASK_PRIO, (TaskHandle_t* )&EventSetBit_Handler); //创建事件标志组处理任务xTaskCreate((TaskFunction_t )eventgroup_task, (const char* )"eventgroup_task", (uint16_t )EVENTGROUP_STK_SIZE, (void* )NULL, (UBaseType_t )EVENTGROUP_TASK_PRIO, (TaskHandle_t* )&EventGroupTask_Handler); //创建事件标志组查询任务xTaskCreate((TaskFunction_t )eventquery_task, (const char* )"eventquery_task", (uint16_t )EVENTQUERY_STK_SIZE, (void* )NULL, (UBaseType_t )EVENTQUERY_TASK_PRIO, (TaskHandle_t* )&EventQueryTask_Handler); vTaskDelete(StartTask_Handler); //删除开始任务taskEXIT_CRITICAL(); //退出临界区
}//设置事件位的任务
void eventsetbit_task(void *pvParameters)
{u8 key;while(1){if(EventGroupHandler!=NULL){key=KEY_Scan(0);switch(key){case KEY1_PRES:xEventGroupSetBits(EventGroupHandler,EVENTBIT_1); break;case KEY2_PRES:xEventGroupSetBits(EventGroupHandler,EVENTBIT_2); break;}}vTaskDelay(10); //延时 10ms,也就是 10 个时钟节拍}
}//事件标志组处理任务
void eventgroup_task(void *pvParameters)
{EventBits_t EventValue;while(1){if(EventGroupHandler!=NULL){//等待事件组中的相应事件位EventValue=xEventGroupWaitBits((EventGroupHandle_t )EventGroupHandler, (4)(EventBits_t ) EVENTBIT_ALL,(BaseType_t )pdTRUE,(BaseType_t )pdTRUE,(TickType_t )portMAX_DELAY);printf("事件标志组的值:%d\r\n",EventValue);}else{vTaskDelay(10); //延时 10ms,也就是 10 个时钟节拍}}
}
//事件查询任务
void eventquery_task(void *pvParameters)
{EventBits_t NewValue,LastValue;while(1){if(EventGroupHandler!=NULL){NewValue=xEventGroupGetBits(EventGroupHandler); //获取事件组的 (5)if(NewValue!=LastValue){LastValue=NewValue;printf("事件标志组的值:%d\r\n",NewValue);}}vTaskDelay(50); //延时 50ms,也就是 50 个时钟节拍}
}
//中断服务函数
void EXTI3_IRQHandler(void)
{BaseType_t Result,xHigherPriorityTaskWoken;delay_xms(50); //消抖if(KEY0==0){Result=xEventGroupSetBitsFromISR(EventGroupHandler,EVENTBIT_0,\ (1)&xHigherPriorityTaskWoken);if(Result!=pdFAIL){portYIELD_FROM_ISR(xHigherPriorityTaskWoken);}}__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); //清除中断标志位
}

任务通知模拟二值信号量

//DataProcess_task 函数
void DataProcess_task(void *pvParameters)
{u32 NotifyValue;while(1){
//第一个参数设置为 pdTRUE。模拟二值信号量,所以需要在获取任务通知以后将任务通知值清零NotifyValue=ulTaskNotifyTake(pdTRUE,portMAX_DELAY); //获取任务通知 (1)if(NotifyValue==1){ //清零之前的任务通知值为 1,说明任务通知有效 (2)//处理串口中断发送过来的数据,调用全局buffer}else {vTaskDelay(10); //延时 10ms,也就是 10 个时钟节拍}}
}extern TaskHandle_t DataProcess_Handler;; //接收任务通知的任务句柄
//串口 1 中断服务程序
void USART1_IRQHandler(void)
{BaseType_t xHigherPriorityTaskWoken;......//接收数据处理
//接收到数据,并且接收任务通知的任务有效if((USART_RX_STA&0x8000)&&(DataProcess_Handler!=NULL)){vTaskNotifyGiveFromISR(DataProcess_Handler,&xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换}
}

任务通知模拟计数型信号量

//释放计数型信号量任务函数
void SemapGive_task(void *pvParameters)
{while(1){if(SemapTakeTask_Handler!=NULL) {switch(KEY_Scan(0)){case WKUP_PRES:xTaskNotifyGive(SemapTakeTask_Handler);//发送任务通知 break;}}vTaskDelay(10); //延时10ms,也就是 10 个时钟节拍}
}
//获取计数型信号量任务函数
void SemapTake_task(void *pvParameters)
{uint32_t NotifyValue;while(1){NotifyValue=ulTaskNotifyTake(pdFALSE,portMAX_DELAY);//获取任务通知//NotifyValue 要减一才是当前的任务通知值LCD_ShowxNum(166,111,NotifyValue-1,3,16,0); //显示当前任务通知值vTaskDelay(1000); //延时 1s,也就是 1000 个时钟节拍}
}

任务通知模拟消息邮箱

int main(void)
{//创建开始任务
}
//开始任务任务函数
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //进入临界区//创建 TASK1 任务xTaskCreate((TaskFunction_t )task1_task, (const char* )"task1_task",(uint16_t )TASK1_STK_SIZE, (void* )NULL, (UBaseType_t )TASK1_TASK_PRIO, (TaskHandle_t* )&Task1Task_Handler); //创建按键处理任务xTaskCreate((TaskFunction_t )Keyprocess_task, (const char* )"keyprocess_task", (uint16_t )KEYPROCESS_STK_SIZE,(void* )NULL,(UBaseType_t )KEYPROCESS_TASK_PRIO,(TaskHandle_t* )&Keyprocess_Handler); vTaskDelete(StartTask_Handler); //删除开始任务taskEXIT_CRITICAL(); //退出临界区
}
//task1 任务函数
void task1_task(void *pvParameters)
{u8 key,i=0;BaseType_t err;while(1){key=KEY_Scan(0); //扫描按键if((Keyprocess_Handler!=NULL)&&(key)) {err=xTaskNotify((TaskHandle_t )Keyprocess_Handler, //任务句柄 (uint32_t )key, //任务通知值(eNotifyAction )eSetValueWithOverwrite); //覆写的方式if(err==pdFAIL){printf("任务通知发送失败\r\n");}}vTaskDelay(10); //延时 10ms,也就是 10 个时钟节拍}
}
//Keyprocess_task 函数
void Keyprocess_task(void *pvParameters)
{uint32_t NotifyValue;BaseType_t err;while(1){err=xTaskNotifyWait((uint32_t )0x00, //进入函数的时候不清除任务 bit (2)(uint32_t )ULONG_MAX,//退出函数的时候清除所有的 bit(uint32_t* )&NotifyValue, //保存任务通知值(TickType_t )portMAX_DELAY); //阻塞时间if(err==pdTRUE){ //获取任务通知成功switch((u8)NotifyValue){case WKUP_PRES: //KEY_UP 控制 LED1break;case KEY2_PRES: //KEY2 控制蜂鸣器break;case KEY0_PRES: //KEY0 刷新 LCD 背景break;}}}
}

任务通知模拟事件标志组

int main(void)
{//创建开始任务
}//开始任务任务函数
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //进入临界区//创建设置事件位的任务xTaskCreate((TaskFunction_t )eventsetbit_task, (const char* )"eventsetbit_task", (uint16_t )EVENTSETBIT_STK_SIZE, (void* )NULL, (UBaseType_t )EVENTSETBIT_TASK_PRIO, (TaskHandle_t* )&EventSetBit_Handler); //创建事件标志组处理任务xTaskCreate((TaskFunction_t )eventgroup_task, (const char* )"eventgroup_task", (uint16_t )EVENTGROUP_STK_SIZE, (void* )NULL, (UBaseType_t )EVENTGROUP_TASK_PRIO, (TaskHandle_t* )&EventGroupTask_Handler); vTaskDelete(StartTask_Handler); //删除开始任务taskEXIT_CRITICAL();            //退出临界区
}//设置事件位的任务
void eventsetbit_task(void *pvParameters)
{while(1){if(EventGroupTask_Handler!=NULL){switch(KEY_Scan(0)){case KEY1_PRES:xTaskNotify((TaskHandle_t )EventGroupTask_Handler, (uint32_t )EVENTBIT_1,(eNotifyAction )eSetBits);break;case KEY2_PRES:xTaskNotify((TaskHandle_t )EventGroupTask_Handler,(uint32_t )EVENTBIT_2,(eNotifyAction )eSetBits);break;}}vTaskDelay(10); //延时 10ms,也就是 10 个时钟节拍}
}//事件标志组处理任务
void eventgroup_task(void *pvParameters)
{u8 num=0,enevtvalue;static u8 event0flag,event1flag,event2flag;uint32_t NotifyValue;BaseType_t err;while(1){err=xTaskNotifyWait((uint32_t )0x00, //	获取任务通知值,进入函数的时候不清除任务 bit (3)(uint32_t )ULONG_MAX, //退出函数的时候清除所有的 bit(uint32_t* )&NotifyValue, //保存任务通知值(TickType_t )portMAX_DELAY);//阻塞时间if(err==pdPASS){ //任务通知获取成功if((NotifyValue&EVENTBIT_0)!=0){//事件 0 发生 (4)event0flag=1;}else if((NotifyValue&EVENTBIT_1)!=0){//事件 1 发生event1flag=1;}else if((NotifyValue&EVENTBIT_2)!=0){//事件 2 发生event2flag=1;}enevtvalue=event0flag|(event1flag<<1)|(event2flag<<2); //模拟事件标志组值(5)printf("任务通知值为:%d\r\n",enevtvalue);if((event0flag==1)&&(event1flag==1)&&(event2flag==1)){//三个事件都同时发生//处理同时发生的同步事件event0flag=0; //标志清零event1flag=0;event2flag=0;}}else{printf("任务通知获取失败\r\n");}}
}
//事件标志组句柄
extern TaskHandle_t EventGroupTask_Handler;
//中断服务函数
void EXTI3_IRQHandler(void)
{BaseType_t xHigherPriorityTaskWoken;delay_xms(50); //消抖if(KEY0==0){xTaskNotifyFromISR((TaskHandle_t )EventGroupTask_Handler, //任务句柄 (uint32_t )EVENTBIT_0,    //要更新的 bit(eNotifyAction )eSetBits, //更新指定的 bit(BaseType_t* )xHigherPriorityTaskWoken);portYIELD_FROM_ISR(xHigherPriorityTaskWoken);}__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); //清除中断标志位
}

UCOS使用示例

信号量使用

信号量访问共享资源区/
OS_SEMMY_SEM; //定义一个信号量,用于访问共享资源OSSemCreate ((OS_SEM* )&MY_SEM, //创建信号量,指向信号量(CPU_CHAR* )"MY_SEM", //信号量名字(OS_SEM_CTR )1,       //信号量值为1,可以理解开始有个任务就可以请求到信号量(OS_ERR* )&err);//错误码void task1_task(void *p_arg)
{OS_ERR err;u8 task1_str[]="First task Running!";//请求信号量,参数2:0为死等;参数3:表示信号量无效任务挂起等待信号量;参数4:时间戳OSSemPend(&MY_SEM,0,OS_OPT_PEND_BLOCKING,0,&err);memcpy(share_resource,task1_str,sizeof(task1_str));//向共享资源区拷贝数据delay_ms(200);printf("%s\r\n",share_resource);       //串口输出共享资源区数据OSSemPost(&MY_SEM,OS_OPT_POST_1,&err); //发送信号量
}
void task2_task(void *p_arg)
{OS_ERR err;u8 task2_str[]="Second task Running!";OSSemPend(&MY_SEM,0,OS_OPT_PEND_BLOCKING,0,&err);  //请求信号量(3)memcpy(share_resource,task2_str,sizeof(task2_str));//向共享资源区拷贝数据delay_ms(200);printf("%s\r\n",share_resource);        //串口输出共享资源区数据//OS_OPT_POST_1表示向信号量优先级高的任务发送信号量OSSemPost(&MY_SEM,OS_OPT_POST_1,&err);//发送信号量 
}
/信号量用于任务同步实验
OS_SEM SYNC_SEM; //定义一个信号量,用于任务同步
OSSemCreate ((OS_SEM* )&SYNC_SEM,//创建信号量,指向信号量(CPU_CHAR* )"SYNC_SEM",//信号量名字(OS_SEM_CTR )0,        //信号量值为0(OS_ERR* )&err);       //错误码void task1_task(void *p_arg)
{OS_ERR err;if(KEY_Scan(0)==WKUP_PRES){OSSemPost(&SYNC_SEM,OS_OPT_POST_1,&err);//发送信号量LCD_ShowxNum(150,111,SYNC_SEM.Ctr,3,16,0); //显示信号量值 }
}void task2_task(void *p_arg)
{OS_ERR err;//OS_OPT_PEND_BLOCKING:表示信号量无效任务挂起等待信号量//如是OS_OPT_POST_ALL 向等待该信号量的所有任务发送信号量。OSSemPend(&SYNC_SEM,0,OS_OPT_PEND_BLOCKING,0,&err); //请求信号量LCD_ShowxNum(150,111,SYNC_SEM.Ctr,3,16,0); //显示信号量值OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);//延时1s
}

 内建信号量

//内建信号量///
void task1_task(void *p_arg)
{OS_ERR err;if(KEY_Scan(0) == WKUP_PRES){//OS_OPT_POST_NONE:不指定特定的选项OSTaskSemPost(&Task2_TaskTCB,OS_OPT_POST_NONE,&err);//使用系统内建信号量向任务task2发送信号量LCD_ShowxNum(150,111,Task2_TaskTCB.SemCtr,3,16,0); //显示信号量值}
}void task2_task(void *p_arg)
{OS_ERR err; //参数1:超时时间,0为一直等待信号量;2:信号量被占用则挂起等待;3:时间戳OSTaskSemPend(0,OS_OPT_PEND_BLOCKING, 0,&err);//请求任务内建的信号量LCD_ShowxNum(150,111,Task2_TaskTCB.SemCtr,3,16,0);//显示任务内建信号量值
}

消息传递

消息队列相关函数

消息队列//
#define KEYMSG_Q_NUM 1 //按键消息队列的数量
#define DATAMSG_Q_NUM 4 //发送数据的消息队列的数量
OS_Q KEY_Msg; //定义一个消息队列,用于按键消息传递,模拟消息邮箱
OS_Q DATA_Msg; //定义一个消息队列,用于发送数据void start_task(void *p_arg)
{//......OSQCreate ( (OS_Q* )&KEY_Msg,//指向一个消息队列(CPU_CHAR* )"KEY Msg",//消息队列名称(OS_MSG_QTY )KEYMSG_Q_NUM, //消息队列长度,这里设置为 1(OS_ERR* )&err); //错误码
//创建消息队列 DATA_MsgOSQCreate ( (OS_Q* )&DATA_Msg, //指向一个消息队列(CPU_CHAR* )"DATA Msg",//消息队列的名称(OS_MSG_QTY )DATAMSG_Q_NUM,//消息队列的个数这里是4(OS_ERR* )&err);//错误码
}void tmr1_callback(void *p_tmr,void *p_arg)
{//......sprintf((char*)pbuf,"ALIENTEK %d",msg_num);//发送消息OSQPost((OS_Q* )&DATA_Msg,//指向一个消息队列(void* )pbuf,     //指向要发送的内容void指针(OS_MSG_SIZE )10, //要发送的消息大小,单位字节(OS_OPT )OS_OPT_POST_FIFO,//发送消息操作类型,这里表示发送消息报错队列尾部(OS_ERR* )&err);  //错误码	
}void main_task(void *p_arg)
{u8 key = KEY_Scan(0); //扫描按键//发送消息OSQPost((OS_Q* )&KEY_Msg,(void* )&key,(OS_MSG_SIZE )1,(OS_OPT )OS_OPT_POST_FIFO,(OS_ERR* &err);u8 msgq_remain_size = DATA_Msg.MsgQ.NbrEntriesSize-DATA_Msg.MsgQ.NbrEntries;//消息队列剩余大小sprintf((char*)p,"Total Size:%d",DATA_Msg.MsgQ.NbrEntriesSize);//显示 DATA_Msg 消息队列总的大小
}void Keyprocess_task(void *p_arg)
{u8 num;u8 *key;OS_MSG_SIZE size;OS_ERR err;key=OSQPend((OS_Q* )&KEY_Msg, //指向一个消息队列,整个函数反回的是指针消息数据(OS_TICK )0,     //指定时间没有接收到数据任务就被唤醒,0一直等(OS_OPT )OS_OPT_PEND_BLOCKING,//一直等,直到接收到消息(OS_MSG_SIZE* )&size,//接收消息的字节长度(CPU_TS* )0,//指向一个时间戳(OS_ERR* )&err);//错误码
}
void msgdis_task(void *p_arg)
{u8 *p;OS_MSG_SIZE size;OS_ERR err; p=OSQPend(  (OS_Q* )&DATA_Msg, (OS_TICK )0,(OS_OPT )OS_OPT_PEND_BLOCKING,(OS_MSG_SIZE* )&size;(CPU_TS* )0,(OS_ERR* )&err);LCD_ShowString(5,270,100,16,16,p);
}

 任务内建消息队列

#define TASK_Q_NUM 4 //任务内建消息队列的长度void tmr1_callback(void *p_tmr,void *p_arg)
{//......sprintf((char*)pbuf,"ALIENTEK %d",msg_num);OSTaskQPost((OS_TCB* )&Msgdis_TaskTCB, //向任务msgdis_task发送消息(void* )pbuf,      //指向要发送的内容void指针(OS_MSG_SIZE )10,  //指定要发送消息的大小(OS_OPT )OS_OPT_POST_FIFO,//发送消息报错在队列末尾(OS_ERR* )&err);//错误码
}void msgdis_task(void *p_arg)
{//......u8 *p;OS_MSG_SIZE size;OS_ERR err; p=OSTaskQPend((OS_TICK )0, //超时时间没有接收到数据任务就被唤醒(OS_OPT )OS_OPT_PEND_BLOCKING, //一直等待,直到接收到消息(OS_MSG_SIZE* )&size,  //消息的大小(CPU_TS* )0,  //时间戳(OS_ERR* )&err ); //错误码LCD_ShowString(40,270,100,16,16,p);//P为接收到的数据指针
}

事件标志组

事件标志组//
#define KEY0_FLAG 0x01
#define KEY1_FLAG 0x02
#define KEYFLAGS_VALUE 0X00
OS_FLAG_GRP EventFlags; //定义一个事件标志组void start_task(void *p_arg)
{//......OSFlagCreate((OS_FLAG_GRP* )&EventFlags, //指向事件标志组(CPU_CHAR* )"Event Flags", //名字(OS_FLAGS )KEYFLAGS_VALUE, //事件标志组初始值(OS_ERR* )&err); //错误码
}//向事件标志组 EventFlags 发送标志
void main_task(void *p_arg)
{//......//按下按键1发送flags_num=OSFlagPost((OS_FLAG_GRP*)&EventFlags,//指向事件标志组(OS_FLAGS )KEY0_FLAG,//决定哪些位清零和置位(OS_OPT )OS_OPT_POST_FLAG_SET,//对位进行置位操作,也可清零(OS_ERR* )&err);//返回错误码//按下按键2发送
//向事件标志组 EventFlags 发送标志flags_num=OSFlagPost((OS_FLAG_GRP*)&EventFlags,(OS_FLAGS )KEY1_FLAG,(OS_OPT )OS_OPT_POST_FLAG_SET,(OS_ERR* )&err);				 
}
void flagsprocess_task(void *p_arg)
{//......OS_ERR err; //等待事件标志组OSFlagPend((OS_FLAG_GRP* )&EventFlags, //指向事件标准组(OS_FLAGS )KEY0_FLAG+KEY1_FLAG,//等待 bit0和bit1时,值就为 0X03。(OS_TICK )0,//等待超时时间,为0则一直等待下去(OS_OPT )OS_OPT_PEND_FLAG_SET_ALL+\//多种配置模式:当前配置为等待所有位OS_OPT_PEND_FLAG_CONSUME,//保留事件标志的状态(CPU_TS* )0,//时间戳(OS_ERR* )&err);//返回错误码printf("事件标志组 EventFlags 的值:%d\r\n",EventFlags.Flags);
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com