找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2503|回復(fù): 16
打印 上一主題 下一主題
收起左側(cè)

51單片機單個IO口ADC檢測4個按鍵不穩(wěn)定

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:705846 發(fā)表于 2023-11-23 19:24 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
15W401AS單片機
單個IO口ADC檢測4個按鍵,采用ADC查詢方式。

1,按鍵檢測很不穩(wěn)定,如何增加穩(wěn)定性;
2,如何做到松鍵有效的功能;

        P1M1 = 0x83;
        P1M0 = 0x00;

                while(set_state ==0)
                {        
                //CTR按鍵檢測---------------
                                
                        key_vol = GetADCResult_key()*100; //按鍵電壓放大100倍
                        //reset = 375
                        if(key_vol>365 && key_vol<385) //reset按鍵
                                {
                                        delay_us(10);
                                        if(key_vol>365 && key_vol<385)
                                        {        CTR = CTRoff;
                                                state_cur = 0;
                                        }
                                }         

                        //set按鍵檢測
                        if(key_vol>0 && key_vol<100)
                        //set = 0
                                {
                                        delay_us(10);
                                        if(key_vol>0 && key_vol<100)
                                        {
                                        set_state=1;
                                        setplace=0;
                                        }
                                }
                        //while(!key_vol>1 && key_vol<20);
                }  //默認狀態(tài)結(jié)束

                while(set_state==1)//設(shè)置狀態(tài)
                        {
                        key_vol = GetADCResult_key()*100; //按鍵電壓放大100倍
                        //k2-=335,k1+=252,set=0        

                                if(setplace==0)
                                {
                                        DisplayData[0]=0x31;//時間設(shè)置T00分鐘
                                        DisplayData[1]=DIG_CODE[set1/10%10];
                                        DisplayData[2]=DIG_CODE[set1%10];
                                }
                                if(setplace==1)
                                {
                                        DisplayData[0]=0x73;//檢測功率閥值設(shè)置P00
                                        DisplayData[1]=DIG_CODE[set2/10%10];
                                        DisplayData[2]=DIG_CODE[set2%10];
                                }
                                if(setplace==2)
                                {
                                        DisplayData[0]=0x39;//下降比例設(shè)置C00
                                        DisplayData[1]=DIG_CODE[set3/10%10];
                                        DisplayData[2]=DIG_CODE[set3%10];
                                }
                                if(setplace==3)
                                {
                                        DisplayData[0]=0x3F;//過流功率設(shè)置
                                        DisplayData[1]=0x3E;
                                        DisplayData[2]=0x73;
                                        DisplayData[3]=DIG_CODE[set4/100];
                                        DisplayData[4]=DIG_CODE[set4/10%10];
                                        DisplayData[5]=DIG_CODE[set4%10];
                                }
        
                                if(key_vol>240 && key_vol<265)        //K1+按鍵設(shè)置        
                                {
                                        delay_us(10);
                                        if(key_vol>240 && key_vol<265)
                                        {
                                                if(setplace==0)
                                                {
                                                        set1++;
                                                        if(set1>10)
                                                        set1=10;
                                                }
                                                if(setplace==1)
                                                {
                                                        set2++;
                                                        if(set2>20)
                                                        set2=20;
                                                }
                                                if(setplace==2)
                                                {
                                                        set3++;
                                                        if(set3>99)
                                                        set3=99;
                                                }
                                                if(setplace==3)
                                                {
                                                        set3++;
                                                        if(set3>150)
                                                        set3=150;
                                                }
                                        }        
                                        save();
                                        while(key_vol>240 && key_vol<265);
                                }        
        
                                if(key_vol>325 && key_vol<345)                //K2-按鍵設(shè)置
                                {
                                        delay_us(10);
                                        if(key_vol>325 && key_vol<345)
                                        {
                                                if(setplace==0)
                                                {
                                                        set1--;
                                                        if(set1<1)
                                                        set1=0;
                                                }
                                                if(setplace==1)
                                                {
                                                        set2--;
                                                        if(set2<1)
                                                        set2=1;
                                                }
                                                if(setplace==2)
                                                {
                                                        set3--;
                                                        if(set3<1)
                                                        set3=1;
                                                }
                                                if(setplace==3)
                                                {
                                                        set4--;
                                                        if(set4<1)
                                                        set3=1;
                                                }
        
                                        }        
                                        save();
                                        while(key_vol>325 && key_vol<345);
                                }        
        
                                if(key_vol>0 && key_vol<100)               
                                {
                                        delay_us(10);
                                        if(key_vol>0 && key_vol<100)
                                        {
                                                setplace++;
                                                if(setplace>=4)
                                                {
                                                        setplace=0;
                                                        set_state=0;//返回
                                                }
                                        }        
                                        while(key_vol>0 && key_vol<100);
                                }        
                        } //參數(shù)設(shè)置結(jié)束

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏2 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:213173 發(fā)表于 2023-11-23 21:12 | 只看該作者
ADC檢測按鍵不穩(wěn)定與軟、硬件設(shè)計密切相關(guān)。按鍵電壓放大100倍沒有任何實際意義。如果4個分壓電阻等值,4個按鍵的判斷值就是0、1/2、2/3、3/4 VCC。一般以10ms周期經(jīng)3次以上ADC檢測取平均值。允許一定的誤差。10位ADC的±誤差一般不超過10個字。
回復(fù)

