【吐血总结】FreeRTOS难点、Systick中断-滴答定时器、PendSV中断-任务切换、SVC中断-系统底层、时间片调度-时钟节拍【已完结】

文章详细探讨了FreeRTOS操作系统中的Systick滴答定时器、PendSV中断以及SVC中断在任务调度中的作用。内容包括Systick中断的优先级设置对实时性的影响,SVC中断在任务启动时的角色,以及PendSV如何用于任务切换。文章还提到了时间片调度的概念,并引用了其他博主的相关文章链接,提供了深入学习的资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


🔴🟡🟢其他文章链接,独家吐血整理

【吐血总结】FreeRTOS难点、Systick中断-滴答定时器、PendSV中断-任务切换、SVC中断-系统底层、时间片调度-时钟节拍【已完结】
(第1-8讲)STM32F4单片机,FreeRTOS基础知识总结【视频笔记、代码讲解】【正点原子】【原创】
(第9-10讲)STM32F4单片机,FreeRTOS任务创建和删除(动态方法)【视频笔记、代码讲解】【正点原子】【原创】
(第12讲)STM32F4单片机,FreeRTOS任务创建和删除(静态方法)【视频笔记、代码讲解】【正点原子】【原创】
(第13-14讲)STM32F4单片机,FreeRTOS任务挂起和恢复【视频笔记、代码讲解】【正点原子】【原创】
(第16-17讲)STM32F4单片机,FreeRTOS中断管理简介【视频笔记、代码讲解】【正点原子】【原创】
(第18-19讲)32单片机,FreeRTOS临界段代码保护、任务调度器的挂起和恢复【视频笔记、代码讲解】【原创】
(第20-22讲)STM32F4单片机,FreeRTOS列表和列表项API函数讲解【视频笔记、代码讲解、正点原子】【原创】
(第40-44讲)STM32F4单片机,FreeRTOS信号量【二值、计数、翻转、互斥】【代码讲解】【正点原子】【原创】
(第48-59讲)STM32F4单片机,FreeRTOS【事件标志、任务通知、软件定时器、Tickless低功耗】【纯文字讲解】【原创】

0、2024年1月温故知新(纯文字)

  • 在实时操作系统中,实时性最高的是中断程序,要及时的处理内外部中断,线程内执行的代码因为需要任务调度等,实时性差一些。
  • 如果SysTick优先级调高,影响了用户中断,再加上线程调度本身也不准确,那么整个操作系统没有准确的地方了。因此把SysTick优先级降低,优先保障用户中断的实时性,线程的实时性放到第二位,这样才能体现出操作系统的实时特性。
  • 总结:SysTick中断优先级设置成最高和最低都有缺点,但是设置成最低的缺点可以接受!!!

0、2024年9月补充

在这里插入图片描述

  • 对于文中提到的SysTick和PendSV之间的优先级问题,这里补充了一张参考手册的截图,这里可以看到默认的PendSV的优先级更高一点!SVC的优先级在这三个中是最高!
  • SVC和PendSV中断属于系统内核的东西(没有外部IO通道),它与一般的外部中断有区别(有一个IO通道),SVC中断是一种由用户程序主动触发的异常,用于请求系统服务或调用系统函数。SVC中断的主要用途是产生系统函数的调用请求,例如操作系统提供的系统服务函数。SVC中断由用户程序通过特定的指令(如SVC指令)主动触发,而不是由外部事件或硬件错误触发。
  • PendSV中断通常不由用户程序直接触发,而是由系统内部的任务调度器或中断处理程序根据需要挂起(触发)。PendSV中断的优先级通常设置为最低,以确保在所有其他中断处理完成后才执行。这种设置有助于避免任务切换被高优先级中断打断,从而提高系统的稳定性和实时性。
  • PendSV中断是ARM Cortex系列处理器中的一个特殊异常,主要用于任务调度和上下文切换。它的主要特点是可延时执行,通常在其他中断处理完成后执行,以确保任务切换不会阻碍中断响应。PendSV中断在RTOS(实时操作系统)中广泛应用,作为任务切换的理想选择。

