久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2586|回復: 16
收起左側

51單片機單個IO口ADC檢測4個按鍵不穩定

[復制鏈接]
ID:705846 發表于 2023-11-23 19:24 | 顯示全部樓層 |閱讀模式
15W401AS單片機
單個IO口ADC檢測4個按鍵,采用ADC查詢方式。

1,按鍵檢測很不穩定,如何增加穩定性;
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);
                }  //默認狀態結束

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

                                if(setplace==0)
                                {
                                        DisplayData[0]=0x31;//時間設置T00分鐘
                                        DisplayData[1]=DIG_CODE[set1/10%10];
                                        DisplayData[2]=DIG_CODE[set1%10];
                                }
                                if(setplace==1)
                                {
                                        DisplayData[0]=0x73;//檢測功率閥值設置P00
                                        DisplayData[1]=DIG_CODE[set2/10%10];
                                        DisplayData[2]=DIG_CODE[set2%10];
                                }
                                if(setplace==2)
                                {
                                        DisplayData[0]=0x39;//下降比例設置C00
                                        DisplayData[1]=DIG_CODE[set3/10%10];
                                        DisplayData[2]=DIG_CODE[set3%10];
                                }
                                if(setplace==3)
                                {
                                        DisplayData[0]=0x3F;//過流功率設置
                                        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+按鍵設置        
                                {
                                        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-按鍵設置
                                {
                                        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);
                                }        
                        } //參數設置結束

回復

使用道具 舉報

ID:213173 發表于 2023-11-23 21:12 | 顯示全部樓層
ADC檢測按鍵不穩定與軟、硬件設計密切相關。按鍵電壓放大100倍沒有任何實際意義。如果4個分壓電阻等值,4個按鍵的判斷值就是0、1/2、2/3、3/4 VCC。一般以10ms周期經3次以上ADC檢測取平均值。允許一定的誤差。10位ADC的±誤差一般不超過10個字。
回復

使用道具 舉報

ID:705846 發表于 2023-11-23 23:02 | 顯示全部樓層
如何做到松按鍵有效的功能;
回復

使用道具 舉報

ID:213173 發表于 2023-11-24 07:30 | 顯示全部樓層
samxon 發表于 2023-11-23 23:02
如何做到松按鍵有效的功能;
  1. void KeyScan()//按鍵掃描函數放在約10ms周期的環境運行
  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次檢測值基本穩定
  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()                //按鍵服務程序
  24. {
  25.         switch(Key_value)
  26.         {
  27.                 case 1: /*任務1*/Key_value=0; break;
  28.                 case 2: /*任務2*/Key_value=0; break;
  29.                 case 3: /*任務3*/Key_value=0; break;
  30.                 case 4: /*任務4*/Key_value=0; break;
  31.                 default: break;
  32.         }
  33. }       
復制代碼
回復

使用道具 舉報

ID:123289 發表于 2023-11-24 09:24 | 顯示全部樓層
1、先調試:每個按鍵按下去,分別記下各自的按鍵值作為參考。
2、定標準:以此四個值為中心,給個公差,作為各自按下的界定標準。
這樣就可以了。
回復

使用道具 舉報

ID:705846 發表于 2023-11-24 19:39 | 顯示全部樓層
double GetADCResult_key()
{

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

使用道具 舉報

ID:705846 發表于 2023-11-25 10:27 | 顯示全部樓層

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

void Init_Timer0(void)
{

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

        AUXR |= 0x04;                        //定時器時鐘1T模式
        T2L = 0xCD;                                //設置定時初始值
        T2H = 0xD4;                                //設置定時初始值
        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;
        }
}
回復

使用道具 舉報

ID:192020 發表于 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);我猜應該是為了消抖才加的吧?但從程序看是沒有消抖作用,key_vol的值延時前后都沒有變,應該把延時去掉,多次循環來消抖
回復

使用道具 舉報

