程序如下所示:
首先说明下,此程序为AD转换芯片PCF8591采集电压数据,然后送到1602显示。
现象:1602显示的数字一直频繁的跳动,乱花眼。此现象不是一直出现的,有时候会出现,同样的硬件,同样的程序,昨天还是好好的,今天一开机就会跳动,让人捉摸不透,即使我把中断屏蔽了也不行,后来百度有人说可能是读AD的时候没有把中断关闭,可是我中断已经屏蔽了啊,不纯在不关闭的情况啊?但是我还是按照他给的建议在读AD前加上了EA=0,读后EA=1,然后再试,果然立马好了。
#include <reg51.h>
#include <intrins.h>
sbit SDA=P2^0;
sbit SCL=P2^1;
sbit lcd_rs=P1^0;
sbit lcd_rw=P1^1;
sbit lcd_en=P2^5;
sbit beep=P2^3;
bit ADFlag;
unsigned char num,count;
unsigned char table[]="Voltage: . V";
unsigned char TempData[2];
char shi,ge,bai;
void Delay(unsigned char i)
{
unsigned char j,k;
for(j=i;j>0;j--)
for(k=110;k>0;k--);
}
void NOP()
{
_nop_();
_nop_();
_nop_();
_nop_();
}
/****起始****/
void i2c_start()
{
SDA=1;
NOP();
SCL=1;
NOP();
SDA=0;
NOP();
SCL=0;
NOP();
}
/****停止****/
void i2c_stop()
{
SDA=0;
NOP();
SCL=1;
NOP();
SDA=1;
NOP();
}
/****写字节****/
void Write_Byte(unsigned char date)
{
unsigned char i,temp;
temp=date;
for(i=0;i<8;i++)
{
temp=temp<<1;
SDA=CY;
NOP();
SCL=1;
NOP();
SCL=0;
NOP();
}
SDA=0;
NOP();
SCL=1;
NOP();
SCL=0;
NOP();
}
/****应答i2c****/
void Ack(void)
{
SDA=0;
NOP();
SCL=1;
NOP();
SCL=0;
NOP();
}
/****非应答i2c****/
void No_Ack(void)
{
SDA=1;
NOP();
SCL=1;
NOP();
SCL=0;
NOP();
}
//读字节。注意:读数据时SCL与SDA的先后顺序
unsigned char Read_Byte()
{
unsigned char i,temp=0;
SCL=0;
NOP();
SDA=1;
for(i=0;i<8;i++)
{
temp=temp<<1;
NOP();
temp=temp|SDA;
SCL=1;
NOP();
SCL=0;
NOP();
}
return temp;
}
//读取AD模数转换的值,有返回值
unsigned char Read_PCF8591_ADC()
{
unsigned char temp;
i2c_start();
Delay(20);
Write_Byte(0x90); //写入地址
Delay(20);
Write_Byte(0x42); //选择通道
Delay(20);
i2c_start();
Write_Byte(0x91); //读命令
temp= Read_Byte();
i2c_stop();
return temp;
}
void lcd1602_write_com(unsigned char a)
{
lcd_rs=0;
Delay(5);
lcd_rw=0;
Delay(5);
P0=a;
Delay(5);
lcd_en=1;
Delay(5);
lcd_en=0;
}
void lcd1602_write_date(unsigned char b)
{
lcd_rs=1;
Delay(5);
lcd_rw=0;
Delay(5);
P0=b;
Delay(5);
lcd_en=1;
Delay(5);
lcd_en=0;
}
void lcd1602_init()
{
lcd_en=0;
Delay(5);
lcd1602_write_com(0x38);
Delay(5);
//lcd1602_write_com(0x08);
Delay(5);
lcd1602_write_com(01);
Delay(5);
lcd1602_write_com(0x06);
Delay(5);
lcd1602_write_com(0x0c);
Delay(5);
}
void lcd1602_Display()
{
lcd1602_write_com(0x80+0x01);
for(num=0;num<15;num++)
{
lcd1602_write_date(table[num]);
Delay(20);
}
lcd1602_write_com(0x80+0x40+1);
}
//定时器中断程序
void Timer0_init()
{
TMOD=0x01; //定时器0,模式1,16位定时器
TR0=1;
TH0=(65535-50000)/256; //高8位,=60
TL0=(65536-50000)%256; //低8位
ET0=1; //使能定时器0中断
EA=1; //开总中断
}
void main()
{
// unsigned char AD_temp; //如果用此语句,会在值达到255后溢出,并重新计数
long AD_temp;
long kk;
lcd1602_init();
Timer0_init();
while(1)
{
if(ADFlag)
{
ADFlag=0;
lcd1602_Display();
EA=0;
AD_temp=Read_PCF8591_ADC();
EA=1;
kk=AD_temp*5*100/256;
bai=kk/100;
shi=kk%100/10;
ge=kk%10;
// shi=AD_temp*5*100/256;
// ge=(AD_temp%50)/10;
lcd1602_write_com(0x80+0x40+7);
lcd1602_write_date(0x30+bai);
lcd1602_write_com(0x80+0x40+8);
lcd1602_write_date(0x2e); //小数点
lcd1602_write_com(0x80+0x40+9);
lcd1602_write_date(0x30+shi);
lcd1602_write_com(0x80+0x40+10);
lcd1602_write_date(0x30+ge);
Delay(2000);
}
}
}
void timer0() interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65535-50000)%256; //50000*(11.0592/12)ms定时,若晶振为12MHz,则为50ms
count++;
if(count=18)
{
count=0;
ADFlag=1;
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)