#include "reg51.h"
#define uchar unsigned char
#define uint unsigned int
sbit SCL=P2^0;
sbit SDA=P2^1;
sbit rs=P2^4; //1602数据/命令选择引脚
sbit rw=P2^5; //1602读写引脚
sbit e =P2^6; //1602使能引脚
sbit duan=P2^2;
sbit wei=P2^3;
//数码管编码
uchar code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
uchar time=0;//系统变量
uint volt=0;//电压
uchar disp[]="U:0.00V";
//延时函数
void delay_uint(uint i)
{
while(i--);
}
//1602命令函数
void write_com(uchar com)
{
e=0;
rs=0;
rw=0;
P0=com;
delay_uint(20);
e=1;
delay_uint(20);
e=0;
}
//1602写数据函数
void write_data(uchar dat)
{
e=0;
rs=1;
rw=0;
P0=dat;
delay_uint(20);
e=1;
delay_uint(20);
e=0;
}
//设置当前行和列
void write_sfm(uchar hang,uchar add)
{
if(hang==1) //设置当前行
write_com(0x80+add);
else
write_com(0x80+0x40+add);
}
//改变液晶中某位的值
void write_string(uchar hang,uchar add,uchar *p)
{
if(hang==1)
write_com(0x80+add);
else
write_com(0x80+0x40+add);
while(1)
{
if(*p == '\0') break;
write_data(*p);
p++;
}
}
//初始化1602液晶
void init_1602()
{
write_com(0x38);//数据总线为8位,显示2行,5x7点阵
write_com(0x0c);//开显示,有光标,光标闪烁
write_com(0x06);//光标自动右移
delay_uint(1000);//等待设置完成
}
void Delay10us()
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=3;a>0;a--);
}
void I2c_delay(uint i)
{
while(i--);
}
void I2cStart()//开始
{
SDA=1;
Delay10us();
SCL=1;
Delay10us();//建立时间是SDA保持时间>4.7us
SDA=0;
Delay10us();//保持时间是>4us
SCL=0;
Delay10us();
}
void I2cStop()//结束
{
SDA=0;
SCL=0;
Delay10us();
SCL=1;
Delay10us();//建立时间大于4.7us
SDA=1;
Delay10us();
}
void I2cSendByte(unsigned char dat)//发送
{
unsigned char a=0,b=0;//最大255,一个机器周期为1us,最大延时255us。
for(a=0;a<8;a++)//要发送8位,从最高位开始
{
SDA=dat>>7; //起始信号之后SCL=0,所以可以直接改变SDA信号
dat=dat<<1;
Delay10us();
SCL=1;
Delay10us();//建立时间>4.7us
SCL=0;
Delay10us();//时间大于4us
}
SDA=1;
Delay10us();
SCL=1;
while(SDA)//等待应答,也就是等待从设备把SDA拉低
{
b++;
if(b>200) //如果超过2000us没有应答发送失败,或者为非应答,表示接收结束
{
SCL=0;
Delay10us();
return;
}
}
SCL=0;
Delay10us();
}
unsigned char I2cReadByte()//读1B
{
unsigned char a=0,dat=0;
SDA=1;//起始和发送一个字节之后SCL都是0
Delay10us();
for(a=0;a<8;a++)//接收8个字节
{
SCL=1;
Delay10us();
dat<<=1;
dat|=SDA;
Delay10us();
SCL=0;
Delay10us();
}
SCL=1;
Delay10us();
SCL=0;
Delay10us();
return dat;
}
/*********************************************
读取ADC
**********************************************/
uchar PCF8591_read1(uchar channel)//通道
{
uchar dat;
switch(channel)
{
case 0:dat=0x40;break;
case 1:dat=0x41;break;
case 2:dat=0x42;break;
case 3:dat=0x43;
}
I2cStart();
I2cSendByte(0x90);//器件地址0
I2cSendByte(dat);//0123
I2cStart();
I2cSendByte(0x91);//器件地址0
dat=I2cReadByte();
I2cStop();
return dat;
}
uchar PCF8591_read(uchar channel)//通道
{
uchar i=0;
i=PCF8591_read1(channel);
I2c_delay(1000);
i=PCF8591_read1(channel);
return i;
}
//串口发送
void send(uchar i)
{
SBUF=i;
while(!TI);
TI=0;
}
//延时
void delay(uint i)
{
while(i--);
}
void main()//主函数
{
init_1602();
SCON=0X50;//设置为工作方式1
TMOD=0X20;//设置计数器工作方式2
TH1=0XFD;
TL1=0XFD;
TR1=1;//打开计数器
TMOD|=0X01;
TH0=(65536-50000)/256;//50ms
TL0=(65536-50000)%256;
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
while(1)
{
P0=smgduan[volt/100]+0x80;duan=1;duan=0;
P0=0xfe;wei=1;delay(100);P0=0xff;wei=0;
P0=smgduan[volt%100/10];duan=1;duan=0;
P0=0xfd;wei=1;delay(100);P0=0xff;wei=0;
P0=smgduan[volt%10];duan=1;duan=0;
P0=0xfb;wei=1;delay(100);P0=0xff;wei=0;
}
}
//定时器中断
void Timer0() interrupt 1
{
float i;
if(time<10)//0.5s
time++;
else
{
time=0;
P0=0xff;
duan=0;
wei=0;
i=PCF8591_read(0);//测量电压
volt=i*500/255;
send(volt/100+0x30);//串口发送
send('.');
send(volt%100/10+0x30);
send(volt%10+0x30);
send(0x0d);
disp[2]=volt/100+0x30;//显示
disp[4]=volt%100/10+0x30;
disp[5]=volt%10+0x30;
write_string(1,0,disp);
}
TH0=(65536-50000)/256;//50ms
TL0=(65536-50000)%256;
}
#define uchar unsigned char
#define uint unsigned int
sbit SCL=P2^0;
sbit SDA=P2^1;
sbit rs=P2^4; //1602数据/命令选择引脚
sbit rw=P2^5; //1602读写引脚
sbit e =P2^6; //1602使能引脚
sbit duan=P2^2;
sbit wei=P2^3;
//数码管编码
uchar code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
uchar time=0;//系统变量
uint volt=0;//电压
uchar disp[]="U:0.00V";
//延时函数
void delay_uint(uint i)
{
while(i--);
}
//1602命令函数
void write_com(uchar com)
{
e=0;
rs=0;
rw=0;
P0=com;
delay_uint(20);
e=1;
delay_uint(20);
e=0;
}
//1602写数据函数
void write_data(uchar dat)
{
e=0;
rs=1;
rw=0;
P0=dat;
delay_uint(20);
e=1;
delay_uint(20);
e=0;
}
//设置当前行和列
void write_sfm(uchar hang,uchar add)
{
if(hang==1) //设置当前行
write_com(0x80+add);
else
write_com(0x80+0x40+add);
}
//改变液晶中某位的值
void write_string(uchar hang,uchar add,uchar *p)
{
if(hang==1)
write_com(0x80+add);
else
write_com(0x80+0x40+add);
while(1)
{
if(*p == '\0') break;
write_data(*p);
p++;
}
}
//初始化1602液晶
void init_1602()
{
write_com(0x38);//数据总线为8位,显示2行,5x7点阵
write_com(0x0c);//开显示,有光标,光标闪烁
write_com(0x06);//光标自动右移
delay_uint(1000);//等待设置完成
}
void Delay10us()
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=3;a>0;a--);
}
void I2c_delay(uint i)
{
while(i--);
}
void I2cStart()//开始
{
SDA=1;
Delay10us();
SCL=1;
Delay10us();//建立时间是SDA保持时间>4.7us
SDA=0;
Delay10us();//保持时间是>4us
SCL=0;
Delay10us();
}
void I2cStop()//结束
{
SDA=0;
SCL=0;
Delay10us();
SCL=1;
Delay10us();//建立时间大于4.7us
SDA=1;
Delay10us();
}
void I2cSendByte(unsigned char dat)//发送
{
unsigned char a=0,b=0;//最大255,一个机器周期为1us,最大延时255us。
for(a=0;a<8;a++)//要发送8位,从最高位开始
{
SDA=dat>>7; //起始信号之后SCL=0,所以可以直接改变SDA信号
dat=dat<<1;
Delay10us();
SCL=1;
Delay10us();//建立时间>4.7us
SCL=0;
Delay10us();//时间大于4us
}
SDA=1;
Delay10us();
SCL=1;
while(SDA)//等待应答,也就是等待从设备把SDA拉低
{
b++;
if(b>200) //如果超过2000us没有应答发送失败,或者为非应答,表示接收结束
{
SCL=0;
Delay10us();
return;
}
}
SCL=0;
Delay10us();
}
unsigned char I2cReadByte()//读1B
{
unsigned char a=0,dat=0;
SDA=1;//起始和发送一个字节之后SCL都是0
Delay10us();
for(a=0;a<8;a++)//接收8个字节
{
SCL=1;
Delay10us();
dat<<=1;
dat|=SDA;
Delay10us();
SCL=0;
Delay10us();
}
SCL=1;
Delay10us();
SCL=0;
Delay10us();
return dat;
}
/*********************************************
读取ADC
**********************************************/
uchar PCF8591_read1(uchar channel)//通道
{
uchar dat;
switch(channel)
{
case 0:dat=0x40;break;
case 1:dat=0x41;break;
case 2:dat=0x42;break;
case 3:dat=0x43;
}
I2cStart();
I2cSendByte(0x90);//器件地址0
I2cSendByte(dat);//0123
I2cStart();
I2cSendByte(0x91);//器件地址0
dat=I2cReadByte();
I2cStop();
return dat;
}
uchar PCF8591_read(uchar channel)//通道
{
uchar i=0;
i=PCF8591_read1(channel);
I2c_delay(1000);
i=PCF8591_read1(channel);
return i;
}
//串口发送
void send(uchar i)
{
SBUF=i;
while(!TI);
TI=0;
}
//延时
void delay(uint i)
{
while(i--);
}
void main()//主函数
{
init_1602();
SCON=0X50;//设置为工作方式1
TMOD=0X20;//设置计数器工作方式2
TH1=0XFD;
TL1=0XFD;
TR1=1;//打开计数器
TMOD|=0X01;
TH0=(65536-50000)/256;//50ms
TL0=(65536-50000)%256;
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
while(1)
{
P0=smgduan[volt/100]+0x80;duan=1;duan=0;
P0=0xfe;wei=1;delay(100);P0=0xff;wei=0;
P0=smgduan[volt%100/10];duan=1;duan=0;
P0=0xfd;wei=1;delay(100);P0=0xff;wei=0;
P0=smgduan[volt%10];duan=1;duan=0;
P0=0xfb;wei=1;delay(100);P0=0xff;wei=0;
}
}
//定时器中断
void Timer0() interrupt 1
{
float i;
if(time<10)//0.5s
time++;
else
{
time=0;
P0=0xff;
duan=0;
wei=0;
i=PCF8591_read(0);//测量电压
volt=i*500/255;
send(volt/100+0x30);//串口发送
send('.');
send(volt%100/10+0x30);
send(volt%10+0x30);
send(0x0d);
disp[2]=volt/100+0x30;//显示
disp[4]=volt%100/10+0x30;
disp[5]=volt%10+0x30;
write_string(1,0,disp);
}
TH0=(65536-50000)/256;//50ms
TL0=(65536-50000)%256;
}