找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3059|回复: 1
打印 上一主题 下一主题
收起左侧

c51单片机PCF8591 lcd1602做的电压表显示问题

[复制链接]
跳转到指定楼层
楼主
ID:447078 发表于 2018-12-17 16:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
200黑币
整个流程为:mcu通过内部中断PWM方式产生可调输出电压,接到PCF8591的AIN3,返回uchar类型,然后通过mcu显示到lcd上。
现在问题是:不论我如何改变pwm的占空比,再或者不论PCF有没有输入都会输出4.8。之前在考虑是不是i2c读字节前需要空读,但是没有能够写出来,求助。
有思路的可以留言可以QQ联系,谢谢。

只要能解决,500黑币都给!

main.c
  1. <div>#include <reg51.h> //51寄存器文件
  2. #include <intrins.h>
  3. #include <I2C.H>
  4. #include"1602.h"
  5. #define  PCF8591 0x90    //PCF8591 地址</div><div>typedef unsigned int uint;//WORD代替unsigned int
  6. typedef unsigned char uchar;
  7. unsigned char timer0,timer1,second,second1;
  8. unsigned int count,count1,mid;
  9. unsigned int  key;
  10. unsigned char v,ss,aa;
  11. unsigned long test_ss;
  12. sbit PWM=P3^7;
  13. unsigned int i,j;
  14. unsigned char  Data,keyFlag;
  15. uint a,b,c;
  16. uchar shi,ge,ms,vt;
  17. uint a,b,c,o;
  18. float why;</div><div>void scan_key();
  19. int T1s();</div><div>uchar dis1[] = {"V1:"};
  20. uchar dis2[] = {"V2:"};
  21. uchar dis1t[] = {"T1:"};
  22. uchar dis2t[] = {"T2:"};
  23. uchar dist1[] = "00.0s";
  24. uchar dist2[] = "00.0x";</div><div>void system_Ini()
  25. {
  26.     TMOD = 0x11;
  27.         //PWM  
  28.         TH0 = 0xff;
  29.         TL0 = 0xf7;
  30.         TH1 = 0xff;
  31.         TL1 = 0xf7;
  32.         EA = 1;
  33.         ET0 = 1;
  34.         ET1 = 1;
  35.         TR0  = 1;
  36.         TR1  = 1;
  37.     //IE =0x8A;        
  38. }

  39. /*******************************************************************
  40. ADC发送字节[命令]数据函数               
  41. *******************************************************************/
  42. bit ISendByte(unsigned char sla,unsigned char c)
  43. {
  44.    Start_I2c();              //启动总线
  45.    SendByte(sla);            //发送器件地址
  46.    if(ack==0)return(0);
  47.    SendByte(c);              //发送数据
  48.    if(ack==0)return(0);
  49.    Stop_I2c();               //结束总线
  50.    return(1);
  51. }

  52. /*******************************************************************
  53. ADC读字节数据函数               
  54. *******************************************************************/
  55. unsigned char IRcvByte(unsigned char sla)
  56. {  unsigned char c = 0;

  57.    Start_I2c();          //启动总线
  58.    SendByte(sla+1);      //发送器件地址
  59.    if(ack==0)return(0);
  60.    c=RcvByte();      //读取第1路电压值,范围是0-255
  61.    c=0;
  62.    c=RcvByte();      //读取第1路电压值,范围是0-255

  63.    //for(what=0;what<5;what++)//连续读5次,取最后一次,以便读取稳定值
  64.                   

  65.    Ack_I2c(1);           //发送非就答位
  66.    Stop_I2c();           //结束总线
  67.    return(c);
  68. }

  69. main()
  70. {
  71.         BYTE i;
  72.         //uchar shi,ge;
  73.         lcd_init();                                //初始化LCD        
  74.         system_Ini();               
  75.         delay(10);
  76.         lcd_pos(0);                                //设置显示位置为第一行的第1个字符
  77.         i = 0;
  78.         while(dis1[i] != '\0')
  79.         {                                                //显示字符"一号电压"
  80.                 lcd_wdat(dis1[i]);
  81.                 i++;
  82.         }
  83.         lcd_pos(8);                                //设置显示位置为第一行的第9个字符
  84.         i = 0;
  85.         while(dis1[i] != '\0')
  86.         {                                                //显示字符"一号时间"
  87.                 lcd_wdat(dis1t[i]);
  88.                 i++;
  89.         }
  90.         lcd_pos(0x40);                        //设置显示位置为第二行第1个字符
  91.         i = 0;
  92.         while(dis2[i] != '\0')
  93.         {
  94.                 lcd_wdat(dis2[i]);        //显示字符"二号电压"
  95.                 i++;
  96.         }
  97.         lcd_pos(0x48);                        //设置显示位置为第二行第9个字符
  98.         i = 0;
  99.         while(dis2[i] != '\0')
  100.         {
  101.                 lcd_wdat(dis2t[i]);        //显示字符"二号时间"
  102.                 i++;
  103.         }
  104.         lcd_pos(0x4b);                                //设置显示位置为第一行的第12个字符
  105.         lcd_wdat(0x30+0);
  106.         lcd_pos(0x4c);                                //设置显示位置为第一行的第12个字符
  107.         lcd_wdat(0x30+0);
  108.         lcd_pos(0x4d);                                //设置显示位置为第一行的第12个字符
  109.         lcd_wdat('.');
  110.         lcd_pos(0x4e);                                //设置显示位置为第一行的第12个字符
  111.         lcd_wdat(0x30+0);
  112.         //while(1);        
  113.         lcd_pos(3);                                //设置显示位置为第一行的第12个字符
  114.         lcd_wdat(0x30+0);
  115.         lcd_pos(4);                                //设置显示位置为第一行的第12个字符
  116.         lcd_wdat('.');
  117.         lcd_pos(5);                                //设置显示位置为第一行的第12个字符
  118.         lcd_wdat(0x30+0);

  119.     while(1)
  120.     {
  121.         //if(ms>0) ISendByte(PCF8591,0x43);
  122.         if((count>0)&&(keyFlag == 1))
  123.         {
  124.         ISendByte(PCF8591,0x43);
  125.     Data=IRcvByte(PCF8591);
  126.         ss=Data*48/255;
  127.         a = ss/10 ;
  128.         b = (ss)%10;
  129.         //c = (ss-a*100-b*10)%10;


  130.         lcd_pos(3);                                //设置显示位置为第一行的第12个字符
  131.         lcd_wdat('0'+a);
  132.         lcd_pos(4);                                //设置显示位置为第一行的第12个字符
  133.         lcd_wdat('.');
  134.         lcd_pos(5);                                //设置显示位置为第一行的第12个字符
  135.         lcd_wdat(0x30+b);
  136.         //lcd_pos(6);                                //设置显示位置为第一行的第12个字符
  137.         //lcd_wdat(0x30+c);
  138.         
  139.         shi=second/10;
  140.         ge=second%10;
  141.         lcd_pos(0x4b);                                //设置显示位置为第2行的第12个字符
  142.         lcd_wdat(0x30+shi);
  143.         lcd_pos(0x4c);                                //设置显示位置为第2行的第12个字符
  144.         lcd_wdat(0x30+ge);
  145.         lcd_pos(0x4d);                                //设置显示位置为第2行的第12个字符
  146.         lcd_wdat('.');
  147.         lcd_pos(0x4e);                                //设置显示位置为第2行的第12个字符
  148.         lcd_wdat(0x30+ms);
  149.         }
  150.     }                        
  151. }

  152. /*************************************
  153. [ t1 (0.5ms)中断] 中断中做 PWM 输出
  154.   ------------1000/(0.02ms*250)=200Hz
  155. *************************************/
  156. void T0zd(void) interrupt 1    //3 为定时器1的中断号  1 定时器0的中断号 0 外部中断1 2 外部中断2  4 串口中断
  157. {
  158.         scan_key();                                                                   //检测按键
  159.    switch(key){
  160.    case 8:
  161.    {
  162.            keyFlag  = 1;
  163.         TR0 = 0;
  164.         TH0 = 0xff;
  165.         TL0 = 0xf7;
  166.         TR0 = 1;
  167.          timer1++;

  168.          if(timer1>=100)
  169.           {
  170.                 timer1=0;
  171.                 ms++;
  172.                 vt++;
  173.         }
  174.     if(timer1<=0) PWM=1;
  175.     else PWM=0;
  176.         if(ms == 10)
  177.         {
  178.                  ms = 0;
  179.                 count++;
  180.         if(count == 10)
  181.         {
  182.                 count = 0;
  183.                 second++;
  184.                 if(second == 60)
  185.                 {
  186.                          second = 0;
  187.                 }
  188.         }}
  189.         else
  190.         {
  191.                  }
  192.         }break;
  193.         default:;
  194.         }
  195. }

  196. void T1zd(void) interrupt 3    //3 为定时器1的中断号  1 定时器0的中断号 0 外部中断1 2 外部中断2  4 串口中断
  197. {

  198. }

  199. void scan_key()                                                         //按键检测函数
  200. {
  201.         if(P1== 0xfe)
  202.                 key= 1;
  203.         if(P1== 0xfd)
  204.                 key= 2;
  205.         if(P1== 0xfb)
  206.                 key= 3;
  207.         if(P1== 0xf7)
  208.                 key= 4;
  209.         if(P1== 0xef)
  210.                 key= 5;
  211.         if(P1== 0xdf)
  212.                 key= 6;
  213.         if(P1== 0xbf)
  214.                 key= 7;
  215.         if(P1== 0x7f)
  216.                 key= 8;

  217. }
  218. </div>
