freertos随意记录
freertos是一个开源免费的嵌入式实时操作系统非常好用也比较简单对freertos的学习过程做一些记录。1、移植freertos的移植应该是比较简单的下载官方最新版的LTS版本然后拷贝一些文件和做一些设置就行了。a、文件复制在目标工程下新建文件夹freertos将freertos-kernel根目录下的C文件复制到前面的文件夹中复制including文件夹复制portable文件夹中的文件我使用的是正点原子的STM32H750开发板使用的keil ac6创建的工程文件目录及文件如下另外freertos还有内存管理复制下列文件到工程目录freertos还需要一个用于裁剪代码的配置文件直接复制example里面的至此文件的拷贝已经完成了。完整目录结构如下b、工程配置新建一个hal工程把开发板上的led灯和串口初始化然后配置工程添加头文件freertos的任务切换有几个非常重要的中断函数PendSV_Handler SysTick_Handler SVC_Handler这是任务切换的关键需要注释掉hal工程中stm32h7xx_it.c中的这几个函数并在freertosconfig.h文件中添加下列代码让stm32h750的中断和freertos内核的中断关联起来freertos的框架已经搭建起来了下面需要调用freertos的入口函数vTaskStartScheduler()这个地方要注意不要添加错了我之前就添加成xPortStartScheduler()找了好久才发现。vTaskStartScheduler里面会调用xPortStartScheduler不过在这之前需要进行一些闲置任务这些初始化。完成上面这些freertos已经在运行了为了观看效果新建几个任务这是几个简单的任务led和printf任务其中led是可以阻塞的print则没有阻塞。非常不建议print这种写法因为该任务不会离开RUN状态会一直执行导致优先级比他低的任务没有机会执行包括IDLE任务这里仅仅是为了测试项目中千万不要这样写每个任务一定需要离开RUN状态要么延时等待要么等待信号量这些。通过测试print优先级18几个任务都可以正常运行print优先级高于20print任务正常运行led任务无法运行。2、学习记录任务切换原理某个任务正在执行但是系统时钟也在运行其中systick中断设置为1000HZ每1ms进入一次systick中断看下systickHandler干了啥#define xPortSysTickHandler SysTick_Handler void xPortSysTickHandler( void ) { /* The SysTick runs at the lowest interrupt priority, so when this interrupt * executes all interrupts must be unmasked. There is therefore no need to * save and then restore the interrupt mask value as its value is already * known. */ // 屏蔽掉中断优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断我们认为优先级低于这个值的中断可以被屏蔽 portDISABLE_INTERRUPTS(); traceISR_ENTER(); { /* Increment the RTOS tick. */ // 系统tick累加 if( xTaskIncrementTick() ! pdFALSE ) { traceISR_EXIT_TO_SCHEDULER(); /* A context switch is required. Context switching is performed in * the PendSV interrupt. Pend the PendSV interrupt. */ // 产生pendSV中断请求 // portmacro.h文件如下 // #define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) ) // #define portNVIC_PENDSVSET_BIT ( 1UL 28UL ) portNVIC_INT_CTRL_REG portNVIC_PENDSVSET_BIT; } else { traceISR_EXIT(); } } portENABLE_INTERRUPTS(); }其中产生pendSV中断请求从上面的代码可以看出systick中断就干了一件事产生pendSV中断。下面看看pendSV中断又干了啥void xPortPendSVHandler( void ) { /* This is a naked function. */ __asm volatile ( mrs r0, psp \n isb \n \n ldr r3, pxCurrentTCB \n /* Get the location of the current TCB. */ ldr r2, [r3] \n \n tst r14, #0x10 \n /* Is the task using the FPU context? If so, push high vfp registers. */ it eq \n vstmdbeq r0!, {s16-s31} \n \n stmdb r0!, {r4-r11, r14} \n /* Save the core registers. */ str r0, [r2] \n /* Save the new top of stack into the first member of the TCB. */ \n stmdb sp!, {r0, r3} \n mov r0, %0 \n cpsid i \n /* ARM Cortex-M7 r0p1 Errata 837070 workaround. */ msr basepri, r0 \n dsb \n isb \n cpsie i \n /* ARM Cortex-M7 r0p1 Errata 837070 workaround. */ bl vTaskSwitchContext \n mov r0, #0 \n msr basepri, r0 \n ldmia sp!, {r0, r3} \n \n ldr r1, [r3] \n /* The first item in pxCurrentTCB is the task top of stack. */ ldr r0, [r1] \n \n ldmia r0!, {r4-r11, r14} \n /* Pop the core registers. */ \n tst r14, #0x10 \n /* Is the task using the FPU context? If so, pop the high vfp registers too. */ it eq \n vldmiaeq r0!, {s16-s31} \n \n msr psp, r0 \n isb \n \n #ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata workaround. */ #if WORKAROUND_PMU_CM001 1 push { r14 } \n pop { pc } \n #endif #endif \n bx r14 \n \n .ltorg \n ::i ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) ); } void vTaskSwitchContext( void ) { /** 无关代码 ***/ // 查找当前ready的最高优先级并把pxCurrentTCB赋值为最高优先级TCB中的下一个TCB taskSELECT_HIGHEST_PRIORITY_TASK(); portTASK_SWITCH_HOOK( pxCurrentTCB ); } #define taskSELECT_HIGHEST_PRIORITY_TASK() \ do { \ UBaseType_t uxTopPriority uxTopReadyPriority; \ \ /* Find the highest priority queue that contains ready tasks. */ \ while( listLIST_IS_EMPTY( ( pxReadyTasksLists[ uxTopPriority ] ) ) ! pdFALSE ) \ { \ configASSERT( uxTopPriority ); \ --uxTopPriority; \ } \ \ /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \ * the same priority get an equal share of the processor time. */ \ listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, ( pxReadyTasksLists[ uxTopPriority ] ) ); \ uxTopReadyPriority uxTopPriority; \ } while( 0 ) /* taskSELECT_HIGHEST_PRIORITY_TASK */ ldr r3, pxCurrentTCB \n /* Get the location of the current TCB. */获取到当前的任务的TCB bl vTaskSwitchContext \n任务切换函数寻找处于ready的最高优先级并把pxCurrentTCB赋值为最高优先级中的下一个如果有如果没有不变后面的代码看注释知道是加载pxCurrentTCB中的寄存器值然后进行跳转完成任务切换。最后看一下SVCHandlervoid vPortSVCHandler( void ) { __asm volatile ( ldr r3, pxCurrentTCB \n /* Restore the context. */ ldr r1, [r3] \n /* Get the pxCurrentTCB address. */ ldr r0, [r1] \n /* The first item in pxCurrentTCB is the task top of stack. */ ldmia r0!, {r4-r11, r14} \n /* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */ msr psp, r0 \n /* Restore the task stack pointer. */ isb \n mov r0, #0 \n msr basepri, r0 \n bx r14 \n \n .ltorg \n ); } static void prvPortStartFirstTask( void ) { /* Start the first task. This also clears the bit that indicates the FPU is * in use in case the FPU was used before the scheduler was started - which * would otherwise result in the unnecessary leaving of space in the SVC stack * for lazy saving of FPU registers. */ __asm volatile ( ldr r0, 0xE000ED08 \n /* Use the NVIC offset register to locate the stack. */ ldr r0, [r0] \n ldr r0, [r0] \n msr msp, r0 \n /* Set the msp back to the start of the stack. */ mov r0, #0 \n /* Clear the bit that indicates the FPU is in use, see comment above. */ msr control, r0 \n cpsie i \n /* Globally enable interrupts. */ cpsie f \n dsb \n isb \n svc 0 \n /* System call to start first task. */ nop \n .ltorg \n ); } BaseType_t xPortStartScheduler( void ) { prvPortStartFirstTask(); }这个代码貌似只执行一次就是在vTaskStartScheduler中会执行一次启动第一个任务。configMAX_SYSCALL_INTERRUPT_PRIORITY设置系统最高优先级即如果代码中有优先级大于优先级数值小于configMAX_SYSCALL_INTERRUPT_PRIORITY 的中断不受freertos控制可以正常产生中断如果代码中有优先级小于configMAX_SYSCALL_INTERRUPT_PRIORITY 的中断则会因为freertos调用vPortEnterCritical()函数进入临界状态无法进入中断。比如串口非常重要不想让串口被系统打断那么如果configMAX_SYSCALL_INTERRUPT_PRIORITY设置为16串口的中断优先级就需要设置为16;按键中断不是很重要可能在发送数据的时候不需要响应按键可以把按键的中断优先级设置为大于16那么在进入临界状态时候按键中断是无法响应的。// 进入临界状态禁止中断 void vPortEnterCritical( void ) { // 进入临界状态禁止中断 portDISABLE_INTERRUPTS(); uxCriticalNesting; /* This is not the interrupt safe version of the enter critical function so * assert() if it is being called from an interrupt context. Only API * functions that end in FromISR can be used in an interrupt. Only assert if * the critical nesting count is 1 to protect against recursive calls if the * assert function also uses a critical section. */ if( uxCriticalNesting 1 ) { configASSERT( ( portNVIC_INT_CTRL_REG portVECTACTIVE_MASK ) 0 ); } } #define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS() #define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI() // 将configMAX_SYSCALL_INTERRUPT_PRIORITY 的值写入basepri屏蔽优先级小于configMAX_SYSCALL_INTERRUPT_PRIORITY 的中断优先级数值大于configMAX_SYSCALL_INTERRUPT_PRIORITY portFORCE_INLINE static void vPortRaiseBASEPRI( void ) { uint32_t ulNewBASEPRI; __asm volatile ( mov %0, %1 \n \ cpsid i \n \ msr basepri, %0 \n \ isb \n \ dsb \n \ cpsie i \n \ : r ( ulNewBASEPRI ) : i ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : memory ); }在更精巧的设计中需要对中断掩蔽进行更细腻的控制——只掩蔽优先级低于某一阈值 的中断——它们的优先级在数字上大于等于某个数。那么这个数存储在哪里就存储在 BASEPRI中。不过如果往BASEPRI中写0则另当别论——BASEPRI将停止掩蔽任何中断。例 如如果你需要掩蔽所有优先级不高于0x60的中断则可以如下编程 MOV R0, #0x60 MSR BASEPRI, R0 如果需要取消BASEPRI 对中断的掩蔽则示例代码如下 MOV R0, #0 MSR BASEPRI, R0 《CORTEX M3 权威指南》退出临界状态void vPortExitCritical( void ) { configASSERT( uxCriticalNesting ); uxCriticalNesting--; if( uxCriticalNesting 0 ) { portENABLE_INTERRUPTS(); } } #define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS() #define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 ) // 将0写入basepri恢复所有中断 portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue ) { __asm volatile ( msr basepri, %0 ::r ( ulNewMaskValue ) : memory ); }待续...

