代码:     //-----------------------函数声明,变量定义------------------------ 
#include <reg51.h> 
#include <intrins.h> 
sbit SCL=P1^1;                   // 将p1.2口模拟时钟口 
sbit SDA=P1^2;                   // 将p1.3口模拟数据口 
bit askflag; 
#define uchar unsigned char 
#define uint  unsigned int 
#define disdata  P0              //显示数据码输出口
sbit LCD_RS = P2^4;              
sbit LCD_RW = P2^5; 
sbit LCD_EN = P2^6; 
#include <lcd.h>
uint data dis[4]={0x00,0x00,0x00,0x00};  
                          //定义3个显示数据单元和1个数据存储单元
//uchar code dis4[] = {"1- .  V  2- .  V"}; 
//uchar code dis5[] = {"3- .  V  4- .  V"};
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();}; 
                  
bit   bdata SystemError;                //从机错误标志位
/*********************** PCF8591专用变量定义 ***********************/
#define PCF8591_WRITE 0x90  
#define PCF8591_READ  0x91 
#define  NUM  4              //接收和发送缓存区的深度 
uchar idata receivebuf[NUM];    //数据接收缓冲区
/*******************************************************************/ 
/*                                                                 */ 
/*  延时函数                                                       */ 
/*                                                                 */ 
/*******************************************************************/
void delay(int ms) 
{ 
    while(ms--) 
{ 
      uchar i; 
  for(i=0;i<250;i++)   
   { 
    _nop_();     
_nop_(); 
_nop_(); 
_nop_(); 
   } 
} 
}
/*******************************************************************/ 
/*                                                                 */ 
/*检查LCD忙状态                                                    */ 
/*lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据。      */ 
/*                                                                 */ 
/*******************************************************************/ 
bit lcd_busy() 
 {                           
    bit result; 
    LCD_RS = 0; 
    LCD_RW = 1; 
    LCD_EN = 1; 
    delayNOP(); 
    result = (bit)(P0&0x80); 
    LCD_EN = 0; 
    return(result);  
 }
/******************************************************************/ 
/*                                                                */ 
/* 数据处理与显示                                                 */ 
/* 将采集到的数据进行16进制转换为ASCLL码。                        */ 
/*                                                                */ 
/******************************************************************/
void show_value(uchar ad_data)
{    
    dis[2]=ad_data/51;   //AD值转换为3为BCD码,最大为5.00V。 
    dis[2]=dis[2]+0x30;  //转换为ACSII码 
    dis[3]=ad_data%51;   //余数暂存 
    dis[3]=dis[3]*10;    //计算小数第一位 
    dis[1]=dis[3]/51; 
    dis[1]=dis[1]+0x30;  //转换为ACSII码 
    dis[3]=dis[3]%51; 
    dis[3]=dis[3]*10;    //计算小数第二位 
    dis[0]=dis[3]/51;                                                                             // 
    dis[0]=dis[0]+0x30;  //转换为ACSII码            
}  
//------------------------------------------------------------------- 
// 函数名称: iic_start() 
// 函数功能: 启动I2C总线子程序 
//------------------------------------------------------------------- 
void iic_start(void) 
{ //时钟保持高,数据线从高到低一次跳变,I2C通信开始 
SDA = 1;      
SCL = 1; 
delayNOP();      // 延时5us  
    SDA = 0; 
delayNOP(); 
    SCL = 0; 
} 
//------------------------------------------------------------------- 
// 函数名称: iic_stop() 
// 函数功能: 停止I2C总线数据传送子程序 
//------------------------------------------------------------------- 
void iic_stop(void) 
{   
SDA = 0;       //时钟保持高,数据线从低到高一次跳变,I2C通信停止 
SCL = 1; 
delayNOP(); 
SDA = 1; 
delayNOP(); 
    SCL = 0; 
} 
//------------------------------------------------------------------ 
// 函数名称: iicInit_() 
// 函数功能: 初始化I2C总线子程序 
//------------------------------------------------------------------ 
 void iicInit(void) 
   { 
   SCL = 0; 
   iic_stop(); 
   }   