复制代码

I2C.c
  1. <div><font size="2">
  2. /*************************此部分为I2C总线的驱动程序*************************************/

  3. #include<reg52.h>
  4. #include <intrins.h>
  5. #include <I2C.H>

  6. #define  NOP()   _nop_()   /* 定义空指令 */
  7. #define  _Nop()  _nop_()   /*定义空指令*/


  8. sbit     SCL=P2^1;       //I2C  时钟
  9. sbit     SDA=P2^0;       //I2C  数据
  10. bit ack;                 /*应答标志位*/
  11.    

  12. /*******************************************************************
  13.                      起动总线函数               
  14. 函数原型: void  Start_I2c();  
  15. 功能:     启动I2C总线,即发送I2C起始条件.  
  16. ********************************************************************/
  17. void Start_I2c()
  18. {
  19.   SDA=1;         /*发送起始条件的数据信号*/
  20.   _Nop();
  21.   SCL=1;
  22.   _Nop();        /*起始条件建立时间大于4.7us,延时*/
  23.   _Nop();
  24.   _Nop();
  25.   _Nop();
  26.   _Nop();   
  27.   SDA=0;         /*发送起始信号*/
  28.   _Nop();        /* 起始条件锁定时间大于4μs*/
  29.   _Nop();
  30.   _Nop();
  31.   _Nop();
  32.   _Nop();      
  33.   SCL=0;       /*钳住I2C总线,准备发送或接收数据 */
  34.   _Nop();
  35.   _Nop();
  36. }

  37. /*******************************************************************
  38.                       结束总线函数               
  39. 函数原型: void  Stop_I2c();  
  40. 功能:     结束I2C总线,即发送I2C结束条件.  
  41. ********************************************************************/
  42. void Stop_I2c()
  43. {
  44.   SDA=0;      /*发送结束条件的数据信号*/
  45.   _Nop();       /*发送结束条件的时钟信号*/
  46.   SCL=1;      /*结束条件建立时间大于4μs*/
  47.   _Nop();
  48.   _Nop();
  49.   _Nop();
  50.   _Nop();
  51.   _Nop();
  52.   SDA=1;      /*发送I2C总线结束信号*/
  53.   _Nop();
  54.   _Nop();
  55.   _Nop();
  56.   _Nop();
  57. }

  58. /*******************************************************************
  59.                  字节数据发送函数               
  60. 函数原型: void  SendByte(UCHAR c);
  61. 功能:     将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
  62.           此状态位进行操作.(不应答或非应答都使ack=0)     
  63.            发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
  64. ********************************************************************/
  65. void  SendByte(unsigned char  c)
  66. {
  67. unsigned char  BitCnt;

  68. for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/
  69.     {
  70.      if((c<<BitCnt)&0x80)SDA=1;   /*判断发送位*/
  71.        else  SDA=0;               
  72.      _Nop();
  73.      SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/
  74.       _Nop();
  75.       _Nop();             /*保证时钟高电平周期大于4μs*/
  76.       _Nop();
  77.       _Nop();
  78.       _Nop();         
  79.      SCL=0;
  80.     }
  81.    
  82.     _Nop();
  83.     _Nop();
  84.     SDA=1;                /*8位发送完后释放数据线,准备接收应答位*/
  85.     _Nop();
  86.     _Nop();   
  87.     SCL=1;
  88.     _Nop();
  89.     _Nop();
  90.     _Nop();
  91.     if(SDA==1)ack=0;     
  92.        else ack=1;        /*判断是否接收到应答信号*/
  93.     SCL=0;
  94.     _Nop();
  95.     _Nop();
  96. }

  97. /*******************************************************************
  98.                  字节数据接收函数               
  99. 函数原型: UCHAR  RcvByte();
  100. 功能:        用来接收从器件传来的数据,并判断总线错误(不发应答信号),
  101.           发完后请用应答函数应答从机。  
  102. ********************************************************************/   
  103. unsigned char   RcvByte()
  104. {
  105.   unsigned char  retc;
  106.   unsigned char  BitCnt;
  107.   
  108.   retc=0;
  109.   SDA=1;                     /*置数据线为输入方式*/
  110.   for(BitCnt=0;BitCnt<8;BitCnt++)
  111.       {
  112.         _Nop();           
  113.         SCL=0;                  /*置时钟线为低,准备接收数据位*/
  114.         _Nop();
  115.         _Nop();                 /*时钟低电平周期大于4.7μs*/
  116.         _Nop();
  117.         _Nop();
  118.         _Nop();
  119.         SCL=1;                  /*置时钟线为高使数据线上数据有效*/
  120.         _Nop();
  121.         _Nop();
  122.         retc=retc<<1;
  123.         if(SDA==1)retc=retc+1;  /*读数据位,接收的数据位放入retc中 */
  124.         _Nop();
  125.         _Nop();
  126.       }
  127.   SCL=0;   
  128.   _Nop();
  129.   _Nop();
  130.   return(retc);
  131. }

  132. /********************************************************************
  133.                      应答子函数
  134. 函数原型:  void Ack_I2c(bit a);
  135. 功能:      主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
  136. ********************************************************************/
  137. void Ack_I2c(bit a)
  138. {
  139.   
  140.   if(a==0)SDA=0;              /*在此发出应答或非应答信号 */
  141.   else SDA=1;
  142.   _Nop();
  143.   _Nop();
  144.   _Nop();      
  145.   SCL=1;
  146.   _Nop();
  147.   _Nop();                    /*时钟低电平周期大于4μs*/
  148.   _Nop();
  149.   _Nop();
  150.   _Nop();  
  151.   SCL=0;                     /*清时钟线,钳住I2C总线以便继续接收*/
  152.   _Nop();
  153.   _Nop();   
  154. }</font>
  155. </div>
复制代码

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:447078 发表于 2018-12-17 16:30 | 只看该作者
补充一点:PWM输出的电压值通过电压表测过啦,是没有问题的。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表