標(biāo)題: stc8g單片機(jī)單個(gè)io口連接5個(gè)按鍵,用adc采集電壓,會(huì)自己跳轉(zhuǎn)功能? [打印本頁(yè)]

作者: Dokkis    時(shí)間: 2024-12-30 16:46
標(biāo)題: stc8g單片機(jī)單個(gè)io口連接5個(gè)按鍵,用adc采集電壓,會(huì)自己跳轉(zhuǎn)功能?
用的是stc8g1k08a單片機(jī),用p5.4口接5個(gè)按鍵,電壓分別是0.33v、1.18v、2.87v、3.79v、4.59v,想讓這幾個(gè)按鍵分別調(diào)光0、25%、50%、75%、100%,按鍵按下的時(shí)候可以執(zhí)行此功能,但是過(guò)一會(huì)兒(有時(shí)幾秒有時(shí)一分鐘)就會(huì)自己跳成別的亮度,比如我按下25%,過(guò)一會(huì)兒亮度就會(huì)變成50
%或者是0。我用萬(wàn)用表測(cè)了p5.4口的電壓,沒(méi)有按鍵按下的時(shí)候一直是5.03v左右,想知道這是啥原因嘞,是adc采集的問(wèn)題嗎,還是我的程序邏輯不對(duì)嘞,電路板我只是用萬(wàn)能板拼接的,還是是硬件的問(wèn)題,有沒(méi)有大神幫我看看

部分代碼:
unsigned long timer0_count = 0;
unsigned char PWM_T = 0;   //0-250占空比控制變
unsigned char current_brightness = 0;        //當(dāng)前亮度
signed int    brightness = 0;
#define IT_HZ        100000        //中斷頻率
#define TIM0_VALUE        65536UL - (MAIN_Fosc / IT_HZ)


//設(shè)置高電平占空比
//num: 0-100%
void set_duty_cycle(unsigned char num)
{
        current_brightness = num;        if(num > 0)
        {
                light_switch_state = 1;
        }
        else
        {
                light_switch_state = 0;
        }
        PWM_T = (float)(num / 100.0)*250;
}

/********************* Timer0中斷函數(shù)************************/
void timer0_int (void) interrupt TIMER0_VECTOR
{
         timer0_count++;    //每次定時(shí)器溢出加1
         
         if(timer0_count==250)   //PWM周期 100個(gè)單位
                 {
                        timer0_count=0;  //使t=0,開(kāi)始新的PWM周期
                        LIGHT = 1;        //開(kāi)燈
                 }
         
         if(PWM_T==timer0_count)  //按照當(dāng)前占空比切換輸出為高電平
                 {  
                        LIGHT = 0;        //關(guān)燈
                 }
}

//獲取燈光占空比
//返回值: 0-100
int get_light_pwm(void)
{
        return PWM_T*100/250;
        // return 0;
}



#define ADC_CHANNEL 4 // 使用P5.4作為ADC輸入,對(duì)應(yīng)ADC通道4
#define VCC 5000      // 供電電壓,單位mV

// 初始化系統(tǒng)
void System_Init(void)
        {
    P_SW2 |= 0x80;
    ADCTIM = 0x3f;                   //設(shè)置ADC內(nèi)部時(shí)序
    P_SW2 &= 0x7f;

    ADCCFG = 0x2f;                   //設(shè)置ADC時(shí)鐘為系統(tǒng)時(shí)鐘/2/16
    // 設(shè)置ADC
    ADC_CONTR = 0x84; // 選擇ADC通道4
        }

// 讀取ADC值
int Read_ADC(void)
{
                int res;
        
    ADC_CONTR |= 0x40; // 開(kāi)始ADC轉(zhuǎn)換
    while(!(ADC_CONTR & 0x20)); // 等待轉(zhuǎn)換完成
                ADC_CONTR &= ~0x20;
    res = (ADC_RES << 8) | ADC_RESL; // 返回10位ADC結(jié)果
          return res;
}

