第九章? 獨立按鍵
按鍵的作用相當于一個開關,按下時接通(或斷開),松開后斷開(或接通)。實物圖、原理圖、封裝
9.2 需求描述
通過 SW1、SW2、SW3、SW4 四個獨立按鍵分別控制 LED1、LED2、LED3、LED4
的亮滅,具體要求是,按一下(按下并松開)SW,LED 點亮,再按一下 SW,LED 熄滅。
9.3 硬件設計
9.3.1 實現思路
為實現上述需求,需要設法令單片機感知到按鍵被按下,也就是說在按鍵被按下時,
需要向單片機發送一個信號,當單片機收到該信號后,再執行控制 LED 的邏輯即可。
由于 51 單片機的 GPIO 引腳的默認均為高電平,因此只需將按鍵的一側接入單片機的
某個 GPIO 引腳,另一側接地。這樣一來,當按鍵按下時,引腳直接接地,就相當于向單
片機發送了一個低電平信號。
9.3.2 硬件原理圖
9.4 軟件設計
9.4.1 初步實現
按照原理圖,SW1 按下時,P4.2 引腳會被拉低;SW2 按下時,P4.3 引腳會被拉低;
SW3 被按下時,P3.2 引腳會被拉低;SW4 按下時,P3.3 引腳會被拉低。
因此只需檢測上述引腳是否變為低電平即可,若檢測到變為低電平,就執行控制 LED
的邏輯。需要注意的是,按鍵的檢測需要持續進行,所以需要不停的檢查上述引腳是否變
為低電平。
9.4.2 按鍵單次觸發
當前代碼的邏輯是,只要按鍵處在按下的狀態,就觸發控制 LED 的邏輯。為實現單次
觸發,可以在按鍵按下后,等待按鍵抬起,并在抬起的一刻,執行控制 LED 的邏輯。
9.4.3 按鍵消抖
由于按鍵的抖動,單片機引腳的信號切換并不像我們想象的那樣干脆,實際情況如下
圖所示
9.4.4 規范代碼
按照前文的編碼規范,我們將檢測按鍵的代碼單獨抽取到 Int 層,具體代碼如下。
(1)Int_Key.h
?
#ifndef __INT_KEY_H__
#define __INT_KEY_H__
#include <STC89C5xRC.H>
#include "Util.h"
/**
* @brief 檢測 SW1 按鍵是否按下
*
* @return bit 是或否
*/
bit Int_Key_IsSW1Pressed();
/**
* @brief 檢測 SW2 按鍵是否按下
*
* @return bit 是或否
*/
bit Int_Key_IsSW2Pressed();
/**
* @brief 檢測 SW3 按鍵是否按下
*
* @return bit 是或否
*/
bit Int_Key_IsSW3Pressed();
/**
* @brief 檢測 SW4 按鍵是否按下
*
* @return bit 是或否
*/
bit Int_Key_IsSW4Pressed();
#endif /* __INT_KEY_H__ */
(2)Int_Key.c
#include "Int_Key.h"
#include <STC89C5xRC.H>
#include "Com_Util.h"
#define SW1 P42
#define SW2 P43
#define SW3 P32
#define SW4 P33bit Int_Key_IsSW1Pressed()
{if (SW1 == 0) {Com_Util_Delay1ms(10);if (SW1 == 0) {while (SW1 == 0);return 1;}}return 0;
}bit Int_Key_IsSW2Pressed()
{if (SW2 == 0) {Com_Util_Delay1ms(10);if (SW2 == 0) {while (SW2 == 0);return 1;}}return 0;
}bit Int_Key_IsSW3Pressed()
{if (SW3 == 0) {Com_Util_Delay1ms(10);if (SW3 == 0) {while (SW3 == 0);return 1;}}return 0;
}bit Int_Key_IsSW4Pressed()
{if (SW4 == 0) {Com_Util_Delay1ms(10);if (SW4 == 0) {while (SW4 == 0);return 1;}}return 0;
}
(3)Main.c
#include <STC89C5xRC.H>
#include "Int_Key.h"
#define LED1 P00
#define LED2 P01
#define LED3 P02
#define LED4 P03
void main()
{while (1) {if (Int_Key_IsSW1Pressed()) {LED1 = ~LED1;}if (Int_Key_IsSW2Pressed()) {LED2 = ~LED2;}if (Int_Key_IsSW3Pressed()) {LED3 = ~LED3;}if (Int_Key_IsSW4Pressed()) {LED4 = ~LED4;}}
}
?第 10 章 矩陣按鍵
按下按鍵矩陣中的 SW5 到 SW20 按鍵后,數碼管顯示對應的按鍵編號。
10.2 硬件設計
10.2.1 實現思路
由于按鍵矩陣中共有 4x4=16 個按鍵,如果每個按鍵都接入一個 GPIO 引腳,勢必會造
成引腳的浪費,為了節省引腳,我們同樣可以借用動態掃描的思想,具體邏輯如下。
10.2.2 51 單片機引腳內部結構
在上面的演示中,我們應注意的一個問題是:當高電平引腳和低電平引腳短接時,結
果是高電平引腳被拉低,而不是低電平引腳被拉高。這實際上是由 51 單片機引腳的內部結
構決定的,其簡化結構如下圖所示。
上圖的工作原理是:當端口鎖存器為 0 時,mos 管導通,此時引腳直接接地,輸出低
電平;當端口鎖存器為 1 時,mos 管關閉,引腳靠內部的弱上拉電阻(弱的意思是電流很
微弱,可進一步理解為上拉電阻的阻值很大)拉置高電平。
根據上圖,可以得出結論,當引腳輸出高電平時,很容易被被外部裝置拉低(因為上
拉電阻分壓多),而當引腳輸出低電平時,卻很難被拉高(因為引腳接地)。這就是常說的
弱上拉+強下拉模式。
所以在本節矩陣按鍵的例子中,當我們按下按鍵短接高低引腳,最終結果是高電平引
腳被拉低。
10.2.3 硬件原理圖
10.3 軟件設計
(1)Int_DigitalTube.h 和 Int_DigitalTube.c
數碼管項目中的 Int_DigitalTube.h 和 Int_DigitalTube.c 復制到當前項目的 Int 目錄。
(2)Int_MatrixKey.h
在項目的 Int 目錄下創建 Int_MatrixKey.h,寫入以下內容。
#ifndef __INT_KEYMATRIX_H__
#define __INT_KEYMATRIX_H__
#include"Com_Util.h"u8 Int_KetMatrix_CheckSW();#endif /* __INT_KEYMATRIX_H__ */
(3)Int_MatrixKey.c
在項目的 Int?目錄下創建 Int_MatrixKey.c,寫入以下內容。
#include "Int_KeyMatrix.h"
#include<STC89C5xRC.H>u8 Int_KetMatrix_CheckSW()
{u8 i,j;u8 lines[4]={0xFE,0xFD,0xFB,0xF7};u8 columns[4]={0x10,0x20,0x40,0x80};for (i = 0; i < 4; i++){ P2=lines[i];for ( j = 0; j< 4; j++){if((P2 & columns[j])==0){Com_Util_Delay1ms(10);if((P2 & columns[j])==0){while((P2 & columns[j])==0);return j+5+i*4;}}}}return 0;
}
(4)main.c
#include"Int_KeyMatrix.h"
#include"Int_DigitalTube.h"void main()
{u8 key;Int_DigitalTube_Init();while(1){key=Int_KetMatrix_CheckSW(); //檢測按鍵if(key){Int_DigitalTube_DisplayNum(key); }Int_DigitalTube_Refresh();}
}
?第 11 章 蜂鳴器
11.1 蜂鳴器簡介
蜂鳴器是一種能夠發出聲音的電子元器件,常用于報警、提示和音頻信號輸出等場景。
其內部結構如下圖所示。
當電流通過線圈時會產生電磁場,電磁場與永磁體相互作用,從而使金屬膜產生震動
而發聲。為使金屬膜持續震動,蜂鳴器需要使用震蕩電路進行驅動。有些蜂鳴器元件內部
自帶震蕩驅動電路,這種蜂鳴器叫做有源蜂鳴器(Active Buzzer,自激式蜂鳴器);而有些
則不帶震蕩驅動電路,這種蜂鳴器叫做無源蜂鳴器(Passive Buzzer,它激式蜂鳴器)。
更多信息可參考如下內容。
(1)有源蜂鳴器
(2)無源蜂鳴器
11.2 需求描述
為按鍵矩陣增加按鍵提示音,要求按鍵按下后,蜂鳴器響 0.1s。
11.3 硬件設計
11.3.1 硬件原理圖
本課程使用的是無源蜂鳴器,所以需要從外部輸入一定頻率的方波,方波的頻率就是
蜂鳴器發聲的頻率,這里我們使用 500Hz 的方波即可。
11.4 軟件設計
(1)Int_DigitalTube.h 和 Int_DigitalTube.c
將數碼管項目中的 Int_DigitalTube.h 和 Int_DigitalTube.c 復制到當前項目的 Int 目錄。
(2)Int_MatrixKey.h 和 Int_MatrixKey.c
將按鍵矩陣項目中的 Int_MatrixKey.h 和 Int_MatrixKey.c 復制到當前項目的 Int 目錄。
(3)Int_Buzzer.h
在 Int 目錄下創建 Int_Buzzer.h,寫入以下內容。
#ifndef __INT_BUZZER_H__
#define __INT_BUZZER_H__
#include <STC89C5xRC.H>
#define BUZZ P46
/**
* @brief 蜂鳴器響 0.1s
*
*/
void Int_Buzzer_Buzz();
#endif /* __INT_BUZZER_H__ */
(4)Int_Buzzer.c
在 Int 目錄下創建 Int_Buzzer.c,寫入以下內容。
#include "Int_Buzzer.h"
#include "Util.h"
void Int_Buzzer_Buzz()
{unsigned char counter = 100;while (counter) {BUZZ = ~BUZZ;Delay1ms(1);--counter;}
}
(5)Main.c
#include "Int_DigitalTube.h"
#include "Int_MatrixKey.h"
#include "Int_Buzzer.h"
int main()
{u8 key_pressed = 0;Int_DigitalTube_Init();Int_DigitalTube_DisplayNum(key_pressed);while (1) {key_pressed = Int_MatrixKey_CheckKey();if (key_pressed) {Int_DigitalTube_DisplayNum(key_pressed);Int_Buzzer_Buzz(); //按鍵提示音}Int_DigitalTube_Refresh();}
}