//------------------------------------------------------------------- 
// 函数名称: slave_ACK 
// 函数功能: 从机发送应答位子程序 
//------------------------------------------------------------------- 
void slave_ACK(void) 
{ 
SDA = 0;   
SCL = 1; 
delayNOP(); 
SCL = 0; 
} 
//------------------------------------------------------------------- 
// 函数名称: slave_NOACK 
// 函数功能: 从机发送非应答位子程序,迫使数据传输过程结束 
//------------------------------------------------------------------- 
void slave_NOACK(void) 
{  
SDA = 1; 
SCL = 1; 
delayNOP(); 
SDA = 0; 
    SCL = 0;   
} 
//------------------------------------------------------------------- 
// 函数名称: check_ACK 
// 函数功能: 主机应答位检查子程序,迫使数据传输过程结束 
//------------------------------------------------------------------- 
void check_ACK(void) 
{       
    SDA = 1;        // 将p1.1设置成输入,必须先向端口写1 
SCL = 1; 
askflag = 0; 
delayNOP();    
if(SDA == 1)    // 若SDA=1表明非应答,置位非应答标志askflag 
    askflag = 1; 
    SCL = 0; 
} 
//------------------------------------------------------------------- 
// 函数名称: IICSendByte 
// 入口参数: ch 
// 函数功能: 发送一个字节 
//------------------------------------------------------------------- 
void IICSendByte(uchar ch) 
  
