标题: 学51单片机-基于PCF8591的AD采样和DA输出 [打印本页]
作者: jiajiamei 时间: 2015-4-8 22:48
标题: 学51单片机-基于PCF8591的AD采样和DA输出
首先思考一个问题,我们的世界是数字的还是模拟的?
当然是模拟的了,所有的量都是在一定范围内连续变化的。我们为了能够更加方便的描述这些量,对它们进行了数字化。而数字量就不一样了,它是分立的的几个值。
举个例子,我们形容一个人的身高,模拟的说法是一米七到一米七五之间,数字的说法就是一米七三。
接下来说AD转换器,它的出现也是为了让我们能更方便、更直接的描述电压的高低。AD转换器,英文全称为Analog-to-Digital Converter,是模拟量到数字量的一个转换过程,主要用于电压的采集。它的出现就如同有了一把尺子,很容易就能量出电压的高低。
在电子设备中,经常要检测各种模拟量:温度、压力、速度、流量、重力加速度等等,这些模拟量都被相应的传感器转换为电压信号,我们只需要测量电压的高低,就能得到相应参数。
AD的主要参数有哪些?
1、AD的位数:表明这个AD共有2^n个刻度,8位AD,输出的刻度是0~255.
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之间。
4、DNL:Differencial NonLiner-差分非线性度,理论上说,模数器件相邻量个数据之间,模拟量的差值都是一样的。就相一把疏密均匀的尺子。但实际并不如此。一把分辨率1毫米的尺子,相邻两刻度之间也不可能都是1毫米整。那么,ADC相邻两刻度之间最大的差异就叫差分非线性值(Differencial NonLiner)。DNL值如果大于1,那么这个ADC甚至不能保证是单调的,输入电压增大,在某个点数值反而会减小。这种现象在SAR(逐位比较)型ADC中很常见。
5、基准源:有内部基准源、外部基准源等等。
6、转换速率:也就是转换周期的倒数,转换周期就是完成一次AD转换所需的时间。
今天要用到的器件是PCF8591,为什么选它?太多的开发板上用它做演示了,而且还是IIC总线通信的。既学习了AD采样,又学习了IIC总线。
先上应用电路:
如上图所示,PCF8591的9脚和10脚,一个是数据线SDA,一个是时钟线SCL。分别接到单片机的P2.0 , P2.1上面。
为什么选这两个引脚?因为51单片机上没有IIC总线接口,需要用普通的IO模拟,所以它随便选了两个IO接上就行。
VREF是什么?基准电压,也是它能测量的最大电压。
如何控制?今天先不说IIC总线,只说控制流程。
看器件手册可以知道:
分四步:
1、发送地址字节,选择该器件。
2、发送控制字节,选择相应通道。 //
3、重新发送地址字节,选择该器件。
4、接收目标通道的数据。
这次的程序流程是:AD采样,串口发送,循环执行。
下面是AD采样源代码:
-------------------------------------------------------------------------------------
下面介绍PCF8591的DA输出:
忽然发现,已经写到AD/DA这里来了。严格来说,已经不是51单片机的内容了,而是周边应用电路的一些东西。这些东西涉及的知识面比较广,什么都有可能提到。
关于AD/DA,或者其它设备,我的学习思路是先模仿,再深究。
因为无论是课本也好,器件手册也好,大部分讲的都是原理或者寄存器,起到的是一个工具书的作用,类似于语文课上用的字典。但是这就出现了一个问题,很多人想通过看课本或者看器件手册的方式来掌握这些设备。
这个思路有问题吗?没有问题吗?
还记得我刚才说的话么,它们就类似于语文课上用的字典,但是,有谁是通过看字典学会说话的!!!
我们都是通过模仿别人学会说话的,遇到不认识的字才去查字典!但是很多人或者很多学校都把这两件事的顺序搞反了。
记得之前我在英飞凌官网进行芯片选型,网页都翻烂了,找不到合适的。因为英飞凌不是我家开的,我不能保证每次都能顺利的找到我想要的东西。
但是,我同事参加了一次电子展,在展会上遇到了英飞凌的展台,然后问他们,他们一听我们的需求,马上找出一堆能满足我们要求的芯片。
这就是思路的问题!
扯远了,说回到DA控制。
DA转换(Digital to Analog),是将数字量变成模拟量的一个过程。AD与DA刚好是相反的两个过程,AD是把模拟信号变成单片机可识别的数字信号;DA是把单片机可识别的数字信号变成连续变化的模拟量。这两种功能的应用范围都非常广泛!
主要参数如下,具体什么意思就不讲了,大家可以百度一下。(因为我编不出来了...)
1)分辩率(Resolution)
2) 转换速率(Conversion Rate)
3)量化误差 (Quantizing Error)
4)偏移误差(Offset Error)
5)满刻度误差(Full Scale Error)
6)线性度(Linearity)
其他指标还有:绝对精度(Absolute Accuracy) ,相对精度(Relative Accuracy),微分非线性,单调性和无错码,总谐波失真(Total Harmonic Distotortion缩写THD)和积分非线性。
看到这么多参数,是不是很晕?
搞了这些年电子,感触最深的有一点是:无论做什么,先求有,再求好!
不要总想一口吃个胖子,没那么多天才。参数是很多,但是没要求你一下子全都记住,甚至你可以只记一两个。先把大致的应用流程跑一遍,跑下来,你才对这个设备有一个整体的概念,然后针对你的要求,比对相应的参数,进行修改、调试。
哪怕是在工作中,也不一定会考虑全部的参数。例如转换时间,我到现在也没认真看PIC内部的AD采样转换时间有多久,因为有些设备对实时性要求很低,速度慢一些也没事。
然后是控制流程,认真看器件手册的,或者看了昨天日志的,都知道是怎样一个流程:
第一步:写器件地址;
第二步:写控制位。
第三步:写入数据。
好了,上程序。通过DA输出渐变电压控制LED,形成呼吸灯的效果。里面有个警告:
*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
大家可以研究下,如何消除警告。
程序源码如下:
- /**********************51单片机学习例程************************
- * 平台: Keil U34 + STC89C52RD
- * 名称:IIC协议 PCF8591ADDA转换 ,此程序通过IIC协议对DAAD芯片操作, 并输出模拟量,用LED亮度渐变指示
- * 编写:起航
- * 晶振:11.0592MHZ
- ******************************************************************/
- #include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
- #include <intrins.h> //包含NOP空指令函数_nop_();
- #define AddWr 0x90 //写数据地址
- #define AddRd 0x91 //读数据地址
- sbit RST=P2^4; //关掉时钟芯片输出
- sbit Sda=P2^0; //定义总线连接端口
- sbit Scl=P2^1;
- sbit Fm=P2^3; //FM
- sbit dula=P2^6;
- sbit wela=P2^7;
- // bit ADFlag; //定义AD采样标志位
- unsigned char code Datatab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//7段数共阴码管段码表
- data unsigned char Display[8];//定义临时存放数码管数值
- /*------------------------------------------------
- 延时程序
- ------------------------------------------------*/
- void mDelay(unsigned char j)
- {
- unsigned int i;
- for(;j>0;j--)
- {
- for(i=0;i<125;i++)
- {;}
- }
- }
- /*------------------------------------------------
- 初始化定时器1
- ------------------------------------------------*/
- void Init_Timer1(void)
- {
- TMOD |= 0x10;
- TH1=0xff; /* Init value */
- TL1=0x00;
- //PT1=1; /* 优先级 */
- EA=1; /* interupt enable */
- ET1=1; /* enable timer1 interrupt */
- TR1=1;
- }
- /*------------------------------------------------
- 启动IIC总线
- ------------------------------------------------*/
- void Start(void)
- {
- Sda=1;
- _nop_();
- Scl=1;
- _nop_();
- Sda=0;
- _nop_();
- Scl=0;
- }
- /*------------------------------------------------
- 停止IIC总线
- ------------------------------------------------*/
- void Stop(void)
- {
- Sda=0;
- _nop_();
- Scl=1;
- _nop_();
- Sda=1;
- _nop_();
- Scl=0;
- }
- /*------------------------------------------------
- 应答IIC总线
- ------------------------------------------------*/
- void Ack(void)
- {
- Sda=0;
- _nop_();
- Scl=1;
- _nop_();
- Scl=0;
- _nop_();
- }
- /*------------------------------------------------
- 发送一个字节
- ------------------------------------------------*/
- void Send(unsigned char Data)
- {
- unsigned char BitCounter=8;
- unsigned char temp;
- do
- {
- temp=Data;
- Scl=0;
- _nop_();
- if((temp&0x80)==0x80)
- Sda=1;
- else
- Sda=0;
- Scl=1;
- temp=Data<<1;
- Data=temp;
- BitCounter--;
- }
- while(BitCounter);
- Scl=0;
- }
- /*------------------------------------------------
- 写入DA数模转换值
- ------------------------------------------------*/
- void DAC(unsigned char Data)
- {
- Start();
- Send(AddWr); //写入芯片地址
- Ack();
- Send(0x40); //写入控制位,使能DAC输出
- Ack();
- Send(Data); //写数据
- Ack();
- Stop();
-
- }
- void fmg(void)//fm关
- {
- Fm=1; // 关 fm
- }
- void cmg(void)//数码管锁存函数 关时钟DS1302
- {
- dula=1;
- P0=0x00;
- dula=0;
- wela=1;
- P0=0x00;
- wela=0;
- RST=0; // 关时钟DS1302
- }
- /*------------------------------------------------
- 主程序
- ------------------------------------------------*/
- void main()
- {
- unsigned char num; //DA数模输出变量
- Init_Timer1();
- cmg();//数码管锁存
- fmg();
- while(1)
- {
- DAC(num); //DA输出,可以用LED模拟电压变化
- num++; //累加,到256后溢出变为0,往复循环。显示在LED上亮度逐渐变化
- mDelay(20); //延时用于清晰看出变化
- }
- }
复制代码下载链接:
PCF8591DAC_LED.zip
(29.03 KB, 下载次数: 409)
作者: 槑呆呆 时间: 2015-5-28 18:23
请问楼主,PCF8591适合做心电信号的AD采样吗?求指导啊
作者: hahaha123 时间: 2015-6-27 19:37
看了一下,刚学哎
作者: leafye 时间: 2015-7-21 16:47
正在学习AD/DA!谢谢
作者: 764200352 时间: 2015-7-26 11:15
不错,正在学ad/da
作者: 喜欢句号 时间: 2015-8-8 11:18
很好很强大
作者: mr.coco 时间: 2015-8-12 17:43
//unsigned char code Datatab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
//data unsigned char Display[8];
警告应该是因为这两句是多余的
作者: wzc1339 时间: 2015-10-6 16:04
楼主,我是小白。收获好多,谢谢
作者: badpeter 时间: 2015-11-19 11:13
很好的东西~谢谢楼主
作者: badpeter 时间: 2015-11-19 11:14
很好的东西,谢谢楼主
作者: 火云邪神 时间: 2015-11-27 11:35
请问“发送一个字节”这一段程序是干啥用的,为啥要用着个程序呢,谢谢我是小白
作者: zdluffy 时间: 2015-11-28 15:52
很好的东西~谢谢楼主
作者: 驹哥来记得喊我i 时间: 2015-12-1 19:31
刚开始学数模转换,谢谢楼主啦。
作者: mcs51hello 时间: 2015-12-3 10:47
深度好贴,谢谢楼主了。
作者: 你的温柔给了谁 时间: 2015-12-21 10:50
很好的文章,刚好要用……
作者: kanganhui 时间: 2016-1-11 10:51
楼主东西很好,对我帮助很大
作者: li3781695 时间: 2016-1-18 23:35
学习了,学习了,感谢楼主
作者: tongwuting 时间: 2016-2-23 11:13