相关新闻

什么是外盘期货

什么是外盘期货

外盘期货,也称为境外期货,是指在中国大陆以外的合规交易所挂牌上市、公开流通的标准化期货合约,与国内四大交易所运行的内盘期货相对应,是全球主流的大宗商品与金融指数交易品类。它依托国际成熟金融市场运行,价格由全…

2026/10/14 12:43:15 阅读更多 →
轻量鞋材助剂赋能产业发展

轻量鞋材助剂赋能产业发展

现代鞋材行业持续迭代,轻量化、高颜值、高品质成为PVC鞋材核心发展方向,而助剂的合理搭配是提升PVC鞋材综合品质的关键。佳百特(jabetter)深耕PVC鞋材助剂领域多年,打造的PVC鞋材稳定剂(PVC shoe material stabilizer)…

2026/10/15 2:19:25 阅读更多 →
AS01/AS02/AS03固定资产界面增强

AS01/AS02/AS03固定资产界面增强

增强效果如下:CMOD:创建增强-》AIST0002在EXIT_SAPLAIST_002实现如下代码:ANLA I_ANLA . ANLV I_ANLV . ANLU I_ANLU . GD_MODE I_MODE . GD_XSUBNO I_XSUBNO . GT_ANLZ[] T_ANLZ[] . GT_ANLB[] T_ANLB[] .GV_XMXG I_ANLU-XMXG. GV_FLAG . GV_C…

