当前位置: 首页 > news >正文

RTOS随笔之FreeRTOS启动与同步方法

RTOS启动与同步机制

  • RTOS启动
  • 任务切换场景
  • 任务同步机制
    • 队列
    • 信号量
    • 事件组
    • 任务通知
  • 任务延时

RTOS启动

FreeRTOS在任务创建完成后调用函数vTaskStartScheduler()启动任务调度器。
vTaskStartScheduler()任务启动函数详解

void vTaskStartScheduler( void )
{BaseType_t xReturn;xReturn = xTaskCreate(	prvIdleTask,"IDLE", configMINIMAL_STACK_SIZE,( void * ) NULL,( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),&xIdleTaskHandle );//创建空闲任务,空闲任务优先级最低#if ( configUSE_TIMERS == 1 )//是否使用软件定时器{if( xReturn == pdPASS ){xReturn = xTimerCreateTimerTask();//创建软件定时器任务}else{mtCOVERAGE_TEST_MARKER();}}#endif if( xReturn == pdPASS ){portDISABLE_INTERRUPTS();//关闭中断#if ( configUSE_NEWLIB_REENTRANT == 1 ){_impure_ptr = &( pxCurrentTCB->xNewLib_reent );}#endif xNextTaskUnblockTime = portMAX_DELAY;xSchedulerRunning = pdTRUE;//调度器开始运行xTickCount = ( TickType_t ) 0U;portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();//实现任务统计功能,具体由用户实现if( xPortStartScheduler() != pdFALSE )//初始化任务硬件相关的功能,Systick/PendSV/FPU{//如果调度器启动成功,xPortStartScheduler()没有返回值,不会运行到这里}else{//不会运行到这里,除非调用xTaskEndScheduler()}}else{//创建空闲任务或定时器任务失败,内存不足configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );}//防止编译器报错,INCLUDE_xTaskGetIdleTaskHandle定义为0,编译器会提示( void ) xIdleTaskHandle;
}

xPortStartScheduler()任务硬件相关函数详解

BaseType_t xPortStartScheduler( void )
{portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;//设置PendSV中断为最低优先级portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;//设置Systick中断为最低优先级vPortSetupTimerInterrupt();//设置Systick周期uxCriticalNesting = 0;//初始化临界区嵌套计数prvEnableVFP();//使能FPU浮点运算*( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;//采用惰性压栈的特性自动保存寄存器/*惰性压栈猜测:惰性压栈指的是异常产生时只将通用寄存器的值进行压栈,浮点寄存器值不压栈,除非异常处理函数中存在浮点运算才会将浮点寄存器压栈。具有浮点运算的处理器,总线错误和MemManage错误等异常可能会在惰性压栈期间产生。惰性压栈特性推迟了浮点寄存器的压栈,只有当异常处理中存在浮点运算时才会将浮点寄存器的值先压栈,后执行异常处理中的浮点运算。*/prvStartFirstTask();//在SVC异常中启动第一个任务return 0;
}

prvStartFirstTask()启动第一个任务函数详解

__asm void prvStartFirstTask( void )
{PRESERVE8  ldr r0, =0xE000ED08  //向量表偏移寄存器VTOR的地址,存储栈顶地址,对该寄存器VTOR的值进行解引用获得栈顶地址ldr r0, [r0] //取R0地址处的值赋给R0,R0地址处的值是一个地址ldr r0, [r0] //取R0地址处的值赋给R0, R0地址处的值是栈顶msr msp, r0  //复位栈顶MSPcpsie i      //使能中断(清除PRIMASK)cpsie f      //使能中断(清除FAULTMASK)dsb          //数据同步屏障isb          //指令同步屏障svc 0        //触发SVC异常nopnop
}

vPortSVCHandler()SVC异常处理函数详解

__asm void vPortSVCHandler( void )
{PRESERVE8ldr	r3, =pxCurrentTCB   //获取pxCurrentTCB指针的地址赋值R3ldr r1, [r3]            //获取pxCurrentTCB指针指向的值赋值R1ldr r0, [r1]            //获取R1地址处的值赋值给R0,获取任务栈栈顶指针,即任务控制块的第一个数据就是任务栈顶指针ldmia r0!, {r4-r11, r14}//R4~R11,R14寄存器出栈,栈顶移动36=4x9个字节,用户手动出栈msr psp, r0             //设置进程栈指针,PSP=R0isb                     //指令同步屏障mov r0, #0              //R0=0msr	basepri, r0         //basepri寄存器=0,开中断bx r14                  //硬件自动恢复R0~R3,R12,LR,PC,xPSP值,PC指向下一条指令
}

