时基法编程之从一颗LED灯讲起

堵塞编程

如下是一个最普通的LED闪烁代码

void delay_ms(unsigned int xms)
{
	unsigned int x,y;
	for(x=xms;x>0;x--)
		for(y=110;y>0;y--);
}
void main(void)
{
	while(1)
	{
		LED = 0;
		delay_ms(500);
		LED = 1;
		delay_ms(500);
	}
}

上面代码的缺点是显而易见的,单片机近乎100%的性能都消耗在delay中,大量时间单片机都在空跑等待。
如果整个程序的任务仅仅是闪烁一颗灯,那么这样的代码还能接受。但如果这是一个较复杂的应用呢?闪烁LED灯这个任务仅仅是做为程序上电运行指示的作用,在这之后还有按键、数码管、各种传感器驱动、业务逻辑等等。又怎么办呢?

非堵塞式编程

分析任务目标我们知道,让LED灯闪烁,我们要做的是每隔一定时间去反转一下LED控制口的电平。
想象一下,假如你现在在上网,同时你手上有一个任务,每隔10分钟去评论一条微博,你会怎么做?
先评论第1条微博,然后一直等在那里?等10分钟?再去评论第二条微博?
你肯定不会这样。在评论完第一条微博后你会去干其它事情,时不时看一下时间,10分钟有没有到,如果到了10分钟,再去评论第二条微博。这就是非堵塞式编程

程序实现上述思路如下:

//LED灯驱动时基
unsigned int LED_ScanCnt = 0;
//LED灯电平翻转间隔时间
#define LED_FLASH_TIM	500

//时基提供
void timer_Deal(void)
{
	static unsigned char BaseCnt = 100;
	if(--BaseCnt)return;//100个循环LED_ScanCnt自加1
	BaseCnt = 100;
	LED_ScanCnt ++;
}
void LED_Flash(void)
{
	//如果LED_ScanCnt计数器时间未到,退出该函数,出去做其它事情
	if(LED_ScanCnt < LED_FLASH_TIM)	return;
	//否则清零计数器,并翻转LED控制电平
	LED_ScanCnt	= 0;
	LED	= ~LED;
}
void main(void)
{
	while(1)
	{
		timer_Deal();
		LED_Flash();
		//其它进程..
	}
}

以上代码程序是一直在循环运行的,不会停在某一刻不停delay。
然而上面代码还是有很大的缺陷,那就是时间是不可控的,没修改一次代码,LED_ScanCnt自加1所需要的时间就不同,如果我想要让LED以精确的1Hz频率闪烁,我还需要用示波器去调节宏LED_FLASH_TIM的值。现在的大多数单片机都有定时器,要解决时间不可控的缺陷,我们只需要用定时器中断替代timer_Deal()就可以了,这就是时基法编程

	//LED灯驱动时基
	unsigned int LED_ScanCnt = 0;
	//LED灯电平翻转间隔时间
	#define LED_FLASH_TIM	500
	void LED_Flash(void)
	{
		//如果LED_ScanCnt计数器时间未到,退出该函数,出去做其它事情
		if(LED_ScanCnt < LED_FLASH_TIM)	return;
		//否则清零计数器,并翻转LED控制电平
		LED_ScanCnt	= 0;
		LED	= ~LED;
	}
	void main(void)
	{
		//定时器初始化....
		
		while(1)
		{
			LED_Flash();
		}
	}
	//定时器中断1ms
	void Timer0_Interrupt() interrupt 1
	{
	    LED_ScanCnt	++;
	}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值