使用道具 舉報

板凳
ID:705846 發(fā)表于 2023-11-23 23:02 | 只看該作者
如何做到松按鍵有效的功能;
回復(fù)

使用道具 舉報

地板
ID:213173 發(fā)表于 2023-11-24 07:30 | 只看該作者
samxon 發(fā)表于 2023-11-23 23:02
如何做到松按鍵有效的功能;
  1. void KeyScan()//按鍵掃描函數(shù)放在約10ms周期的環(huán)境運行
  2. {
  3.         static unsigned char count=0;
  4.         static bit sign=0;
  5.         key_vol = GetADCResult_key();//10位ADC,最大值1023
  6.         if(key_vol<1015)//有鍵按下
  7.         {
  8.                 if(++count>3 && !sign)//丟掉前3次檢測,第4次檢測值基本穩(wěn)定
  9.                 {
  10.                         sign=1;
  11.                         if(key_vol<=10)Key_value=1;//xx的值由實際采用的分壓電阻計算
  12.                         else if(key_vol>10 && key_vol<=xx)Key_value=2;
  13.                         else if(key_vol>xx && key_vol<=xx)Key_value=3;
  14.                         else if(key_vol>xx && key_vol<=xx)Key_value=4;
  15.                 }
  16.         }
  17.         else //key_vol>=1015表示松手或沒有鍵按下
  18.         {
  19.                 count=0;
  20.                 sign=0;
  21.         }
  22. }
  23. void key_service()                //按鍵服務(wù)程序
  24. {
  25.         switch(Key_value)
  26.         {
  27.                 case 1: /*任務(wù)1*/Key_value=0; break;
  28.                 case 2: /*任務(wù)2*/Key_value=0; break;
  29.                 case 3: /*任務(wù)3*/Key_value=0; break;
  30.                 case 4: /*任務(wù)4*/Key_value=0; break;
  31.                 default: break;
  32.         }
  33. }       
復(fù)制代碼
回復(fù)

使用道具 舉報

5#
ID:123289 發(fā)表于 2023-11-24 09:24 | 只看該作者
1、先調(diào)試:每個按鍵按下去,分別記下各自的按鍵值作為參考。
2、定標準:以此四個值為中心,給個公差,作為各自按下的界定標準。
這樣就可以了。
回復(fù)

使用道具 舉報

