实时操作系统Freertos开坑学习笔记:(五):任务调度和时间片调度

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、任务调度
    • 1.开启任务调度器函数
    • 2.启动第一个任务
  • 二、任务切换的原理
  • 三、时间片调度
    • 1.基本概念
    • 2.看一个实际例程
      • ①我们设置滴答定时器中断时间为50ms,即一个时间片是50ms,那么任务一有一个delay10ms的延时(这里不能用系统非阻塞延时),算上延时和打印语句,总共可能会执行四次左右,然后一个时间片消耗完,转向任务二也执行4次,二者循环往复
      • ②为什么要加入临界区保护呢?
      • ③现象不解释了,就是次数不断增大。


前言

不多逼逼,直接上内容:
在这里插入图片描述
在这里插入图片描述
这些内容基本上都是讲解源码,比较深,比较枯燥。

一、任务调度

1.开启任务调度器函数

在这里插入图片描述

void vTaskStartScheduler( void )
{BaseType_t xReturn;/* Add the idle task at the lowest priority. */#if ( configSUPPORT_STATIC_ALLOCATION == 1 ){StaticTask_t * pxIdleTaskTCBBuffer = NULL;StackType_t * pxIdleTaskStackBuffer = NULL;uint32_t ulIdleTaskStackSize;/* The Idle task is created using user provided RAM - obtain the* address of the RAM then create the idle task. */vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,configIDLE_TASK_NAME,ulIdleTaskStackSize,( void * ) NULL,       /*lint !e961.  The cast is not redundant for all compilers. */portPRIVILEGE_BIT,     /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */pxIdleTaskStackBuffer,pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */if( xIdleTaskHandle != NULL ){xReturn = pdPASS;}else{xReturn = pdFAIL;}}#else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */{/* The Idle task is being created using dynamically allocated RAM. */xReturn = xTaskCreate( prvIdleTask,configIDLE_TASK_NAME,configMINIMAL_STACK_SIZE,( void * ) NULL,portPRIVILEGE_BIT,  /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */&xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */}#endif /* configSUPPORT_STATIC_ALLOCATION */#if ( configUSE_TIMERS == 1 ){if( xReturn == pdPASS ){xReturn = xTimerCreateTimerTask();}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configUSE_TIMERS */if( xReturn == pdPASS ){/* freertos_tasks_c_additions_init() should only be called if the user* definable macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is* the only macro called by the function. */#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT{freertos_tasks_c_additions_init();}#endif/* Interrupts are turned off here, to ensure a tick does not occur* before or during the call to xPortStartScheduler().  The stacks of* the created tasks contain a status word with interrupts switched on* so interrupts will automatically get re-enabled when the first task* starts to run. */portDISABLE_INTERRUPTS();#if ( configUSE_NEWLIB_REENTRANT == 1 ){/* Switch Newlib's _impure_ptr variable to point to the _reent* structure specific to the task that will run first.* See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html* for additional information. */_impure_ptr = &( pxCurrentTCB->xNewLib_reent );}#endif /* configUSE_NEWLIB_REENTRANT */xNextTaskUnblockTime = portMAX_DELAY;xSchedulerRunning = pdTRUE;xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;/* If configGENERATE_RUN_TIME_STATS is defined then the following* macro must be defined to configure the timer/counter used to generate* the run time counter time base.   NOTE:  If configGENERATE_RUN_TIME_STATS* is set to 0 and the following line fails to build then ensure you do not* have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your* FreeRTOSConfig.h file. */portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();traceTASK_SWITCHED_IN();/* Setting up the timer tick is hardware specific and thus in the* portable interface. */if( xPortStartScheduler() != pdFALSE ){/* Should not reach here as if the scheduler is running the* function will not return. */}else{/* Should only reach here if a task calls xTaskEndScheduler(). */}}else{/* This line will only be reached if the kernel could not be started,* because there was not enough FreeRTOS heap to create the idle task* or the timer task. */configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );}/* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0,* meaning xIdleTaskHandle is not used anywhere else. */( void ) xIdleTaskHandle;/* OpenOCD makes use of uxTopUsedPriority for thread debugging. Prevent uxTopUsedPriority* from getting optimized out as it is no longer used by the kernel. */( void ) uxTopUsedPriority;
}

比较复杂而且难,我也看不懂。后面再说。
在这里插入图片描述

2.启动第一个任务

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
只能说这部分确实是枯燥难懂,我目前也不想花时间了解,等以后有时间再来深入探究吧。

二、任务切换的原理

在这里插入图片描述
任务切换的本质:就是CPU寄存器的切换。
假设当由任务A切换到任务B时,主要分为两步:
第一步:需暂停任务A的执行,并将此时任务A的寄存器保存到任务堆栈,这个过程叫做保存现场;
第二步:将任务B的各个寄存器值(被存于任务堆栈中)恢复到CPU寄存器中,这个过程叫做恢复现场;对任务A保存现场,对任务B恢复现场,这个整体的过程称之为:上下文切换
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
也很复杂,我也不想去深入了解,哎。就先留个图。

三、时间片调度

1.基本概念

在这里插入图片描述
首先,时间片调度机制是针对同等优先级的任务的。
其次,一个时间片大小:在FreeRTOS中,一个时间片就等于SysTick 中断周期,也就是1ms。
重点是这几句话:
在这里插入图片描述

2.看一个实际例程

在这里插入图片描述
注意,两个任务的优先级要相同。
代码如下(示例):