// 判斷按鍵
void Check_Keys(int adc_value)
        {
                            //按鍵1
                              if(adc_value >= 20 && adc_value < 144)
                                        {
                                                        delay_ms(10);
                                                        if (adc_value >= 20 && adc_value < 144)
                                                        {
                                                                        brightness = 0;
                                                                        set_duty_cycle(brightness);
                                                        }
                                        }
                              //按鍵2
                                        else if (adc_value >= 144 && adc_value < 307)
                                        {
                                                        delay_ms(10);
                                                        if (adc_value >= 144 && adc_value < 307)
                                                        {
                                                                        brightness = 25;
                                                                        set_duty_cycle(brightness);
                                                        }
                                        }
                            //按鍵3
                                       
                                else if (adc_value >= 308 && adc_value < 588)
                                        {
                                                delay_ms(10);
                                                if (adc_value >= 308 && adc_value < 588)
                                                {
                                                                brightness = 50;
                                                                set_duty_cycle(brightness);
                                                }
                                        }
                            //按鍵4
                                else if (adc_value >= 589 && adc_value < 860)
                                        {
                                                delay_ms(10);
                                                if (adc_value >= 589 && adc_value < 860)
                                                {
                                                                brightness = 75;
                                                                set_duty_cycle(brightness);
                                                }
                                        }
                            //按鍵5
                              else   if(adc_value >=861 && adc_value <983)
                                           {
                                                 delay_ms(10);
                                                  if(adc_value >=861 && adc_value <983)
                                                {
                                                        brightness = 100;
                                                        set_duty_cycle(brightness);
                                                }
                                         }
        }

// 主函數(shù)
void main(void)
        {
                P5M0 = 0x00; P5M1 = 0x10; // 設(shè)置P5.4為高阻輸入
                P3M0 = 0x08; P3M1 = 0xf7; // P3.3為推挽輸出
               System_Init();
                light_init();                //使用定時(shí)器0作pwm功能
                delay_ms(5);
                EA = 1;                                
                                       
                while (1)
                        {
                               int adc_value = Read_ADC(); // 讀取ADC值
                                delay_ms(10);
                                 Check_Keys(adc_value);           // 檢查按鍵
                                set_duty_cycle(brightness);
      }
        }

我的電路圖大概是這樣的,估計(jì)是沒(méi)連接好,干擾有點(diǎn)多,后面在電路上加個(gè)102電容就可以了,感謝各位大神,只是現(xiàn)在還有個(gè)問(wèn)題,像三樓說(shuō)的那樣,開(kāi)機(jī)時(shí)會(huì)高亮一下,我在EA=1后面加一個(gè)LIGHT=0也還是不行,請(qǐng)問(wèn)這個(gè)怎么解決呀







作者: lkc8210    時(shí)間: 2024-12-31 09:20
官方的解釋是你的外圍電路做的不好
請(qǐng)按手冊(cè)來(lái)畫(huà)
作者: Graves    時(shí)間: 2024-12-31 10:50
首先Check_Keys中的delay_ms(10);沒(méi)什么作用,因?yàn)閍dc_value在Check_Keys運(yùn)行時(shí)就不會(huì)改變,加上延遲指也是不會(huì)變的。然后Read_ADC沒(méi)做濾波,這兩個(gè)方面處理下應(yīng)該好很多
                       
作者: zhuls    時(shí)間: 2024-12-31 11:00
AD按鍵串,要沒(méi)按鍵時(shí),電壓確實(shí)是高的,約=于電源電壓。除非你的接法比較另類(lèi)。
10bit的ADC,分5檔有4個(gè)節(jié)點(diǎn),平均每節(jié)點(diǎn)相差256個(gè)計(jì)數(shù),為了容錯(cuò),節(jié)點(diǎn)上下+-128個(gè)計(jì)數(shù):
0檔<=128;
1檔<=384,>128;
2檔<=640,>384;
3檔<=896,>640;
4檔>896;
基實(shí),人眼對(duì)光的敏感度并不是線性的,所以,“0、25%、50%、75%、100%”的值不一定適合。。
在數(shù)據(jù)處理時(shí),0檔和4檔不需要輸出PWM,直接IO出低電平或出高電平;
ADC在采樣時(shí)要有數(shù)字濾波比較好。
然后就是按鍵的接觸電阻要穩(wěn)定、分壓電阻要穩(wěn)定。。
===
我曾用電位器調(diào)整ADC的值,來(lái)控制PWM輸出實(shí)現(xiàn)無(wú)級(jí)調(diào)光,好用是好用,但發(fā)現(xiàn)有2個(gè)缺點(diǎn),
就是在某些范圍內(nèi)的占空比時(shí),明顯看到燈會(huì)閃,不同的頻率周期,這個(gè)范圍也不盡相同,
可能軟件還要做個(gè)關(guān)于PWM的周期與占空比的適配。。
另一個(gè)問(wèn)題是,只要配置了PWM,IO就輸出高電平,然后再按PWM配置輸出占空比,
表現(xiàn)為開(kāi)機(jī)時(shí)燈會(huì)高亮一下,再按PWM顯示亮度。。

