找回密码
 立即注册

QQ登录

只需一步,快速开始

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

单片机+pcf8591读通道0的不知道哪里错了,最大只能读127,大神帮忙看一下

[复制链接]
跳转到指定楼层
楼主
电路原理图如下:


单片机源程序:
  1. #include <reg52.h>
  2. #include <intrins.h>        //_nop_()延时头文件
  3. typedef unsigned char uChar8;
  4. typedef unsigned int uInt16;
  5. sbit SDA = P1^0;
  6. sbit SCL = P1^1;
  7. #define PCF8591Add 0x90        //PCF8591的器件地址和写操作


  8.                                                                  
  9. void DelayMS(uInt16 lValMS)        //延时函数
  10. {
  11.         uInt16 luiVal,lujVal;
  12.         for(luiVal = 0; luiVal < lValMS; luiVal++)
  13.                 for(lujVal = 0; lujVal < 113; lujVal++);
  14. }
  15. void Delay5us(void)
  16. {
  17.         _nop_();_nop_();_nop_();
  18.         _nop_();_nop_();_nop_();
  19. }



  20. //IIC总线空闲时均为高电平
  21. void IICInit(void)                //IIC初始化
  22. {
  23.         SDA=1;
  24.         SCL=1;
  25. }



  26. //SCL高电平期间SDA由高到低的变化为起始信号
  27. void IICStart(void)        //起始信号
  28. {
  29.         SCL = 0;
  30.         Delay5us();
  31.         SDA = 1;
  32.         Delay5us();
  33.         SCL = 1;
  34.         Delay5us();
  35.         SDA = 0;
  36.         Delay5us();
  37.         //防止接下来SDA数据变化导致IIC总线误判        
  38.         SCL = 0;         
  39. }



  40. //SCL高电平期间SDA由低到高的变化为终止信号
  41. void IICStop(void)                //停止信号
  42. {
  43.         SCL = 0;
  44.         Delay5us();
  45.         SDA = 0;
  46.         Delay5us();
  47.         SCL = 1;
  48.         Delay5us();
  49.         SDA = 1;
  50.         Delay5us();
  51.         //防止接下来SDA数据变化导致IIC总线误判        
  52.         SCL = 0;
  53. }



  54. //一个脉冲期间,SDA为低电平为应答
  55. void IICAck(void)                //应答信号
  56. {
  57.         SCL = 0;
  58.         Delay5us();
  59.         SDA = 0;
  60.         Delay5us();
  61.         SCL = 1;
  62.         Delay5us();
  63.         SCL = 0;                 
  64. }



  65. /*cpu读应答信号,如果应答了则
  66. 继续传输数据,否则在一定时间里,
  67. 默认已经应答,继续传数据
  68. */
  69. void IICReadAck(void)        //读应答信号
  70. {
  71.         uChar8 li = 0;
  72.         SCL = 0;
  73.         SDA = 1;  //确保读出的值为0,因此先送1
  74.         Delay5us();
  75.         SCL = 1;
  76.         Delay5us();
  77.         //如果没有应答或时间没有超过预定时间则停在此处
  78.         while((1 == SDA)&&(li<255))li++;
  79.         SCL = 0;
  80.         Delay5us();               
  81.         SDA = 1;                        
  82. }



  83.         //        写1个字节,先写高位。
  84. void IICWriteOneByte(uChar8 lByteVal)                                        //写一个字节
  85. {
  86.         uChar8 li,liVal;
  87.         liVal = lByteVal;

  88.         for(li=0;li<8;li++)         
  89.         {
  90.                
  91.                 SCL = 0;
  92.                 Delay5us();        
  93.                 SDA = (bit)(liVal&0x80);        //把数据准备好等待传送
  94.                 Delay5us();        
  95.                 SCL = 1;
  96.                 Delay5us();
  97.                 liVal <<= 1;
  98.         }
  99.         SCL = 0;
  100.         Delay5us();        
  101.         SDA = 1;
  102. }



  103. //读取一个字节并把读到的值返回
  104. uChar8 IICReadOneByte(void)
  105. {
  106.         uChar8 li,liVal;
  107.         SCL = 0;
  108.         SDA = 1;
  109.         for(li=0;li<8;li++)
  110.         {
  111.                 liVal <<= 1;
  112.                 SCL = 0;
  113.                 Delay5us();
  114.                 SCL = 1;
  115.                 Delay5us();
  116.                 liVal = (liVal|SDA);
  117.         }
  118.         SCL = 0;
  119.         return liVal;
  120. }


  121.         
  122. //Regulate控制器,这里写控制函数
  123. void PCF8591WriteRegulate(void)
  124. {
  125.         IICStart();
  126.         IICWriteOneByte(PCF8591Add);         //PCF8591的地址,写控制
  127.         IICReadAck();
  128.         IICWriteOneByte(0x00);                //写入控制字
  129.         IICReadAck();
  130.         IICStop();
  131. }        
  132. uChar8  ReadDataPCF8591(void)
  133. {
  134.         uChar8 liVal;
  135.         IICStart();
  136.         IICWriteOneByte(PCF8591Add|0x01);         //PCF8591的地址,读控制        
  137.         liVal = IICReadOneByte();
  138.         IICAck();
  139.         IICStop();
  140.         return liVal;         
  141. }



  142. void main()
  143. {
  144.         IICInit();
  145.         while(1)
  146.         {         
  147.                   PCF8591WriteRegulate();
  148.                  P2 = ReadDataPCF8591();
  149.                  DelayMS(10);
  150.         }
  151. }

复制代码


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

使用道具 举报

沙发
ID:272144 发表于 2018-8-15 20:01 | 只看该作者
头很大啊  开发板上面也是这个情况
回复

使用道具 举报

板凳
ID:272144 发表于 2018-8-15 20:05 | 只看该作者
开发板上也是这样
回复

使用道具 举报

地板
ID:111634 发表于 2018-8-16 06:42 | 只看该作者
本帖最后由 zl2168 于 2018-8-17 22:05 编辑

实例85  PCF8591 I2C串行A-D(1602显示)
Proteus仿真一下,确认有效。
实例85 PCF8591 I2C串行A-D.rar (57.96 KB, 下载次数: 29)

以上摘自张志良编著《80C51单片机仿真设计实例教程——基于Keil CProteus》清华大学出版社ISBN 978-7-302-41682-1书中电路和程序设计有详细说明,程序语句条条有注解。
回复

使用道具 举报

5#
ID:782968 发表于 2021-2-9 16:38 | 只看该作者
我天我也遇到了一样的问题
回复

使用道具 举报

6#
ID:966079 发表于 2021-11-18 21:13 | 只看该作者
我刚刚也遇到了一样的问题,经过检查是在读取AD转换结果的函数中,发送了地址和读控制之后,不可以立刻进行读取,而是先WaitACK()等待应答(也就是楼主代码的162行和163行中间),等SDA总线拉高之后再开始读取,否则读回来最大值只会是01111111,而不是11111111,希望可以帮助到大家。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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