星星点灯(三)-LED点灯高阶

前面两篇《星星点灯(一)-LED点灯初阶.docx》《星星点灯(二)-LED点灯中阶.docx》我们把基本教学的LED点灯程序简单的讲解了一遍,并且对其利弊进行了分析。通过这两篇文章我们学会了几个技能:

  1. 如何把一个开发系统系统跑起来。
  2. 如果初始化I/O,如何去驱动一颗LED。
  3. 用软件的方式进行延时控制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讨论
原创文章,欢迎转载,请注明来源,未经书面允许,请勿用于商业用途。
在这里插入图片描述

发布了18 篇原创文章 · 获赞 7 · 访问量 5654

猜你喜欢

转载自blog.csdn.net/huangbinvip/article/details/104977337