FreeRTOS学习
前言
Cotex-M3 的 NVIC 最多支持 240 个 IRQ(中断请求)、1 个不可屏蔽中断(NMI)、1 个 Systick(滴
答定时器)定时器中断和多个系统异常。
提示:以下是本篇文章正文内容,下面案例可供参考
一、中断管理
一、优先级分组(区分)
如果使用 ALIENTEK 的基础例程的话默认配置的组 2,所以在将基础例程中的外设驱动移
植到 FreeRTOS 下面的时候需要修改优先级配置。主要是 FreeRTOS 的中断配置没有处理亚优
先级这种情况,所以只能配置为组 4,直接就 16 个优先级,使用起来也简单!
二、FreeRTOS开关中断
FreeRTOS 开关中断函数为 *portENABLE_INTERRUPTS ()*和 portDISABLE_INTERRUPTS(),
这两个函数其实是宏定义,在 portmacro.h 中有定义,如下:
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI(0)
三、临界段代码
临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段,比如有的外设
的初始化需要严格的时序,初始化过程中不能被打断。FreeRTOS 在进入临界段代码的时候需要
关闭中断,当处理完临界段代码以后再打开中断。FreeRTOS 系统本身就有很多的临界段代码,
这些代码都加了临界段代码保护,我们在写自己的用户程序的时候有些地方也需要添加临界段
代码保护。
FreeRTOS 与 临 界 段 代 码 保 护 有 关 的 函 数 有 4 个 :
taskENTER_CRITICAL()
taskEXIT_CRITICAL()
taskENTER_CRITICAL_FROM_ISR()
taskEXIT_CRITICAL_FROM_ISR()
这四个函数其实是宏定义,在 task.h 文件中有定义。这四个函数的区别是前两个是***任务级***的临界段代码保护,后两个是***中断级***的临界段代码保护
void taskcritical_test(void)
{
while(1)
{
taskENTER_CRITICAL(); (1)//进入临界区
total_num+=0.01f;
printf("total_num 的值为: %.4f\r\n",total_num);
taskEXIT_CRITICAL(); (2)//退出临界区
vTaskDelay(1000);
} }
注意临界区代码一定要精简!(因为进入临界区会关闭中断,这样会导致优先级低于 configMAX_SYSCALL_INTERRUPT_PRIORITY的中断得不到及时响应 )
只有所有的临界段代码都退出以后才会使能中断
四、
最低中断优先级15、最高中断优先级5
0-4不归FreeRTOS管理,5-15FreeRTOS可管理
二、中断测试实验
1.实验要求
2.相关代码
问题:
注意:这里的delay_xms()不会引起任何任务调度,建议不使用vTaskDelay();
主要代码
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "FreeRTOS.h"
#include "task.h"
//ÈÎÎñÓÅÏȼ¶
#define START_TASK_PRIO 1
//ÈÎÎñ¶ÑÕ»´óС
#define START_STK_SIZE 256
//ÈÎÎñ¾ä±ú
TaskHandle_t StartTask_Handler;
//ÈÎÎñº¯Êý
void start_task(void *pvParameters);
//ÈÎÎñÓÅÏȼ¶
#define INTERRUPT_TASK_PRIO 2
//ÈÎÎñ¶ÑÕ»´óС
#define INTERRUPT_STK_SIZE 256
//ÈÎÎñ¾ä±ú
TaskHandle_t INTERRUPTTask_Handler;
//ÈÎÎñº¯Êý
void interrupt_task(void *p_arg);
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//ÉèÖÃϵͳÖжÏÓÅÏȼ¶·Ö×é4
delay_init(); //ÑÓʱº¯Êý³õʼ»¯
uart_init(115200); //³õʼ»¯´®¿Ú
LED_Init(); //³õʼ»¯LED
TIM3_Int_Init(10000-1,7200-1); //³õʼ»¯¶¨Ê±Æ÷3£¬¶¨Ê±Æ÷ÖÜÆÚ1S
TIM5_Int_Init(10000-1,7200-1); //³õʼ»¯¶¨Ê±Æ÷5£¬¶¨Ê±Æ÷ÖÜÆÚ1S
//´´½¨¿ªÊ¼ÈÎÎñ
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); //ÈÎÎñ¾ä±ú
vTaskStartScheduler(); //¿ªÆôÈÎÎñµ÷¶È
}
//¿ªÊ¼ÈÎÎñÈÎÎñº¯Êý
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //½øÈëÁÙ½çÇø
//´´½¨ÖжϲâÊÔÈÎÎñ
xTaskCreate((TaskFunction_t )interrupt_task, //ÈÎÎñº¯Êý
(const char* )"interrupt_task", //ÈÎÎñÃû³Æ
(uint16_t )INTERRUPT_STK_SIZE, //ÈÎÎñ¶ÑÕ»´óС
(void* )NULL, //´«µÝ¸øÈÎÎñº¯ÊýµÄ²ÎÊý
(UBaseType_t )INTERRUPT_TASK_PRIO, //ÈÎÎñÓÅÏȼ¶
(TaskHandle_t* )&INTERRUPTTask_Handler); //ÈÎÎñ¾ä±ú
vTaskDelete(StartTask_Handler); //ɾ³ý¿ªÊ¼ÈÎÎñ
taskEXIT_CRITICAL(); //Í˳öÁÙ½çÇø
}
//ÖжϲâÊÔÈÎÎñº¯Êý
void interrupt_task(void *pvParameters)
{
static u32 total_num=0;
while(1)
{
total_num+=1;
if(total_num==5)
{
portDISABLE_INTERRUPTS(); //¹Ø±ÕÖжÏ
delay_xms(5000); //ÑÓʱ5s
portENABLE_INTERRUPTS();
}
LED0=~LED0;
vTaskDelay(1000);
}
}
总结
今天学了比较重要的中断管理以及中断优先级设置时注意的一些小细节,真不错~
继续加油!