找回密码
 立即注册
搜索
热搜: 中医 针灸 咳嗽
查看: 142|回复: 0

ADC 转换 I2C操作PCF8591

[复制链接]

3706

主题

1

回帖

1万

积分

管理员

积分
11870
发表于 2023-2-18 17:07:51 | 显示全部楼层 |阅读模式
开发板上的接线原理图:



开发板完整原理图:


  1. #include <reg52.h>
  2. #include <intrins.h>
  3. #define MAIN_Fosc    11059200UL // 宏定义主时钟HZ
  4. #define PCF8591_ADDR 0x90       // PCF8591地址
  5. #define DACOUT_EN    0x40       // DAC输出使能

  6. /*====================================
  7. 自定义类型名
  8. ====================================*/
  9. typedef unsigned char INT8U;
  10. typedef unsigned char uchar;

  11. typedef unsigned int INT16U;
  12. typedef unsigned int uint;

  13. /*====================================
  14. 硬件接口位声明
  15. ====================================*/
  16. sbit SDA  = P2 ^ 0; // I2C串行数据
  17. sbit SCL  = P2 ^ 1; // I2C串行时钟
  18. sbit DU   = P2 ^ 6; // 数码管段选
  19. sbit WE   = P2 ^ 7; // 数码管位选
  20. sbit LED1 = P1 ^ 0; // 读取AD的值是否成功(亮成功,灭失败)
  21. sbit LED2 = P1 ^ 1; // DAC成功输出(亮成功,灭失败)
  22. sbit BEEP = P2 ^ 3; // 蜂鸣器引脚定义

  23. uchar AD_Value; // 存储AD转换回的数字量
  24. /*====================================
  25. 共阴极数码管段选码
  26. ====================================*/
  27. uchar code table[] = {
  28.     // 0                1         2     3     4     5     6     7     8
  29.     0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F,
  30.     // 9     A     B           C         D           E         F                -         .          关显示
  31.     0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x40, 0x80, 0x00};

  32. /*====================================
  33. 数码管位选码
  34. ====================================*/
  35. // 第1位        2位          3位         4位   5位        6位          7位        8位
  36. uchar code T_COM[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f}; // 数码管位码

  37. /*====================================
  38. 函数:void Delay_Ms(INT16U ms)
  39. 参数:ms,毫秒延时形参
  40. 描述:12T 51单片机自适应主时钟毫秒级延时函数
  41. ====================================*/
  42. void Delay_Ms(INT16U ms)
  43. {
  44.     INT16U i;
  45.     do {
  46.         i = MAIN_Fosc / 96000;
  47.         while (--i)
  48.             ; // 96T per loop
  49.     } while (--ms);
  50. }

  51. /*====================================
  52. 函数:void Delay5us()
  53. 描述:12T 51单片机5微秒延时函数自适应时钟(11.0592M,12M,22.1184M)
  54. ====================================*/
  55. void Delay5us()
  56. {
  57. #if MAIN_Fosc == 11059200
  58.     _nop_();
  59. #elif MAIN_Fosc == 12000000
  60.     _nop_();
  61. #elif MAIN_Fosc == 22118400
  62.     _nop_();
  63.     _nop_();
  64.     _nop_();
  65. #endif
  66. }

  67. /*====================================
  68. 函数:void Display(INT8U Value)
  69. 参数:Value,显示值 取值0-255
  70. 描述:共阴极数码管显示函数可显示一个字节的数
  71. ====================================*/
  72. void Display(INT8U Value)
  73. {
  74.     //------------------------------
  75.     DU = 1;
  76.     P0 = table[Value / 100]; // 管显示百位
  77.     DU = 0;

  78.     P0 = 0xff; // 清除断码

  79.     WE = 1;
  80.     P0 = T_COM[0]; // 第一位数码管
  81.     WE = 0;
  82.     Delay_Ms(5);
  83.     //-------------------------------
  84.     DU = 1;
  85.     P0 = table[Value % 100 / 10]; // 显示十位
  86.     DU = 0;

  87.     P0 = 0xff; // 清除断码

  88.     WE = 1;
  89.     P0 = T_COM[1]; // 第二位数码管
  90.     WE = 0;
  91.     Delay_Ms(5);
  92.     //-------------------------------
  93.     DU = 1;
  94.     P0 = table[Value % 10]; // 显示个位
  95.     DU = 0;

  96.     P0 = 0xff; // 清除断码

  97.     WE = 1;
  98.     P0 = T_COM[2]; // 第三位数码管
  99.     WE = 0;
  100.     Delay_Ms(5);
  101. }

  102. /*====================================
  103. 函数:I2C_init()
  104. 描述:I2C总线初始化
  105. ====================================*/
  106. void I2C_init()
  107. {
  108.     SDA = 1; // 数据总线高
  109.     _nop_();
  110.     SCL = 1; // 时钟总线高
  111.     _nop_();
  112. }

  113. /*====================================
  114. 函数:I2C_Start()
  115. 描述:I2C起始信号
  116. ====================================*/
  117. void I2C_Start()
  118. {
  119.     SCL = 1;
  120.     _nop_();
  121.     SDA = 1;
  122.     Delay5us();
  123.     SDA = 0;
  124.     Delay5us();
  125. }

  126. /*====================================
  127. 函数:I2C_Stop()
  128. 描述:I2C停止信号
  129. ====================================*/
  130. void I2C_Stop()
  131. {
  132.     SDA = 0;
  133.     _nop_();
  134.     SCL = 1;
  135.     Delay5us();
  136.     SDA = 1;
  137.     Delay5us();
  138. }

  139. /*====================================
  140. 函数:Master_ACK(bit i)
  141. 参数:i 为0时发送非应答 为1时发送应答
  142. 描述:I2C主机发送应答
  143. ====================================*/
  144. void Master_ACK(bit i)
  145. {
  146.     SCL = 0; // 拉低时钟总线允许SDA数据总线上的数据变化
  147.     _nop_(); // 让总线稳定
  148.     if (i)   // 如果i = 1 那么拉低数据总线 表示主机应答
  149.     {
  150.         SDA = 0;
  151.     } else {
  152.         SDA = 1; // 发送非应答
  153.     }
  154.     _nop_(); // 让总线稳定
  155.     SCL = 1; // 拉高时钟总线 让从机从SDA线上读走 主机的应答信号
  156.     _nop_();
  157.     SCL = 0; // 拉低时钟总线, 占用总线继续通信
  158.     _nop_();
  159.     SDA = 1; // 释放SDA数据总线。
  160.     _nop_();
  161. }

  162. /*====================================
  163. 函数:Test_ACK()
  164. 返回:0为非应答 1为应答
  165. 描述:I2C检测从机应答
  166. ====================================*/
  167. bit Test_ACK() // 检测从机应答
  168. {
  169.     SCL = 1; // 时钟总线为高电平期间可以读取从机应答信号
  170.     Delay5us();
  171.     if (SDA) {
  172.         SCL = 0;
  173.         I2C_Stop();
  174.         return (0);
  175.     } else {
  176.         SCL = 0;
  177.         return (1);
  178.     }
  179. }

  180. /*====================================
  181. 函数:I2C_send_byte(uchar byte)
  182. 参数:byte 要发送的字节
  183. 描述:I2C发送一个字节
  184. ====================================*/
  185. void I2C_send_byte(uchar byte)
  186. {
  187.     uchar i;
  188.     for (i = 0; i < 8; i++) {
  189.         SCL = 0;
  190.         _nop_();
  191.         if (byte & 0x80) //
  192.         {
  193.             SDA = 1;
  194.             _nop_();
  195.         } else {
  196.             SDA = 0;
  197.             _nop_();
  198.         }
  199.         SCL = 1;
  200.         _nop_();
  201.         byte <<= 1;
  202.     }
  203.     SCL = 0;
  204.     _nop_();
  205.     SDA = 1;
  206.     _nop_();
  207. }

  208. /*====================================
  209. 函数:I2C_read_byte()
  210. 返回:读取的字节
  211. 描述:I2C读一个字节
  212. ====================================*/
  213. uchar I2C_read_byte()
  214. {
  215.     uchar i, dat;
  216.     SCL = 0;
  217.     _nop_();
  218.     SDA = 1;
  219.     _nop_();
  220.     for (i = 0; i < 8; i++) {
  221.         SCL = 1;
  222.         _nop_();
  223.         dat <<= 1;
  224.         if (SDA) {
  225.             dat |= 0x01;
  226.         }
  227.         _nop_();
  228.         SCL = 0;
  229.         _nop_();
  230.     }
  231.     return (dat);
  232. }

  233. /*DAC输出*/
  234. bit DAC_OUT(uchar DAT)
  235. {
  236.     I2C_Start();
  237.     I2C_send_byte(PCF8591_ADDR + 0);
  238.     if (!Test_ACK()) {
  239.         return (0);
  240.     }
  241.     I2C_send_byte(DACOUT_EN); // DA输出使能
  242.     if (!Test_ACK()) {
  243.         return (0);
  244.     }
  245.     I2C_send_byte(DAT);
  246.     if (!Test_ACK()) {
  247.         return (0);
  248.     }
  249.     I2C_Stop();
  250.     return (1);
  251. }

  252. /*读AD数据*/
  253. bit ADC_Read(uchar CON)
  254. {
  255.     I2C_Start();
  256.     I2C_send_byte(PCF8591_ADDR + 0);
  257.     if (!Test_ACK()) {
  258.         return (0);
  259.     }
  260.     I2C_send_byte(CON);
  261.     Master_ACK(0);
  262.     I2C_Start();
  263.     I2C_send_byte(PCF8591_ADDR + 1);
  264.     if (!Test_ACK()) {
  265.         return (0);
  266.     }
  267.     AD_Value = I2C_read_byte();
  268.     Master_ACK(0);
  269.     I2C_Stop();
  270.     return (1);
  271. }

  272. void main()
  273. {
  274.     I2C_init();
  275.     while (1) {
  276.         /*
  277.          // 单端输入,读出通道2的值
  278.         //ADC_Read()   传入的参数说明:

  279.         00 AN0 ->0x00H
  280.         01 AN1 ->0x01H
  281.         10 AN2 ->0x02H
  282.         11 AN3 ->0x03H

  283.         该开发板中00表示 模式0  0  ,0X00H 读的是AN0的通道 该通道接光敏   
  284.         该开发板中01表示 模式0  1  ,0X01H 读的是AN1的通道 该通道接热敏
  285.         该开发板中10表示 模式1  0  ,0X02H 读的是AN2的通道 改线路接了一个10K的电位器,可以通过改变电位器测试数值
  286.         该开发板中11表示 模式1  0  ,0X03H 读的是AN3的通道 目前悬空外挂,如果需要测试,可以外接设备进行读取
  287.         */
  288.       
  289.   
  290.         if (ADC_Read(0x00))//如果返回为1 证明正确的读取到了AD数值
  291.             LED1 = 0;
  292.         else
  293.             LED1 = 1;
  294.         if (DAC_OUT(AD_Value))//如果单片机成功的数据传给DAC
  295.             LED2 = 0;
  296.         else
  297.             LED2 = 1;
  298.         Display(AD_Value);//如果需要输出电压 直接可以---用这代码Display(AD_Value*0.0196*10);
  299.         if (AD_Value < 100)//预警,当读取到的数值,达到一定条件 蜂鸣器开始预警
  300.             BEEP = 0;
  301.         else
  302.             BEEP = 1;
  303.         Delay_Ms(5);
  304.     }
  305. }
复制代码


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

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

本版积分规则

Archiver|手机版|小黑屋|私人站点 ( 冀ICP备2023028127号-2 )

GMT+8, 2025-4-19 23:02 , Processed in 0.085175 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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