任务切换场景

任务切换场景:
1.执行系统调用接口(含有taskYIELD()的API)
2.Systick定时器中断

任务在哪里切换:任务在PendSV的异常中切换

__asm void xPortPendSVHandler( void )
{extern uxCriticalNesting;extern pxCurrentTCB;extern vTaskSwitchContext;PRESERVE8mrs r0, psp //读取进程栈指针,保存在R0寄存器中isb  ldr	r3, =pxCurrentTCB //获取当前任务控制块的指针ldr	r2, [r3] //将当前任务控制块的地址保存在R2寄存器中tst r14, #0x10it eq    //判断是否使用FPU,使用的话在进行任务切换的时候要手动保存FPU寄存器到任务栈中vstmdbeq r0!, {s16-s31}//保存S16~S31这16个FPU寄存器stmdb r0!, {r4-r11, r14}//保存R4~R11,R14寄存器str r0, [r2]//将R0的值保存到R2所保存的地址中去,R2保存当前任务控制块的地址,等于更新任务块栈顶指针stmdb sp!, {r3}//将R3的值入栈mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITYmsr basepri, r0//关闭中断进入临界区dsbisbbl vTaskSwitchContext//调用vTaskSwitchContext()获取下一个运行的任务mov r0, #0msr basepri, r0//打开中断,退出临界区ldmia sp!, {r3}//R3的值出栈,新的任务控制块ldr r1, [r3]ldr r0, [r1]//获取新的任务的栈顶指针,保存到R0中ldmia r0!, {r4-r11, r14}//R4~R11,R14出栈tst r14, #0x10it eqvldmiaeq r0!, {s16-s31}//判断当前任务是否使用FPU,是的话手动恢复FPU寄存器msr psp, r0//跟新进程栈指针isb#ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */#if WORKAROUND_PMU_CM001 == 1push { r14 }pop { pc }nop#endif#endifbx r14/*硬件自动恢复R0~R3,R12,LR,PC,xPSP值,确定异常返回后进入处理器模式还是进程模式,使用主栈指针MSP还是进程栈指针PSP。后续进入进程模式,使用进程栈指针,PC的值指向新任务的函数,新任务开始运行*/
}

任务同步机制

  • 队列
  • 信号量(二值/计数/互斥)
  • 事件组
  • 任务通知(消息邮箱)
    在这里插入图片描述

队列

队列传输数据的两种方式:

  • 拷贝:把数据复制进队列
  • 引用:把数据地址复制进队列,数据要做保护

多任务发送队列,怎么区别数据来源:

  • 结构体:ID+数据形式
  • 位拼接:高位表示ID,低位表示数据
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
BaseType_t xQueueReset( QueueHandle_t pxQueue);
void vQueueDelete( QueueHandle_t xQueue );
BaseType_t xQueueSend(QueueHandle_t xQueue,const void *pvItemToQueue,TickType_t xTicksToWait);
BaseType_t xQueueSendToBackFromISR(QueueHandle_t xQueue,const void *pvItemToQueue,BaseType_t *pxHigherPriorityTaskWoken);
BaseType_t xQueueReceive( QueueHandle_t xQueue,void * const pvBuffer,TickType_t xTicksToWait );
BaseType_t xQueueReceiveFromISR(QueueHandle_t xQueue,void *pvBuffer,BaseType_t *pxTaskWoken);
UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue );//返回队列已有数据空间个数
UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue );//返回队列剩余数据空间个数
BaseType_t xQueueOverwrite(QueueHandle_t xQueue,const void * pvItemToQueue);//队列覆盖写
BaseType_t xQueueOverwriteFromISR(QueueHandle_t xQueue,const void * pvItemToQueue,BaseType_t*pxHigherPriorityTaskWoken);
BaseType_t xQueuePeek(QueueHandle_t xQueue,void * const pvBuffer,TickType_t xTicksToWait);//复制队列中的数据,不删除数据,队列中无数据时阻塞
BaseType_t xQueuePeekFromISR(QueueHandle_t xQueue,void *pvBuffer,);

信号量

  • 通知作用
  • 计数型信号,信号初值自定义,发送加1,接收减1
  • 二进制信号,信号初值是0,发送加1,接收减1
  • 互斥信号,防止同时访问共享资源(共享资源:全局变量,静态变量,公共函数)
  • 互斥信号禁止中断中使用
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);
SemaphoreHandle_t xSemaphoreCreateBinary( void );
SemaphoreHandle_t xSemaphoreCreateMutex( void );//互斥锁,他人也能解锁
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void );//递归锁,自己上锁自己解锁,他人无法解锁
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
BaseType_t xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore,BaseType_t *pxHigherPriorityTaskWoken);
BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore,TickType_t xTicksToWait);
BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,BaseType_t *pxHigherPriorityTaskWoken);

