FreeRTOS学习笔记(一)

一、基础知识思维导图

在这里插入图片描述
vtaskdelay函数会开启中断,所以在临界区不能用vtaskdelay

二、任务的创建与删除

2.1、任务的动态创建与删除
在这里插入图片描述

........

#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );

#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    task1_handler;
void task1( void * pvParameters );

.........

int main()
{

.......

    xTaskCreate((TaskFunction_t         )   start_task,						//任务函数名
                (char *                 )   "start_task",
                (configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,			//任务堆栈大小
                (void *                 )   NULL,
                (UBaseType_t            )   START_TASK_PRIO,				//任务优先级
                (TaskHandle_t *         )   &start_task_handler );			//任务句柄
	vTaskStartScheduler();
}

void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();               /* 进入临界区 */
    xTaskCreate((TaskFunction_t         )   task1,
                (char *                 )   "task1",
                (configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK1_PRIO,
                (TaskHandle_t *         )   &task1_handler );
    vTaskDelete(NULL);					//删除任务
    taskEXIT_CRITICAL();                /* 退出临界区 */
}

/* 任务一,实现LED0每500ms翻转一次 */
void task1( void * pvParameters )
{
    while(1)
    {
        printf("task1正在运行!!!\r\n");
        LED0_TOGGLE();
        vTaskDelay(500);
    }
}

在这里插入图片描述

三、任务的恢复与挂起

/* 任务三,判断按键KEY0,按下KEY0删除task1 */
void task3( void * pvParameters )
{
    uint8_t key = 0;
    while(1)
    {
        key = key_scan(0);
        if(key == KEY0_PRES)			//按键一按下
        {
            printf("挂起task1\r\n");
            vTaskSuspend(task1_handler);	//任务挂起函数,使用时需将宏 INCLUDE_vTaskSuspend  配置为1。
        }else if(key == KEY1_PRES)		//按键二按下
        {
            printf("在任务中恢复task1\r\n");
            vTaskResume(task1_handler);	
        }
        vTaskDelay(10);
    }
}

如果在中断中用恢复函数需要在函数后带FromISR后缀,vTaskResumeFromISR()

四、freertos中断管理

系统所管理的优先级范围:5~15,也就是说优先级在0-4以内的中断freertos不能控制它们。

五、FreeRTOS临界段代码保护及任务调度器挂起和恢复

5.1、临界代码段

什么是临界段:临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段,如:iic、spi的初始化等。

在这里插入图片描述
在这里插入图片描述

5.2、任务调度器的挂起与恢复

在这里插入图片描述
在这里插入图片描述
1、与临界区不一样的是,挂起任务调度器,未关闭中断;
2、它仅仅是防止了任务之间的资源争夺,中断照样可以直接响应;
3、挂起调度器的方式,适用于临界区位于任务与任务之间;既不用去延时中断,又可以做到临界区的安全;

六、FreeRTOS列表和列表项

6.1、列表相关API函数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
总结:函数vListInsert(),是将待插入列表的列表项按照列表项值升序进行排序,有序地插入到列表中
在这里插入图片描述
总结:函数vListInsertEnd(),是将待插入的列表项插入到列表 pxIndex 指针指向的列表项前面;它是一种无序的插入方法!!
在这里插入图片描述
在这里插入图片描述

七、任务调度

7.1、启动第一个任务

prvStartFirstTask () 	/* 开启第一个任务 */
vPortSVCHandler () 	/* SVC中断服务函数 */

1、中断产生时,硬件自动将xPSR,PC(R15),LR(R14),R12,R3-R0出/入栈;而R4~R11需要手动出/入栈
2、进入中断后硬件会强制使用MSP指针 ,此时LR(R14)的值将会被自动被更新为特殊的EXC_RETURN

7.2、prvStartFirstTask ()函数
用于初始化启动第一个任务前的环境,主要是重新设置MSP 指针,并使能全局中断

什么是MSP指针?
程序在运行过程中需要一定的栈空间来保存局部变量等一些信息。当有信息保存到栈中时,MCU 会自动更新 SP 指针,ARM Cortex-M 内核提供了两个栈空间:
在这里插入图片描述
为什么是 0xE000ED08?
因为需从 0xE000ED08 获取向量表的偏移,为啥要获得向量表呢?因为向量表的第一个是 MSP 指针!取 MSP 的初始值的思路是先根据向量表的位置寄存器 VTOR (0xE000ED08) 来获取向量表存储的地址;在根据向量表存储的地址,来访问第一个元素,也就是初始的 MSP

CM3 允许向量表重定位——从其它地址处开始定位各异常向量 这个就是向量表偏移量寄存器,向量表的起始地址保存的就是主栈指针MSP 的初始值

7.3、vPortSVCHandler ()
当使能了全局中断,并且手动触发 SVC 中断后,就会进入到 SVC 的中断服务函数中
在这里插入图片描述
在这里插入图片描述
7.4、任务切换
任务切换的本质:就是CPU寄存器的切换。

在这里插入图片描述
注意:任务切换的过程在PendSV中断服务函数里边完成
在这里插入图片描述
PendSV中断是如何触发的?
1、滴答定时器中断调用
2、执行FreeRTOS提供的相关API函数:portYIELD()
本质:通过向中断控制和状态寄存器 ICSR 的bit28 写入 1 挂起 PendSV 来启动 PendSV 中断

在这里插入图片描述

总结

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式学习者。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值