stm32软件编程的框架及注意事项——rtos篇
0、通常,嵌入式软件(这里指单片机系统)的框架千变万化,有带rtos的,也有裸机的。
0.1、写过带系统的,也写过裸机的,这里总结一下两个类型的框架,记录下自己的心得,主要是文字描述,框架图可以后期添加。
1、freertos框架
1.1、使用标准库,网上有很多一直教程,也有现成移植好的,如果自己使用,可以在config文件下,自己需要根据项目的大小进行系统的裁剪,这方面的教程有很多,官方的,原子的,野火的等等。
1.2、使用hal库,可以直接使用freertos的中间件,在代码中,cubemx其实已经把freertos的接口函数封装了一遍,以至于和原来的freertos的接口函数不一样的,但是实现的功能是一样的,这个宗旨是不能变的。项目中通常采用1000hz的调度频率。
但是使用的方法有些不一样,比如延时函数等,这个可以参考stm32方面的教程,文档名称是《STM32 嵌入式操作系统介绍》(或《STM32RTOS培训_嵌入式操作系统介绍》)这个文档介绍了基本的使用方法。尤其是接口函数的使用。英文也有:
https://arm-software.github.io/CMSIS-FreeRTOS/General/html/index.html
1.3、在cubemx中,可以进行系统的裁剪,可以分配多少空间给任务,默认是128字(128×4个字节),最后可以看看还剩多少空间,根据项目的任务数量来具体分配,还有信号量队列,互斥量,软件定时器一般不怎么用,用的最多的是信号量(用于任务或中断的同步),互斥量(临界区的数据保护)。
1.4、开发中,首先要将信号量,任务先建立,没有中断的芯片驱动可以首先初始化。
如果外部芯片有中断的,可以最后初始化,因为如果初始化后,芯片就会产生一个外部中断,从而调用信号量,但是此时你却没有初始化信号量,从而导致死机,这个一定要注意!
1.5、可以使用一个开始任务,把外设初始化、任务创建放在里面,结束后,删除自己即可。
1.6、中断基本上使用信号量来同步,这个比标志位更方便,在任务中判断信号量是否有新,无效则一直等待,也可以设置一个等待时间,一般都是一直等待,这样任务可以挂起,不影响其他任务的运行,这个裸机是有区别的,而且不用清零标志位。
1.7、任务的周期不能太短,100ms基本上ok,50ms也行的,但是这个任务不能长期执行,否则将导致其他任务饥饿,得不到系统运行的时间。
1.8、任务里面尽量不要使用for循环,可以使用计数器的方式代替,比如一个周期只采样一个通道,这个是比较好的方法,否则for循环会导致占用很多cpu资源,导致其他任务无法运行,或者一个任务,只执行了一半的程序。
1.9、任务基本上采用时间片的方式,其实就是将每个任务的优先级设置为一样,这样系统就会在1ms的时刻运行一次某个任务,下1ms运行下一个任务(就是任务切换),直到所有任务都各自运行了1ms,从头开始运第一个任务。这样基本上不用作临界资源的保护动作。
假如,任务1的延时时间是100ms,程序需要运行30ms,任务2的延时时间是50ms,程序需要运行40ms。那么cpu先在前60ms,间隔运行任务1、任务2,每次运行1ms,60ms后,任务1已经运行完毕,进入挂起态。任务2继续运行,运行到70ms后,任务2也运行完毕,进入挂起态,之后到80ms后重新运行任务2。
可以看看下面的示意图。只说明了大概意思,时间点可能不准确,大家也可以提提意见。
2、软件框架:
通信方式使用tcp协议或者modbus协议。
tcp的物理介质是网线,要注意,交叉线和直连线。
modbus使用rs485的总线,使用rtu方式。
2.1总的框架是:应用逻辑使用java实现,在pc或高级的cpu处理器(可以跑linux这种),单片机实现底层的驱动。
2.2、上位机下发一条指令——>单片机串口接收到数据——>检查数据合法性——>置位相关的标志位——>进行一次设备的操作——>清零相关的标志位——>结束
2.3、串口接收结合定时器的方法,modbus就是使用的这种,3.5T以上如没有数据了,说明一帧数据已经结束。可以进行数据解析了。
2.4、使用标志位的目的是,命令来一次,我单片机只操作一次设备,众所周知,rtos中单片机有好几个死循环的,一直在运行的,因此标志位清零后,就达到了目的,以免频繁的操作设备。有的需要自动控制的,那么,就要合理添加标志位,因此标志位的使用比较关键的,要好好规划。
3、另外一种用的较多的是状态机的方法。
通常我们在使用按键的时候会使用状态机的思想,状态机的思想,我最先是在FPGA的课程中用到,后面就陆续在网上看到这单片机中也经常使用的。因此我在任务中,经常使用到,尤其是与外部设备进行通信的过程中。
3.1、一般串口通信我会分如下几个步骤:
空闲态——这个状态没有任何发送和接收
接收态——数据正在接收,同时定时器在该状态中,判断是否已经有4ms的超时,超时了,立即转为“完成态”,并触发一个接收中断,告知单片机可以处理数据解析,这个时刻可以锁定串口不再接收新的数据,等完成处理,发送回上位机后(如果有必要这个步骤),再开启接收的功能,这样可以创造单片机有一个“数据解析处理”的单独的时间,当然前提是:上位机只有接收到单片机的数据后,才能发送下一条数据。
3.2、当然还可以添加一些其他的状态:
超时
数据帧错误
超载状态
基本上6个状态已经可以够用了,比较健壮的。
3.3、同时还可以添加一个状态机,用于描述一个通信状态是否完成。我这里添加了一个事件的状态机:
初始态——数据没有发送、没有接受
完成态——对应于串口的超时、数据帧错误、超载状态、完成态,这样可以告知单片机,一个时间已经完成,可以进行后续的工作。这个在我单片机要发送两次串口任务中使用到,因为要发送两次停机命令,有两个欧姆龙温控器(modbus控制)。
小结:rtos的框架,基本上使用任务+信号量+状态机,就可以解决中小型的项目,而且有一个优点,任务之间耦合性较低,时间控制方面也是比较好的,基本上有的地方可以不用定时器了,编写代码更加省心,比如点led灯,在裸机里面,必须要使用定时器。
效率方便,代写完裸机后,在进行总结一下。