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