ID:705846 發表于 2023-11-25 10:52 | 顯示全部樓層
qq475878026 發表于 2023-11-25 10:36
if(key_vol>365 && key_vol365 && key_vol

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

使用道具 舉報

ID:213173 發表于 2023-11-25 14:00 | 顯示全部樓層
samxon 發表于 2023-11-25 10:27
請教,把key_scan() 放到1毫秒計時器2內,整個程序都堵死了,是什么原因呢。

void Init_Timer0(void)
...

中斷中不宜運行較多代碼,只要做個時間標志,代碼放在主函數中運行。
void Init_Timer0(void)
{
        AUXR |= 0x80;                        //定時器時鐘1T模式
        TMOD &= 0xF0;                        //設置定時器模式
        TL0 = 0xCD;                                //設置定時初始值
        TH0 = 0xD4;                                //設置定時初始值
        TR0 = 1;                                //定時器0開始計時
        ET0 = 1;                                //使能定時器0中斷
       
        AUXR |= 0x04;                        //定時器時鐘1T模式
        T2L = 0xCD;                                //設置定時初始值
        T2H = 0xD4;                                //設置定時初始值
        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();
                }       
                //其它子程序
        }
}
回復

使用道具 舉報

ID:192020 發表于 2023-11-25 14:18 | 顯示全部樓層
samxon 發表于 2023-11-25 10:52
沒有達到目的。key_scan()設置1秒刷新,程序可以正常,10ms就堵死。另外key_vol, key_value似乎也讀取不 ...

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

使用道具 舉報

ID:705846 發表于 2023-11-25 18:49 | 顯示全部樓層

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

使用道具 舉報

ID:213173 發表于 2023-11-25 20:28 | 顯示全部樓層
samxon 發表于 2023-11-25 18:49
能不能解釋下 if(++count>3 && !sign)//丟掉前3次檢測,第4次檢測值基本穩定,
!sign是什么意思

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

使用道具 舉報

ID:213173 發表于 2023-11-25 21:06 | 顯示全部樓層
void KeyScan()//按鍵掃描函數放在約10ms周期的環境運行
{
        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次檢測值基本穩定
                {
                        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()                //按鍵服務程序
{
        switch(Key_value)
        {
                case 1: /*任務1*/Key_value=0; break;
                case 2: /*任務2*/Key_value=0; break;
                case 3: /*任務3*/Key_value=0; break;
                case 4: /*任務4*/Key_value=0; break;
                default: break;
        }
}

回復

使用道具 舉報

ID:1034262 發表于 2023-11-25 21:25 | 顯示全部樓層
STC15W408AS系列的ADC是10位,我做過比較多的ADC按鍵是8~32個鍵,32個鍵時每個鍵占讀數32,而408AS的誤差最大10個字,抖動一般小于4個字,足夠的。
回復

使用道具 舉報

ID:705846 發表于 2023-11-26 09:27 | 顯示全部樓層
wulin 發表于 2023-11-25 21:06
void KeyScan()//按鍵掃描函數放在約10ms周期的環境運行
{
        static unsigned char count=0;

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

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

按鍵問題解決;

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

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

void KeyScan()//按鍵掃描函數放在約10ms周期的環境運行
{
        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次檢測值基本穩定
                {
                        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;
        }
}
回復

使用道具 舉報

ID:213173 發表于 2023-11-26 14:16 | 顯示全部樓層
samxon 發表于 2023-11-26 09:27
雖然問題解決,但還有幾個問題不明白,請指點一下:
1)為什么ADC結果換算后就判定不準確;
2)按鍵檢 ...

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

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 欧美不卡在线 | 九九免费视频 | 天天拍天天插 | 欧美精品一区三区 | 日本91av视频 | www.国产一区 | av高清毛片 | 亚州午夜精品 | 日本精品久久久久久久 | 正在播放国产精品 | 日本欧美在线 | 久久久观看 | 亚洲网站免费看 | 中文字幕成人在线 | 日韩欧美一级精品久久 | 国产一区二区三区四区 | 欧美视频福利 | 成人国产精品 | 国产精品免费一区二区 | 风间由美一区二区三区在线观看 | 精品一区二区三区四区 | 国产精品区一区二区三 | 亚洲区一区二 | 韩三级在线观看 | 四虎影院在线观看免费视频 | 特一级黄色毛片 | 国产精品国产成人国产三级 | 国产综合在线视频 | 日韩精品一区二区三区视频播放 | 一级二级三级黄色 | 国产在线一区二区三区 | 羞羞视频在线观看 | 91资源在线观看 | 国产成人精品视频在线观看 | 三级成人在线 | 欧美日韩中文在线 | 综合久久一区 | 精品欧美乱码久久久久久1区2区 | 成人在线免费观看视频 | 日韩欧美国产精品一区二区 | 久久av网 |