事件组

  • 事件发生,广播所有任务
  • 事件可以与或组合
  • 多任务可以同步
EventGroupHandle_t xEventGroupCreate( void );
void vEventGroupDelete( EventGroupHandle_t xEventGroup );
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet );
EventBits_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet ,BaseType_t * pxHigherPriorityTaskWoken);
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToWaitFor,const BaseType_t xClearOnExit,const BaseType_t xWaitForAllBits,TickType_t xTicksToWait );
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet,const EventBits_t uxBitsToWaitFor,TickType_t xTicksToWait );

任务通知

  • 明确通知的任务,数据任务独享
  • 不额外开辟内存
  • 效率更高
  • 中断中只能发送数据给任务
/*任务通知计数功能函数*/
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, BaseType_t *pxHigherPriorityTaskWoken );
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
/*任务通知复杂功能函数*/
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyActioneAction );
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction,BaseType_t *pxHigherPriorityTaskWoken );
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,uint32_t ulBitsToClearOnExit,uint32_t *pulNotificationValue,TickType_t xTicksToWait );

任务延时

vTaskDelay(n):进入vTaskDelay到退出间隔至少n个Tick中断
xTaskDelayUntil(&Pre, n):两次退出 xTaskDelayUntil 的时间至少是n个Tick中断,也就是任务运行时的Tick+Delay的Tick

在这里插入图片描述

相关文章:

RTOS随笔之FreeRTOS启动与同步方法