2026/10/11 22:04:10 阅读更多 →

最新新闻

基于 AWS CDK (Go) 构建 S3 上传触发 Rekognition 图像识别并写入 DynamoDB 的完整实战

基于 AWS CDK (Go) 构建 S3 上传触发 Rekognition 图像识别并写入 DynamoDB 的完整实战

【免费下载链接】aws-cdk-examples Example projects using the AWS CDK 项目地址: https://gitcode.com/gh_mirrors/aw/aws-cdk-examples 点击查看 免费下载 导读 本文以 aws-cdk-examples 仓库中的 go/rekognition-lambda-s3-trigger 示例为主线,系统…

2026/10/15 2:19:18 阅读更多 →
Unity BakeMesh粒子层级问题解决:从原理到Shader排序实战

Unity BakeMesh粒子层级问题解决:从原理到Shader排序实战

简介:这份资源聚焦Unity开发中粒子特效与UI层级冲突的常见难题,面向需要将粒子效果嵌入界面、并希望像UGUI一样灵活控制层级的开发者。内容围绕BakeMesh方案展开,对比了RenderTexture渲染与多Canvas调整Sort in Layer两种传统思路的优劣&…

2026/10/15 2:19:18 阅读更多 →
空间锚点建模:打工人可复用的AI能力迁移方法论

