51微控制器入門:獨立按鍵(02)

Arciab發表於2024-11-26

標題:

​ 51微控制器入門:獨立按鍵(02)

一、獨立按鍵的基本結構和功能

image-20241126151245755

二、獨立按鍵在微控制器的位置

image-20241126151350021

三、初次使用獨立按鍵

設計第1個程式,使用按鍵K1控制D1的亮滅

#include<regx52.h>

void main()
{
	while(1)
	{
		if(P3_1 == 0)  // 按下按鈕相當於接地 P3_1 == 0; 
		{
			P2_0 = 0;  // 亮
		}
		else
		{
			P2_0 = 1;  // 滅
		}
	}	
}

解釋一下為什麼是P3_1==0,看原理圖可以發現按下後P3_1接地,此時為低電平,且此時P3_1為讀取值,所以等於零表示按下獨立按鍵

image-20241126181304080

實現現象:

需要指出的是,由於Proteus軟體是在最理想的情況下模擬,完全消除了按鍵抖動的影響,所以這段簡單的程式碼無法有效實現單次點選後LED常亮或熄滅,關於按鍵抖動下面會介紹到。

動畫

四、新的知識點也是重點:抖動

在我們按下或鬆開“獨立按鍵”時,由於材料原因金屬彈片就會在極短的時間內上下波動,造成整個電路的頻繁開關。這段抖動時間極短,大約只有10ms(不會察覺到),但由於微控制器執行頻率都在兆赫茲,所以這種抖動可以被微控制器檢測到並做出反應,所以如果不消除抖動的影響就會造成按鍵“失靈”的現象。

img

抖動的消除:可以分成硬體消抖和軟體消抖(這些圖片都是在網上找到的,對於原作者在這裡表示感謝。)

硬體消抖原理:利用電容充/放電需要時間起到延時的作用消抖,這種方式也可以使用軟體來實現,下面將會介紹到。

image-20241126152752647

當按下按鈕K1後電容開始放電,此時引腳KeyIn1檢測到的依然是高電平1,當電容放電結束「在這段時間中按鍵抖動已消除」KeyIn1接地導通檢測到低電平0;當鬆開按鈕K1後電容開始充電,此時引腳keyIn1檢測到的依然是低電平0,當電容充電結束「在這段時間中按鍵抖動已消除」KeyIn1接地導通檢測到高電平1。

軟體消抖原理:新增延時函式,在按鍵按下後延時一段時間(一般為20ms)跳過抖動。(重點)

這也是第2個程式:獨立按鍵控制LED狀態

#include<regx52.h>  // 標頭檔案

void Delay(unsigned int n) //設定延時函式,實現軟體消抖,這個函式執行依次大約延時1ms
{
	unsigned char j;
	while(n--)
	{
		for(j = 0; j < 113; j++);
	}
}

void main()
{
	while(1)
	{	
		if(P3_1 == 0)
		{
			Delay(20);					//按下按鍵延時20ms消抖
			while(P3_1 == 0);			//如果按鍵持續按下,就進入這個迴圈直到鬆開,進入下面的延時函式
			Delay(20);					//鬆開按鍵延時20ms消抖
			
			P2_0 = ~P2_0;				//取反,實現按鍵控制LED狀態
		}
	}
}

實驗現象:

動畫

五、獨立按鍵控制LED燈顯示二進位制

第3個程式:

#include<regx52.h>

void Delay(unsigned int n)  // 延時函式
{
	unsigned char j;
	while(n--)
	{
		for(j = 0; j < 113; j++);
	}
}

void main()
{
	unsigned char NUM = 0;  //0000 0000 定義初始值
	while(1)
	{
		if(P3_1 == 0)
		{
			Delay(20);
			while(P3_1 == 0);
			Delay(20);
			
			NUM++;		 //舉例: 0000 0001  每次加1 實現二進位制  如下次為 0000 0010
			P2 = ~NUM;   //舉例: 1111 1110  將NUM取反變成 1111 1101 只點亮特定的LED	
		}
	}
}

感覺上面說的不明白,在下面詳細解釋下:

// 首先定義無符號字元型變數NUM
// 將 NUM 賦初值為 0  換算為二進位制就為 0000 0000 
// 進入 while 迴圈
	// 按鍵按下 NUM + 1  此時NUM等於1 二進位制表示 0000 0001   取反  1111 1110  點亮D1
	// 按鍵按下 NUM + 1  此時NUM等於2 二進位制表示 0000 0010   取反  1111 1101  點亮D2
	// 按鍵按下 NUM + 1  此時NUM等於3 二進位制表示 0000 0011   取反  1111 1100  點亮D1、D2
	// 依次類推……
	// 按鍵按下 NUM + 1  此時NUM等於15 二進位制表示 1111 1111   取反  0000 0000  點亮D1、D2、D3、D4、D5、D6、D7、D8
	
	// 按下按鍵 NUM + 1  此時NUM等於16 資料溢位 NUM等於0 開始重新計數

實驗現象:

動畫

六、獨立按鍵控制LED燈左右移動

這個部分需要重點介紹移位運算子,第4個程式:

#include<regx52.h>

void Delay(unsigned int n)  // 延時函式
{
	unsigned char j;
	while(n--)
	{
		for(j = 0; j < 113; j++);
	}
}

unsigned char LEDNum = 0; // 定義無符號字元型變數 LEDNum

void main()
{
	P2_0 = 0; // 初始化,點亮第一個LED
	while(1)
	{
		if(P3_0 == 0)
		{
			Delay(20);
			while(P3_0 == 0); // 這部分都是按鍵操作,下面不再註釋
			Delay(20);
			
			LEDNum++;  // 設定移位數
			if(LEDNum >= 8) // 由於是從D1(不是D0)開始移位 LEDNum 等於 7 就是D8點亮,所以當LEDNum等於8時要使其制0歸位
				LEDNum = 0; // LEDNum 置0
			
			P2 = ~(0X01 << LEDNum); // << 左移位運算子 舉例: 0000 0001  <<  2 就成為 0000 0100 取反 1111 1011
		}
		
		if(P3_1 == 0)
		{
			Delay(20);
			while(P3_1 == 0); // 按鍵
			Delay(20);
			
			if(LEDNum == 0) // 由於LEDNum是無符合字元型,小於0時LEDNum會從1111 1111倒數,所以要防止其小於0置7,使D8點亮
				LEDNum = 7;
			else
				LEDNum--;   // LEDNum依次遞減
			
			P2 = ~(0X01 << LEDNum); // << 左移位運算子 舉例: 0000 0001  <<  7 就成為 1000 0000 取反 0111 1111
		}		
	}
}

實驗現象:

動畫

相關文章