完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
电子发烧友论坛|
本帖最后由 lvhoujun 于 2014-2-28 00:37 编辑
这是本人以ATMEGA128为例编写的C语言程序框架,做简单的修改即适合AVR所有单片机。可以说是一个单片机最简操作系统,希望各位同仁补充改进。
AVR单片机程序框架(V1.0).rar
(68.86 KB, 下载次数: 959
)
程序框架采用事件触发机制,主程序可以编程为按事件优先级运行,也可以编程为顺序运行。主程序在App.c文件中,框架的核心程序在OSAL_App.h中,程序事件和运行标志定义在App.h文件中。 |
|
相关推荐
67 个讨论
|
|
|
有同学询问怎样使主程序按事件优先级处理?怎样按顺序处理?在这里给大家介绍一下:
在程序框架的App.c文件中,主程序: int main(void) { ......//各种资源初始化 wdt_enable(WDTO_2S);//使能看门狗 while(1) { wdt_reset();//复位看门狗 if( events ) { //处理事件函数 events = process_evts(); } } } 可以看出,主程序就是循环查询有无事件发生,如果有事件发生,就运行事件处理函数process_evts(); 现在我们看事件处理函数: int process_evts(void) { if( events & OCCURRED_1_EVT ) { ;//添加事件OCCURRED_1_EVT的处理函数 return (events ^= OCCURRED_1_EVT); } if( events & OCCURRED_2_EVT ) { ;//添加事件OCCURRED_2_EVT的处理函数 return (events ^= OCCURRED_2_EVT); } return 0; } 该函数查询发生了什么事件,假设是OCCURRED_1_EVT 。关键是事件处理完后,有一句: return (events ^= OCCURRED_1_EVT);这句话的意思是,清零该事件,退出process_evts()。如果 OCCURRED_1_EVT事件一直发生,下次进入事件处理时,仍然只处理OCCURRED_1_EVT, OCCURRED_2_EVT永远得不到处理。除非不发生OCCURRED_1_EVT事件,才可能处理 OCCURRED_2_EVT事件。也就是说, OCCURRED_1_EVT比 OCCURRED_2_EVT优先级高。这就是按事件的优先级运行。 这种编程方法的优点是,保证优先级高的事件在最短的时间内得到处理。 那么,程序怎样按顺序运行? 我们把return (events ^= OCCURRED_1_EVT);改成: events ^= OCCURRED_1_EVT 不用return返回,则处理完OCCURRED_1_EVT事件处理程序后,则继续执行下一个if语句,从而使 OCCURRED_2_EVT 事件得以处理。 这就是按事件顺序执行程序。 如果程序中有两个以上的事件都必须尽快处理,就把顺序运行和优先运行结合起来使用。比如前两个事件处理不加return返回语句,第三个以后再加返回语句等等。 还有一些状况,虽说事件发生了,但由于某些条件不具备,还不能处理该事件怎么办?比如GSM通信编程时,发生了一个发送短信事件SMS_SEND_EVT,如果此时正在传送TCP报文,必须等到关闭TCP连接后,才能发送短信。那么我们在process_evts()中可以这样处理: if( events &SMS_SEND_EVT) { if( TCP连接还没有关闭 ) { continue; } ...... //发送短信 return (events ^= SMS_SEND_EVT); } 即在这次执行process_evts()的时候,用 continue退出该事件处理程序,保留SMS_SEND_EVT事件,继续执行后边的事件处理程序。等到下次运行process_evts()时再处理SMS_SEND_EVT事件,直到 TCP连接关闭后,发出短信,才能清零SMS_SEND_EVT。 |
|
|
|
|
|
|
|
|
从大家给我的QQ留言中,看到有些初学者看不懂这个程序框架。下面我想详细讲解一下:
该程序框架的核心程序在OSAL_App.h文件中。请打开该文件参考我下面的讲解阅读程序。 其中,有一个void osal_heartbeat(void)函数,该函数的功能是启动T2定时器,并每10毫秒产生一次定时中断。这是程序框架的心跳,一般在主程序初始化完成之后立即执行该程序,使程序的心脏每10毫秒跳动一次。 SIGNAL(SIG_OUTPUT_COMPARE2)是T2中断的处理程序,即每10毫秒自动执行一次该处理程序。该中断程序首先检查UART0和UART1是否收到一个完整的报文,然后查看是否有新的按键按下,再然后查询是否有延迟事件要启动。 至于检查UART0和UART1是否收到一个完整的报文的机理在后续UART0和UART1驱动中讲解;查看是否有新按键按下的机理在后续按键驱动中讲解。我们首先看中断程序是如何处理事件的。 在OSAL_App.h的全局变量定义中,定义了一个16位的事件寄存器events。我们让events的每一位代表一个事件,各位均为0时,说明无事件发生;某位为1时,说明有对应的事件发生。这样events就可以标记16种事件,这对于一般的单片机应用程序足够了。 具体事件的定义在App.h文件中: #define OCCURRED_1_EVT 0x0001 #define OCCURRED_2_EVT 0x0002 #define OCCURRED_3_EVT 0x0004 #define OCCURRED_4_EVT 0x0008 #define OCCURRED_5_EVT 0x0010 #define OCCURRED_6_EVT 0x0020 #define OCCURRED_7_EVT 0x0040 #define OCCURRED_8_EVT 0x0080 #define OCCURRED_9_EVT 0x0100 #define OCCURRED_10_EVT 0x0200 #define OCCURRED_11_EVT 0x0400 #define OCCURRED_12_EVT 0x0800 #define OCCURRED_13_EVT 0x1000 #define OCCURRED_14_EVT 0x2000 #define OCCURRED_15_EVT 0x4000 #define KEY_CHANGE_EVT 0x8000 事件名称由编程者根据实际应用改写成有意义的字符,例如最后一个事件KEY_CHANGE_EVT,一看就知道是按键发生变化事件。这样我们就可以任意设置一个事件,或者清空一个事件了。 OSAL_App.h文件中,有一个立即设置事件的函数: void osal_set_event( unsigned int event) { events |= event; } 其实,这个函数只有events |= event这一句程序。比如我们设置1#事件置位,只要执行 osal_set_event( OCCURRED_1_EVT);就可以了。 |
|
|
|
|
|
|
|
|
正用AVR做毕设,很有帮助
|
|
|
|
|
|
|
|
|
真的那么好吗
|
|
|
|
|
|
|
|
|
看看了,感谢楼主分享。。。 |
|
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
AVR Atmega16 Bootloader程序与上位机LabView程序
5658 浏览 6 评论
#include <ioavr.h>这个头文件我应该下什么编译器
8117 浏览 0 评论
3361 浏览 2 评论
3346 浏览 1 评论
10517 浏览 1 评论
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-3 13:51 , Processed in 1.165694 second(s), Total 82, Slave 69 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