6#
ID:705846 發(fā)表于 2023-11-24 19:39 | 只看該作者
double GetADCResult_key()
{

        ADC_CONTR = 0x8F; //按鍵檢測電壓采集10001111 P1.7采集器
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        while(!(ADC_CONTR & 0x10)); //等待ADC轉(zhuǎn)換完成
        ADC_CONTR &= ~0x10; //CLOSE ADC
        return (ADC_RES*256+ADC_RESL)*(5.05)/1024; // 根據(jù)電壓判定按鍵
}
回復(fù)

使用道具 舉報

7#
ID:705846 發(fā)表于 2023-11-25 10:27 | 只看該作者

請教,把key_scan() 放到1毫秒計時器2內(nèi),整個程序都堵死了,是什么原因呢。

void Init_Timer0(void)
{

        AUXR |= 0x80;                        //定時器時鐘1T模式
        TMOD &= 0xF0;                        //設(shè)置定時器模式
        TL0 = 0xCD;                                //設(shè)置定時初始值
        TH0 = 0xD4;                                //設(shè)置定時初始值
        TR0 = 1;                                //定時器0開始計時
        ET0 = 1;                                //使能定時器0中斷

        AUXR |= 0x04;                        //定時器時鐘1T模式
        T2L = 0xCD;                                //設(shè)置定時初始值
        T2H = 0xD4;                                //設(shè)置定時初始值
        AUXR |= 0x10;                        //定時器2開始計時
        IE2 |= 0x04;                        //使能定時器2中斷

}

void Timer2_isr(void) interrupt 12           //定時器2中斷入口
{
        time_cur++;
        if(time_cur == Time1s)
        {
        time_cur=0;
        }
        keyadc++;
        if(keyadc == 10)
        {       
                KeyScan();
                keyadc=0;
        }
}
回復(fù)

使用道具 舉報

8#
ID:192020 發(fā)表于 2023-11-25 10:36 | 只看該作者
                        if(key_vol>365 && key_vol<385) //reset按鍵
                                {
                                        delay_us(10);
                                        if(key_vol>365 && key_vol<385)
                                        {        CTR = CTRoff;
                                                state_cur = 0;
                                        }
                                }     
這個delay_us(10);我猜應(yīng)該是為了消抖才加的吧?但從程序看是沒有消抖作用,key_vol的值延時前后都沒有變,應(yīng)該把延時去掉,多次循環(huán)來消抖
回復(fù)

使用道具 舉報

