一)按鍵行列掃描與蜂鳴器
(1)技術體會:在行列式掃描結構的薄膜按鍵里,干擾很大,按鍵掃描程序非常講究,尤其是去抖動的處理。
(2)功能需求:每按一個按鍵,蜂鳴器就響一次。
(3)硬件原理:
(a)用4個IO來做2X2按鍵行列掃描,其中作為輸入的2個IO口必須接上拉電阻20K左右。
(b)用1個IO經過8050三極管來驅動有源蜂鳴器,有源蜂鳴器通電就一直響,斷電就停止。而無源蜂鳴器是要靠斷斷續續的開關信號來驅動才能響,就是要頻率來驅動。
(4)源碼適合的單片機:PIC18F4620,晶振為22.1184MHz
(5)源代碼講解如下:
#include //包含芯片相關頭文件
//補充說明:吳堅鴻程序風格是這樣的,凡是輸出IO后綴都是_dr,凡是輸入的//IO后綴都//是_sr
#define beep_dr LATA1 //蜂鳴器輸出
#define key_dr1 LATB3 //2X2按鍵行輸出
#define key_dr2 LATB4 //2X2按鍵行輸出
#define key_sr1 RB6 //2X2按鍵行輸入
#define key_sr2 RB7 //2X2按鍵行輸入
//補充說明:吳堅鴻程序風格是這樣的,凡是做延時計數閥值的常量
//前綴都用cnt_表示。
#define cnt_delay_cnt1 25 //按鍵去抖動延時閥值
#define cnt_delay_cnt2 5 //按鍵行輸出信號穩定的小延時閥值
#define cnt_voice_time 60 //蜂鳴器響的聲音長短的延時閥值
void delay1(unsigned int de) ;//小延時程序,時間不宜太長,因為內部沒有喂看門狗
//補充說明:吳堅鴻程序風格是這樣的,凡是按鍵掃描函數都放在定時中
//斷里,凡是按鍵服務程序都是放在main函數循環里。有人說不應該把子程序//放在中斷里,別聽他們,信鴻哥無坎坷。
void key_scan(); //按鍵掃描函數,放在定時中斷里
void key_service(); //按鍵服務函數,放在main函數循環里
//補充說明:吳堅鴻程序風格是這樣的,凡是switch()語句括號里面的變量名
//后綴都用_step表示。
unsigned char key_step=1; //按鍵掃描步驟變量,在switch()語句的括號里
//補充說明:吳堅鴻程序風格是這樣的,凡是按鍵或者感應輸入的自鎖變量名
//后綴都用_lock表示。
unsigned char key_lock1=0; //按鍵自鎖標志
//補充說明:吳堅鴻程序風格是這樣的,凡是計數器延時的變量
//后綴都用_cnt表示。
unsigned int delay_cnt1=0; //延時計數器的變量
unsigned int delay_cnt2=0; //延時計數器的變量
unsigned int voice_time_cnt; //蜂鳴器響的聲音長短的計數延時
//補充說明:吳堅鴻程序風格是這樣的,凡是做類型的變量的分類
//后綴都用_sec表示。
Unsigned char key_sec=0; //哪個按鍵被觸發
//主程序
main()
{
ADCON0=0x00;
ADCON1=0x0f; //全部為數字信號
ADCON2=0xa1; //右對齊
RBPU=0; //上拉電阻
SSPEN=0; //決定RA5不作為串口
TRISB3=0; //配置按鍵行掃描IO為輸出
TRISB4=0; //配置按鍵行掃描IO為輸出
TRISB6=1; //配置按鍵列掃描IO為輸入
TRISB7=1; //配置按鍵列掃描IO為輸入
T1CON=0x24; //定時器中斷配置
TMR1H=0xF5;
TMR1L=0x5F;
TMR1IF=0;
TMR1IE=1;
TMR1ON=1;
TMR1IE=1;
//補充說明,以上的內容為寄存器配置,每種不同的單片機會有點差異,
//大家不用過度關注以上寄存器的配置,只要知道有這么一回事即可
beep_dr=0; //關蜂鳴器,上電初始化IO
while(1)
{
CLRWDT(); //喂看門狗,大家不用過度關注此行
key_service(); //按鍵服務
}
}
void key_scan() //按鍵掃描函數
{
//補充說明:如果中斷一次就把所有的按鍵都掃描完,中斷占用的時間片就會太多,勢//必會影響main函數里其他子程序的運行,為了避免一口氣把所//的按鍵都掃描完,此
//處用switch語句把4個按鍵分成2等分,一次中斷只掃描2個按鍵
switch(key_step) //按鍵掃描步驟,
{
case 1: //掃描1號鍵,2號鍵
key_dr1=0; //按鍵行掃描輸出第一行低電平
key_dr2=1;
delay_cnt2=0; //延時計數器清零
key_step++; //切換到下一個運行步驟
break;
case 2:
delay_cnt2++;
if(delay_cnt2>cnt_delay_cnt2) //小延時,但不是去抖動延時,替代一直受網友爭議的delay1(40)
{
delay_cnt2=0;
key_step++; //切換到下一個運行步驟
}
break;
case 3:
if(key_sr1==1&&key_sr2==1)
{ //如果沒有按鍵按下,則2個IO輸入都是高電平
key_step++; //如果沒有按鍵按下,下一個中斷掃描下2個