![]() |
#include <reg52.h> #include <stdio.h> #include <intrins.h> #include "lcd016.h" #define uchar unsigned char #define uint unsigned int sbit LCD_RS=P2^0; sbit LCD_RW=P2^1; sbit LCD_EN=P2^2; #define LCD_Data_Port P0 sbit ADCS=P1^0; sbit ADCLK=P1^1; sbit ADDI=P1^2; sbit ADDO=P1^2; sbit LED=P1^4; uint dat = 0x00; //AD值 uchar adc=0;//存儲adc0832值 uint voltage = 0; uchar pwm=0;//PWM占空比參數 uchar time=0; uchar LED_buffer1[16] = {"ADC:000LX"};//ADC顯示緩沖 uchar LED_buffer2[16] = {"voltage:0.00V"};//電壓顯示緩沖 uchar adc2[4]; uchar voltage2[4]; /*------------------------------------------------ 延時函數,含有輸入參數 unsigned int t,無返回值 unsigned int 是定義無符號整形變量,其值的范圍是 0~65535 ------------------------------------------------*/ void Delay(unsigned int t) { while(--t); } // 從ADC讀取數據的函數 uchar ADC_read_data(unsigned char channel) { unsigned char i = 0; unsigned char j; unsigned int dat = 0; unsigned char ndat = 0; if (channel == 0) channel = 2;//通道1 if (channel == 1) channel = 3;//通道2 ADDI = 1;//輸入引腳拉高 _nop_();//延時1us _nop_();//延時1us ADCS = 0;//片選 _nop_();//延時1us _nop_();//延時1us ADCLK = 1;//拉高時鐘 _nop_();//延時1us _nop_();//延時1us ADCLK = 0;//拉低時鐘 _nop_();//延時1us _nop_();//延時1us ADCLK = 1;//拉高時鐘 ADDI = channel & 0x1; _nop_();//延時1us _nop_();//延時1us ADCLK = 0;//拉低時鐘 _nop_();//延時1us _nop_();//延時1us ADCLK = 1;//拉高時鐘 ADDI = (channel >> 1) & 0x1; _nop_();//延時1us _nop_();//延時1us ADCLK = 0;//拉低時鐘 ADDI = 1;//輸出1 _nop_();//延時1us _nop_();//延時1us dat = 0; //存儲清零 for (i = 0; i < 8; i++) //循環8次 { dat |= ADDO;//讀取引腳 ADCLK = 1; //拉高時鐘 _nop_();//延時1us _nop_();//延時1us ADCLK = 0;//拉低時鐘 _nop_();//延時1us _nop_();//延時1us dat <<= 1;//左移 最低位從外面進去,最高位往左頂依舊是最高位 即0832數據最高位先進去 if (i == 7) dat |= ADDO;//讀取引腳 } for (i = 0; i < 8; i++)//循環8次 { j = 0; j = j | ADDO; //讀取引腳 ADCLK = 1; //拉高時鐘 _nop_();//延時1us _nop_();//延時1us ADCLK = 0; //拉低時鐘 _nop_();//延時1us _nop_();//延時1us j = j << 7; //左移7位 ndat = ndat | j; //合并數據 if (i < 7) ndat >>= 1;//去掉符號 } ADCS = 1; //清除片選 ADCLK = 0;//拉低時鐘 ADDO = 1; //輸出1 dat <<= 8;//數據移位 dat |= ndat;//合并數據 return(ndat); } void init_timer1()//定時器1的初始化函數 { TMOD|=0X01; //設置計時器1為工作模式1,計時器0為工作模式1 TH0=0X3c; //設置計時器1的計數器高位為0x3C,讓定時器1產生一個50ms的中斷信號 TL0=0XB0; //設置計時器1的計數器低位為0xB0 ET0=1; //打開定時器1中斷允許 EA=1; //打開總中斷 TR0=1; //打開計時器1,若是定時器0則是TH0\TL0\ET0\TR0\TMOD=0X01 } void main() { LCD_Init(); // 初始化LCD init_timer1(); while (1) { adc = ADC_read_data(0);//讀取adc值 voltage = adc * 500.0 / 255;//將adc值換算成電壓 LED_buffer1[4] = adc / 100 + '0'; //取adc百位 LED_buffer1[5] = adc % 100 / 10 + '0'; //取adc十位 LED_buffer1[6] = adc % 10 + '0'; //取adc個位 LED_buffer2[8] = voltage / 100 + '0'; //取電壓個位 LED_buffer2[9] = '.';//小數點 LED_buffer2[10] = voltage / 10 % 10 + '0'; //取電壓十分位 LED_buffer2[11] = voltage % 10 + '0'; //取電壓百分位 LCD_ShowString(1, 1, LED_buffer1); //顯示字符串 LCD_ShowString(2, 1, LED_buffer2); //顯示字符串 } } //定時器1中斷函數 void Timer1() interrupt 1 { uchar i; pwm=adc/2; if(i<100) //輸出PWM調光,將一個周期具體化為100等分,從而易得高電平多少分來計算pwm i++;//不斷自增代表對一個周期100等分中每個等分進行檢查此時是高電平還是低電平。在這100中方波越疏越暗,越密越亮。 else i=0; if(i<84) LED=0; else LED=1; TH0 = 0x3C; // 設置定時器1計數初值,用于控制LED亮度的PWM值 TL0 = 0xB0; // 設置定時器1計數初值,用于控制LED亮度的PWM值 } 這樣改似乎程序進入不了中斷了 |
Y_G_G 發表于 2023-3-29 00:40 我把led程序和adc讀取顯示兩個程序調換,即led顯示程序放入中斷后,led直接常亮了 |
1:LED顯示的延時一定要均勻,2mS和500uS的延時幾乎是沒有區別的 2:不能有一個突變的延時,比如,你LED的延時一直是1mS,ADC的時候,延時突然變成了2mS,這個時候是一定會閃的 解決建議: LED顯示用定時器中斷掃描顯示,這樣就不會被ADC打斷了 |
有沒有大神幫忙修改一下,如何解決頻閃,led亮度隨adc控制的pwm變化 |
zch5200 發表于 2023-3-28 13:09 ad采集放在主函數里led的頻閃會更嚴重直接出現頻閃 |
這程序寫的臃腫,AD采集最好不要放在中斷里。低電平點亮LED,調試先看看單一功能:AD的值對不對,定時器運行時間,LED點亮等。都沒問題了再合起來。 |
每過一段時間會頻閃,代碼已貼上求指點如何更改 |
#include <reg52.h> #include <stdio.h> #include <intrins.h> #include "lcd016.h" #define uchar unsigned char #define uint unsigned int sbit LCD_RS=P2^0; sbit LCD_RW=P2^1; sbit LCD_EN=P2^2; #define LCD_Data_Port P0 sbit ADCS=P1^0; sbit ADCLK=P1^1; sbit ADDI=P1^2; sbit ADDO=P1^2; sbit LED=P1^4; uint dat = 0x00; //AD值 uchar adc=0;//存儲adc0832值 uint voltage = 0; uchar pwm=0;//PWM占空比參數 uchar time=0; uchar LED_buffer1[16] = {"ADC:000LX"};//ADC顯示緩沖 uchar LED_buffer2[16] = {"voltage:0.00V"};//電壓顯示緩沖 /*------------------------------------------------ 延時函數,含有輸入參數 unsigned int t,無返回值 unsigned int 是定義無符號整形變量,其值的范圍是 0~65535 ------------------------------------------------*/ void Delay(unsigned int t) { while(--t); } // 從ADC讀取數據的函數 uchar ADC_read_data(unsigned char channel) { unsigned char i = 0; unsigned char j; unsigned int dat = 0; unsigned char ndat = 0; if (channel == 0) channel = 2;//通道1 if (channel == 1) channel = 3;//通道2 ADDI = 1;//輸入引腳拉高 _nop_();//延時1us _nop_();//延時1us ADCS = 0;//片選 _nop_();//延時1us _nop_();//延時1us ADCLK = 1;//拉高時鐘 _nop_();//延時1us _nop_();//延時1us ADCLK = 0;//拉低時鐘 _nop_();//延時1us _nop_();//延時1us ADCLK = 1;//拉高時鐘 ADDI = channel & 0x1; _nop_();//延時1us _nop_();//延時1us ADCLK = 0;//拉低時鐘 _nop_();//延時1us _nop_();//延時1us ADCLK = 1;//拉高時鐘 ADDI = (channel >> 1) & 0x1; _nop_();//延時1us _nop_();//延時1us ADCLK = 0;//拉低時鐘 ADDI = 1;//輸出1 _nop_();//延時1us _nop_();//延時1us dat = 0; //存儲清零 for (i = 0; i < 8; i++) //循環8次 { dat |= ADDO;//讀取引腳 ADCLK = 1; //拉高時鐘 _nop_();//延時1us _nop_();//延時1us ADCLK = 0;//拉低時鐘 _nop_();//延時1us _nop_();//延時1us dat <<= 1;//左移 最低位從外面進去,最高位往左頂依舊是最高位 即0832數據最高位先進去 if (i == 7) dat |= ADDO;//讀取引腳 } for (i = 0; i < 8; i++)//循環8次 { j = 0; j = j | ADDO; //讀取引腳 ADCLK = 1; //拉高時鐘 _nop_();//延時1us _nop_();//延時1us ADCLK = 0; //拉低時鐘 _nop_();//延時1us _nop_();//延時1us j = j << 7; //左移7位 ndat = ndat | j; //合并數據 if (i < 7) ndat >>= 1;//去掉符號 } ADCS = 1; //清除片選 ADCLK = 0;//拉低時鐘 ADDO = 1; //輸出1 dat <<= 8;//數據移位 dat |= ndat;//合并數據 return(ndat); } void init_timer1()//定時器1的初始化函數 { TMOD|=0X11; //設置計時器1為工作模式1,計時器0為工作模式1 TH1=0X3c; //設置計時器1的計數器高位為0x3C,讓定時器1產生一個50ms的中斷信號 TL1=0XB0; //設置計時器1的計數器低位為0xB0 ET1=1; //打開定時器1中斷允許 EA=1; //打開總中斷 TR1=1; //打開計時器1,若是定時器0則是TH0\TL0\ET0\TR0\TMOD=0X01 } void main() { uchar i=0; LCD_Init(); // 初始化LCD init_timer1(); while (1) { if(i<100) //輸出PWM調光,將一個周期具體化為100等分,從而易得高電平多少分來計算pwm i++;//不斷自增代表對一個周期100等分中每個等分進行檢查此時是高電平還是低電平。在這100中方波越疏越暗,越密越亮。 else i=0; if(i<84) LED=0; else LED=1; } } //定時器1中斷函數 void Timer1() interrupt 3 { if(time<8) time++; else { adc = ADC_read_data(0);//讀取adc值 voltage = adc * 500.0 / 255;//將adc值換算成電壓 LED_buffer1[4] = adc / 100 + '0'; //取adc百位 LED_buffer1[5] = adc % 100 / 10 + '0'; //取adc十位 LED_buffer1[6] = adc % 10 + '0'; //取adc個位 LED_buffer2[8] = voltage / 100 + '0'; //取電壓個位 LED_buffer2[9] = '.';//小數點 LED_buffer2[10] = voltage / 10 % 10 + '0'; //取電壓十分位 LED_buffer2[11] = voltage % 10 + '0'; //取電壓百分位 LCD_ShowString(1, 1, &LED_buffer1[0]); //顯示字符串 LCD_ShowString(2, 1, &LED_buffer2[0]); //顯示字符串 } TH1 = 0x3C; // 設置定時器1計數初值,用于控制LED亮度的PWM值 TL1 = 0xB0; // 設置定時器1計數初值,用于控制LED亮度的PWM值 } 不看其他只看P14口的led,正常應該經過pwm調制后led燈是暗的(圖3),但圖2是閃一下暗的然后常亮。 發現是正常的p14口高低電平交替輸出,不正常的是一直是低電平。 可是我用的代碼是一模一樣的,不知道哪里出問題了 |