本帖最后由 discovery0x01 于 2009-11-6 01:40 编辑
在很多的单片机编程中,我一直保持着寻找捷径,哪怕是想方设法的少打一对{}也好。在编写基于C语言的程序时,大家一定会少不了编写main()函数,对各式各样的外部硬件予以init(),对响应遥控和按键也是通过不停的查询来完成。这些工作经常复制来,复制去的,很是麻烦。而且特别是硬件编程,有时候在PCB改动的时候,会牵连到一大片的内容。我不喜欢这样的编程方式,我更偏爱于兼容性更好的编程方式,把能够通过#define定义的最低级操作全都放在mydef.h里,把原先编写好的程序放在c:\inc\的目录下,让编译器自己去找。而且有了IAR编译器C++的支持,很多硬件的init()函数可以在CLASS的构造函数里完成,当我们实例化一个类的时候,它就已经初始化了,而如果我们在头文件了已经实例化了一个类的话,在我们的main.cpp里,只需要#include" c:\inc\xxx.h"就已经基本上满足我们的要求。废话不多说了,先让大家来看看我的FrameAVR。这个框架是经过很多程序验证了的。源程序如下:有些头文件大家不必详知,只要理解这个class的工作过程即可。
/*
本程序框架适用于IAR
定义一下宏打开某项特定功能
// 定义MCU型号,编译器将会自动添加相应的io.h
#define MCU_MEGA32
// 定义MCU时钟,它会影响到很多时序程序
#define OSC_8M
// 定义MCU时钟偏移 默认值为1.00
#define OSC_REL 1.00
// 打开MSG消息驱动(KEY),由msg传递给proc
#define KEY_PORT (PINB&0x3F)
// 打开遥控接收程序,选择其中一个,不可同时打开2个。将会占用INT0和T0
//#define REMOTE_SAA3010
//#define REMOTE_TC9012
//#define REMOTE_HT6221
// 打开此宏后AVR的Run()将与IRQ_RTOS同步,当完成AVR::Run()后MCU进入睡眠状态
// 打开此宏后需要在main.cpp里添加一个中断函数通过调用RE_START()来
// 唤醒CPU主程序
//#define IRQ_RTOS IRQ_T2
// 定义RTOS的时间(uS)
//#define TIMER_RTOS 10000
// 打开此宏后将定义AVR::Timer()与AVR::Run()的调用比例
#define AVR_TIMER 10
// 看门狗计时最大时间,定义此宏后AVR_MAIN在完成RUN()后将复位WDT
#define WDT_TIME WDT_2200ms
*/
#ifndef AVR_MAIN_H
#define AVR_MAIN_H
#include "c:\inc\message.h"
#define NULL 0
#ifdef WDT_TIME
#include "c:\inc\avr_wdt.h"
#endif
#ifdef RTOS
#include "c:\inc\stanby.h"
STANBY stanby;
void ExitStanby()
{
stanby.exit();
}
#ifdef IRQ_RTOS_TIMER0
#include "c:\inc\avr_t0.h"
#endif
#ifdef IRQ_RTOS_TIMER1
#include "c:\inc\avr_t1.h"
#endif
#ifdef IRQ_RTOS_TIMER2
#include "c:\inc\avr_t2.h"
#endif
#endif
class FrameAVR
{
private:
#ifdef AVR_TIMER
UINT avr_timer;
void Timer();// 如果定义了AVR_TIMER ,这个函数会以AVR_TIMER:1的比例相对于Run()运行Timer()
#endif
public:
void init(); // 这两个函数需要在main.cpp里重新编写。编写剩余IO的处理
void Run();// 主程序需要重复运行的程序放在这里,如果定义了RTOS,那么Run()将会以RTOS定义的时间重复调用,否则将会接连不停的调用,仿佛我们平时的main()主循环
FrameAVR()
{
#ifdef AVR_TIMER
UINT avr_i;
avr_timer=AVR_TIMER+0;
#endif
#ifdef RTOS
#ifdef IRQ_RTOS_TIMER0
timer0.init(true,RTOS,ExitStanby);
#endif
#ifdef IRQ_RTOS_TIMER1
timer1.init(true,RTOS,ExitStanby);
#endif
#ifdef IRQ_RTOS_TIMER2
timer2.init(true,RTOS,ExitStanby);
#endif
#endif
init();// 初始化用户定义的IO
msg.flush();// 初始化MSG
seI();// 使能IRQ
// 初始化WDT
#ifdef WDT_TIME
initWDT(WDT_TIME);
#endif
while(1)
{
#ifdef _REMOTE_MSG_H_
msg.GetREM();// 获取遥控信号
#endif
#ifdef KEY_PORT
msg.GetKEY(KEY_PORT);// 获取按键信号
#endif
// TIMER呼叫延迟
Run();// 运行
#ifdef AVR_TIMER
if(avr_timer)// 计算比例
{
if(++avr_i >= avr_timer)
{
avr_i=0;
Timer();// 运行FrameAVR::Timer()
#ifdef _MESSAGE_H_
msg = ON_TIMER ;
#endif
}
}
#endif
// 自动复位WDT
#ifdef WDT_TIME
ResetWDT();
#endif
// 系统休闲
#ifdef RTOS
stanby.start();// 在stanby类里,我们可以获取MCU的占用率
#endif
}
}
};
int main()
{
FrameAVR avr_main;// 我把FrameAVR放在main()内部实例化是为了让其它硬件先能够得到构造
return 0;
}
#endif
把上面这个程序复制到保存为c:\inc\FrameAVR.h.那么在我们的main.cpp里,无需编写void main()函数,因为它已经有了。而且它能够满足我们的需求。这个框架是基于消息的,所有的按键和遥控编码都会通过msg类转换为特定的消息,我们无需再去查看自己的PCB到底按键在哪个引脚,只要在一开始的时候定义#define KEY_PORT (PINB&0x3F)即可,最大支持16位的按键输入。是不是很方便呢?我在编写基于DS1302的程序的时候,框架会在1s到来的时候向我们特定的函数发送msg,这个特点是我在win32编程里学到的。呵呵,大家有时间多多交流,我是懒人,少做一件重复的事是我的快乐。 |