{ 
   unsigned char idata n=8;     // 向SDA上发送一位数据字节,共八位
while(n--) 
{  
if((ch&0x80) == 0x80)    // 若要发送的数据最高位为1则发送位1 
   { 
  SDA = 1;    // 传送位1 
SCL = 1; 
    delayNOP(); 
// SDA = 0; 
SCL = 0;  
   } 
else 
{   
SDA = 0;    // 否则传送位0 
SCL = 1; 
delayNOP(); 
   SCL = 0; 
} 
ch = ch<<1;    // 数据左移一位 
} 
} 
//------------------------------------------------------------------- 
// 函数名称: IICreceiveByte 
// 返回接收的数据 
// 函数功能: 接收一字节子程序 
//------------------------------------------------------------------- 
uchar IICreceiveByte(void) 
{ 
uchar idata n=8;     // 从SDA线上读取一上数据字节,共八位 
uchar tdata=0; 
while(n--) 
{ 
   SDA = 1; 
   SCL = 1; 
   tdata =tdata<<1;     //左移一位 
    if(SDA == 1) 
  tdata = tdata|0x01;   // 若接收到的位为1,则数据的最后一位置1 
else  
  tdata = tdata&0xfe;   // 否则数据的最后一位置0 
   SCL = 0; 
 }
 return(tdata); 
} 
//------------------------------------------------------------------- 
// 函数名称: DAC_PCF8591 
// 入口参数: slave_add从机地址,n要发送的数据个数 
// 函数功能: 发送n位数据子程序 
//------------------------------------------------------------------- 
void DAC_PCF8591(uchar controlbyte,uchar w_data) 
{    
iic_start();                    // 启动I2C 
delayNOP();
IICSendByte(PCF8591_WRITE);     // 发送地址位 
check_ACK();                    // 检查应答位 
    if(askflag == 1) 
 {  
SystemError = 1; 
return;                     // 若非应答,置错误标志位 
     } 
    IICSendByte(controlbyte&0x77); //Control byte  
check_ACK();                    //检查应答位 
    if(askflag == 1) 
 {  
SystemError = 1; 
return;                    // 若非应答,置错误标志位 
 } 
    IICSendByte(w_data);        //data byte 
check_ACK();                  // 检查应答位 
    if(askflag == 1) 
 {  
SystemError = 1; 
     return;   // 若非应答表明器件错误或已坏,置错误标志位SystemError 
 } 
iic_stop();         // 全部发完则停止 
delayNOP(); 
delayNOP(); 
delayNOP(); 
delayNOP(); 
} 
//------------------------------------------------------------------- 
// 函数名称: ADC_PCF8591 
// 入口参数: controlbyte控制字 
// 函数功能: 连续读入4路通道的A/D转换结果到receivebuf 
//------------------------------------------------------------------- 
void ADC_PCF8591(uchar controlbyte) 
{  
    uchar idata receive_da,i=0; 
while(i<4) 
{  
iic_start();
IICSendByte(PCF8591_WRITE); //控制字 
check_ACK(); 
if(askflag == 1) 
{ 
SystemError = 1; 
return; 
}
IICSendByte(controlbyte + i); //控制字 
check_ACK(); 
if(askflag == 1) 
{ 
SystemError = 1; 
return; 
}
    iic_start();                //重新发送开始命令 
    IICSendByte(PCF8591_READ); //控制字 
check_ACK(); 
if(askflag == 1) 
{ 
SystemError = 1; 
return; 
} 
  
    IICreceiveByte();   //空读一次,调整读顺序 
    slave_ACK();        //收到一个字节后发送一个应答位
//while(i<4) 
//{   
  receive_da=IICreceiveByte(); 
  receivebuf[i++]=receive_da; 
  slave_ACK();       //收到一个字节后发送一个应答位 
} 
slave_NOACK();       //收到最后一个字节后发送一个非应答位 
iic_stop(); 
} 
//------------------------------------------------------------------- 
// 函数名称: main 
// 函数功能: 主程序 
//------------------------------------------------------------------- 
main() 
{ 
    //uchar i,l; 
 uchar l;
    delay(10);                 //延时 
    LCD_init();                //初始化LCD              
  LCD_write_str(0,0,"1- .  V  2- .  V");
  LCD_write_str(1,0,"3- .  V  4- .  V");
  while(1) 
  {
iicInit();               //I2C总线初始化 
    ADC_PCF8591(0x04);
if(SystemError == 1)   //有错误,重新来 
  { 
   iicInit();   //I2C总线初始化 
    ADC_PCF8591(0x04); 
   }   
for(l=0;l<4;l++) 
 { 
        show_value(receivebuf[0]); //显示通道0        
        LCD_write_char(0,2,dis[2]);        //整数位显示 
  LCD_write_char(0,3,'.');     //小数点
        LCD_write_char(0,4,dis[1]);        //第一位小数显示  
        LCD_write_char(0,5,dis[0]);        //第二位小数显示
        show_value(receivebuf[1]); //显示通道1   
        LCD_write_char(0,11,dis[2]);        //整数位显示 
  LCD_write_char(0,12,'.');     //小数点
        LCD_write_char(0,13,dis[1]);        //第一位小数显示  
        LCD_write_char(0,14,dis[0]);        //第二位小数显示
        show_value(receivebuf[2]); //显示通道2            
        LCD_write_char(1,2,dis[2]);        //整数位显示 
  LCD_write_char(1,3,'.');     //小数点
        LCD_write_char(1,4,dis[1]);        //第一位小数显示  
        LCD_write_char(1,5,dis[0]);        //第二位小数显示
        show_value(receivebuf[3]); //显示通道3   
        LCD_write_char(1,11,dis[2]);        //整数位显示 
  LCD_write_char(1,12,'.');     //小数点
        LCD_write_char(1,13,dis[1]);        //第一位小数显示  
        LCD_write_char(1,14,dis[0]);        //第二位小数显示
      iicInit();               //I2C总线初始化   
      DAC_PCF8591(0x40,receivebuf[0]); //D/A输出
    if(SystemError == 1)   //有错误,重新来 
    { 
    iicInit();   //I2C总线初始化 
 DAC_PCF8591(0x40,receivebuf[0]); //D/A输出 
    }         
      //delay(50);                       //延时 
 }
   } 
}
LCD.h
/******************************************************
*MCU at89s52
*晶振 12MHz
*LCD1602 4位数据线程序
*   端口名称              端口符号     MCU端口    LCD引脚
*   RS数据/指令选择线        RS          P0^0       4    P2^4
*   R/W读写选择线            R/W         GND        5    P2^5
*   EN写使能线               EN          PD0^1      6    P2^6
*   数据总线                 D0-D3       NC        7-10
*                            D4          P1^4      11    P0^4
*                            D5          P1^5      12    P0^5
*                            D6          P1^6      13            P0^6
*                            D7          P1^7      14    P0^7
*   其他端口连接:
*                        电源负     VSS             1
*                        电源正+4.5--+5.5V   VDD    2
*                        对比度调节    VL  用1(10k左右电阻连接至地)  3
*                        背光负        BLK   VDD   15    
*                        背光正        BLA   GND   16
*********************************************************************************/
#define uint unsigned int
#define uchar unsigned char
//#define disdata P0
//sbit RS=P2^4;
//sbit RW=P2^5;
//sbit LCD_EN=P2^6;
void delay_nms(uint z)//毫秒级延时函数
 {
   uint i,j;
   for(i=0;i<z;i++)
   for(j=0;j<120;j++);
 }
