STM32 嵌入式學習入門(3)——STM32F103 按鍵輸入控制LED燈

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/FelikZhang/article/details/79264181
STM32 嵌入式學習入門(3)—— STM32F103 按鍵輸入控制LED燈

按鍵是單片機上一個很重要的輸入設備,也很容易掌握,只要明白了IO口最基本的使用,就可以操作按鍵了。
我們的目的是控制開發板上板載的三個按鍵來操作開發板上板載的兩個LED燈實現亮或滅(按鍵第一次按下時燈亮,再按下時燈滅,以此類推)。
博主所用的開發板是正點原子的mini板(STM32F103RCT6)和戰艦板(STM32F103ZET6),因此下面的內容的例子以這兩款開發板爲例,但是相關的原理對任何開發板來說都是一樣的,只要自己的開發板上板載了按鍵和LED燈(這兩個資源應該是所有開發板上都有的資源吧),然後查看自己開發板的數據手冊和硬件電路圖、原理圖,找到各個按鍵對應的IO口就好了。

在開發板上,板載硬件資源(比如我們這裏用到的按鍵和LED燈)都是和確定的GPIO相連的,要使用這些硬件資源,實際上可以理解成對這些IO口的操作。


下面先大致說一下整個流程。
1.首先要使用這些硬件資源,就要對其進行初始化。初始化包括使能IO口時鐘和初始化IO口參數兩個部分,這兩點在上一篇博文中有提到了。
2.初始化完成後就可以操作IO口了,就是寫相關的邏輯代碼。這裏是按鍵控制LED燈,所以我們首先要掃描與按鍵相連的IO口的電平。如果IO電平發生變化,那麼說明按鍵被按下了,我們就要讓燈的狀態發生反轉。如果IO電平沒有發生變化,那麼說明按鍵沒有被按下,我們可以過一個很小的時間間隔再去掃描與按鍵相連的IO口看是否發生變化,這樣形成了一個死循環。

下面上一段代碼,是正點原子Mini STM32F103RCT6開發板(mini板)按鍵實驗的主函數部分:

#define LED0 PAout(8)	// PA8
#define LED1 PDout(2)	// PD2

#define KEY0_PRES	1	//KEY0  
#define KEY1_PRES	2	//KEY1 
#define WKUP_PRES	3	//WK_UP
 
int main(void)
{	
	u8 t=0;	  
 	
	delay_init();	    	//延時函數初始化	  
	LED_Init();		//初始化與LED連接的硬件接口
	KEY_Init();          	//初始化與按鍵連接的硬件接口
	
	LED0=0;					//點亮LED0
	
	while(1){
		t=KEY_Scan(0);		//得到鍵值	KEY_Scan(0);即不支持連續有效。如果需要支持連續按,這裏參數設置爲1.	
		switch(t){
			case KEY0_PRES:		LED0=!LED0;			break;
			case KEY1_PRES:		LED1=!LED1;			break;
			case WKUP_PRES:		LED0=!LED0;	LED1=!LED1;	break;
			default:		delay_ms(10);	
		}
	}//while(1)	
}

代碼比較長,但整體邏輯還是很容易理解的,首先解釋一下前兩行的宏定義,這裏是通過位操作,實現了對PA8/PD2的電平輸出的操作的,這一行代碼其實挺複雜的,準確說是博主也講不出原理(如果你去查看stm32的官方庫函數,會發現這裏的PAout(n)是通過很多層宏定義得到的),但是我會調用。總之,這樣定義了以後,下面的代碼你對LED0賦1對應着設置IO口爲高電平,賦0就是設置IO口爲低電平。下面的三個宏定義是爲下面switch-case服務的,增強了代碼的可讀性。
接下來就是主函數了,首先是調用三個初始化函數,這個等下後面具體說。初始化完成後,然後LED0=0;這一句,點亮LED0。接着就是while(1)循環了,死循環裏面先調用KEY_Scan(0);函數對按鍵進行檢測,該函數的返回值有四種情況,即KEY0_PRES、KEY1_PRESWKUP_PRES、0。前三個返回值表明相應的按鍵被按下了,返回0表明當前沒有按鍵按下。然後是switch-case結構了,如果有按鍵按下,執行相應分支,對LED上的電平進行反轉,實現按一次亮,再按一次滅,以此類推,這樣的效果。如果沒有按鍵按下,那麼延時10ms,然後繼續檢測有沒有按鍵按下。整體程序的執行過程就是這樣。

