前面两篇《星星点灯(一)-LED点灯初阶.docx》,《星星点灯(二)-LED点灯中阶.docx》我们把基本教学的LED点灯程序简单的讲解了一遍,并且对其利弊进行了分析。通过这两篇文章我们学会了几个技能:
- 如何把一个开发系统系统跑起来。
- 如果初始化I/O,如何去驱动一颗LED。
- 用软件的方式进行延时控制LED闪烁。
现在,请你基本上忘记前面的方法(出来LED初始化和驱动输出相关的可以继续使用),因为那种开发方法最多只能用来作为功能验证使用,是绝对不能用到实际产品中去的,否则你会害死自己的….
本章我们还是在简单的驱动两颗LED的功能上,来设计一种全新的方案,保证系统最高效率的运行,同时可以很容易的处理不同的LED驱动需求。本节的目标是解放CPU,同时让两颗LED闪烁的速度一快一慢。
系统大概流程如下:
首先初始化相关的接口,然后进入一个无限等待的循环,根据是否有消息需要处理,来做相应的动作,如果没有,系统就进入休眠状态,降低功耗。
流程图如下:
主循环代码如下:
int main(void)
{
SystemInitialize();
SetTimer(TIMER_ID1,500,TRUE); //500ms的定时器
SetTimer(TIMER_ID2,100,TRUE); //100ms的定时器
while(1)
{
MSGTYPE msg;
if(GetMessage(&msg) == FALSE)
{
//没有任何事情需要处理,可以进入休眠状态
__WFI(); //任何中断发生后唤醒继续执行
continue;
}
switch(msg.type)
{
case MSG_TIMER:
if(msg.wParam == TIMER_ID1)
{
LedToggle(LED_1);
}
else if(msg.wParam == TIMER_ID2)
LedToggle(LED_2);
break;
default: break;
}
}
}
上面的代码显得清爽怡人,而且逻辑分明,处理起来自然顺畅,这就是软件架构的魅力。
我们实际上构建了一个基于消息驱动的系统,所有的事情都是根据对应的消息来执行相关的动作,比如在这里我们示例了一个定时器消息,来驱动两颗LED灯,而且两颗灯的闪烁频率完全不一样。
后面我们逐渐的添加进来更多的事件,比如按键,串口接收完成,发送完成,AD转换完成等等。
消息系统的接口如下,详细原理我们在另外文章详细讲解:
#define MSG_NULL 0x00000000
#define MSG_KEYDOWN 0x00000001 //按键按下
#define MSG_KEYUP 0x00000002 //按键谈起
#define MSG_SECOND 0x00000003 //秒钟中断
#define MSG_TIMER 0x00000004 //定时器中断
#define MSG_CREATE 0x00000006 //初始化窗口消息
#define MSG_DESTROY 0x00000007 //销毁窗口消息
#define MSG_PAINT 0x00000008 //重画窗口消息
#define MSG_DUMMY 0x0FFFFFFF //虚假信息,占位
//不同的消息类型,参数意义不一样
#define MAX_MSG 16 //最大消息数量
typedef struct __tagMessage {
UINT32 type; //消息类型
UINT32 wParam; //参数
}MSGTYPE;
typedef struct __tagMsgQueue {
MSGTYPE Msg_Queue[MAX_MSG]; //消息队列
UINT16 In; //消息入队位置
UINT16 Out; //消息出队位置
}MSGQUEUE;
/***************************消息队列说明**********************************
1.消息队列为先进先出类型,队列满的时候覆盖最先进入的消息。
2.支持在中断函数里面发送消息。(要实现DISABLE_INTERRUPT,ENABLE_INTERRUPT宏)
***************************************************************************/
/***************************************************************************
函数名称: MessageQueueInit
功能描述:初始化消息队列
输入参数: 无
返回值 : 无
使用注意:
***************************************************************************/
SYS_EXTERN void MessageQueueInit(void);
/***************************************************************************
函数名称: SendMessage
功能描述:发送一条消息
输入参数: msg: 要发送的消息
返回值 : 无
使用注意:
***************************************************************************/
SYS_EXTERN void SendMessage(MSGTYPE *msg);
/***************************************************************************
函数名称: SendMessageEx
功能描述:发送一条消息
输入参数: type:消息类型
wParam:消息参数1
lParam:消息参数2
返回值 : 无
使用注意:
***************************************************************************/
SYS_EXTERN void SendMessageEx(UINT32 type,UINT32 wParam);
/***************************************************************************
函数名称: GetMessage
功能描述:获取一条消息
输入参数: 无
输出参数: msg,保持读取到的消息内容
返回值 : TRUE:有消息返回,FALSE:没有消息
使用注意:
***************************************************************************/
SYS_EXTERN UINT32 GetMessage(MSGTYPE *msg);
/***************************************************************************
函数名称: MessageQueueClear
功能描述:清空消息队列
输入参数: 无
输出参数: 无
使用注意:
***************************************************************************/
SYS_EXTERN void MessageQueueClear(void);
同时我们提供了一个数量无限制的软件定时器来发送定时器消息,详细原理后续专门章节分享:
/*
下面实现了一组软件定时器,个数不限,定时时间以10ms为间隔单位
也就是说如果你传入参数15ms,会被处理为10ms
为什么不采用1ms:系统绝大多数应用,比如延时,按键等等,10ms的间隔
精度足够了。10ms的中断间隔比起1ms会降低系统的中断负荷,提高中断响应时间。
如果需要,修改内部实现即可。
*/
#define TIMER_MAX 5 //最大定时器数量
typedef struct tagtimeout {
UINT16 SetValue[TIMER_MAX]; //设置的值
UINT16 CntValue[TIMER_MAX]; //计数的值
UINT16 reload[TIMER_MAX]; //计数完成是否重载FALSE:一次,TRUE:重载
UINT16 enable[TIMER_MAX]; //FALSE:disable,TRUE:enable
UINT16 run; //0:disable,1:enable
}TIMEER;
typedef enum {
TIMER_ID1 = 0,
TIMER_ID2 = 1,
TIMER_ID3 = 2,
TIMER_ID4 = 3,
TIMER_ID5 = 4,
TIMER_IDMAX = TIMER_MAX,
}TIMERID;
/***************************************************************************
函数名称: SetTimer
功能描述: 设置定时器
输入参数:
id:定时器id
ms:以ms为单位的定时时间(最小10ms)
reload:是否重载,TRUE is reload,for loop
输出参数: 无
返回值 :
使用注意: 不检查要设定的定时器id是否使用,如果已经使用,则用新值替代
最大计数值:65536*10ms = 655秒
***************************************************************************/
SYS_EXTERN void SetTimer(TIMERID id,UINT32 ms,UINT32 reload);
/***************************************************************************
函数名称: StopTimer
功能描述: 停止id指定的timer
输入参数: id: 定时器id
输出参数: 无
返回值 :
使用注意:
***************************************************************************/
SYS_EXTERN void StopTimer(UINT16 id);
/***************************************************************************
函数名称: ResetTimer
功能描述:复位id指定的timer
输入参数: id: 定时器id
输出参数: 无
返回值 :
使用注意:
***************************************************************************/
SYS_EXTERN void ResetTimer(UINT16 id);
/***************************************************************************
函数名称: CheckSoftTimer
功能描述:检查软定时是否有到时间的
输入参数: 无
输出参数: 无
返回值 :无
使用注意: 默认是在10ms中断调用,有消息会发送消息到消息队列
***************************************************************************/
#define SOFTTIMER_SENDMSG(cnt) SendMessageEx(MSG_TIMER,cnt) //发送消息id
SYS_EXTERN void CheckSoftTimer(void);
工程源码链接分享:
链接:https://pan.baidu.com/s/1R3NFs0brW30YlUVbd2BBTg
提取码:orv1
相关问题可以加QQ群‘开源斌哥开发群1’:1090541942讨论
原创文章,欢迎转载,请注明来源,未经书面允许,请勿用于商业用途。