1、Systick滴答定时器

在这里插入图片描述
在这里插入图片描述
Systick异常请求=滴答定时器中断,原子的这颗F429芯片晶振是180MHZ,重装载值是18000,从18000计数减到0是一次心跳周期=1/1000s=1ms,这个systick定时器开启是在开启任务调度函数里面的
在这里插入图片描述
在这里插入图片描述
这个空任务就是空闲任务,任务优先级是0,即任务最低优先级(不是中断优先级)

在这里插入图片描述

其实我仍然不太明白嵌套计数器的含义,前几篇文章也分析过,总觉得理解不对

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

这个时间片计数轮询表述不恰当,这里其实是开启滴答定时器中断,用于PendSV任务切换使用

在这里插入图片描述至于Systick和PendSV两者之间谁的优先级高?这个我也不知道,待补充

开启定时器中断就是滴答定时器,里面有PendSV切换, 第6步里面全是汇编语言,反正我看不懂,待补充

2、SVC中断

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
已经创建好任务了,才进入的SVC中断,SVC中断是讲任务结构体数据依次按地址pop到cpu寄存器中(SVC中断只在启动第一次任务时会调用一次,以后均不调用),这里的使能全局中断相当于汇编语言开启中断,因为前面有进入临界区保护时关掉了中断,此时手动又开启了(具体为什么,我没有详细研究,会用大致上理解就行了)

在这里插入图片描述
绿色颜色很重要,这块原子讲得很详细,建议去看下视频

3、PendSV中断

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

上图中的if( xTaskIncrementTick() != pdFALSE )判断中的xTaskIncrementTick() 函数里面就是一些链表的操作,即列表项之间的判断,插入,删除,阻塞之类的,因为列表项之间判断决定了是否进行任务切换,因为创建任务就是创建了列表

在这里插入图片描述

原子中的delay延时函数内部调用了上面橙色圈的函数,也就是说delay可以导致任务切换

在这里插入图片描述

这个是宏替换之后的PendSV中断函数,全是汇编语言,后面不想看了,太细了也很难

