打印
[应用笔记]

C语言实现简单的伪RTOS

[复制链接]
1036|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
modesty3jonah|  楼主 | 2023-1-29 12:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
单片机中,笔者认为只有两个线程,一个是主线程,一个是中断线程。主线程运行在main中,是按顺序执行的代码序列,中断线程运行在特定硬件事件发生后,有对应的服务函数。这两个线程最大的特点是,主线程运行后,如果此时中断出现,系统会保护当前的各种重要数据,例如通用寄存器R0-R12和PC寄存器等等,这些信息都保存好,然后重新载入一系列中断服务函数需要的寄存器值,从而实现从主线程跳转到中断线程。
笔者认为,一个中断服务函数相当于一个中断线程,多个中断服务函数的话,会出现抢占的问题,但是优秀的处理器会处理好这些抢占的问题,例如NVIC不就是管理这些事情的吗?反正笔者认为线程的切换,换汤不换药,就是先保护现场,然后跳转到特定的程序段,覆盖现场,执行完以后回到之前的现场。
这让笔者联想到交换两变量数值的算法
//交换a 和 b 里面的数值
void swap(uint8_t * a , uint8_t *b){
uint8_t temp;
temp = *a ; //保护现场,因为*a马上就要被覆盖了
*a = *b ; //覆盖的事情发生了,这样做以后,程序会跳转
*b = temp;//回到最初的状态继续运行主函数
}

笔者认为,如果RTOS中TASK的概念是建立在上述这样的线程之上的,是真RTOS,因为它是真正的实时抢占的,好比51里面主函数正运行某一个函数,这时中断线程来了,主函数没有执行完,但是不给你执行完的时间了,立刻切换。TASK也是,如果有两个TASK,其中一个TASK正在运行,此时优先级更高的(笔者认为51单片机的主线程是低优先级TASK,任意中断服务函数是高于主线程的TASK)TASK出现,优先级低的TASK立刻保护现场,转而执行到另一个TASK中来!
这里的真RTOS,笔者认为晦涩,因为和底层芯片级的操作密切相关,微机原理,编译原理,这些太困难,也只有像TI等等这些芯片公司或者FREERTOS这样的开源组织能够提供技术方案。移植真RTOS的时候会发现与底层寄存器相关程度太高了,如果没有前人相应的经验,移植起来实在困难。(这里笔者说的是把FREERTOS的源码移植进自己的工程,而不是使用芯片厂商的一系列开发工具链)
相对应的,笔者想分享的是假RTOS,类似CC2541提供的操作系统一般,使用时间片轮询法实现一个假的实时操作系统。
这个假RTOS,笔者在大学的时候和实验室的朋友讨论过,朋友说,有一定的可能WINDOWS就是用的这个假实时的方法。因为电脑的主控速度太快了,你看不出是假实时,又可能是因为人类的输入方式太慢了,人的反应速度太慢了,你根本感受不出来这是假实时。这无从考证,毕竟不开源。随口一提,不必当真!
笔者认为,如果TASK的概念是基于上下文顺序的,一个任务的执行必须等待上一个正在执行任务结束才能执行的,是伪RTOS,如果主频够快,你也能感受到这两个任务是同时运行一般。
举个例子吧,按键和LED灯,两个TASK我希望他能通同时运行,并且采用伪操作系统的思维。
这里写的简单一点,只是想分享方法,伪RTOS需要时钟sysTick来实现延时,在单片机里可以用任意定时器中断来实现它,这里笔者阐明 SYS_TICK会在1ms的时候置1一次,实现方法:在1ms定时器中断函数中将其置1,具体代码不写。
void toggle_led(void); //执行此函数一次,LED闪烁一次
bool get_key(void);//执行此函数,如果按下返回false 否则返回true
//上文阐明SYS_TICK变量会在1ms后置1一次
extern bool SYS_TICK;

//创建两个任务,实现检测到按键事件,LED闪烁
void main(){
bool task_button_start = false;
bool task_led_start =false;
bool button_pressed_message =false;
uint32_t button_tick=0;
//一系列硬件初始化
while(1){
if(SYS_TICK){
//此函数类似时间片调度器
SYS_TICK = false;
//当查询到SYS_TICK置1,认为1ms已经过去,这里做计时用
button_tick ++;
if(button_tick > 100){
button_tick = 0;
task_button_start = true; //100ms开启一次key监测任务
}
if(button_pressed_message ){
//发现了按键消息,如果没有收到对应的数据,线程被挂起,这个if永远是false
button_pressed_message = false;
toggle_led();
}
if(task_button_start){
task_button_start = false;
//button task被调度
if(!get_key())
button_pressed_message = true;
}
}
}
}
显然,这里创建了两个TASK ,一个是LED TASK 这个TASK一般是挂起的,等待KEY被按下的事件触发,BUTTON TASK是100ms执行一次的,由时间片调度器给到开始条件。
仔细看的话,LED TASK 和 BUTTON TASK的优先级 很明显是 LED TASK优先级高,因为 LED TASK在上下文 BUTTON TASK之前,每次while(1)都先运行LED TASK 然后再运行BUTTON TASK。 当然调度时间片的任务优先级就不谈了,他算不上TASK。
这里简单的分享了笔者对假RTOS的认识,当然内容还有很多,比如操作系统里的任务管理,TASK之间的消息传递,implement这些接口之后,咱伪RTOS都得一个个实现。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

27

主题

1445

帖子

2

粉丝