嵌入式单片机编程入门心得——架构篇

写在最前面:纯属个人见解,如果您不同意,那您对!如果对你有帮助,恭喜你。

嵌入式单片机编程入门心得–思维篇

承接上文,思维是基础,在思维的基础上,理解架构,会更加容易。如果没有看过上篇的朋友们,可以先花几分钟看看上文,可以更好的理解本文。

先立个Flag,程序架构的作用,就是让思维更有条理,让程序易读,容易移植,容易传承。你可以不要架构写程序,也能跑的很好,也能做产品,就是容易让别人蛋疼,等时间久了,重拾祖传代码,会让自己也蛋疼。所以,初学者最好一开始就学架构,以后的路会顺很多。

先从思维出发,上篇说了,任何程序都是在时间上的离散化,我们让离散化得有规律一点,就是架构了。简单来说,就是定时,周期性(规律)的执行。

在这个基础上,有两个分支,没有好坏之分,看你高兴选择哪个。一个是重事件,称之为事件驱动;一个是重定时,称之为定时驱动。不论哪种架构,都有个基础时间计时器,大家非常熟悉常用的一般都是1ms。下面详细解释下两者区别:
一、事件驱动:就是每个任务,独立的计时间隔去循环。以任务分类为主,各个任务按照自己的时间间隔处理循环。优点是事件独立,不用考虑任务之间的影响。
二、定时驱动:在几个特殊的时间间隔上,按照优先级顺序处理各项任务。以处理时间间隔分类任务,比如所有以20ms为间隔的任务放到一起按顺序处理,以100ms为间隔的任务,放到一起按顺序处理。优点是,在某个时间节点,集中处理任务,同步性比较强,后续的时间可以直接进行休眠,比较适合低功耗的场合。缺点是先后顺序会造成一些覆盖,需要避免这些情况。

先举例解释,后上代码。
比如有一个LED闪烁任务,和按键扫描任务。
事件驱动的处理方式是,1ms的时基,时基到了,各任务执行一次。LED闪烁任务有个定时累加器,到达500的时候灭,到达1000的时候亮,然后清零。一直这样循环。按键扫描任务也有个累加器,到达20的时候执行一次扫描,然后计数器清零,一直这样循环。
定时驱动的处理方式是,1ms的时基,根据这个时基有个定时累加器,累加器被20整除的时候,有个20ms标记,被500整除的时候有个500ms标记,被1000整除的时候有个1s标记,同时清零定时累加器。在20ms标记下,放入按键扫描任务。在500ms标记下,放入灭LED指令,在1s标记下,放入亮LED指令。
两者达到的效果是一样的。文字表述这种比较晦涩,上代码。

事件驱动架构代码:

LED_Flash_Event(void)
{	
	static uint16_t led_timer_counter;
	if(led_1ms_flag)
	{
		led_1ms_flag = 0;
		led_timer_counter++;
		if(led_timer_counter>=1000) led_timer_counter = 0;
		if(led_timer_counter<500) LED1_TURNON();
		if(led_timer_counter<1000) LED1_TURNOFF();
	}
}
void main(void)
{
	Init();
	 while(1)
	 {		
	 		Intrrupt_Process();	 	
			LED_Flash_Event(); 
			KEY_Scan_Event();
			Sensor_Collent_Event();	
					
	 }
}

上面代码中,定时器中断置1ms的flag,就不贴代码。懂就行了。这就是事件驱动的常用架构,大致如此。

定时驱动架构代码如下:

void main(void)
{
	static uint8_t TimerCounter;
	Init();
	 while(1)
	 {		
	 		Intrrupt_Process();	 
	 		if(TimerFlag&TIMER_20MS_FLAG)
	 		{
	 			TimerFlag&=~TIMER_20MS_FLAG;
	 			TimerCounter++;
	 			if(TimerCounter>=50) TimerCounter= 0;
	 			if(0=(TimerCounter%5)) TimerFlag|=TIMER_100MS_FLAG;
	 			if(0=(TimerCounter%25)) TimerFlag|=TIMER_500MS_FLAG;
	 			if(0=(TimerCounter%50)) TimerFlag|=TIMER_1000MS_FLAG;
	 			{			//20ms loop
	 				KEY_Scan_Event();
	 				Sensor_Collent_Event();	
	 			}
	 			if(TimerFlag&TIMER_100MS_FLAG)
	 			{
	 				TimerFlag&=~TIMER_100MS_FLAG;
	 				LED_Flash_Event(); 
	 				Sensor_Process_Event();	
	 			}
	 			if(TimerFlag&TIMER_500MS_FLAG)
	 			{
	 				TimerFlag&=~TIMER_500MS_FLAG;
	 			}
	 			if(TimerFlag&TIMER_1000MS_FLAG)
	 			{
	 				TimerFlag&=~TIMER_1000MS_FLAG;
	 				RTC_Timer_Process();
	 			}
	 		}						
			Enter_Sleep();			 		
	 }
}

定时驱动的框架如上面的代码,大家自己可以发挥改进,个人比较喜欢使用定时驱动的框架,因为写过汇编的就知道,汇编的架构也是和这个一样,按照这个框架写下来,程序流程非常清晰,也易读。当有做低功耗的时候,这个框架也非常舒服。

这是裸机的框架。实时操作系统类的程序,也是差不多的框架,可以把事件和定时驱动结合起来,独特的事件,以事件驱动自己做一个任务,其他一些不是很重要的,用一个任务做出最小时基,以定时驱动去做。

框架大概就是这样,其他就是怎么套入的问题。建议初学者,一定要使用框架去编程,不要一条程序写到底,各种任务混在一起,到时候改不能改,移植不好移植。

你可能感兴趣的:(嵌入式单片机程序心得,单片机,架构,嵌入式硬件)