=====這是一個(gè)宿醉剛起、頭腦尚未完全清醒者的發(fā)言====
====以?xún)?nèi)容上僅供參考,不負(fù)任何法律或道義上的責(zé)任====
作者: WL0123    時(shí)間: 2024-12-31 11:01
stc8g1k08a有現(xiàn)成的硬件PWM不用?定時(shí)器中斷頻率過(guò)高有可能影響ADC。ADC連續(xù)采樣3次,拋棄前兩次數(shù)據(jù),以第3次數(shù)據(jù)為準(zhǔn)或連續(xù)采樣8-10次取平均值。ADC輸入端加1K電阻和102電容組成低通濾波。 Check_Keys函數(shù)去掉delay_ms(10),不需要軟件防抖。
作者: WL0123    時(shí)間: 2024-12-31 11:22
不宜在主循環(huán)內(nèi)定義變量
// 主函數(shù)
void main(void)
{
        int adc_value;
        P5M0 = 0x00; P5M1 = 0x10; // 設(shè)置P5.4為高阻輸入
        P3M0 = 0x08; P3M1 = 0xf7; // P3.3為推挽輸出
        System_Init();
        light_init();                //使用定時(shí)器0作pwm功能
        delay_ms(5);
        EA = 1;                              
       
        while (1)
        {
                adc_value = Read_ADC(); // 讀取ADC值
                delay_ms(10);
                Check_Keys(adc_value);           // 檢查按鍵
                set_duty_cycle(brightness);
        }
}
作者: zhuls    時(shí)間: 2024-12-31 13:46
WL0123 發(fā)表于 2024-12-31 11:22
不宜在主循環(huán)內(nèi)定義變量
// 主函數(shù)
void main(void)


你老師說(shuō)的嗎?
還是你師傅教的?
或是你哪本書(shū)上看到的?

這好象說(shuō)不過(guò)去啊,也不影響什么的。。
作者: coody_sz    時(shí)間: 2024-12-31 15:18
可以參考STC官方的ADC鍵盤(pán)電路,16個(gè)鍵的。
作者: WL0123    時(shí)間: 2024-12-31 15:41
zhuls 發(fā)表于 2024-12-31 13:46
你老師說(shuō)的嗎?
還是你師傅教的?
或是你哪本書(shū)上看到的?

你仔細(xì)看了樓主的代碼嗎?
作者: lkc8210    時(shí)間: 2024-12-31 17:40
1. adc_value 在Check_Keys()函數(shù)內(nèi)是不變的,if()delay()if的多余的,不要死抄按鍵消抖
2. 主循環(huán)的set_duty_cycle(brightness)也很多余,Check_Keys()函數(shù)內(nèi)有按鍵已經(jīng)運(yùn)行一次了,不用在主循環(huán)不斷運(yùn)行
3. 可以試試中值濾波
  1. #define ARRAY_SIZE 10

  2. // 中值濾波函數(shù)
  3. unsigned char median_filter() {
  4.     unsigned char sorted[ARRAY_SIZE];
  5.     unsigned char i, j, k;
  6.        
  7.     for (i = 0; i < ARRAY_SIZE; i++) {
  8.                 sorted[i] = Read_ADC(); // 讀取ADC值
  9.     }
  10.         // 冒泡排序 sorted 數(shù)組
  11.         for (j = 0; j < ARRAY_SIZE - 1; j++) {
  12.                 for (k = 0; k < ARRAY_SIZE - j - 1; k++) {
  13.                         if (sorted[k] > sorted[k + 1]) {
  14.                                 // 交換
  15.                                 unsigned char temp = sorted[k];
  16.                                 sorted[k] = sorted[k + 1];
  17.                                 sorted[k + 1] = temp;
  18.                         }
  19.                 }
  20.         }
  21.         // 找到中值并賦值給輸出
  22.    return sorted[ARRAY_SIZE / 2];
  23. }

  24. // 主函數(shù)
  25. void main(void)
  26. {
  27.         P5M0 = 0x00;
  28.         P5M1 = 0x10; // 設(shè)置P5.4為高阻輸入
  29.         P3M0 = 0x08;
  30.         P3M1 = 0xf7; // P3.3為推挽輸出
  31.         System_Init();
  32.         light_init();                //使用定時(shí)器0作pwm功能
  33.         delay_ms(5);
  34.         EA = 1;

  35.         while (1)
  36.         {
  37.                 int adc_value = median_filter();
  38.                 Check_Keys(adc_value);           // 檢查按鍵
  39.         }
  40. }
