当习惯了使用裸机之后便开始觉得有很多东西不够完善,特别是当遇到其中一个延时函数在跑的时候特别尴尬,很多事情都做不了,只能等这个东东延时完成之后才能继续 本人使用的板子是STM32F4VET6的板子。。。。。。
实现“同时”运行多个任务的方法有很多种(本来就是并行处理的FPGA就不用管这个了)
1.中断
2.状态机
3.嵌入式OS
当然最推荐的就是使用嵌入式OS了,在众多的嵌入式OS中,适合选择的有很多,Linux,UCOS,freeRTOS等等
在工控行业使用最多而且简单易学的应该算是UCOS了,而UCOS分为II和III,可以直接入手UCOSIII,功能更多,使用的人群也相当多。
推荐资料:
- 《嵌入式实时操作系统uc/OS-III》——Jean J. Labrosse
- 《嵌入式实时操作系统uc/OS-III 应用开发》——Jean J. Labrosse
- 正点原子UCOSIII教程
按照正点原子的教程利用LED源码的例程,直接移植进入UCOSIII,其实移植过程说白了就是各种copy替换,虽然还不明白这么替换的具体原因但是还是照做了,现在只需要知道如何使用API函数的调用以及整个操作系统的组成以及各个部分的功能即可,等使用熟练之后再来认真学习UCOS的源码。
移植完UCOSIII,利用任务调度成功的让LED灯闪亮之后,这便成了我的第一个UCOSIII项目,同时也可以成为其他所有项目的模板Template。有必要回头看一下移植完成后的项目中的一些问题:
滴答定时器SysTick(这个定时器在CortexM3,M4的权威指南中完全一样,可以参考权威指南查询)
这个定时器是是为了使用操作系统专用的一个定时器,为OS产生心跳时节律,当然也能用来做一些高精度延时。
**包括4个寄存器:
控制及状态寄存器
重装载寄存器
当前数值寄存器
校准数值寄存器(一般不去使用)**
在正点原子提供的System文件夹下面一共3个文件
sys.c/h
delay.c/h
usart.c/h
其中sys.c/h 和裸机使用的代码一致。
delay.c中使用的是滴答定时器来进行延时操作的。
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS定义了,说明要支持OS了(不限于UCOS).
//宏定义内容
#endif
很多都是定义了操作系统之后才会编译的内容
void delay_init(u8 SYSCLK)
{
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
u32 reload;
#endif
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//SYSTICK使用外部时钟源
fac_us=SYSCLK/8; //不论是否使用OS,fac_us都需要使用
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
reload=SYSCLK/8; //每秒钟的计数次数 单位为K
reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec设定溢出时间
//reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右
fac_ms=1000/delay_ostickspersec; //代表OS可以延时的最少单位
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断
SysTick->LOAD=reload; //每1/OS_TICKS_PER_SEC秒中断一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
#else
fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数
#endif
}
时钟选用的外部时钟(时钟为168M)
SYSCLK=168
fac_us=168/8=21(不管定不定义OS这个都是需要的)
reload(这个是将要重装载在滴答定时器里的)
delay_ostickspersec即心跳频率,可以查看定义的源头,可知这里是200(200Hz)
即每1000000/delay_ostickspersec(us)心跳一次,5ms心跳一次。
Systick的频率21MHz,周期时间为1/21 us
而重装载的数值应该为
21*1000000/delay_ostickspersec
所以如果想要使用不同的心跳,只需要修改相应的心跳频率参数的定义处即可。
使用延时时,delay_us和delay_ms中如果延时时间少于心跳时间不能引起任务调度。
usart.c文件中变化的是串口中断函数多加了两句话
#if SYSTEM_SUPPORT_OS //使用UCOS操作系统
OSIntEnter();
......//中断函数的内容
#if SYSTEM_SUPPORT_OS
OSIntExit(); //退出中断
#endif
以后写中断函数的时候也需要写OSIntEnter()和OSIntExit()
其他的一样。
总之现在成功移植了UCOSIII的操作系统,以后进一步学习UCOS的任务管理等方面的知识,包括任务的创建,删除,以及各种任务的切换等。