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);//挂起任务 1
		break;
		case KEY1_PRES:
		vTaskResume(Task1Task_Handler);//恢复任务 1
		break;
		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_Queue
	Key_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_Queue
				switch(key){
				case WKUP_PRES: //KEY_UP 控制 LED1
				break;
				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_Queue
		 err=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 控制 LED1
			break;
			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_Msg
	OSQCreate ( (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);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值