void write_num(uchar num)     //写数据线命令(四线模式数据要分两次写)
   {
     disdata &= 0x0F;         //清高四位端口
     disdata |= (num&0xF0);   //写高四位数据
     delay_nms(2);     //小于 2ms出现少首字符现象
     LCD_EN = 1;              //EN=1
     LCD_EN = 0;             //EN=0 
     disdata &= 0x0F;              //清高四位端口
     disdata |= ((num&0x0F)<<4);   //写低四位数据
     delay_nms(2);
     LCD_EN = 1;              //EN=1
     LCD_EN = 0;             //EN=0
 
   }
void write_com(uchar com)  //写指令
   {
    LCD_RS = 0;
  LCD_RW = 0;
    write_num(com);
   }
  
void write_dat(uchar dat)  //写函数
   {
    LCD_RS = 1;
 LCD_RW = 0;
    write_num(dat);
   }
void LCD_init(void)       //LCD初始化
   {
    delay_nms(15);         //原来1602初始化成4位数据线之前必需先初始化成8位
    write_com(0x33);       //(此时命令发送方式是8位格式,但数据线只需接4位),
    delay_nms(5);          //然后再改到4位线宽,这样初始化才稳定
    write_com(0x32);
    delay_nms(5); 
    write_com(0x28);   //四线模式设置
    write_com(0x0f);   //显示开--对应开关显示控制指令
    write_com(0x01);   //清屏--对应清屏指令
    delay_nms(5);
   }
void LCD_pos(uchar x,uchar y)//写地址函数
   {
     if(x)
         write_com(0xc0+y); //第二行显示
     else
         write_com(0x80+y); //第一行显示
   }
 
void LCD_write_char(uchar x,uchar y,uchar zifu) //写字符函数
   {
      LCD_pos(x,y);
      write_dat(zifu);
   }
  
void LCD_write_str(uchar x,uchar y,uchar *s)//写字符串函数
   {
      LCD_pos(x,y);
      while(*s)
     {
         write_dat(*s);
         s++;
  
      }
    }
回复
| 有奖活动 | |
|---|---|
| 硬核工程师专属补给计划——填盲盒 | |
| “我踩过的那些坑”主题活动——第002期 | |
| 【EEPW电子工程师创研计划】技术变现通道已开启~ | |
| 发原创文章 【每月瓜分千元赏金 凭实力攒钱买好礼~】 | |
| 【EEPW在线】E起听工程师的声音! | |
| 高校联络员开始招募啦!有惊喜!! | |
| 【工程师专属福利】每天30秒,积分轻松拿!EEPW宠粉打卡计划启动! | |
| 送您一块开发板,2025年“我要开发板活动”又开始了! | |
			
			
			
						
			
										
 我要赚赏金