空间锚点建模:打工人可复用的AI能力迁移方法论

1. 这不是玄学,是可复现的驾驶能力迁移实验最近刷屏的“科目二AI两把过关”视频,表面看是段子,实则藏着一套被低估的、可拆解、可复现的能力迁移路径。我连续两周蹲守驾校训练场,跟拍了6位真实学员(含3位零基础打工人&…

2026/10/15 2:19:18 阅读更多 →
Unity Cloud Content Delivery:面向热更新的原生资源分发方案

Unity Cloud Content Delivery:面向热更新的原生资源分发方案

1. 项目概述:这不是“云存储”,而是为Unity游戏量身定制的资源分发流水线Unity Cloud Content Delivery(UCD)这个名字刚出现时,我第一反应是:“又一个带‘Cloud’的营销词?”——直到在某次跨平…

2026/10/15 2:19:18 阅读更多 →
pyecharts交互式数据可视化实战:从时间刷选到地图下钻

pyecharts交互式数据可视化实战:从时间刷选到地图下钻

有一次,同事跑过来丢给我一句话:“我们想要一个自己能点着看的页面,不是截图,也不是PDF。” 当时他在做月度复盘,数据已经躺在Excel里了,但画出来的折线图、柱状图一旦转发给他,就变成死图片。他…

2026/10/15 2:19:18 阅读更多 →
Java 面向对象|大二学习笔记,把最难啃的这块讲明白

Java 面向对象|大二学习笔记,把最难啃的这块讲明白

之前把 Java 基础语法过完了,if、for、数组、方法写起来还算顺手,可一碰到面向对象直接卡壳。很长一段时间我都觉得:不就是写个 class 然后 new 对象吗?好像看懂了,但一写代码就乱,分不清什么时候用继承、什…

2026/10/15 2:18:18 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →