FreeRTOS学习历程
总结:
关键词:动态创建 静态创建 任务级 中断级
一个任务至少有一个 do
{
vtaskDelay(10);
}while(1);
0.0FreeRTOSv9.0移植
0.1任务相关API函数(*打开相应的宏)
*uxTaskPriorityGet("任务句柄");
*vTaskPrioritySet("任务句柄","任务优先级");
*uxTaskGetSystemState("任务状态","任务状态数组大小","系统中的运行时间");
*uxTaskGetNumberOfTasks();
*xTaskGetCurrentTaskHandle();
*xTaskGetHandle("任务名字");
*uxTaskGetStackHighWaterMark("任务句柄");
eTaskGetState("任务句柄");
xTaskGetTickCount();
相对重要API函数:
vTaskList("定义缓冲区");
vTaskGetRunTimeStats:
打开相应的宏:
configGENERATE_RUN_TIME_STATS 1
configUSE_STATS_FORMATTING_FUNCTIONS 1
之后需要自实现两个宏定义:
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() ConfigureTimeForRunTimeStats()
#define portGET_RUN_TIME_COUNTER_VALUE() FreeRTOSRunTimeTicks
vTaskGetRunTimeStats("定义缓冲区");
1.任务的动态创建:
遇到错误:( char i=0;
动态创建任务API:
#define START_TASK_PRIO 1
#define START_STK_SIZE 120
void start_tast( void * pvParameters );
TaskHandle_t StartTask_Handler;
xTaskCreate((TaskFunction_t ) start_tast,
(char * ) "start_tast",
(uint16_t ) START_STK_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIO,
(TaskHandle_t * ) &StartTask_Handler);
vTaskStartScheduler();
vTaskDelete(StartTask_Handler);
2.任务的静态创建:
遇到错误:()
重要宏和函数:
configSUPPORT_STATIC_ALLOCATION 1
static StaticTask_t IdleTaskTCB;
static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];
static StaticTask_t TimerTaskTCB;
static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH];
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer,
uint32_t *pulIdleTaskStackSize)
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize)
#define START_STK_SIZE 128
#define START_TASK_PRIO 1
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,
(char * ) "start_task",
(uint32_t ) START_STK_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIO,
(StackType_t * ) StartTaskStack,
(StaticTask_t * ) &StartTaskTCB );
vTaskStartScheduler();
vTaskDelete(StartTask_Handler);
3.任务的挂起和恢复:
遇到错误:()
临界区:(临界区代码一定要精简,临界区会关闭中断,导致优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断得不到及时响应)
任务级临界代码保护:
taskENTER_CRITICAL();
taskEXIT_CRITICAL();
任务:
vTaskSuspend("任务句柄");
vTaskResume("任务句柄");
4.开关中断:
遇到错误:(任务中如果使用到延时函数要使用delay_xms();因为其他延时中带有中断,关闭中断之后可能一调用延时立马就把中断给打开。所以看不到效果 )
需要设置FreeRTOS的PendSV SysTick中断优先级
临界区:(临界区代码一定要精简,临界区会关闭中断,导致优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断得不到及时响应)
中断级临界代码保护:
x = taskENTER_CRITICAL_FROM_ISR();
taskEXIT_CRITICAL_FROM_ISR( x );
中断:
portDISABLE_INTERRUPTS();
portENABLE_INTERRUPTS();
5.列表和列表项:
遇到错误:(在末尾添加列表项,遍历没搞完全清楚)
重要宏和函数:
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1开启列表完整性检查
List_t ListText;
ListItem_t ListItem1;
vListInitialise(&ListText);
vListInitialiseItem(&ListItem1);
vListInsert(&ListText,&ListItem1);
uxListRemove(&ListItem1);
6.时间管理:
相对延时:
vTaskDelay("ms");
绝对延时(相对于相对延时来说):
定义变量:
const TickType_t TimeIncrement = pdMS_TO_TICKS(1000);
PreviousWakeTime = xTaskGetTickCount();
实现:
vTaskDelayUntil(&PreviousWakeTime,TimeIncrement);
7.消息队列:(全局变量尽量不要随意使用)
全局变量的弊端:(可以使用记录当前状态,最忌讳用来传递参数)
0.增加程序之间的耦合性,应用层也要关注驱动层的事情,导致分层不合理与模块化编程相违背
2.阅读比较吃力,可维护性极差,需要找到全局的出处和所有使用的过程,除了原创作者其他人很难维护
3.全局变量任何地方都被修改,使系统变得不可预测,软件安全性得不到保证,导致产品最终走向死亡
4.后期维护非常困难,对于全局满天飞的系统
5.程序初始化就诞生,程序结束才消亡,始终占用数据段上的空间一定程度上造成内存浪费
6.不让维护人员戳你的脊梁骨养成一个良好的编程习惯
全局变量应对之道:
0.全局变量超过3个使用结构体包起来
1.static到需要使用的文件中
2.(返回值)return出去这样属性就是只读,使用起来就不用担心使用时修改值
3.(传参)非要修改值的话可以使用函数传参方式
4.非要非要extern的话要严格控制在自己.h中,不要放到公共的.h中丢人现眼
遇到错误:
创建:
QueueHandle_t Key_Queue;
#define Key_Q_Temp 1
Key_Queue = xQueueCreate(Key_Q_Temp,sizeof(u8));
QueueHandle_t Key_Queue;
#define Key_Q_Temp 1
u8 buff[Key_Queue+1];
StaticQueue_t QueueBuff;
Key_Queue = xQueueCreateStatic(Key_Q_Temp,sizeof(u8),buff,QueueBuff);
任务级:
err = xQueueSend(Key_Queue,&key,10);
err = xQueueSendToBack(Key_Queue,&key,10);
err = xQueueSendToFront(Key_Queue,&key,10);
err = xQueueOverwrite(Key_Queue,&key);
err = xQueueReceive(Key_Queue,&key,portMAX_DELAY);
err = xQueuePeek(Key_Queue,&key,portMAX_DELAY);
中断级:
err = xQueueSendFromISR(Message_Queue,USART_RX_BUF,&HigherPriorityTaskWoken);/ /同下完全一样
err = xQueueSendToBackFromISR(Message_Queue,USART_RX_BUF,&HigherPriorityTaskWoken);
err = xQueueSendToFrontFromISR(Message_Queue,USART_RX_BUF,&HigherPriorityTaskWoken);
err = xQueueOverwriteFromISR(Message_Queue,USART_RX_BUF,&HigherPriorityTaskWoken);
err = xQueueReceiveFromISR(Message_Queue,Message_Buff,&TaskWoken);
err = xQueuePeekFromISR(Message_Queue,Message_Buff);
锁:
上锁:
prvLockQueue();
解锁:
prvUnlockQueue();
8.信号量:(#include "semphr.h")
遇到错误:被按键队列的接收死等给卡死了
优先级翻转:低优先级任务占据信号量时间较长,高优先级任务无法使用此信号量导致高优先级任务阻塞,
使不使用此信号量的比中等优先级任务比高优先级任务早得到CPU的处理
二值信号量创建:(没有优先级继承,适用于同步。优先级翻转问题)
动态创建:
SemaphoreHandle_t BinarySemaphore;
BinarySemaphore = xSemaphoreCreateBinary();
静态创建:
StaticSemaphore_t SemaphoreBuff;
BinarySemaphore = xSemaphoreCreateBinaryStatic(SemaphoreBuff);
计数型信号量创建:
动态创建:
SemaphoreHandle_t CountingSemaphore;
CountingSemaphore = xSemaphoreCreateCounting("MAX","InitValue");
CountingValue = uxSemaphoreGetCount(CountingSemaphore);
静态创建:
SemaphoreHandle_t CountingSemaphore;
StaticSemaphore_t SemaphoreBuffer;
CountingSemaphore = xSemaphoreCreateCountingStatic( "MAX","InitValue",&SemaphoreBuffer );
互斥信号量创建:(有优先级继承,适用于简单的互斥访问。只能用于任务,不能用于中断。优化优先级翻转问题)
动态创建:
SemaphoreHandle_t MutexSemaphore;
MutexSemaphore = xSemaphoreCreateMutex();
静态创建:
SemaphoreHandle_t MutexSemaphore;
StaticSemaphore_t MutexBuffer;
MutexSemaphore = xSemaphoreCreateMutexStatic(&MutexBuffer);
递归互斥信号量创建:(与之前三种信号量的释放和获取不同。只能用于任务,不能用于中断。)
#define configUSE_RECURSIVE_MUTEXES 1;
动态创建:
SemaphoreHandle_t RecursiveMutexSemaphore;
RecursiveMutexSemaphore = xSemaphoreCreateRecursiveMutex();
静态创建:
SemaphoreHandle_t RecursiveMutexSemaphore;
StaticSemaphore_t RecursiveMutexBuffer;
RecursiveMutexSemaphore = xSemaphoreCreateRecursiveMutexStatic(&RecursiveMutexBuffer);
任务级私用信号量释放和获取:(only)
BaseType_t err;
信号量释放:
err = xSemaphoreGiveRecursive(RecursiveMutexSemaphore);
信号量获取:
err = xSemaphoreTakeRecursive(RecursiveMutexSemaphore,"portTICK_PERIOD_MS");
信号量释放和获取:
任务级:
信号量释放:
xSemaphoreGive(BinarySemaphore);
信号量获取:
xSemaphoreTake(BinarySemaphore,portMAX_DELAY);
中断级:
BaseType_t HigherPriorityTaskWoken;
BaseType_t err;
信号量释放:
err = xSemaphoreGiveFromISR(BinarySemaphore,&HigherPriorityTaskWoken);
(当HigherPriorityTaskWoken为psTRUE退出中断服务函数之前一定要进行一次任务切换)
portYIELD_FROM_ISR(HigherPriorityTaskWoken);
信号量获取:
err = xSemaphoreTakeFromISR(BinarySemaphore,&HigherPriorityTaskWoken);
在保存变量(HigherPriorityTaskWoken)为pdTRUE时退出中断服务函数之前一定要进行一次任务切换
9.软件定时器:(#include "timers.h")
遇到错误:
创建:
TimerHandle_t TimerHandle;
void CallbackFunction( TimerHandle_t xTimer );
StaticTimer_t TimerBuffer;
动态创建:
单次/周期定时器:
TimerHandle = xTimerCreate((const char * ) "CallbackFunction",
(TickType_t ) 1000,
(UBaseType_t ) pdFALSE,
(void * ) 1,
(TimerCallbackFunction_t ) CallbackFunction );
静态创建:
单次/周期定时器:
PeriodTimer = xTimerCreateStatic(const char * ) "CallbackFunction",
(TickType_t ) 1000,
(UBaseType_t ) pdFALSE,
(void * ) 2,
(TimerCallbackFunction_t) CallbackFunction,
(StaticTimer_t * ) TimerBuffer );
复位软件定时器:.
BaseType_t err;
BaseType_t HigherPriorityTaskWoken;
任务级:
err = xTimerReset(TimerHandle,0);
中断级:
err = xTimerResetFromISR(TimerHandle,&HigherPriorityTaskWoken);
开启软件定时器:
BaseType_t err;
BaseType_t HigherPriorityTaskWoken;
任务级:
err = xTimerStart(TimerHandle,0);
中断级:
err = xTimerStartFromISR(TimerHandle,&HigherPriorityTask);
关闭软件定时器:
任务级:
err = xTimerStop(TimerHandle,0);
中断级:
err = xTimerStopFromISR(TimerHandle,&HigherPriorityTask);
10.事件标志组:(#include "event_groups.h")
遇到错误:
悉知:事件标志组的高八位不能用,16(16-8)位只能表示8个事件,32位能表示24(32-8)个事件
创建:
EventGroupHandle_t EventGroupHandle;
EventGroupHandle_t EventGroupBuffer;
动态创建:
EventGroupHandle = xEventGroupCreate();
静态创建:
EventGroupHandle = xEventGroupCreateStatic(&EventGroupBuffer);
设置事件位:
#define BIT_0 (1 << 0)
#define BIT_1 (1 << 1)
#define BIT_ALL (BIT_0|BIT_1)
置0:
任务级:
EventBits_t EventGroupValue;
EventGroupValue = xEventGroupClearBits(EventGroupHandle,BIT_0);
中断级:
BaseType_t EventGroupValue;
EventGroupValue = xEventGroupClearBitsFromISR(EventGroupHandle,BIT_0);
置1:
任务级:
EventBits_t EventGroupValue;
EventGroupValue = xEventGroupSetBits(EventGroupHandle,BIT_0);
中断级:
BaseType_t EventGroupValue;
BaseType_t HigherPriorityTaskWoken;
EventGroupValue = xEventGroupSetBitsFromISR(EventGroupHandle,BIT_0,&HigherPriorityTaskWoken);
在保存变量(HigherPriorityTaskWoken)为pdTRUE时退出中断服务函数之前一定要进行一次任务切换
获取事件标志组值:
EventBits_t err;
任务级:
err = xEventGroupGetBits(EventGroupHandle);
中断级:
err = xEventGroupGetBitsFromISR(EventGroupHandle);
等待指定的事件位:
EventBits_t EventValue;
EventValue = xEventGroupWaitBits((EventGroupHandle_t ) EventGroupHandle,
(EventBits_t ) BIT_ALL,
(BaseType_t ) pdFALSE,
(BaseType_t ) pdFALSE,
(TickType_t ) portMAX_DELAY);
11.任务通知:(#include "tasks.h")
遇到错误:
悉知:需要打开宏才能使用 #define configUSE_TASK_NOTIFICATIONS 1
typedef enum
{
eNoAction = 0,
eSetBits,
eIncrement,
eSetValueWithOverwrite,
eSetValueWithoutOverwrite
} eNotifyAction;
发送任务通知:
任务级:
xTaskNotifyGive(Task2Task_Handler);
err = xTaskNotify(Task2Task_Handler,Value,"枚举");
err = xTaskNotifyAndQuery(Task2Task_Handler,Value,"枚举",&PreviousNotifyValue);
中断级:
vTaskNotifyGiveFromISR(Task2Task_Handler,&HigherPriorityTaskWoken);
err = xTaskNotifyFromISR(Task2Task_Handler,value,"枚举",&HigherPriorityTaskWoken);
err = xTaskNotifyAndQueryFromISR(Task2Task_Handler,value,"枚举",&PreviousNotifyValue,&HigherPriorityTaskWoken);
在保存变量(HigherPriorityTaskWoken)为pdTRUE时退出中断服务函数之前一定要进行一次任务切换
获取任务通知:
vlaue = ulTaskNotifyTake(pdTRUE,portMAX_DELAY);
err = xTaskNotifyWait(0,0xffffffff,&NotificationValue,portMAX_DELAY);
12.低功耗Tickless:
打开宏:#define configUSE_TICKLESS_IDLE 1
自定义两个函数对接官方给的宏:
#define configPRE_SLEEP_PROCESSING PreSleepProcessing
#define configPOST_SLEEP_PROCESSING PostSleepProcessing
函数继承声明:
extern void PreSleepProcessing(uint32_t ulExpectedIdleTime);
extern void PostSleepProcessing(uint32_t ulExpectedIdleTime);
主函数进行函数实现:
void PreSleepProcessing(uint32_t ulExpectedIdleTime)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, DISABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, DISABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, DISABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, DISABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, DISABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, DISABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH, DISABLE);
}
void PostSleepProcessing(uint32_t ulExpectedIdleTime)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH, ENABLE);
}
13.空闲任务钩子函数:
打开宏#define configUSE_IDLE_HOOK 1
实现钩子函数 void vApplicationIdleHook(void)
void vApplicationIdleHook(void)
{
__disable_irq();
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
BeforeEnterSleep(void);
__wfi();
AfterExitSleep(void);
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
__enable_irq();
}
14.内存管理:
u8 *buffer;
size_t freemem;
内存申请:
buffer=pvPortMalloc(30);
内存释放:
vPortFree(buffer);
buffer=NULL;
获取剩余内存大小:
freemem = xPortGetFreeHeapSize();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)