RTOS启动与同步机制RTOS启动任务切换场景任务同步机制队列信号量事件组任务通知任务延时RTOS启动 FreeRTOS在任务创建完成后调用函数vTaskStartScheduler()启动任务调度器。 vTaskStartScheduler()任务启动函数详解 void vTaskStartScheduler( void ) {BaseType_t xReturn;xR…...

【AI/NLP】InstructGPT数据标注问题

文章目录1 背景介绍2 标记员筛选2.1 标记员筛选标准3 数据集及其标注3.1 预训练3.2 微调3.2.1 SFT-demonstration data3.2.2 RM-comparison data3.3 数据集大小4 模型实现1 背景介绍 ChatGPT的训练过程与InstructGPT相近,大致分为三步: SFT&#xff1a…...

三次握手和四次挥手

文章目录TCP三次握手为什么要三次握手三次握手可以携带数据吗?三次握手失败,服务端会如何处理?ISN代表什么,意义,何要动态随机什么是半连接队列第2次握手传回了ACK,为什么还要传回SYN?为什么要四次挥手TCP…...

Jmeter常用断言之响应断言详解

响应断言是最常用的一种断言方法,主要是对响应结果中的文本内容进行断言,比如响应结果是否包含指定的值,或者是否等于指定的值。响应断言可以适用各种返回类型的响应结果,如:Test、html、application/json、applicatio…...

【Python学习笔记】36.Python3 MySQL - mysql-connector 驱动(1)

前言 MySQL 是最流行的关系型数据库管理系统,本章节为大家介绍使用 mysql-connector 来连接使用 MySQL, mysql-connector 是 MySQL 官方提供的驱动器。 Python3 MySQL - mysql-connector 驱动 我们可以使用 pip 命令来安装 mysql-connector&#xff1…...

计算机SCI论文课题设计需要注意什么? - 易智编译EaseEditing

课题设计就要本着严谨性和可行性来进行。实验设计的类型要选择准确,统计学的方法要运用合理,研究对象和观察指标的选择也要符合研究目的的要求,技术路线要清晰明了。 关于课题的设计的可行性也要综合考虑,比如前期的相关工作基础…...

Quartz入门教程

本文参考文章编写 Quartz 官网 Quartz 是 OpenSymphony 开源组织在 Job Scheduling 领域又一个开源项目,是完全由 Java 开发的一个开源任务日程管理系统,“任务进度管理器”就是一个在预先确定(被纳入日程)的时间到达时&#xff…...

TypeScript 学习之 function

函数可以实现抽象层,模拟类,信息隐藏和模块。 函数有:有名字的函数、匿名函数 在 JavaScript 中的函数 // 有名字的函数 function add(x, y) {return x y; }// 匿名函数 let myAdd function (x, y) {return x y; };函数类型 typescript 可…...

【云计算自学路线】

云计算包含的技术内容和涉及的方向比较多,一定要进行系统化的学习才能更好的掌握这门技术。 云计算作为互联网新技术领域,现阶段也是出于高速发展期,想学习加入云计算行业的小伙伴可以抓紧机会了,跟着小课一起来了解云计算以及它…...

code01 v2黑屏、花屏、死机、断电重启、休眠死机的进来

症状解决 长话简说,症状如下: 使用浏览器、播放视频等,遇到突然死机或花屏死机的情况 关闭硬件加速,如:浏览器中设置关闭硬件加速,出现这种症状的软件都需要设置 开机电流音、播放与暂停时喇叭吱吱想、打…...

分享107个HTML电子商务模板,总有一款适合您

分享107个HTML电子商务模板,总有一款适合您 107个HTML电子商务模板下载链接:https://pan.baidu.com/s/1VW67Wjso1BRpH7O3IlbZwg?pwd0d4s 提取码:0d4s Python采集代码下载链接:采集代码.zip - 蓝奏云 Aplustemplates 购物模板…...

Barra模型因子的构建及应用系列三之Momentum因子

一、摘要 在之前的Barra模型系列文章中,我们已经初步讲解、构建了Size因子和Beta因子,并分别创建了对应的单因子策略。通过回测发现,其中Size因子的小市值效应具有很强的收益能力。而本篇文章将在该系列下进一步构建Momentum因子。 二、模型…...

8.2.1.3 索引合并优化

索引合并访问方法检索具有多个范围扫描的行,并将其结果合并为一个。此访问方法仅合并来自单个表的索引扫描,而不是跨多个表的扫描。合并可以生成其基础扫描的合并、交叉或交叉的合并。 可以使用索引合并的查询示例: SELECT * FROM tbl_name…...

水雨情在线小能手-雨量水位报警站

雨量水位报警站由水位探测器、雨量传感器、报警灯、扩音器、太阳能板和采集传输控制器组成。实时采集水位等级,三个水位探测器对应3个水位等级,当现场水面浸没相应探测器时,本机会实时发出语音报警,同时可发送相应的预警/报警等级…...

【蓝桥杯集训4】双指针专题(6 / 6)

目录 3768. 字符串删减 - 滑动窗口ac 799. 最长连续不重复子序列 - 滑动窗口 800. 数组元素的目标和 - 二分ac 2816. 判断子序列 - 双指针 1238. 日志统计 - 滑动窗口 1240. 完全二叉树的权值 - 双指针 1、前缀和 - 通过了 5/12个数据 2、双指针 3768. 字符串删减 -…...

文件流,gzip解压,压缩

目录 文件画布 写入 (空文件Foutnew File(Parent,entry.getName());)FileOutputStream outnew FileOutputStream(Fout);BufferedOutputStream Boutnew BufferedOutputStream(out);其他流量基于基础包装文件--文件流---字节流 顺序pbf一般是形成后再压缩目…...

在线开会,来开开圆桌会议吧~

圆桌会议应用场景:适合内部培训、部门会议亦或是头脑风暴等较为轻松的场景,有兴趣的朋友可以联系我来测试哦~~ 上图: 图:圆桌会议应用截图 在圆桌布局之下,企业可以将每一位参会者和座位绑定,1:1模拟线下圆…...

使用营销自动化的 7 大主要优势

对于大多数企业家来说,自动化已成为在数字时代简化业务的必要条件。那么,您可以采取哪些步骤来实施营销自动化呢? 1. 社交媒体整合 拥有吸引人的社交媒体形象是成功的先决条件。您不可能完成所有社交媒体营销任务,使用自动化软件&…...

【图像分类】基于PyTorch搭建GRU实现MNIST手写数字体识别(单/双向GRU,附完整代码和数据集)

写在前面: 首先感谢兄弟们的关注和订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 在https://blog.csdn.net/AugustMe/article/details/128969138文章中,我们使用了基于PyTorch搭建LSTM实现MNIST手…...

day14_oop_抽象_接口

今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、作业 二、抽象 三、接口 零、 复习昨日 多态的好处: 扩展性强.加入新的功能,不需要改动代码降低代码耦合度(解耦合或者松耦合) 一、抽象类 1.1 抽象类…...

python/java环境配置

环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

为什么要创建 Vue 实例

核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏

一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...

spring Security对RBAC及其ABAC的支持使用

RBAC (基于角色的访问控制) RBAC (Role-Based Access Control) 是 Spring Security 中最常用的权限模型,它将权限分配给角色,再将角色分配给用户。 RBAC 核心实现 1. 数据库设计 users roles permissions ------- ------…...