9#
ID:705846 發(fā)表于 2023-11-25 10:52 | 只看該作者
qq475878026 發(fā)表于 2023-11-25 10:36
if(key_vol>365 && key_vol365 && key_vol

沒有達到目的。key_scan()設(shè)置1秒刷新,程序可以正常,10ms就堵死。另外key_vol, key_value似乎也讀取不到值。調(diào)整了ADC的采樣速度也沒有改善,注釋掉定時器2的key_scan(),程序可以運行起來。
回復(fù)

使用道具 舉報

10#
ID:213173 發(fā)表于 2023-11-25 14:00 | 只看該作者
samxon 發(fā)表于 2023-11-25 10:27
請教,把key_scan() 放到1毫秒計時器2內(nèi),整個程序都堵死了,是什么原因呢。

void Init_Timer0(void)
...

中斷中不宜運行較多代碼,只要做個時間標志,代碼放在主函數(shù)中運行。
void Init_Timer0(void)
{
        AUXR |= 0x80;                        //定時器時鐘1T模式
        TMOD &= 0xF0;                        //設(shè)置定時器模式
        TL0 = 0xCD;                                //設(shè)置定時初始值
        TH0 = 0xD4;                                //設(shè)置定時初始值
        TR0 = 1;                                //定時器0開始計時
        ET0 = 1;                                //使能定時器0中斷
       
        AUXR |= 0x04;                        //定時器時鐘1T模式
        T2L = 0xCD;                                //設(shè)置定時初始值
        T2H = 0xD4;                                //設(shè)置定時初始值
        AUXR |= 0x10;                        //定時器2開始計時
        IE2 |= 0x04;                        //使能定時器2中斷

}

void Timer2_isr(void) interrupt 12           //定時器2中斷入口
{
        static unsigned char count=0;
        time_cur++;
        if(time_cur == Time1s)
        {
                time_cur=0;
        }
        if(time_cur%10==0)//10ms
        {
                flag=1;
        }
}

void main()
{
        P1M0 = 0x00;
        P1M1 = 0x01;//P1.0高阻
        Init_Timer0();
        InitADC();
        while(1)
        {
                if(flag)       
                {
                        flag=0;
                        KeyScan();
                        key_service();
                }       
                //其它子程序
        }
}
回復(fù)

使用道具 舉報

11#
ID:192020 發(fā)表于 2023-11-25 14:18 | 只看該作者
samxon 發(fā)表于 2023-11-25 10:52
沒有達到目的。key_scan()設(shè)置1秒刷新,程序可以正常,10ms就堵死。另外key_vol, key_value似乎也讀取不 ...

這不是說卡死的原因,是說程序有優(yōu)化的空間,整個流程下來的delay_us(10)貌似是消抖,實則只檢測了一次ad就判斷,很容易誤觸發(fā)其他按鍵。
回復(fù)

使用道具 舉報

12#
ID:705846 發(fā)表于 2023-11-25 18:49 | 只看該作者

能不能解釋下 if(++count>3 && !sign)//丟掉前3次檢測,第4次檢測值基本穩(wěn)定,
!sign是什么意思
回復(fù)

使用道具 舉報

13#
ID:213173 發(fā)表于 2023-11-25 20:28 | 只看該作者
samxon 發(fā)表于 2023-11-25 18:49
能不能解釋下 if(++count>3 && !sign)//丟掉前3次檢測,第4次檢測值基本穩(wěn)定,
!sign是什么意思

這樣寫的依據(jù)是一旦ADC檢測結(jié)果小于1015(經(jīng)驗值)就判斷有鍵按下,但由于按鍵會有抖動,并且ADC檢測值也沒有穩(wěn)定,需要延時10~20ms等待穩(wěn)定。當按鍵掃描函數(shù)在約10ms周期的環(huán)境運行時,經(jīng)過前3次采樣(當然可以更多次),ADC檢測值基本處于穩(wěn)定狀態(tài)。第4次檢測值就可以作為判斷依據(jù)(為簡化沒有采用多次采樣取平均值)。sign位變量既可以反映按鍵當前狀態(tài),也是自鎖。長時間持續(xù)按住不松手或其它鍵此時被誤按也不會有響應(yīng)。在此期間count無論加到什么數(shù)都不會再次觸發(fā)。只有等待松手 count、sign清0后按鍵掃描函數(shù)才恢復(fù)初始狀態(tài)。
回復(fù)

使用道具 舉報

14#
ID:213173 發(fā)表于 2023-11-25 21:06 | 只看該作者
void KeyScan()//按鍵掃描函數(shù)放在約10ms周期的環(huán)境運行
{
        static unsigned char count=0;
        static bit sign=0;
        key_vol = GetADCResult_key();//10位ADC,最大值1023
        if(key_vol<1015)//有鍵按下
        {
                if(++count>3 && !sign)//丟掉前3次檢測,第4次檢測值基本穩(wěn)定
                {
                        sign=1;
                        //ADC值以4個等值(10K)分壓電阻計算
                        if(key_vol<16)                     Key_value=1;//  0 VCC   0 +/- 16
                        else if(key_vol>496 && key_vol<528)Key_value=2;//1/2 VCC 512 +/- 16
                        else if(key_vol>666 && key_vol<698)Key_value=3;//2/3 VCC 682 +/- 16
                        else if(key_vol>752 && key_vol<784)Key_value=4;//3/4 VCC 768 +/- 16
                }
        }
        else //key_vol>=1015表示松手或沒有鍵按下
        {
                count=0;
                sign=0;
        }
}

void key_service()                //按鍵服務(wù)程序
{
        switch(Key_value)
        {
                case 1: /*任務(wù)1*/Key_value=0; break;
                case 2: /*任務(wù)2*/Key_value=0; break;
                case 3: /*任務(wù)3*/Key_value=0; break;
                case 4: /*任務(wù)4*/Key_value=0; break;
                default: break;
        }
}

回復(fù)

使用道具 舉報

15#
ID:1034262 發(fā)表于 2023-11-25 21:25 | 只看該作者
STC15W408AS系列的ADC是10位,我做過比較多的ADC按鍵是8~32個鍵,32個鍵時每個鍵占讀數(shù)32,而408AS的誤差最大10個字,抖動一般小于4個字,足夠的。
回復(fù)

使用道具 舉報

16#
ID:705846 發(fā)表于 2023-11-26 09:27 | 只看該作者
wulin 發(fā)表于 2023-11-25 21:06
void KeyScan()//按鍵掃描函數(shù)放在約10ms周期的環(huán)境運行
{
        static unsigned char count=0;

雖然問題解決,但還有幾個問題不明白,請指點一下:
1)為什么ADC結(jié)果換算后就判定不準確;
2)按鍵檢測條件內(nèi)的sign是如何工作的。