復(fù)制代碼

作者: xiaobendan001    時(shí)間: 2024-12-31 19:29
WL0123 發(fā)表于 2024-12-31 15:41
你仔細(xì)看了樓主的代碼嗎?

之前好像是要先聲明才能使用的,但是現(xiàn)在的編譯器是可以這樣寫(xiě)的。
作者: xiaobendan001    時(shí)間: 2024-12-31 19:37
的確里面的延時(shí)沒(méi)有任何意義
  1. //按鍵1
  2.   if(adc_value > 20 && adc_value < 144)
  3.     {
  4.                 set_duty_cycle(0);
  5.                 return;
  6.                 }
  7. //按鍵2
  8.         if (adc_value > 144 && adc_value < 307)
  9.                 {
  10.                 set_duty_cycle(25);
  11.                 return;
  12.                 }
復(fù)制代碼

這樣看起來(lái)簡(jiǎn)潔一些
作者: Dokkis    時(shí)間: 2025-1-6 11:20
zhuls 發(fā)表于 2024-12-31 11:00
AD按鍵串,要沒(méi)按鍵時(shí),電壓確實(shí)是高的,約=于電源電壓。除非你的接法比較另類(lèi)。
10bit的ADC,分5檔有4個(gè) ...

確實(shí)在開(kāi)機(jī)時(shí)會(huì)高亮一下,大神有沒(méi)有什么解決辦法,我試過(guò)在開(kāi)機(jī)的時(shí)候讓IO口直接等于0,還是不行
作者: Dokkis    時(shí)間: 2025-1-6 11:24
WL0123 發(fā)表于 2024-12-31 11:01
stc8g1k08a有現(xiàn)成的硬件PWM不用?定時(shí)器中斷頻率過(guò)高有可能影響ADC。ADC連續(xù)采樣3次,拋棄前兩次數(shù)據(jù),以第 ...

謝謝大神,加上電容確實(shí)解決了,只是不加軟件防抖的話有時(shí)按鍵會(huì)失靈,估計(jì)是按鍵也有點(diǎn)問(wèn)題,加上軟件防抖的話會(huì)有其它什么問(wèn)題嗎
作者: Dokkis    時(shí)間: 2025-1-6 11:29
coody_sz 發(fā)表于 2024-12-31 15:18
可以參考STC官方的ADC鍵盤(pán)電路,16個(gè)鍵的。

官方的電路是在官網(wǎng)看嗎 我只看到一個(gè)觸摸按鍵的演示視頻,還是是在論壇里面搜索呀
作者: Dokkis    時(shí)間: 2025-1-6 11:40
lkc8210 發(fā)表于 2024-12-31 17:40
1. adc_value 在Check_Keys()函數(shù)內(nèi)是不變的,if()delay()if的多余的,不要死抄按鍵消抖
2. 主循環(huán)的set_d ...

后面在電路中加了個(gè)電容解決了,只是不加按鍵消抖的話按鍵有時(shí)有點(diǎn)不靈敏,可能按鍵用久了也不太好用,加上消抖的話會(huì)有什么其他問(wèn)題嗎,之前經(jīng)常這樣用這個(gè)中值濾波我試了,通電的時(shí)候會(huì)自己亮,而且按鍵也完全不起作用了,是不是跟我的電路不太匹配呀,我把我的電路貼到上面了




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1