下面的問題就是三個初始化函數和KEY_Scan(0);函數是怎麼實現的了。
1.延時函數
這裏用到了delay_init();和delay_ms(10);兩個函數。延時函數要想完全搞清楚其中的原理需要了解STM32內核中定時器的知識,不是三兩句可以解釋清楚的,以後有時間再寫一篇詳細介紹一下延時函數,寫完後貼到這裏來。對於剛剛接觸STM32的同學來說,我建議剛開始就會調用這個函數就好了,不要深究其實現原理,因爲涉及其它內容比較多,零基礎剛開始接觸STM32,去看那些,如果看不懂挺打擊人積極性的。這兩個函數的調用方法:delay_ms(10);調用時候傳遞一個整形參數n,表示要延時n毫秒,如果程序中用到了delay_ms(n);函數,那麼在調用延時函數前要調用延時初始化函數delay_init();就是這樣無參調用就好了。另外,delay_ms(n);函數調用時候n的值也不能過大,n的值是有一個上限的,這就像int所能表示的最大值也是有上限的一樣。具體的這個值是多少,是和時鐘頻率有關的,對時鐘頻率爲72M的條件下(這算是個默認條件了),n<=1864。 
上面說的兩個延時函數都不是自己寫的,正點原子的每個實驗代碼的SYSTEM文件夾的delay.c文件中都有這個代碼,所以博主就拿來主義了,很方便。如果是別的開發板,可以查查手冊看怎樣能實現延時的功能,實在不行,下面的代碼也能實現延時……
void Delay(u32 count)
{
  u32 i=0;
  for(;i<count;i++);

}


2.LED_Init();和KEY_Init();函數
這兩個函數是自己寫的,就是對IO口的相關參數進行配置,先上代碼:
void LED_Init(void)
{
 
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE);	 //使能PA,PD端口時鐘
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;				 //LED0-->PA.8 端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推輓輸出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度爲50MHz
	GPIO_Init(GPIOA, &GPIO_InitStructure);					 //根據設定參數初始化GPIOA.8
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;	    		 //LED1-->PD.2 端口配置, 推輓輸出
	GPIO_Init(GPIOD, &GPIO_InitStructure);	  				 //推輓輸出 ,IO口速度爲50MHz
}

void KEY_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);//使能PORTA,PORTC時鐘
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_15;		//PA15
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 		//設置成上拉輸入
 	GPIO_Init(GPIOA, &GPIO_InitStructure);			//初始化GPIOA15
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_5;		//PC5
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 		//設置成上拉輸入
 	GPIO_Init(GPIOC, &GPIO_InitStructure);			//初始化GPIOC5
 
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;//PA0
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0設置成輸入,默認下拉	  
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0	
}

關於GPIO口的初始化,可以參考博主的上一篇文章,STM32 嵌入式學習入門(2)——STM32的GPIO介紹
至於這裏配置爲什麼是這些參數,是根據開發板硬件連接確定的,上面的代碼是正點原子MiniSTM32F103RCT6開發板的代碼,這款開發板的原理圖如下圖:





從這裏可以看出來按鍵對應的IO口以及它們是與高電平相連還是低電平相連。比如兩個LED,硬件上,它們都是與高電平相連的,所以你把另一端設置爲低電平的時候它們就被點亮,如果另一端設置爲高電平,那麼它們就滅。另外IO口的模式也是從硬件連接上確定的。


3.KEY_Scan(0);函數的實現
這個函數的實現其實不難,和STM32的知識沒多大關係,就是C語言的邏輯問題,代碼如下:
//按鍵處理函數
//返回按鍵值
//mode:0,不支持連續按;1,支持連續按;
//返回值:
//0,沒有任何按鍵按下
//KEY0_PRES,KEY0按下
//KEY1_PRES,KEY1按下
//WKUP_PRES,WK_UP按下 
//注意此函數有響應優先級,KEY0>KEY1>WK_UP!!
u8 KEY_Scan(u8 mode)
{	 
	static u8 key_up=1;//按鍵按鬆開標誌
	if(mode)key_up=1;  //支持連按		  
	if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
	{
		delay_ms(10);//去抖動 
		key_up=0;
		if(KEY0==0)
			return KEY0_PRES;
		else 
			if(KEY1==0)
				return KEY1_PRES;
		else
			if(WK_UP==1)
				return WKUP_PRES;
	}else 
	if(KEY0==1&&KEY1==1&&WK_UP==0)
		key_up=1;
	return 0;// 無按鍵按下
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章