前言
FreeRTOS有其特殊的变量命名和函数命名:
比如 char 型变量的前缀是 c,short型变量的前缀是s,long 型变量的前缀是l,portBASE_TYPE 类型变量的前缀是x。还有其他的数据类型,比如数据结构,任务句柄,队列句柄等定义的变量名的前缀也是 x。还包括:如果一个变量是无符号型的那么会有一个前缀 u,如果是一个指针变量则会有一个前缀 p。因此,当我们定义一个无符号的 char 型变量的时候会加一个 uc 前缀,当定义一个char型的指针变量的时候会有一个pc前缀。
函数名的命名:
如果是私有的函数则会加一个prv(private)的前缀。命名的格式一般为:
返回值+源文件名+功能。
如:
①vTaskPrioritySet()函数的返回值为 void 型,在task.c 这个文件中定义。
②xQueueReceive()函数的返回值为 portBASE_TYPE 型,在 queue.c 这个文件中定义。
③vSemaphoreCreateBinary()函数的返回值为 void 型,在 semphr.h 这个文件中定义。
需要注意的事项:
带阻塞时间的函数一般在调度器开始后调用,不然可能没有阻塞时间
带阻塞时间或能引起系统阻塞的函数(如等待信号量等)不能够在中断中使用,但函数名后加FromISR是允许在中断中使用的函数(延时参数为NULL)
使用某些功能要先将对应的宏置1
一、任务的基础操作
①任务句柄 TaskHandle_t StartTask_Handler;
②创建任务 xTaskCreate((TaskFunction_t )start_task, //执行任务的函数名称
(const char* )"start_task", //任务的名称
(uint16_t )128, //任务堆栈大小
(void* )NULL, //参数传递
(UBaseType_t )2, //任务优先级(越大越高)
(TaskHandle_t* )&StartTask_Handler); //任务控制块句柄
返回值为pdPass(BaseType_t类型)表示创建成功,否则返回错误信息。
③删除任务 vTaskDelete(任务句柄)
④开启任务调度 vTaskStartScheduler()
⑤手动任务调度 taskYIELD()
⑥进入临界区 taskENTER_CRITICAL();
⑦退出临界区 taskEXIT_CRITICAL();
二、任务的挂起和解挂
①挂起任务 vTaskSuspend(任务句柄)
②恢复挂起的任务 vTaskResume(任务句柄)
三、消息队列(可多个发送或者多个接收者访问同一个队列)
①消息队列句柄 QueueHandle_t Test_Queue =NULL;
②创建消息队列
Test_Queue = xQueueCreate((UBaseType_t ) QUEUE_LEN, //消息队列包含几个消息
(UBaseType_t ) QUEUE_SIZE); //一个消息多少字节
返回值为任务句柄
③接收消息
uint32_t r_queue; //定义一个接收消息的变量
xQueueReceive( Test_Queue, // 消息队列的句柄
&r_queue, //接收消息的变量地址
portMAX_DELAY); //等待时间
返回值为pdTRUE 表示接收成功
等待时间:0为不等,其他为等待多少ms,portMAX_DELAY是一直等
④发送消息
uint32_t send_data1 = 1; //定义一个发送消息的变量
xQueueSend( Test_Queue, // 消息队列的句柄
&r_queue, //发送的消息内容
portMAX_DELAY); //等待时间
返回值为pdTRUE 表示发送成功
等待时间:0为不等,其他为等待多少ms,portMAX_DELAY是一直等
等效于xQueueSendBack();是向队尾发送消息。xQueueSendToFront(()是向队首发送消息。
四、信号量(互斥信号量解决优先级翻转问题)
①信号量句柄 SemaphoreHandle_t BinarySem_Handle =NULL;
②创建二值信号量 BinarySem_Handle = xSemaphoreCreateBinary();
③创建计数信号量 CountSem_Handle = xSemaphoreCreateCounting(信号量最大值,初值);
④创建互斥信号量 MuxSem_Handle = xSemaphoreCreateMutex();
信号量使用相同的句柄去定义,使用相同的函数释放和接收
⑤获取信号量 xSemaphoreTake(BinarySem_Handle, //信号量句柄
portMAX_DELAY); // 等待时间
若返回值为pdTRUE则证明获取成功
⑥释放信号量 xSemaphoreGive( 信号量句柄 );
若返回值为pdTRUE则证明释放成功
⑦信号量删除 vSemaphoreDelete(句柄)
五、事件(可多个任务等待同一个多条件事件)
①事件句柄 EventGroupHandle_t Event_Handle =NULL;
②创建事件 Event_Handle = xEventGroupCreate();
③等待事件
EventBits_t r_event; //定义一个事件接收变量
r_event = xEventGroupWaitBits(Event_Handle, //事件对象句柄
0x01|0x02, // 接收线程感兴趣的事件 (指定的位)
pdTRUE, //退出时清除参数 2的事件位,dpFalse不清
pdTRUE, //满足感兴趣的所有事件 ,dpFalse满足其一
portMAX_DELAY); //指定超时事件,一直等
返回值r_event为事件中哪些位被置位。
④置位函数 xEventGroupSetBits(句柄,想要置位的位);
返回值为调用函数时事件组中的值
⑤清除指定的位 xEventGroupClearBits(句柄,想要复位的位)
返回值为还没清除事件组中位时的值
⑥ 删除事件 vEventGroupDelete(句柄)
六、软件定时器(精度不如硬件定时器)
①软件定时器句柄 TimerHandle_t Swtmr1_Handle =NULL;
②创建定时器
Swtmr1_Handle=xTimerCreate((const char* )"AutoReloadTimer", //定时器名称
(TickType_t )1000, //定时器周期 1000(tick)
(UBaseType_t )pdTRUE, // 周期模式
(void* )1, //为每个计时器分配一个索引的唯一ID
(TimerCallbackFunction_t)Swtmr1_Callback); //回调函数名
//软件定时器不要调用阻塞函数,也不要进行死循环,应快进快出
void Swtmr1_Callback(void* parameter)
{
TickType_t tick_num1;
tick_num1 = xTaskGetTickCount(); /* 获取滴答定时器的计数值 */
printf("滴答定时器数值=%d\n", tick_num1);
}
③启动定时器 xTimerStart(句柄,阻塞时间);
④停止定时器 xTimerStop(句柄,阻塞时间);
⑤删除定时器 xTimerDelete(句柄,阻塞时间)
七、任务通知(只能向单个任务发送通知)
7.1通知代替消息队列
① 发送通知
uint32_t send2 = 2;
xTaskNotify(Receive2Task_Handler, //任务句柄(哪个任务接收)
send2, // 发送的数据,最大为4字节
eSetValueWithOverwrite ); //覆盖当前通知
若返回值是pdPASS为发送成功
②获取通知
xTaskNotifyWait(0x0, //进入函数的时候不清除任务bit
ULONG_MAX, //退出函数的时候清除所有的bit
&r_num, //保存任务通知值的变量地址
portMAX_DELAY); //阻塞时间
若返回值是pdPASS为接收成功
7.2通知代替二值信号量、计数信号量
①发送通知 xTaskNotifyGive(接收消息的任务的句柄)
若返回值是pdPASS为发送成功
②获取通知 ulTaskNotifyTake(pdTRUE,阻塞时间)
第一个参数若为pdTRUE则在函数退出前将通知值置零,若为pdFALSE则将任务通知值减一(对应二值信号量和计数信号量的使用)
返回值是改变前的通知值
7.3通知代替事件组
①发送通知
xTaskNotify((TaskHandle_t )LED2Task_Handler, //接收任务通知的任务句柄
(uint32_t )0x01, //要触发的事件的位
(eNotifyAction)eSetBits); //设置任务通知值中的位
②接收通知
xTaskNotifyWait(0x0, //进入函数的时候不清除任务bit
ULONG_MAX, //退出函数的时候清除所有的bitR
&r_event, //保存任务通知值
portMAX_DELAY); //阻塞时间
以上发送函数的最后一个参数为更新通知的方式
八、内存管理
① 获取当前内存大小
uint32_t g_memsize;
g_memsize = xPortGetFreeHeapSize();
②申请内存
uint8_t *Test_Ptr = NULL;
Test_Ptr = pvPortMalloc(1024);
③释放内存 vPortFree(Test_Ptr);//释放内存