#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口高低电平交替输出,不正常的是一直是低电平。 可是我用的代码是一模一样的,不知道哪里出问题了 |