
一般而言,当软件功能比较简单时,前后台系统基本都能很好的实现想要的功能,当实现的功能越来越复杂时,就需要引入操作系统,一般称为RTOS,即嵌入式实时操作系统。嵌入式实时操作系统有很多,收费的或者开源的数不胜数,例如FreeRTOS、Vxworks、RT-Thread、µC/OS-III、µC/OS-Ⅱ等,国产的也有Huawei LiteOS、AliOS Things、都江堰操作系统、TencentOS Tiny等。! X& a9 O; P% t 9 U g. E1 \/ M4 z 网上有很多基于Keil来移植µC/OS的教程,用此文章记录下在STM32CubeIDE下移植µC/OS的过程,用于分享和记录。 1 d& b/ b9 s7 X4 G) ?7 X µC/OS-III从2009年开始发行,基于open-source Apache 2.0许可证进行开源,供任何人下载学习。6 y+ d/ R' |3 @; a0 e 官网上提供了大量针对不同处理器移植的例程,只需要注册即可下载(但是不知道为什么国内带.com后缀的邮箱无法注册)。* O; S D' e' z' R ![]() / }' N# P2 }, C5 T# T, |8 y 图1 不同型号处理器例程 ! P4 t! N/ k6 j4 e7 B& { 这里还是以STM32F103C8T6处理器来作为说明,虽然目前这颗芯片的价格已经非常离谱。官网提供的例程里面只包含的部分芯片,但是不重要,只要找到内核相同的都可以使用。例如STM32F103C8T6 属于Arm Cortex-M3,那我们只需要下载例程里面相同内核的芯片STM32F107的例程就可以使用,将其解压后即可得到源文件。) b: X( a) Z8 U9 w ' Z0 a Q1 d8 l+ v6 p ![]() 4 c% O2 O! V! j+ s 图2 STM32F107 例程 参照前几节的文章,使用STM32CubeIDE生成一个STM32F103C8T6的工程,并在工程文件夹内新建一个RTOS文件夹用于存放uCOS-III相关文件。 ![]() 图3 新建RTOS文件夹 - ?& g4 b; ~ M- g" H 将解压出来的源码文件夹中和下图红框所示同名的三个文件夹拷贝到新建的的RTOS文件夹中,并新建一个uC-Config文件夹来存放其他文件。! O* x6 a' k* I" N ![]() , @; k) w' @$ b8 C4 f 图4 拷贝文件 / A3 O; [7 l, o( x! ]/ X* B: v* z- G5 u0 E 然后将下图所示绿框路径下的红框内的文件全部拷贝到刚刚新建的uC-Config文件夹内。7 N: @6 e, F! V" m. x ![]() & ~6 z X' f9 X/ w# `5 ~ 图5 拷贝文件 % X" I# q/ D; ^7 }/ {; K 退后到上一级文件夹,将BSP文件夹的内容也拷贝到新建的uC-Config文件夹内。 ![]() 图6 拷贝文件 ( Z3 O8 r' @: o 0 s& x; H, O( L% v. i Q& b0 q 在STM32CubeIDE工程中刷新一下就可以看到刚刚拷贝过来的文件。) d; h2 T& v. e6 w ![]() 8 u6 a* H: k* A 图7 刷新 将RTOS文件夹增加到Paths and symbols的源文件路径下。2 Y( Y9 [9 i' T3 F; c 3 X6 ` [: v2 s* {3 o4 d ![]() 图8 增加源文件路径 不同编译器的汇编不一样,例程文件夹里面提供了三种主流编译器的汇编文件。不相关文件不参与编译,当然也可以直接删除。 ![]() 图9 去掉不相关文件 : g( C d! r+ j- d, [( c. V& B* H 将RTOS下的所有文件路径全部添加到Include paths中。7 D7 c1 ]- e0 m; d5 @ B$ k ! y7 H m2 D! L2 E ![]() + ?" J: _! E- d; v 图10 包含头文件 6 y% a9 M& q! w$ h" s4 D! F8 w% H9 @' C) W' c 此时可以尝试编译一下,不出意外的会报大量的错误,主要原因为前文拷贝的bsp.c和bsp.h文件中有太多不相关的代码。首先,将bsp.h文件夹内无关内容全部删除,只保留下图所示内容。 ![]() 7 ~/ ]3 U# Z1 T0 z 图11 BSP.h保留内容 ' g# J/ A0 i8 J( {9 `1 w4 n( @9 ]5 u$ Z J: Q bsp.c文件夹中有很多例程平台中的LED配置和操作的代码,全部删除。0 p* R9 Y0 {) d 4 o1 u# t& k0 a3 a* s ![]() 图12 无关的LED操作代码 ) J+ S5 Y7 S& Z8 w" w9 l: s 去掉这些内容再次编译,此时只剩下下图所示获取CPU主频的部分报错。 3 f9 y( L. ]# H+ e% z4 L& H ![]() 8 S0 U/ a4 C2 R# Q 图13 获取CPU主频错误 0 h( |& a% n4 [4 |% V重写该部分,包含 stm32f1xx_hal.h头文件,使用HAL库获取CPU主频,此时编译将不会再报错,编译通过。: j0 G% H& E# c ![]() 图14 使用HAL库获取CPU主频 ; @ Z( ^/ z. ?8 V, G" ]( D8 E5 b- b. Z. G" p8 \4 [ 然后参照例程文件夹里面App.c文件的内容,将UCOS的初始化,创建任务、启动等代码添加到主函数中。# P9 w/ M2 |6 M$ O$ a8 c2 t; | # s! I W- [1 ]& R9 m ![]() 图15 例程App.c + O" [9 d, Q% M# @8 D ![]() 图16 初始化ucos 3 {9 i) B7 Q7 r+ B) l- U7 r9 x! k8 A! D7 `+ G$ y- {2 s 8 ?1 B- `- k( ] 并在启动任务中添加LED翻转用来表明系统在运行。 4 m/ N2 a' g+ [* W& L& ~ ![]() 0 Q! I$ P1 d+ z I4 G 图17 创建启动任务 此时再尝试编译,编译器会报错,提示芯片RAM不够,毕竟STM32F103C8T6也就20K的RAM空间。 ![]() 图18 提示RAM不够 " }( _' w. [$ s" p4 [1 i/ s1 E0 z$ X6 T1 u( a; e- z3 ^6 y 打开工程文件存放的目录,找到里面的debug文件夹的后缀为map的文件。 ) {' q+ a5 Z7 C6 p& _" M6 o [ ![]() 图19 map文件 7 b$ y& ?1 T. j) j0 q. J2 ] S 在map文件中搜索 Linker script and memory map 字段。往下拉到.bss开头的字段,这里描述的是占用的RAM大小,可以看到 lib_mem占用了一个相当大的RAM空间。' z+ p9 i8 U" B- d 7 C3 m& S3 K* f/ m0 o ![]() 图20 查看占用RAM空间大小 2 e" Y9 L6 y$ k0 m8 e3 ^# H$ ]* o% Q4 L" A 打开uC-Config文件夹下的lib_cfg.h文件,找到下图所示的代码, 并将27调整为5,减少UCOS内存方向程序占用的RAM空间。4 A7 {* S. n0 Y# ] ![]() 图21 调整lib_mem占用的RAM大小 & G% [& x& |# s0 V" `& ~* f" e/ d+ b. L; j& a4 z# A' ` - h- ~& x9 ?! s% h" P5 ~ 此时编译正常通过,编译器内存区域窗口给出了当前占用的RAM和FLASH的大小和余量等信息。% I% k V y4 o" q. f7 y : V- O/ T: H- E; R' _ ![]() 0 J7 F: x+ w3 K 图22 RAM和FLASH占用情况 6 N9 ~/ T4 z3 q3 [6 x t( J! P+ v0 b, ?* j/ Q6 T- ~3 } 如果将lib_cfg.h文件的27从5调整为10,可以看到RAM已经所剩无几。 ![]() 5 L9 W, E/ o9 S9 F2 l5 t0 v$ f6 o 图23 RAM和FLASH占用情况 . n( U1 t9 j* X+ ~6 `8 B! k5 z$ ^4 S5 I/ @" d 当然,此时UCOS仍然是不能运行的,还需要再Systick的中断函数中增加OS_CPU_SysTickHandler函数,作为系统的“心脏”。 , {* O2 i% Z0 n/ B* E; n2 Y ![]() 图24 SysTick中断函数 3 Z. A/ f' c" c# p9 K! H8 F$ ?0 m4 Q 5 e) k( G8 \7 M 然后将下图所示文件中的所有的OS_CPU_PendSVHandler替换为PendSV_Handler,使用PendSV_Handler异常来进行任务切换。不同的人有不同的习惯,有些人喜欢修改芯片启动汇编文件中的PendSV_Handler字段内容为OS_CPU_PendSVHandler,也可以达到同样的效果。 1 R5 U: F! j5 g% u/ w; i2 {8 f5 ? ![]() 图25 修改os_cpu_a.s |. z- q, H H+ l2 f. |" e9 S. b' T5 r$ Q& d3 w& g7 L 2 O, O: D' X/ P2 u# M; j 同时注释或者删掉stm32f1xx_it.c文件中的PendSV_Handler函数,否则编译器报错函数多重定义 ![]() 1 L' e$ f3 S# R5 j" e 图26 删除重复的PendSV_Handler函数 , s2 e1 n7 e6 D: S 4 S1 s% X( a2 X: s/ j 编译后下载,按照AppTaskStart中的任务,LED将会一秒翻转一次状态,表明UCOS已经再运行。按照惯例,可以定义一个浮点数来测试浮点运算,同时修改LED翻转时间为500ms让灯闪烁慢一点。 & W( M( @) c, b: W; b9 H ![]() 图27 增加浮点数运算 ! i$ W; E$ @0 s% B& b* h+ P 进入调试模式,可以在现场表达式窗口中,可以看到temp变量正在每500ms间隔增加0.01; & X8 ~+ x( G" p. D" R* { ![]() 图28 查看变量 4 `4 t" t* x$ Y% R( H5 d+ R$ [0 ~# N3 C* s x+ C3 \/ s; c4 u. C" L0 ~" W 自此,可以更进一步体验UCOS的各种功能了。# E, Z4 W) k T$ V! `, P& C ) N9 H3 o( D* D7 J# ]. P |
STM32 ISP IQTune:真正零门槛的免费ISP调整软件
【经验分享】STM32 新建基于STM32F40x 固件库的MDK5 工程
意法半导体MCU双供应链策略,打消中国客户后顾之忧
【经验分享】基于STM32使用HAL库实现USB组合设备CDC+MSC
2024意法半导体工业峰会:赋能智能电源和智能工业,构筑可持续未来
ST推出灵活、面向未来的智能电表通信解决方案,助力能源转型
意法半导体 x Qu-Bit Electronix:推动新一轮的数字声音合成革命
从STM32 MPU产品看嵌入式系统中微处理器的新变化
【Hot!】STM32全系列开发板都支持Arduino开发,你知道吗?
【经验分享】STM32 HAL库移植FreeModbus详细步骤