/* 任务一,实现LED0每500ms翻转一次 */
void task1( void * pvParameters )
{uint32_t task1_num = 0;while(1){taskENTER_CRITICAL();               /* 进入临界区 */printf("task1运行次数:%d\r\n",++task1_num);taskEXIT_CRITICAL();                /* 退出临界区 */delay_ms(10);}
}/* 任务二,列表项的插入和删除实验 */
void task2( void * pvParameters )
{uint32_t task2_num = 0;while(1){taskENTER_CRITICAL();               /* 进入临界区 */printf("task2运行次数:%d\r\n",++task2_num);taskEXIT_CRITICAL();                /* 退出临界区 */delay_ms(10);}
}

①我们设置滴答定时器中断时间为50ms,即一个时间片是50ms,那么任务一有一个delay10ms的延时(这里不能用系统非阻塞延时),算上延时和打印语句,总共可能会执行四次左右,然后一个时间片消耗完,转向任务二也执行4次,二者循环往复

②为什么要加入临界区保护呢?

答:因为 printf(“task1运行次数:%d\r\n”,++task1_num);这个语句的执行也会花一点时间,那么如果不加临界段保护,当每执行到第五次时,可能还没有把文本打印完,就到了50ms的时间片了,导致立刻跳到另一个任务执行,使得数据不完整。

③现象不解释了,就是次数不断增大。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/100493.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于JavaScript粒子流动效果

这是一个HTML文件,主要包含了一些CSS样式和JavaScript代码,用于创建一个动画效果。 在CSS部分,定义了一些基本的样式,包括页面的背景颜色、位置、大小等。特别的,定义了两种球形元素(.ball_A 和 .ball_B&am…

51单片机串口通信

文章目录 一、硬件结构1.1 串口硬件结构1.2 串口控制寄存器1.2.1 SCON寄存器1.2.2 PCON寄存器 二、波特率计算三、程序编写3.1 步骤3.2 示例程序 一、硬件结构 1.1 串口硬件结构 有两个物理上独立的接受、发送缓冲器SBUF,占用了同一个地址99H。 在软件编写时&#…

ELK集群搭建流程(实践可用)

一、概述 ELK 是一个由三个开源软件工具组成的数据处理和可视化平台,包括 Elasticsearch、Logstash 和 Kibana。这些工具都是由 Elastic 公司创建和维护的。 Elasticsearch 是一个分布式的搜索和分析引擎,可以将大量数据存储在一个或多个节点上&#xf…

Xilinx FPGA 超温关机保护

在UG480文档,有关于FPGA芯片热管理的介绍。 首先需要理解XADC中的 Over Temperature(OT)和User Temperature的关系。片上温度测量用于关键温度警告,也支持自动关机,以防止设备被永久损坏。片上温度测量在预配置和自动关…

【建议收藏】Kubernetes 网络策略入门:概念、示例和最佳实践,附云原生资料

目录 摘要 一、Kubernetes 网络策略组件 二、实施网络策略 示例 1:在命名空间中限制流量 示例 2:允许特定 Pod 的流量 示例 3:在单个策略中组合入站和出站规则 示例 4:阻止对特定 IP 范围的出站流量 三、Kubernetes 网络策…

Mac 手动安装 sshpass

1. 下载安装包 https://sourceforge.net/projects/sshpass/ 解压并进入到安装包目录 tar -zxvf sshpass-xx.xx.tar.gz cd sshpass-xx.xx2. 检验环境,编译源码安装 ./configuremake&&make install3. 检测安装是否成功 ▶ sshpass Usage: sshpass [-f|-…

Python爬虫(十八)_多线程糗事百科案例

多线程糗事百科案例 案例要求参考上一个糗事百科单进程案例:https://cloud.tencent.com/developer/article/1021994 Queue(队列对象) Queue是python中的标准库,可以直接import Queue引用;队列时线程间最常用的交互数据的形式。 python下多线程的思考…

python-爬虫-xpath方法-批量爬取王者皮肤图片

import requests from lxml import etree获取NBA成员信息 # 发送的地址 url https://nba.hupu.com/stats/players # UA 伪装 google header {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.3…

【MySQL基础|第一篇】——谈谈SQL中的DDL语句

个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【MySQL学习专栏】🎈 本专栏旨在分享学习MySQL的一点学习心得,欢迎大家在评论区讨论💌 前言&#xff…

C# 中什么是重写(子类改写父类方法)

方法重写是指在继承关系中,子类重新实现父类或基类的某个方法。这种方法允许子类根据需要修改或扩展父类或基类的方法功能。在面向对象编程中,方法重写是一种多态的表现形式,它使得子类可以根据不同的需求和场景提供不同的方法实现。 方法重…

基于单片机的点阵电子显示屏上下左右移加减速系统

一、系统方案 本设计的任务就是完成一个1616的点阵设计,并能滚动显示“********************”内容。 主要内容是,能同时流动显示汉字;能实现显示汉字无闪烁;能实屏幕亮度较高。本LED显示屏能够以动态扫描的方式显示一个1616点阵汉…

【WPF C#】PorphyStruct类卟啉和类咕啉的结构分析

前言 首先,热烈祝贺家姐申请到了国家自然科学基金(8月底),找一些化学领域的程序和软件,助我姐一臂之力,顺便自己研究一下源码。 卟啉类化合物的结构分析 PorphyStruct,一种用于分析不同卟啉类非…