4、💖 Systick、SVC、PendSV小结

  • 定时器中断是在开启任务调度器时开启的Systick中断函数(寄存器开启,1ms进入一次),
  • 里面有PendSV中断函数(寄存器开启,用来根据列表项操作进行任务函数切换),开启任务调度器之后创建了任务(创建任务的同时也就保存了数据),
  • 之后打开了SVC中断(汇编语言,获取任务堆栈地址,将任务数据进行出栈处理给cpu寄存器,用于操作硬件底层)(SVC中断只在启动第一次任务时会调用一次,以后均不调用
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

5、时间片调度

在这里插入图片描述
没用完的时间片丢掉
在这里插入图片描述
在这里插入图片描述
时间片设置的是50ms,这个实验还是比较容易理解滴!因为没有加临界区,导致task1打印一半被阻塞跳到task2接着打印了

        taskENTER_CRITICAL();               /* 进入临界区 */
        printf("task1运行次数:%d\r\n",++task1_num);
        taskEXIT_CRITICAL();                /* 退出临界区 */
        taskENTER_CRITICAL();               /* 进入临界区 */
        printf("task2运行次数:%d\r\n",++task2_num);
        taskEXIT_CRITICAL();                /* 退出临界区 */

解决办法是printf上下加上临界区保护即可

6、🧡 韦东山FreeRTOS部分

void vTask1( void *pvParameters )
{
	const TickType_t xDelay100ms = pdMS_TO_TICKS( 100UL );		
	BaseType_t ret;
	
	/* 任务函数的主体一般都是无限循环 */
	for( ;; )
	{
		/* 打印任务的信息 */
		printf("Task1 is running\r\n");
		
		ret = xTaskCreate( vTask2, "Task 2", 1000, NULL, 2, &xTask2Handle );
		if (ret != pdPASS)
			printf("Create Task2 Failed\r\n");
		
		// 如果不休眠的话, Idle任务无法得到执行
		// Idel任务会清理任务2使用的内存
		// 如果不休眠则Idle任务无法执行, 最后内存耗尽
		vTaskDelay( xDelay100ms );
	}

void vTask2( void *pvParameters )
{	
	/* 打印任务的信息 */
	printf("Task2 is running and about to delete itself\r\n");

	// 可以直接传入参数NULL, 这里只是为了演示函数用法
	vTaskDelete(xTask2Handle);
}

int main( void )
{
	prvSetupHardware();
	
	xTaskCreate(vTask1, "Task 1", 1000, NULL, 1, NULL);

	/* 启动调度器 */
	vTaskStartScheduler();

	/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
	return 0;
}

在这里插入图片描述
在这里插入图片描述
阻塞≠挂起(挂起只能使用具体的挂起函数,阻塞无需),只有freertos自带的taskdelay函数实现了任务切换,即task1被taskdelay挂起,task2执行完之后就delete了自己,因为taskdelay里面调用了vTaskSuspendAll();挂起函数,这里的阻塞就是PendSV里面的列表项操作
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这个tick中断,时间片就是taskdelay延时,taskdelay(1000)就是1000个时间片,这1000ms内这个任务被阻塞,其它任务可以执行,这就是实时操作系统的妙处所在

在这里插入图片描述
svs操作系统底层,pendsv用于任务切换,任务的重要程度肯定比不上系统内核底层,根据上面的小节可知,svs就是获取任务堆栈地址,将任务数据进行出栈处理,用于操作硬件底层

7、💛 其它博主文章链接【转载】

1、FreeRTOS任务切换——PendSV

FreeRTOS任务切换——PendSV
在这里插入图片描述
这篇文章主要就是解释了上面张图,中断可打断PendSV,PendSV的作用,以及具有延时特点。

2、RTOS系列文章(2):PendSV功能,为什么需要PendSV

RTOS系列文章(2):PendSV功能,为什么需要PendSV
这篇文章写得很详细了,和我看完原子视频理解的大差不差

1、将Systick的优先级设置成高于IRQ
在这里插入图片描述
缺点,IRQ=外部中断被耽误,不可容忍

2、将Systick和PendSV的优先级设置为最低
在这里插入图片描述
缺点,IRQ影响Systick时钟,可容忍
3、将SysTick的优先级设置成最高,PendSV的优先级设置为低
在这里插入图片描述
缺点,耽误IRQ,不可容忍

  • 1 PendSV是可悬起系统中断,具有【缓期执行】特征。
  • 2 PendSV一般被嵌入式OS用于 任务调度的上下文切换。
  • 3 使用PendSV时,一般会将PendSV的优先级设置为最低,让外部IRQ先执行,等到没有外部中断后,在执行上下文切换。
  • 4 嵌入式实时操作系统的【实时】概念,并不仅仅指应用程序、任务的调度实时,而是指整个系统的实时性高,具备【可剥夺】特点,当有高优先级的中断、任务具备执行条件时,立刻中断当前正在运行的任务,去执行高优先级的IRQ和高优先级任务。
  • 5 嵌入式OS一般会将SysTick的优先级也设置为最低,保证外部中断IRQ优先,详细的分析,我们下一篇文章讨论。

至于sys中断和pendsv中断谁的优先级更高?不清楚,还是没明白,反正两个都是设置最低!

3、有了Systick中断为什么还要PendSV中断?(此文章有问题,仅作为参考)

有了Systick中断为什么还要PendSV中断?

4、【FreeRTOS】FreeRTOS 源码学习笔记 (5) 任务调度器 + vTaskStartScheduler、xPortPendSVHandler、xPortSysTickHandler

【FreeRTOS】FreeRTOS 源码学习笔记 (5) 任务调度器 + vTaskStartScheduler、xPortPendSVHandler、xPortSysTickHandler

5、FreeRTOS对系统异常优先级寄存器的PendSV和SysTick 的优先级设置过程

FreeRTOS对系统异常优先级寄存器的PendSV和SysTick 的优先级设置过程

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值