电路设计实例(PCF8591芯片使用)

举报
CodeAllen 发表于 2021/10/30 01:33:55 2021/10/30
【摘要】 由于要测多路AD,本身使用的芯片通道不够,差几路决定使用外置ADC完成,后决定使用PCF8591,带IIC后期很好管理。       AD的主要参数: 1、AD的位数:表明这个AD共有2^n个刻度,8位AD,输出的刻度是0~255。 (255=2^8-1)   2、分辨率:...

由于要测多路AD,本身使用的芯片通道不够,差几路决定使用外置ADC完成,后决定使用PCF8591,带IIC后期很好管理。

 

 

 

AD的主要参数:

1、AD的位数:表明这个AD共有2^n个刻度,8位AD,输出的刻度是0~255。 (255=2^8-1)

 

2、分辨率:就是AD能够分辨的最小的模拟量变化,假设5.10V的系统用8位的AD采样,那么它能分辨的最小电压就是5.10/255=0.02V。

 

3、INL:Interger NONliner 积分非线性度,表示了ADC器件在所有的数值点上对应的模拟值,和真实值之间误差最大的那一点的误差值。也就是,输出数值偏离线性最大的距离。单位是LSB(即最低位所表示的量)。比如12位ADC:TLC2543,INL值为1LSB。那么,如果基准4.095V,测某电压得的转换结果是1000,那么,真实电压值可能分布在0.999~1.001V之间。这里是这样这样计算得来的,12位ADC最小分辨率是1/4095。在这里即为4.095*(1/4095)=0.001V。那么1LSB就为0.001V,。转换结果为1000即为1V。

 

4、DNL:Differencial NonLiner-差分非线性度,理论上说,模数器件相邻量个数据之间,模拟量的差值都是一样的。就相一把疏密均匀的尺子。但实际并不如此。一把分辨率1毫米的尺子,相邻两刻度之间也不可能都是1毫米整。那么,ADC相邻两刻度之间最大的差异就叫差分非线性值(Differencial NonLiner)。DNL值如果大于1,那么这个ADC甚至不能保证是单调的,输入电压增大,在某个点数值反而会减小。这种现象在SAR(逐位比较)型ADC中很常见。

 

5、基准源:有内部基准源、外部基准源等等。

 

6、转换速率:也就是转换周期的倒数,转换周期就是完成一次AD转换所需的时间

 

二.PCF8591芯片

1.电路连接图和引脚功能如下:

 

(1).PCF8591是具有I2C总线借口的8位AD/DA转换芯片,内部为单一电源供电(2.5~6V),典型值为5V,CMOS工艺。PCF8591有4路AD输入,属逐次比较型,内含采样保持电路;1路8位DA输出,内含DAC数据寄存器。AD/DA转换的最大速率约为11KHz。

(2).Philips规定AD器件高四位地址为1001,低三位地址为引脚地址A0,A1,A2,由硬件电路决定。

(3).控制寄存器:

 

 

 

3.控制流程。

 看器件手册可以知道:

      在IICa总线中,器件地址必须是起始条件后作为第一个字节发送。发送给PCF8591的第二个字节被存储在控制寄存器,用于控制寄存器的功能。发送给PCF8591的第三个字节被存储到DAC数据寄存器。并使用片上D/A转换成相应的模拟电压。

 

    一个A/D转换周期总是开始于发送一个有效读模式地址给PCF8591之后。A/D转换周期在应答时钟脉冲的后沿被触发。

操作分四步:

(1)、发送地址字节,选择该器件。

(2)、发送控制字节,选择相应通道。               //

(3)、重新发送地址字节,选择该器件。

(4)、接收目标通道的数据。

这次的程序流程是:AD采样,循环执行。

