天天看點

星星點燈(二)-LED點燈中階

經過千辛萬苦,在上一章《星星點燈(一)-LED點燈初階》我們終于把LED點亮了,醜是醜了點,但是總是有進步嘛!萬丈高樓平地起,有了這個基礎,隻要我們本着不抛棄,不放棄的精神,來個打破砂鍋問到底,我想就會百尺竿頭更進一步的。

本章,我們把醜小鴨打扮一下,看看能不能離白天鵝更像一點。

第一步:代碼子產品化

我們把I/O初始化的代碼獨立出去,為以後驅動更多的LED做準備,而且由于各種硬體限制原因,可能驅動LED的端口并沒有集中到一個順序的端口,PA有幾個,PB有幾個等等。那就需要分别的初始化它。

這樣我們把實作代碼分離出來後,上層調用就不需要做任何的修改,隻需要完成底層函數的修改就可以達到這個目的。

把調用和實作分離,這是實作子產品化編寫代碼的第一步。

void LedInit(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);	
}
           

同樣的,我們把延時函數寫成一個通用的函數,就像這樣:

void DelayMS(UINT32 ms)
{
	volatile UINT32 i,j; //注意這個變量一定要用volatile 聲明,否則編譯器會給你優化掉的。
	for(i = 0;i < ms;i++)
	{
		for(j = 0;j < 10 * 800;j++);
	}
}
           

第二步 把宏定義修理一下

還記得那個奇醜無比的LEDON嗎?如果非得定義宏(比如一個系統隻有一顆LED)的方式來操作LED的功能,那至少我們可以這樣來定義它,使他看起來更加紳士一些:

//定義宏
#define LedOn()		(GPIOB->BRR = GPIO_Pin_14)
#define LedOff()	(GPIOB->BSRR= GPIO_Pin_14)

//調用宏
LedOn();
LedOff();
           

這有什麼好處呢?

第一.它至少看起來像一個正常的語句了。

第二.為什麼我們不用全部大寫的方式來定義宏呢?這樣的好處就是當有一天我後悔了,我要用函數的方式來實作這個LedOn()的功能,我隻需要去掉宏的定義,用如下的函數去實作就可以了,但是調用的地方卻不需要做任何修改。

是不是很有智慧的方式啊,你學會了嗎?

void LedOn(void)
{
	GPIOB->BRR = GPIO_Pin_14;
}
           

好了,現在我們的點燈程式,有這些子產品的支援,我們就比較簡潔清爽了,如下:

void main(void)
{
	LedInit();
	while(1)
	{
		LedOn();
		DelayMS(500);
		LedOff();
		DelayMS(500);
	}
}
           

現在是不是看起來比較心情愉悅了很多啊?

我們把實作細節對調用者隐藏起來,比如LedInit()函數,把需要變化的參數,用函數傳遞參數的方式傳入來實作調用和實作的分離,這就是函數的子產品化最簡單的實作。

函數子產品化的好處是便于以後上層代碼的移植,我們需要更換到其他晶片去實作的時候,上層邏輯就不用再去實作,隻要把對應的底層驅動重新編寫,就能達到移植的目的。

上面的代碼現在還有沒有什麼缺陷呢?

那就是DelayMS(500)這個函數,我們總不能讓CPU就在這裡幹等,啥事情都不幹吧?要幹其他事情吧,又怎麼去保證LED點亮的延遲時間呢?這真是一個頭疼的地方。

中斷,對,你第一印象想到的就是中斷,在中斷裡面計數,然後計數到了再點亮或者熄滅LED。大概就是下面這樣子:

//1ms的中斷程式
static int LedCnt = 0;
static int LedStatus = 0;
void TimerInt(void)
{
	if(++LedCnt > 500)
	{
		if(LedStatus == 0)
			LedOn();
		else
			LedOff();
		LedStatus  = ~LedStatus;
	}
}
           

沒毛病,點亮一個LED也對了,在加上一些使能的條件也就差不多了。但是,也就是但是,現在要點亮更多的燈呢?還要玩幾個花式呢?又傻眼了吧!系統裡面還有按鍵,還有好多其他的事情,難道都在中斷裡面去扔一大堆變量?

顯然,這是一個不可能完成的任務,如何來解決?請聽下回分解。

大緻思路提示:

1.消息隊列

2.軟定時器

3.LED操作函數的修改

星星點燈(二)-LED點燈中階