zoukankan      html  css  js  c++  java
  • 嵌入式:FreeRTOS的使用(未完)

    为了方便与UCOS对比,顺序按照UCOS那篇编写。

    0、一些移植、系统相关 

    1、框架写法(个人习惯相关)

    1-1、main 函数里创建一个开始任务

    int main(void)
    {
    	初始化外设
    	
        xTaskCreate();   		//创建开始任务   
    				
        vTaskStartScheduler(); 	//开启任务调度
    }
    

    1-2、开始任务里,创建我们要运行的多个任务

    void start_task(void *pvParameters)
    {
        taskENTER_CRITICAL();           //进入临界区
    
        xTaskCreate(); 	//创建任务  1 
        xTaskCreate(); 	//创建任务  2 
        xTaskCreate(); 	//创建任务  3 
    	
        vTaskDelete(StartTask_Handler); //删除开始任务
        taskEXIT_CRITICAL();            //退出临界区
    }
    

    2、任务创建、挂起、删除

    2-0、相关配置

    #define configSUPPORT_DYNAMIC_ALLOCATION        1                       //支持动态内存申请
    //#define configSUPPORT_STATIC_ALLOCATION        	1                       //支持静态内存申请
    #define configTOTAL_HEAP_SIZE					((size_t)(20*1024))     //系统所有总的堆大小,heap_x.h需要,动态申请

    2-1、任务创建(动态)

    //==================任务创建宏定义,便于修改==================
    
    #define START_TASK_PRIO			1		//任务优先级
    #define START_STK_SIZE 			256  	//任务堆栈大小
    
    TaskHandle_t StartTask_Handler;			//任务句柄
    void start_task(void *pvParameters);	//任务函数
    
    //==================任务创建函数==================
    
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
    			(const char*    )"start_task",          //任务名称
    			(uint16_t       )START_STK_SIZE,        //任务堆栈大小
    			(void*          )NULL,                  //传递给任务函数的参数
    			(UBaseType_t    )START_TASK_PRIO,       //任务优先级
    			(TaskHandle_t*  )&StartTask_Handler);   //任务句柄     

    2-2、任务挂起

    vTaskSuspend(Task1Task_Handler);	//挂起任务1
    

    2-3、任务解挂

    2-3-1、任务内任务解挂

    vTaskResume(Task1Task_Handler);	//恢复任务1
    

    2-3-2、中断内任务解挂

    BaseType_t YieldRequired;
    
    YieldRequired=xTaskResumeFromISR(Task1Task_Handler);    //恢复任务1
    
    portYIELD_FROM_ISR(YieldRequired);    //判断是否需要调度到恢复的任务

    2-4、任务删除

    vTaskDelete(Task1Task_Handler);    //删除任务1
    

    2-5、任务创建(静态)

    2-5-1、静态任务创建

    //==================任务创建宏定义,便于修改==================
    
    #define START_TASK_PRIO		1				//任务优先级
    #define START_STK_SIZE 		128  			//任务堆栈大小	
    
    StackType_t StartTaskStack[START_STK_SIZE];	//任务堆栈
    StaticTask_t StartTaskTCB;					//任务控制块
    
    TaskHandle_t StartTask_Handler;				//任务句柄
    void start_task(void *pvParameters);		//任务函数
    
    //==================任务创建函数==================
    
    StartTask_Handler=xTaskCreateStatic((TaskFunction_t	)start_task,		//任务函数
    									(const char* 	)"start_task",		//任务名称
    									(uint32_t 		)START_STK_SIZE,	//任务堆栈大小
    									(void* 		  	)NULL,				//传递给任务函数的参数
    									(UBaseType_t 	)START_TASK_PRIO, 	//任务优先级
    									(StackType_t*   )StartTaskStack,	//任务堆栈
    									(StaticTask_t*  )&StartTaskTCB);	//任务控制块     
    

    2-5-2、静态创建任务还需实现 空闲任务、定时任务

    //==================任务创建宏定义,便于修改==================
    
    static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];			//空闲任务任务堆栈
    static StaticTask_t IdleTaskTCB;									//空闲任务控制块
    
    static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH];	//定时器服务任务堆栈
    static StaticTask_t TimerTaskTCB;									//定时器服务任务控制块
    
    //==================任务创建函数==================
    
    //获取空闲任务地任务堆栈和任务控制块内存
    void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, 
    								   StackType_t **ppxIdleTaskStackBuffer, 
    								   uint32_t *pulIdleTaskStackSize)
    {
    	*ppxIdleTaskTCBBuffer=&IdleTaskTCB;
    	*ppxIdleTaskStackBuffer=IdleTaskStack;
    	*pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;
    }
    
    //获取定时器服务任务的任务堆栈和任务控制块内存
    void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, 
    									StackType_t **ppxTimerTaskStackBuffer, 
    									uint32_t *pulTimerTaskStackSize)
    {
    	*ppxTimerTaskTCBBuffer=&TimerTaskTCB;
    	*ppxTimerTaskStackBuffer=TimerTaskStack;
    	*pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH;
    }
    

      

    3、时间片轮转

    3-0、相关配置(时间片片长 即 1/Tick中断频率)

    #define configUSE_PREEMPTION					1                       //1使用抢占式内核,0使用协程
    #define configUSE_TIME_SLICING					1						//1使能时间片调度(默认式使能的)
    #define configTICK_RATE_HZ						(20)                  	//时钟节拍频率,20HZ = 50ms

    3-1、两个任务优先级相等

    #define TASK1_TASK_PRIO		2
    #define TASK1_STK_SIZE 		128  
    TaskHandle_t Task1Task_Handler;
    void task1_task(void *pvParameters);
    
    #define TASK2_TASK_PRIO		2
    #define TASK2_STK_SIZE 		128  
    TaskHandle_t Task2Task_Handler;
    void task2_task(void *pvParameters);

    4、钩子函数。

    4-0、相关配置

    #define configUSE_IDLE_HOOK						1                       //1,使用空闲钩子;0,不使用
    #define configUSE_TICK_HOOK						1                       //1,使用时间片钩子;0,不使用
    

    4-1、自己实现钩子函数

    void vApplicationIdleHook( void );        //空闲钩子函数
    void vApplicationTickHook( void );        //时钟节拍钩子函数
    


    5、软件定时器

    5-1、软件定时器创建

    //==============定时器结构体、函数声明==============
    
    TimerHandle_t 	MyTimer_Handle;    //定时器句柄
    void ReloadCallback(TimerHandle_t xTimer); 		//定时器回调函数
    
    //==============定时器创建==============
    
    MyTimer_Handle=xTimerCreate((const char*		)"ReloadTimer",			//定时器名称
    							(TickType_t			)1000,					//周期1s(1000个时钟节拍)
    							(UBaseType_t		)pdTRUE,				//周期模式
    							(void*				)1,						//定时器ID
    							(TimerCallbackFunction_t)ReloadCallback);	//定时器回调函数
    

    5-2、定时器“中断服务函数”,回调函数

    void ReloadCallback(TimerHandle_t xTimer)
    {
        //do something
    }
    

    5-3、定时器开启(也有复位效果)

    xTimerStart(MyTimer_Handle,0);	//开启定时器

    5-4、定时器停止

    xTimerStop(MyTimer_Handle,0); 	//关闭定时器
    

    5-5、定时器复位

    xTimerReset(MyTimer_Handle, 0)
    

    6、消息队列

    6-1、消息队列创建

    //================消息队列宏定义================
     
    #define MESSAGE_Q_NUM   4   		//发送数据的消息队列的数量 
    #define MESSAGE_Q_ITEM_NUM	200		//每个消息的空间大小
    QueueHandle_t Message_Queue;		//信息队列句柄
     
    //================消息队列创建================
    
    Message_Queue=xQueueCreate(MESSAGE_Q_NUM,MESSAGE_Q_ITEM_NUM);
    

    6-2、消息发送

    6-2-1、任务内消息发送

    u8 sendData[MESSAGE_Q_ITEM_NUM];
    BaseType_t err;
    
    err=xQueueSend(Message_Queue,&senddata,10);    //10为发送等待时间,有可能队列已满,err = errQUEUE_FULL 或 err = pdPASS
    

    6-2-2、中断内消息发送

    u8 sendData[MESSAGE_Q_ITEM_NUM];
    BaseType_t xHigherPriorityTaskWoken;
    
    xQueueSendFromISR(Message_Queue,sendData,&xHigherPriorityTaskWoken);    //向队列中发送数据,返回值,依然是 满了或Pass,第三个参数是判断高优先级接受到队列后,退出中断,是否需要调度
    
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换

    6-3、消息接收

    6-3-1、任务内消息接收

    u8 *receiveData;
    
    xQueueReceive(Message_Queue,receiveData,portMAX_DELAY)    //返回值为pdPASS 或 errQUEUE_EMPTY,这里等待时间用了portMAX_DELAY阻塞,所以不用再判断了。

    6-3-2、中断内消息接收

    u8 *receiveData;
    
    err=xQueueReceiveFromISR(Message_Queue,receiveData,&xTaskWokenByReceive); //向队列中接受数据,返回值, FAIL或Pass,第三个参数是判断高优先级接受到队列后,退出中断,是否需要调度
    
    portYIELD_FROM_ISR(xTaskWokenByReceive);//如果需要的话进行一次任务切换

    6-4、队列剩余大小

    u8 remain_size;		//消息队列剩余大小
    
    remain_size=uxQueueSpacesAvailable(Message_Queue);	//得到队列剩余大小
    

    6-5、队列使用大小

    u8 used_size;		//消息队列使用大小
    
    used_size=uxQueueMessagesWaiting(Message_Queue);	//得到队列使用大小
    

    7、二值信号量(还有静态创建函数、中断内接受/发送函数,基本同上,不再重复)

    7-1、二值信号量创建

    SemaphoreHandle_t BinarySemaphore;	//二值信号量句柄
    
    BinarySemaphore=xSemaphoreCreateBinary();	//创建二值信号量	
    

    7-2、二值信号量等待

    BaseType_t err;
    
    err = xSemaphoreTake(BinarySemaphore,portMAX_DELAY);	//获取信号量

    7-3、二值信号量发送

    BaseType_t err;
    
    err = xSemaphoreGive(BinarySemaphore);	//释放二值信号量
    

      

    8、计数信号量(还有静态创建函数、中断内接受/发送函数,基本同上,不再重复)

    8-1、计数信号量创建

    SemaphoreHandle_t CountSemaphore;//计数型信号量
    
    CountSemaphore=xSemaphoreCreateCounting(255,0);		//创建计数型信号量,最大计数和初始化计数,参数没改动的话,为long,所以最大值可以设计为不止255
    

    8-2、计数信号量等待

    UBaseType_t semavalue;
    
    xSemaphoreTake(CountSemaphore,portMAX_DELAY); 	//等待数值信号量,阻塞
    
    semavalue=uxSemaphoreGetCount(CountSemaphore); 	//获取数值信号量值
    

    8-3、计数信号量发送

    BaseType_t err;
    
    err=xSemaphoreGive(CountSemaphore);//释放计数型信号量
    

     

    9、互斥信号量(还有静态创建函数,在中断不能用互斥信号量)

    9-1、互斥信号量创建

    SemaphoreHandle_t MutexSemaphore;	//互斥信号量
    
    MutexSemaphore=xSemaphoreCreateMutex();		//创建互斥信号量
    

    9-2、互斥信号量等待

    xSemaphoreTake(MutexSemaphore,portMAX_DELAY);	//获取互斥信号量,因为是阻塞,也就不需要查看什么返回值
    

    9-3、互斥信号量发送

    xSemaphoreGive(MutexSemaphore);					//释放互斥信号量
    

      

    10、递归互斥信号量(还有静态创建函数,在中断不能用递归互斥信号量)

    10-1、递归互斥信号量创建

    SemaphoreHandle_t RecursiveMutex;
    
    RecursiveMutex = xSemaphoreCreateRecursiveMutex();        //创建递归互斥信号量
    

    10-2、递归互斥信号量等待

    xSemaphoreTakeRecursive(RecursiveMutex,10);        //10为等待节拍
    

    10-3、递归互斥信号量发送

    xSemaphoreGiveRecursive(RecursiveMutex);        //发送递归互斥信号量
    

    11、事件标记组(还有静态创建函数、中断内接受/发送函数,基本同上,不再重复)

    11-1、事件标记组创建

    //例子:3个事件
    #define EVENTBIT_0	(1<<0)				
    #define EVENTBIT_1	(1<<1)
    #define EVENTBIT_2	(1<<2)
    #define EVENTBIT_ALL	(EVENTBIT_0|EVENTBIT_1|EVENTBIT_2)
    
    
    EventGroupHandle_t EventGroupHandler;	        //事件标志组句柄
    
    EventGroupHandler=xEventGroupCreate();	 //创建事件标志组
    

    11-2、事件标记组置位

    xEventGroupSetBits(EventGroupHandler,EVENTBIT_1);        //事件1置位
    

    11-3、事件标记组清除置位

    xEventGroupClearBits(EventGroupHandler,EVENTBIT_1);        //事件1清除
    

    11-4、事件标记组值获取

    EventBits_t NewValue;
    
    NewValue = xEventGroupGetBits(EventGroupHandler);	//获取事件组的
    

    11-5、事件标记位组等待

    EventValue=xEventGroupWaitBits((EventGroupHandle_t	)EventGroupHandler,		//句柄	
    							   (EventBits_t			)EVENTBIT_ALL,			//标志位
    							   (BaseType_t			)pdTRUE,				//获取成功后 清除	
    							   (BaseType_t			)pdTRUE,				//等待所有标志位 置位
    							   (TickType_t			)portMAX_DELAY);		//阻塞
    

    12、内存管理

    12-1、内存申请

    u8 *buffer;
    
    buffer=pvPortMalloc(30);			//申请内存,30个字节
    

    12-2、内存释放

    vPortFree(buffer);	//释放内存
    

    12-3、获取内存剩余空间

    u32 freeSize;
    
    freeSize = xPortGetFreeHeapSize();		//获取剩余内存大小

     13、通知

    13-1、通知事件发送(++)

    xTaskNotifyGive(task_Handler);    //给task_Handler发送个通知
    

    13-2、通知事件获取(--,并根据参数是否清0)

    u32 NotifyValue;
    
    NotifyValue=ulTaskNotifyTake(pdTRUE,portMAX_DELAY);	    //获取任务通知,参数1,读完清0,参数2阻塞
    

    13-3、通知值发送

    13-3-1、通知值发送(设置通知值,可发送一个数据)

    u8 data;
    BaseType_t err;
    
    err=xTaskNotify((TaskHandle_t	)Task_Handler,		//接收任务通知的任务句柄
    				(uint32_t		)data,						//任务通知值
    				(eNotifyAction	)eSetValueWithOverwrite);	//覆写的方式发送任务通知
    

    13-3-2、通知值发送(设置通知值,可做标记位组)

    #define EVENTBIT_1	(1<<1)
    
    xTaskNotify((TaskHandle_t	)Task_Handler,		//接收任务通知的任务句柄
    			(uint32_t		)EVENTBIT_1,		//要更新的bit
    			(eNotifyAction	)eSetBits);			//更新指定的bit

    13-4、通知值获取(获取通知值,并判断是否需要清0)

    BaseType_t err;
    uint32_t NotifyValue;
    
    err=xTaskNotifyWait((uint32_t	)0x00,				//进入函数,没有接受到通知,不清除任何bit
    					(uint32_t	)ULONG_MAX,			//退出函数,接受到通知,清除所有(0xffffffffUL)位的bit,
    					(uint32_t*	)&NotifyValue,		//保存任务通知值
    					(TickType_t	)portMAX_DELAY);	//阻塞时间
    

      

      

    ================================================ 为了好与UCOS的文章对比,这些内容也放下面================================================

    1、中断

    1-0、相关配置

    #ifdef __NVIC_PRIO_BITS
    	#define configPRIO_BITS       		__NVIC_PRIO_BITS	//STM32库自带
    #else
    	#define configPRIO_BITS       		4  					//STM32提供4Bit的中断优先级	
    #endif
    
    #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			15                      //中断最低优先级
    #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	5                       //系统可管理的最高中断优先级
    #define configKERNEL_INTERRUPT_PRIORITY 			( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )	//内核中断优先级,用来配置上下文切换、时钟节拍优先级,因为STM32优先级寄存器用高4位,所以要左移
    #define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )	//用来屏蔽中断的阈值,左移原因同上
    
    
    
    #define xPortPendSVHandler 	PendSV_Handler
    #define vPortSVCHandler 	SVC_Handler
    

    1-1、中断处理

    无需特殊处理

    2、临界段处理

    2-1、任务内临界段处理

    taskEXIT_CRITICAL();
    
    //任务处理
    
    taskEXIT_CRITICAL();
    

    2-2、中断内临界段处理

    taskENTER_CRITICAL_FROM_ISR();
    
    //中断内处理
    
    taskEXIT_CRITICAL_FROM_ISR();
    

    3、引起调度函数

    3-1、延时

     vTaskDelay(1000);                           //延时1000个时钟节拍,也就是1s
    
  • 相关阅读:
    自动化测试知识点汇总(200421)
    Mac_使用allure 生成测试报告
    mac_使用Charles抓取Firefox 链接
    工具列表
    Appium_iOS_Safari测试脚本(2)
    日志学习(一)
    java中==和equals的区别(转)
    jackson使用localdatetime转换json出现问题
    js复习--基础
    复习下CSS-零碎要点
  • 原文地址:https://www.cnblogs.com/leonlincq/p/6372323.html
Copyright © 2011-2022 走看看