程序如下:

 


  
  1. <span style="font-size:18px;">/*
  2. 项目名称:PCF8591实现AD转换
  3. 项目内容:A/D转换,并把转换的数字信号送给P0口控制LED灯
  4. ,调节电位器时观察LED的变化
  5. 作者:YUAN
  6. */
  7. #include <reg52.h>
  8. #include <intrins.h> //_nop_()延时头文件
  9. typedef unsigned char uChar8;
  10. typedef unsigned int uInt16;
  11. sbit SDA = P1^0;
  12. sbit SCL = P1^1;
  13. #define PCF8591Add 0x90 //PCF8591的器件地址和写操作
  14. //延时函数
  15. void DelayMS(uInt16 lValMS);
  16. void Delay5us(void);
  17. //IIC操作的几个函数
  18. void IICInit(void); //IIC初始化
  19. void IICStart(void); //起始信号
  20. void IICStop(void); //停止信号
  21. void IICAck(void); //应答信号
  22. void IICReadAck(void); //读应答信号
  23. void IICWriteOneByte(uChar8 lByteVal); //写一个字节
  24. uChar8 IICReadOneByte(void); //读一个字节
  25. void PCF8591WriteRegulate(uChar8 lREGVal); //Regulate控制器,这里写控制函数
  26. uChar8 ReadDataPCF8591(void);
  27. void main()
  28. {
  29. IICInit();
  30. while(1)
  31. {
  32. /*写入控制字00,即模拟量输出关闭,选择通道0,
  33. 不自动增加通道,模拟量输入围方式0*/
  34. PCF8591WriteRegulate(0x00);
  35. P0 = ReadDataPCF8591();
  36. DelayMS(10);
  37. }
  38. }
  39. void DelayMS(uInt16 lValMS) //延时函数
  40. {
  41. uInt16 luiVal,lujVal;
  42. for(luiVal = 0; luiVal < lValMS; luiVal++)
  43. for(lujVal = 0; lujVal < 113; lujVal++);
  44. }
  45. void Delay5us(void)
  46. {
  47. _nop_();_nop_();_nop_();
  48. _nop_();_nop_();_nop_();
  49. }
  50. //IIC总线空闲时均为高电平
  51. void IICInit(void) //IIC初始化
  52. {
  53. SCL = 0;
  54. SDA=1;
  55. Delay5us();
  56. SCL=1;
  57. }
  58. //SCL高电平期间SDA由高到低的变化为起始信号
  59. void IICStart(void) //起始信号
  60. {
  61. SCL = 0;
  62. Delay5us();
  63. SDA = 1;
  64. Delay5us();
  65. SCL = 1;
  66. Delay5us();
  67. SDA = 0;
  68. Delay5us();
  69. //防止接下来SDA数据变化导致IIC总线误判
  70. SCL = 0;
  71. }
  72. //SCL高电平期间SDA由低到高的变化为终止信号
  73. void IICStop(void) //停止信号
  74. {
  75. SCL = 0;
  76. Delay5us();
  77. SDA = 0;
  78. Delay5us();
  79. SCL = 1;
  80. Delay5us();
  81. SDA = 1;
  82. Delay5us();
  83. //防止接下来SDA数据变化导致IIC总线误判
  84. SCL = 0;
  85. }
  86. //一个脉冲期间,SDA为低电平为应答
  87. void IICAck(void) //应答信号
  88. {
  89. SCL = 0;
  90. Delay5us();
  91. SDA = 0;
  92. Delay5us();
  93. SCL = 1;
  94. Delay5us();
  95. SCL = 0;
  96. }
  97. /*cpu读应答信号,如果应答了则
  98. 继续传输数据,否则在一定时间里,
  99. 默认已经应答,继续传数据
  100. */
  101. void IICReadAck(void) //读应答信号
  102. {
  103. uChar8 li = 0;
  104. SCL = 0;
  105. SDA = 1; //确保读出的值为0,因此先送1
  106. Delay5us();
  107. SCL = 1;
  108. Delay5us();
  109. //如果没有应答或时间没有超过预定时间则停在此处
  110. while((1 == SDA)&&(li<255))li++;
  111. SCL = 0;
  112. Delay5us();
  113. SDA = 1;
  114. }
  115. /*
  116. 写1个字节,先写高位。
  117. */
  118. void IICWriteOneByte(uChar8 lByteVal) //写一个字节
  119. {
  120. uChar8 li,liVal;
  121. liVal = lByteVal;
  122. for(li=0;li<8;li++)
  123. {
  124. SCL = 0;
  125. Delay5us();
  126. SDA = (bit)(liVal&0x80); //把数据准备好等待传送
  127. Delay5us();
  128. SCL = 1;
  129. Delay5us();
  130. liVal <<= 1;
  131. }
  132. SCL = 0;
  133. Delay5us();
  134. SDA = 1;
  135. }
  136. /*
  137. 读取一个字节并把读到的值返回
  138. */
  139. uChar8 IICReadOneByte(void)
  140. {
  141. uChar8 li,liVal;
  142. SCL = 0;
  143. SDA = 1;
  144. for(li=0;li<8;li++)
  145. {
  146. liVal <<= 1;
  147. SCL = 0;
  148. Delay5us();
  149. SCL = 1;
  150. Delay5us();
  151. liVal = (liVal|SDA);
  152. }
  153. SCL = 0;
  154. return liVal;
  155. }
  156. //Regulate控制器,这里写控制函数
  157. void PCF8591WriteRegulate(uChar8 lREGVal)
  158. {
  159. IICStart();
  160. IICWriteOneByte(PCF8591Add); //PCF8591的地址,写控制
  161. IICReadAck();
  162. IICWriteOneByte(lREGVal); //写入控制字
  163. IICReadAck();
  164. IICStop();
  165. }
  166. uChar8 ReadDataPCF8591(void)
  167. {
  168. uChar8 liVal;
  169. IICStart();
  170. IICWriteOneByte(PCF8591Add|0x01); //PCF8591的地址,读控制
  171. liVal = IICReadOneByte();
  172. IICAck();
  173. IICStop();
  174. return liVal;
  175. }
  176. </span>

 

文章来源: allen5g.blog.csdn.net,作者:CodeAllen的博客,版权归原作者所有,如需转载,请联系作者。

原文链接:allen5g.blog.csdn.net/article/details/80071365

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。