程序在下面,仿真可以通过。就是接硬件的时候,不论输入电压怎么变,LCD一直显示2.5v。 单片机源程序如下:
- #include <reg52.h>
- #include <intrins.h>
- #define uint unsigned int
- #define uchar unsigned char
- #define WRITEADDR 0x90 //写地址
- #define READADDR 0x91 //读地址
- #define somenop() _nop_(),_nop_(),_nop_(),_nop_(),_nop_(),_nop_()
- sbit SCL=P2^1;
- sbit SDA=P2^0;
- sbit RS=P2^2;
- sbit RW=P2^3;
- sbit E=P2^4;
- sbit V= P2^6;
- uchar dat[6];
- void delay_ms(uint xms)
- {
- uint i,j;
- for(i=xms;i>0;i--)
- for(j=110;j>0;j--) ;
- }
- void I2C_Start() //起始
- {
- SDA=1;
- somenop();
- SCL=1;
- somenop();
- SDA=0;
- somenop();
- }
- void I2C_Stop() //终止
- {
- SDA=0;
- somenop();
- SCL=1;
- somenop();
- SDA=1;
- somenop();
- }
- void I2C_SendByte(uchar dat, uchar ack) //发送一个字节
- {
- uchar i,j,b=0;
- for(i=0;i<8;i++)
- {
- SCL=0;
- somenop();
- SDA=(bit)(dat&0x80); //每次取最高位进行发送
- dat<<=1;
- SCL=1; //上升沿时发送数据
- somenop();
- }
- SCL=0;
- somenop();
- SDA=1;
- somenop();
- SCL=1;
- _nop_();
- while((SDA==1)&&(j<250)) j++; //等待应答
- SCL=0;
- _nop_();
- }
- uchar I2C_ReadByte() //读一个字节
- {
- uchar i,dat=0;
- SCL=0; //此处也可以不置低
- somenop();
- SDA=1; //拉高准备数据读取
- _nop_();
- for(i=0;i<8;i++) //读取8位数据
- {
- SCL=1;
- somenop();
- dat<<=1;
- if(SDA==1)
- dat=dat|0x01;
- somenop();
- SCL=0; //下降沿时读取数据
- somenop();
- }
- return dat;
- }
- uchar Lcd1602_ReadBusy() //判断忙的状态
- {
- uchar temp;
- RS=0;
- RW=1;
- _nop_();
- P0=0xff; //读某IO口数据前,先将该口置为1
- _nop_();
- E=1;
- _nop_();
- temp=P0; //读取此时lcd1602的状态字
- _nop_();
- E=0;
- return (temp&0x80); //如果忙
- /*temp&0x80得1表示忙,得0表示不忙*/
- }
- void Lcd1602_WriteCom(uchar com) //写命令
- {
- while(Lcd1602_ReadBusy()); //判忙
- RS=0; //命令
- RW=0; //写
- _nop_();
- P0=com; //准备发送命令
- _nop_();
- E=1; //时序图
- _nop_();
- _nop_();
- E=0; //时序图
- _nop_();
- _nop_();
- }
- void Lcd1602_WriteData(uchar dat) //写数据
- {
- while(Lcd1602_ReadBusy()); //判忙
- RS=1; //数据
- RW=0; //写
- _nop_();
- P0=dat;
- _nop_();
- E=1;
- _nop_();
- _nop_();
- E=0;
- _nop_();
- _nop_();
- }
- void Lcd1602_init() //初始化函数
- {
- delay_ms(15);
- Lcd1602_WriteCom(0x38); //显示模式设置
- delay_ms(5);
- Lcd1602_WriteCom(0x38);
- delay_ms(5);
- Lcd1602_WriteCom(0x38);
- Lcd1602_WriteCom(0x0c); //显示开
- Lcd1602_WriteCom(0x01); //显示清屏
- Lcd1602_WriteCom(0x06); //显示光标
- Lcd1602_WriteData('P');
- }
- void Pcf8591SendByte(uchar channel)
- {
- I2C_Start();
- I2C_SendByte(WRITEADDR); //发送写器件地址
- I2C_SendByte(0x40|channel); //发送控制寄存器
- I2C_Stop();
- }
- uchar Pcf8591ReadByte()
- {
- uchar num;
- I2C_Start();
- I2C_SendByte(READADDR); //发送读器件地址
- num=I2C_ReadByte(); //读取数据
- I2C_Stop(); //结束总线
- return num;
- }
- void main()
- {
- uint adNum,i;
- float value;
- Lcd1602_init();
- while(1)
- {
- if(V==1)
- {
- Pcf8591SendByte(0); //使用通道0
- /*adNum一定是0到255之间的一个数,因为pcf8591是8位的AD/DA芯片,所以输出的范围为00000000到11111111,即0到255*/
- adNum=Pcf8591ReadByte(); //读出数值
- /*将adNum转换成电压值,单片机的电压为5V,则电位器的电压为0到5V,用0到255表示0到5V,则每一个1代表5/255V,即0.01953V*/
- value=adNum*0.01953; //转为电压值
- adNum=value*100; //保留两位小数,以便显示出来
- dat[0]=adNum/1000+'0'; //加上'0'是表示数字转换成字符,1602只能显示字符
- dat[1]=adNum%1000/100+'0';
- dat[2]='.';
- dat[3]=adNum%100/10+'0';
- dat[4]=adNum%10+'0';
- dat[5]='v';
- Lcd1602_WriteCom(0x80);
- for(i=0;i<6;i++)
- {
- Lcd1602_WriteData(dat[i]);
- }
- }
- }
- }
复制代码 全部资料51hei下载地址:
电压表.zip
(156.24 KB, 下载次数: 33)
|