楼主,这两个圈里的器件指的应该是同一个器件吧?那为什么第152行代码中器件地址是SLAVEADDR,而第159行代码中器件地址是SLAVEADDR+1?为什么要加1呢?
作者: tongwuting 时间: 2016-2-24 08:39
我突然明白了,152行的SLAVEADDR是要写,159行的SLAVEADDR+1是要读,所以要加1
作者: yyzzm 时间: 2016-5-10 16:27
学习了,谢谢!
作者: 模霸世界 时间: 2016-5-13 11:56
DA输出之前没怎么了解 今天恶补 谢谢
作者: aether17 时间: 2016-5-21 09:52
谢谢分享!!
作者: bismarck 时间: 2016-5-26 14:33
很好,十分有用。感谢分享。
作者: sunny360day 时间: 2016-5-30 10:45
请问,你们有遇到DA输出的时候电压不够的情况吗?测到VCC有5.19V,但是输出最大只能到4.42V,
作者: 逆风天使 时间: 2016-6-15 18:09
请问转换周期怎么计算,或者说具体采样频率怎么计算
作者: zhangdoudou 时间: 2016-6-21 15:41
PCF8591和PCF8591T有什么区别吗?是不是管脚不同?
作者: yd665c 时间: 2016-10-3 11:57
楼主威武 楼主万岁万岁万万岁
作者: 梁伟波 时间: 2016-11-5 23:58
终于在这找到了,正需要
作者: 米99不好 时间: 2016-11-9 20:30
涨姿势
作者: 米99不好 时间: 2016-11-9 20:31
加油啊
作者: 这么近、那么远 时间: 2016-11-17 17:25
貌似很不错
作者: select326 时间: 2016-12-17 21:40
感谢分享
作者: 缘分注定生死 时间: 2017-3-27 15:50
没有黑币啊,好苦恼。。。。。。。
作者: ttttyx2 时间: 2017-4-19 22:15
w2 w3是什么东西??
作者: qxw199586 时间: 2017-4-22 13:26
很给力!!
作者: zhao416129 时间: 2017-5-7 09:52
谢谢楼主,毕设正好需要这个器件
作者: zhao416129 时间: 2017-5-12 10:59
谢谢楼主,!!!
作者: 小51hei56565 时间: 2017-8-22 11:06
请问,我没加上拉电阻,数值一直在跳,等我加上上拉电阻,求平均值后 数据会稳定下来吗
作者: haveme 时间: 2018-2-7 09:45
厉害啊,好东西
作者: emily929627260 时间: 2018-4-23 10:00
还没看见 不知道是不是深度好文,现在正在登陆
作者: 284213945 时间: 2018-5-10 20:51
学习了,学习了,感谢楼主
作者: 111199 时间: 2018-6-4 23:16
学习中666
作者: ~Roll~、 时间: 2018-7-9 17:01
学到了很多,谢谢楼主
作者: 青宁 时间: 2018-8-30 19:14
谢楼主分享,论坛有你更精彩
作者: liven丶 时间: 2018-11-20 20:44
虽然帖子很好,不过少了电路图没法对应学,共享的资料也有程序而已
作者: 时光倒影 时间: 2018-12-12 19:43
谢谢分享
作者: zhouwei0815 时间: 2018-12-13 11:47
很好的资料 正好在研究逐日系统 可以用到这个
作者: liu631208 时间: 2019-1-18 19:41
很好很强,初入门有点看不懂
作者: 277563114 时间: 2019-2-20 14:55
请问楼主ad程序里面的ans定义了之后值是怎么取的呢
我好像没有看到有哪里给ans赋了值
作者: 13306446378 时间: 2019-4-8 20:39
帮助很大
作者: rebios 时间: 2019-8-23 17:45
T1定时器打开了,在程序中是做什么用的
作者: 003 时间: 2020-6-7 14:30
楼主,你好,ad差分输入的转换结果跟单端输入的转换结果是一样的吗
作者: vscos 时间: 2022-1-11 19:17
那是这个IIC地址的0位是代表读写的位,0时是只读,1时可以写入
作者: Listentoyou 时间: 2022-3-1 10:24
楼主,FPC8591的DA转换就往里写0-255数据就可以了吗,因为我看另外一个ISP协议的xpt2046居然是用单片机时钟芯片产生pwm来DA的,有点复杂,pcf8591好多都是和你这个类似的,我把矩阵按键输入的电压值(0-5.0v)转换成0-255,好像Proteus 8 Professional仿真出来有点问题
部分代码:
DA_8=DA_buf[1]*51+DA_buf[3]*5; //转换输出的电压,
PCF8591_DAC(0x43,DA_8); //DA转换
作者: hefqeury 时间: 2023-12-1 16:37
pcf8591在Altium中怎么找,在哪个库
欢迎光临 (http://www.51hei.com/bbs/) |
Powered by Discuz! X3.1 |