改進后的代碼
ADC改為中斷模式
keyscan()放在定時器內(nèi)10ms運行
ADC_init()放定時器內(nèi)10ms運行

按鍵問題解決;

以前是:key_vol = (ADC_RES*256+ADC_RESL)*(5.05)/1024 //key_vol換算成電壓后,放大100倍再判定值。

現(xiàn)在是:key_vol = (ADC_RES*256+ADC_RESL); //直接判定key_vol

void KeyScan()//按鍵掃描函數(shù)放在約10ms周期的環(huán)境運行
{
        static unsigned char count=0;
        static bit sign=0;
        temp_keyvol = key_vol;//10位ADC,最大值1023
        if(key_vol<1000)//有鍵按下
        {
                if(++count>3 && !sign) //丟掉前3次檢測,第4次檢測值基本穩(wěn)定
                {
                        sign=1;
                        if(temp_keyvol<=50)key_value=1;//set鍵按下
                        else if(temp_keyvol>450 && temp_keyvol<=550)key_value=2; //K1+鍵按下
                        else if(temp_keyvol>650 && temp_keyvol<=700)key_value=3; //K2-鍵按下
                        else if(temp_keyvol>750 && temp_keyvol<=800)key_value=4; //Reset鍵按下
                }
        }
        else //key_vol>=1015表示松手或沒有鍵按下
        {
                count=0;
                sign=0;
        }
}
回復(fù)

使用道具 舉報

17#
ID:213173 發(fā)表于 2023-11-26 14:16 | 只看該作者
samxon 發(fā)表于 2023-11-26 09:27
雖然問題解決,但還有幾個問題不明白,請指點一下:
1)為什么ADC結(jié)果換算后就判定不準確;
2)按鍵檢 ...

1)為什么ADC結(jié)果換算后就判定不準確;
你不是做電壓表,轉(zhuǎn)換結(jié)果不需要換算成電壓值。如果VCC不十分精準或有波動再加上運算后舍棄小數(shù)誤差就更大。因為轉(zhuǎn)換結(jié)果是比值,直接使用轉(zhuǎn)換結(jié)果不會因VCC變化而變化。
2)按鍵檢測條件內(nèi)的sign是如何工作的。
sign初始為0,當檢測到有鍵按下,count開始計數(shù),但計數(shù)到4,滿足判斷條件,執(zhí)行花括號內(nèi)代碼,sign=1;。當再次運行到 if(++count>3 && !sign) ,判斷條件已經(jīng)不成立。也就不會重復(fù)響應(yīng)。必須等按鍵松手才能恢復(fù)初始狀態(tài)。sign在這里起到自鎖作用。
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表