裸机和rtos两种开发方式的区别 |
您所在的位置:网站首页 › rtos和裸机哪个难 › 裸机和rtos两种开发方式的区别 |
一、裸机开发
1.轮询方式
轮询,顾名思义就是事情一件件按顺序来,同一时间只能做一件事情。举个例子,一个妈妈要做两件事情,喂饭和回信息,只能先喂好饭,然后再回信息,两件事情不能同时做有先后顺序。 void main() { while (1) { 喂一口饭(); 回一个信息(); } } 2.事件驱动事件是一个宽泛的概念,什么叫事件?可以是:按下了按键、串口接收到了数据、模块产生了中断、某个全局变量被设置了。 什么叫事件驱动?当某个事件发生时,才调用对应函数,这就叫事件驱动。放到MCU来讲,我们可以理解为来了一个按键中断,这时就要调用中断处理函数处理中断信息。 再以上个例子为例,妈妈一直给小孩喂饭,就做这件事情,某个时间点同事发来一条信息,这时就需要妈妈去处理这个信息,处理完成后继续喂饭。 void main() { while (1) { 喂饭(); } } void message_isr() /* 同事发来信息触发中断 */ { 回一个信息(); }对于中断的处理,原则是"尽快"。否则会影响到其他中断,导致其他中断的处理被延迟、甚至丢失,所以中断处理的事情要尽量的精简。 3.定时器方式上述例子中只有两个任务,如果有更多的任务,很多有经验的工程师会使用定时器来驱动: 设置一个定时器,比如每1ms产生一次中断,以此为时间基准 对于函数A,可以设置它的执行周期,比如每1ms执行一次 对于函数B,可以设置它的执行周期,比如每2ms执行一次 对于函数C,可以设置它的执行周期,比如每3ms执行一次 注意:1ms、2ms、3ms只是假设,你可根据实际情况调整。 typedef struct soft_timer { int remain; int period; void (*function)(void); }soft_timer, *p_soft_timer; static soft_timer timers[] = { {1, 1, A}, {2, 2, B}, {3, 3, C}, }; void main() { while (1) { } } void timer_isr() { int i; /* timers数组里每个成员的expire都减一 */ for (i = 0; i < 3; i++) timers[i].remain--; /* 如果timers数组里某个成员的expire等于0: * 1. 调用它的函数 * 2. 恢复expire为period */ for (i = 0; i < 3; i++) { if (timers[i].remain == 0) { timer[i].function(); timers[i].remain = timers[i].period; } } }但这时又出现个问题,如果某个函数处理的时间过长,这又会影响其他函数,或者时间基准。当然也可以把函数分得更精简,一件事情拆成多个步骤完成,这样可以解决这个问题。 也可以可以做以下改进,将任务放回主函数中,这样做就退回轮询方式。 typedef struct soft_timer { int remain; int period; void (*function)(void); }soft_timer, *p_soft_timer; static soft_timer timers[] = { {1, 1, A}, {2, 2, B}, {3, 3, C}, }; void main() { int i; while (1) { /* 如果timers数组里某个成员的expire等于0: * 1. 调用它的函数 * 2. 恢复expire为period */ for (i = 0; i < 3; i++) { if (timers[i].remain == 0) { timer[i].function(); timers[i].remain = timers[i].period; } } } } void timer_isr() { int i; /* timers数组里每个成员的expire都减一 */ for (i = 0; i < 3; i++) if (timers[i].remain) timers[i].remain--; } 4.状态机方式假设要调用两个函数AB,AB执行的时间都很长,又要AB任务都可以及时得到响应,裸机就很难处理这种场景,这时就需要使用状态机方式,将一个任务拆多个任务处理。 void feed_kid(void) { static int state = 0; switch (state) { case 0: /* 开始 */ { /* 盛饭 */ state++; return; } case 1: /* 盛菜 */ { /* 盛菜 */ state++; return; } case 2: { /* 拿勺子 */ state++; return; } } } void send_msg(void) { static int state = 0; switch (state) { case 0: /* 开始 */ { /* 打开电脑 */ state++; return; } case 1: { /* 观看信息 */ state++; return; } case 2: { /* 打字 */ state++; return; } } } void main() { while (1) { feed_kid(); send_msg(); } } 二、rtos开发由以上裸机开发方式可见,在处理多任务方面,裸机开发或多或少都存在缺陷,这时就急需引入一种多任务并行运行的方式,实时处理信息。rtos的开发方式就由此而来。 有人可能会说,我使用状态机也可以实现同样的效果呀,为啥那么麻烦学习rtos。使用rtos的关键就是在于可以多任务并行,遇到执行时间长的任务,也不需要像状态机那样将任务分拆,而且每个任务之间的资源和栈都是独立的,程序的耦合性大大降低,可移植性和可读性大大增强。 举例如下: // RTOS程序 喂饭() { while (1) { 喂一口饭(); } } 回信息() { while (1) { 回一个信息(); } } void main() { create_task(喂饭); create_task(回信息); start_scheduler(); while (1) { sleep(); } } |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |