STC89C52R单片机以及CF85911的AD转换

第一章 器件清单以及器件介绍

表1 器件清单

序号

器件

型号

数量

1

51开发板

MCS-51

1

2

AD/DA转换模块

PCF8591P

1

3

杜邦线

15cm

11

4

指示灯

\

8

5

光敏电阻

\

1

1. 1 AD/DA转换模块:

STC89C52R单片机以及CF85911的AD转换_第1张图片

图1 AD/DA转换模块电路图

AIN0~AIN3为模拟量输入(可以选择输入方式)
A0~A2为硬件地址引脚,用来编码地址
AOUT应该为模拟量输出(DA转换)
SCL、SDA即为IIC通信时的总线引脚

1. 1. 1 设备地址

STC89C52R单片机以及CF85911的AD转换_第2张图片

图2 设备地址

高四位为固定的编码,用来标识PCF8591,第四位就是硬件引脚+读写位。

1. 1. 2 控制字

STC89C52R单片机以及CF85911的AD转换_第3张图片

图3 控制字示意图

第6位:控制模拟量输出使能
第5和4位:模拟量输入的方式
第2位:自动增量使能,每次A/D 转换后通道号将自动增加
第1和0位:模拟输入的通道选择

STC89C52R单片机以及CF85911的AD转换_第4张图片

图4 原理图

根据原理图可以确定硬件设备地址。

1. 1. 3 AD转换的操作

分别来看写和读的时序

写:

STC89C52R单片机以及CF85911的AD转换_第5张图片

图5 总线协议写模式,D/A转换

读:

STC89C52R单片机以及CF85911的AD转换_第6张图片

图6 总线协议写模式,A/D转换

若要完成一次AD转换,应严格按照时序图进行:

开启总线-----发送地址+写-----发送控制字节-----等待PCF8591响应-----停止总线-----重新启动总线-----发送地址+读------读取数据-----主机发送非应答信号-----停止总线

1. 2 MCS-51

STC89C52R单片机以及CF85911的AD转换_第7张图片

图7 51单片机原理图

由于AD-DA转换模块由SDA、SCL两个的状态来控制,故可以通过控制51单片机的P2.0以及P2.1来控制AD-DA转换的读入与读出。同时,也可以通过控制51单片机来控制数码管的显示。

STC89C52R单片机以及CF85911的AD转换_第8张图片

图8 STC89C52RC 实物图

VCC(40脚)、VSS(20脚)—单片机的电源引脚,不同型号的单片机需要接入对应的电源电源电压。开发板上配带的单片机的供电电压为5V,低压单片机的电压为3.3V,用户在使用时要查看芯片手册,确保接入正确的电压。

XTAL1(19脚)、XTAL2(18脚)—外部时钟引脚,XTAL1为内部振荡电路的输入端,XTAL2为内部振荡电路的输出端。8051的时钟有两种方式,一种是片内时钟振荡方式,需要在这两个引脚上外接石英晶体和振荡电容,振荡电容的值一般为10pf~30pf;另一种是外部时钟方式,需要将XTAL1接地,外部时钟信号由XTAL2脚输入。

RST(9脚)—单片机复位引脚。当输入连续两个机器周期以上为高电平时为有效,用来完成单片机的复位初始化操作,复位后程序计数器PC=0000H,即复位后将从程序存储器的0000H单元读取第一条指令码,通俗的讲,就是单片机从头开始执行程序。

PSEN(29脚)—程序存储器允许输出控制端。在读外部程序存储器时PSEN低电平有效,以实现外部程序存储器单元的读操作,由于现在我们使用的单片机内部已经有足够大的ROM,所以几乎没有人再去扩展外部ROM,因此这个引脚大家只需了解即可。

ALE/PROG(30脚)—在单片机扩展外部RAM时,ALE用于控制把P0口的输出低8位地址送锁存器锁存起来,以实现低位地址和数据的隔离。ALE有可能是高电平也可能是低电平,当ALE是高电平时,允许地址锁存信号,当访问外部存储器时,ALE信号会跳变(即由正变负)将P0口上低8位地址信号送入锁存器;当ALE是低电平时,P0口上的内容和锁存器输出一致。关于锁存器的内容,我们后面会有详细介绍。在没有访问外部存储器期间,ALE以1/6振荡周期频率输出(即6分频),当访问外部存储器时,以1/12振荡周期输出(即12分频)。从这里可以看到,当系统没有进行扩展时,ALE会以1/6振荡周期的固定频率输出,因此可以作为外部时钟,或作为外部定时脉冲使用。PROG为编程脉冲的输入端,单片机的内部有程序存储器(ROM),它的作用是用来存放用户需要执行的程序,那么我们怎样才能将写好的程序存入这个ROM中呢?实际上,我们是通过编程脉冲输入才写进去的,这个脉冲的输入端口就是PROG。现在有很多单片机都已经不需要编程脉冲引脚往内部写程序了,比如我们用的STC单片机,它可以直接通过串口往里面写程序,只需要三条线与计算机相连即可。而且现在的单片机内部都已经带有丰富的RAM,所以也不需要再扩展RAM了,因此ALE/PROG这个引脚的用处也已经不大。

EA(31脚)— EA接高电平时,单片机读取内部程序存储器。当扩展有外部ROM时,当读取完内部ROM后自动读取外部ROM。EA接低电平时,单片机直接读取外部ROM。8031单片机内部是没有ROM的,所以在使用8031单片机时,这个引脚是一直接低电平的。8751单片机烧写内部EPROM时,利用此引脚输入21V的烧写电压。因为现在我们用的单片机都有内部ROM,所以一般在设计电路时此引脚始终接高电平。

I/O口引脚—P0口、P1口、P2口和P3口。

P0口(32脚~39脚)—双向8位三态I/O口,每个口可独立控制。51单片机P0口内部没有上拉电阻,为高阻状态,所以不能正常地输出高/低电平,因此该组I/O口在使用时务必要外接上拉电阻,一般我们选择接入10k欧的上拉电阻。

P1口(1脚~8脚)—准双向8位I/O口,每个口可独立控制,内带上拉电阻,这种接口输出没有高阻状态,输入也不能锁存,故不是真正的双向I/O口。之所以称它为“准双向”是因为该口在作为输入使用前,要先向该口进行写1操作,然后单片机内部才可正确读出外部信号,也就是要使其先有个“准”备过程,所以才称为准双向口。单片机P1.0引脚的第二功能为T2定时器/计数器的外部输入,P1.1引脚的第二功能为T2EX捕捉、重装触发,即T2的外部控制端。

P2口(21脚~28脚)—准双向8位I/O口,每个口可独立控制,内带上拉电阻,与P1口相似。

P3口(10脚~17脚)—准双向8位I/O口,每个口可独立控制,内带上拉电阻,作为第一功能使用时就当做普通I/O口,与P1口相似,作为第二功能使用时,各引脚的定义如下表所示。值得强调的是,P3口的每一个引脚均可独立定义为第一功能的输入/输出或第二功能。

P3口的第二功能定义

STC89C52R单片机以及CF85911的AD转换_第9张图片

图9 P3口的第二功能定义

1. 3 数码管以及驱动电路

STC89C52R单片机以及CF85911的AD转换_第10张图片

图10 六位数码管原理图

数码管的各段是由发光二极管组成的,按显示格式可分为八段和“米”字段,若按驱动方式可分为共阴和共阳。本项目使用的是八段码共阴数码管。

STC89C52R单片机以及CF85911的AD转换_第11张图片

图11 数码管驱动电路原理图

STC89C52R单片机以及CF85911的AD转换_第12张图片

图12 数码管硬件电路示意图

第二章 方案设计

2. 1 AD/DA转换模块

先由光敏电阻由于外界环境中的光强变化引起电阻的大小的变化,再由AD转换模块吧电信号转换为数字信号,传输到51单片机里,通过51单片机来显示当前光强(相对值0~255),显示在数码管上,再通过比较数值的大小来确定灯的强弱(由灯珠亮的数量大小来确定)。

表2 亮灯情况与环境亮度的关系

序号

显示数

灯珠数量

1

0~20

0

2

20~40

1

3

40~60

2

4

60~80

3

5

80~100

4

6

100~120

5

7

120~140

6

8

140~160

7

9

160~255

8

    

     这里的灯珠亮的数量与灯的光强大小成正比,灯珠亮的数量越多,说明灯越亮,在0~20之间很亮,故灯不亮,而大于160时几乎没有光线,则为最亮。

     将AIN0通道的模拟电压进行A/D转换后,将数字量通过LED数码管显示出来,同时再将该数字量写入PCF8591中,通过其内部的D/A转换为模拟电压输出驱动LED发光二极管。动态数码管显示电压值(相对值0~255),通过光敏电阻改变电压值,使用到了I2C总线驱动程序,PCF8591驱动程序。

I2C总线特点可以概括如下:

(1)在硬件上,I2C总线只需要一根数据线和一根时钟线两根线,总线接口已经集成在芯片内部,不需要特殊的接口电路,而且片上接口电路的滤波器可以滤去总线数据上的毛刺。因此I2C总线简化了硬件电路 PCB 布线,降低了系统成本,提高了系统可靠性。因为I2C芯片除了这两根线和少量中断线,与系统再没有连接的线,用户常用IC可以很容易形成标准化和模块化,便于重复利用。

(2)I2C总线是一个真正的多主机总线,如果两个或多个主机同时初始化数据传输,可以通过冲突检测和仲裁防止数据破坏,每个连接到总线上的器件都有唯一的地址,任何器件既可以作为主机也可以作为从机,但同一时刻只允许有一个主机。数据传输和地址设定由软件设定,非常灵活。

STC89C52R单片机以及CF85911的AD转换_第13张图片

图13 I2C总线原理示意图

2. 2 数码管模块

STC89C52R单片机以及CF85911的AD转换_第14张图片

图14 数字编码表

数码管要正常显示,就要用驱动电路来驱动数码管的各个段码,从而显示出我们要的数字。

STC89C52R单片机以及CF85911的AD转换_第15张图片

图2.LED数码管引脚定义

数码管动态显示接口是单片机中应用最为广泛的一种显示方式之一,动态驱动是将所有数码管的8个显示笔划"a,b,c,d,e,f,g,dp"的同名端连在一起,另外为每个数码管的公共极COM增加位选通控制电路,位选通由各自独立的I/O线控制,当单片机输出字形码时,所有数码管都接收到相同的字形码,但究竟是哪个数码管会显示出字形,取决于单片机对位选通COM端电路的控制,所以我们只要将需要显示的数码管的选通控制打开,该位就显示出字形,没有选通的数码管就不会亮。通过分时轮流控制各个数码管的的COM端,就使各个数码管轮流受控显示,这就是动态驱动。在轮流显示过程中,每位数码管的点亮时间为1~2ms,由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感,动态显示的效果和静态显示是一样的,能够节省大量的I/O端口,而且功耗更低。

以上都是废话看代码(Keil、VW(推荐)下运行,使用的为TX-1C 51单片机开发板)

;//程序将AIN0通道的模拟电压进行A/D转换后,将数字量通过LED数码管显示出来,同时再将该数字量写入PCF8591中,通过其内部的D/A转换为模拟电压输出驱动LED发光二极管。
      ACK BIT 20H.0 ;应答标志位ACK=0表示无应答
      SCL BIT P2.1 ;时钟线
      SDA BIT P2.0 ;数据线
      WADD EQU 21H ;器件地址(即从地址)
      SUBD EQU 22H ;器件内部地址(即子地址)
      NUMBR EQU 23H ;需读取的字节数
      NUMBW EQU 24H ;需写入的字节数
      RDATA EQU 25H ;读出数据的存放首地址
      WDATA EQU 26H ;写入数据的存放首地址
      ORG 0000H
      SJMP MAIN
      ORG 0030H

MAIN:
     MOV 55H,#11H
     MOV 54H,#00H
     MOV 53H,#00H
     MOV 60H,#00H ;显示的百位清零
     MOV 61H,#05H ;显示的十位清零
     MOV 62H,#00H ;显示的个位清零
     MOV WADD,#90H ;写入PCF8591的地址
     MOV P0,#0FFH ;关闭显示
     MOV P2,#0FFH
     MOV SUBD,#40H ;写入PCF8591的控制字
     MOV NUMBR,#1 ;写入需读取的字节数
     MOV NUMBW,#1 ;写入需写入的字节数
     MOV RDATA,#30H ;送入首地址
     MOV WDATA,#40H ;送入首地址

     MOV 50H,#0 ;显示的百位清零
     MOV 51H,#0 ;显示的十位清零
     MOV 52H,#0 ;显示的个位清零

M1:  LCALL READI2C ;读PCF8591子程序
     MOV 40H,30H
     MOV NUMBR,#1
     MOV NUMBW,#1
     LCALL DAT
     LCALL DISP
     LCALL WRITEI2C ;写PCF8591子程序

     SJMP M1

;数据处理子程序

DAT:
     MOV A,30H
     MOV B,#100
     DIV AB
     MOV 52H,A
     MOV A,#10
     XCH A,B
     DIV AB
     MOV 51H,A
     MOV 50H,B
     
CMPDAT:
     MOV A,#00 ;将被减数送累加器A
     CLR C ;清借位
     SUBB A,52H ;减法运算
     JC CMPD1 ;如果有借位转
;说明数小于100
     MOV A,#01 ;将被减数送累加器A
     CLR C ;清借位
     SUBB A,51H ;减法运算
     JC CMPD2 ;如果有借位转
;说明数小于20
     MOV P1,#11111111B;0个灯珠亮
;说明数大于20
     RET
     
CMPD2:
     MOV A,#03 ;将被减数送累加器A
     CLR C ;清借位
     SUBB A,51H ;减法运算
     JC CMPD3 ;如果有借位转
;说明数小于40
     MOV P1,#11111110B;1个灯珠亮
     RET
     
;说明数大于40
CMPD3:
     MOV A,#05 ;将被减数送累加器A
     CLR C ;清借位
     SUBB A,51H ;减法运算
     JC CMPD4 ;如果有借位转
;说明数小于60
     MOV P1,#11111100B;2个灯珠亮
     RET
;说明数大于60

CMPD4:
     MOV A,#07 ;将被减数送累加器A
     CLR C ;清借位
     SUBB A,51H ;减法运算
     JC CMPD5 ;如果有借位转
;说明数小于80
     MOV P1,#11111000B;3个灯珠亮
     RET
     
;说明数大于80
CMPD5:
     MOV P1,#11110000B;4个灯珠亮
     RET
     
CMPD1:
     MOV A,#01 ;将被减数送累加器A
     CLR C ;清借位
     SUBB A,52H ;减法运算
     JC CMPD8 ;如果有借位转
     MOV A,#01 ;将被减数送累加器A
     CLR C ;清借位
     SUBB A,51H ;减法运算
     JC CMPD6 ;如果有借位转
;说明数小于120
     MOV P1,#11100000B;5个灯珠亮
;说明数大于120
     RET
     
CMPD6:
     MOV A,#03 ;将被减数送累加器A
     CLR C ;清借位
     SUBB A,51H ;减法运算
     JC CMPD7 ;如果有借位转
;说明数小于140
     MOV P1,#11000000B;6个灯珠亮
     RET
;说明数大于140
CMPD7:
     MOV A,#05 ;将被减数送累加器A
     CLR C ;清借位
     SUBB A,51H ;减法运算
     JC CMPD8 ;如果有借位转
;说明数小于160
     MOV P1,#10000000B;7个灯珠亮
     RET
;说明数大于160
CMPD8:
     MOV P1,#00000000B;8个灯珠亮
     RET



;显示子程序
DISP:
     MOV R3,#0FEH
     MOV R6,#6
     MOV R1,#55H
LP:
     MOV P0,#0FFH
     SETB P2.7
     CLR P2.7
     MOV A,@R1
     DEC R1
     MOV DPTR,#TABLE ;查表取得段码
     MOVC A,@A+DPTR
     MOV P0,A
     SETB P2.6
     CLR P2.6
     MOV P0,R3
     SETB P2.7
     CLR P2.7
     MOV A,R3
     RL A
     MOV R3,A
     LCALL DELAY
     DJNZ R6,LP
     MOV P0,#0FFH
     SETB P2.7
     CLR P2.7
     RET



;从I2C总线读取N个字节数据子程序
READI2C:
      LCALL STARTI2C ;启动I2C总线
      MOV A,WADD ;送入器件地址
      LCALL WI2C ;向I2C总线发送一个字节数据子程序
      LCALL RACK ;读取从机应答位子程序
      JNB ACK,ROUT ;判断从机有无应答ACK=0则无应答
      MOV A,SUBD ;送入器件内部地址
      LCALL WI2C
      LCALL RACK
      LCALL STARTI2C
      MOV A,WADD
      INC A ;改总线为读取状态
      LCALL WI2C
      LCALL RACK
      JNB ACK,READI2C
      MOV R0,RDATA ;送入读出数据的存放首地址
RI2C2:
      LCALL RI2C
      MOV @R0,A
      DJNZ NUMBR,RI2C1 ;判断字节读取完否
      LCALL NMACK ;调主机非应答子程序
ROUT:
      LCALL STOPI2C ;调I2C总线停止子程序
      MOV RDATA,#30H
      RET
RI2C1:
      LCALL MACK ;调主机应答子程序
      INC R0

      SJMP RI2C2 ;向I2C总线发送N个字节数据子程序
WRITEI2C:
      LCALL STARTI2C ;启动I2C总线
      MOV A,WADD ;送入器件地址
      LCALL WI2C ;向I2C总线发送一个字节数据子程序
      LCALL RACK ;读取从机应答位子程序
      JNB ACK,WOUT ;判断从机有无应答ACK=0则无应答
      MOV A,SUBD ;送入器件内部地址
      LCALL WI2C
      LCALL RACK
      JNB ACK,WOUT
      MOV R0,WDATA ;送入写入数据的存放首地址
WI2C1:
      MOV A,@R0
      LCALL WI2C
      LCALL RACK
      JNB ACK,WRITEI2C
      INC R0
      DJNZ NUMBW,WI2C
WOUT:
      LCALL STOPI2C
      MOV WDATA,#40H
      RET

;I2C总线启动子程序
STARTI2C:
      SETB SDA
      SETB SCL
      NOP
      NOP
      NOP
      NOP
      NOP
      CLR SDA
      NOP
      NOP
      NOP
      NOP
      NOP
      CLR SCL
      RET

;I2C总线停止子程序
STOPI2C:
      CLR SDA
      SETB SCL
      NOP
      NOP
      NOP
      NOP
      NOP
      SETB SDA
      RET

;主机应答子程序
MACK:
      CLR SDA
      SETB SCL
      NOP
      NOP
      NOP
      NOP
      NOP
      CLR SCL
      RET

;主机非应答子程序
NMACK:
      SETB SDA
      SETB SCL
      NOP
      NOP
      NOP
      NOP
      NOP
      CLR SCL
      RET

;向I2C总线发送一个字节数据子程序
WI2C:
      MOV R7,#8
WLP:
      RLC A
      MOV SDA,C
      NOP
      SETB SCL
      NOP
      NOP
      NOP
      NOP
      NOP
      CLR SCL
      DJNZ R7,WLP
      RET

;从I2C总线读取一个字节数据子程序
RI2C:
      MOV R7,#8
      CLR A
      SETB SDA
      NOP
RLP:
      SETB SCL
      NOP
      NOP
      MOV C,SDA
      NOP
      CLR SCL
      RLC A
      NOP
      NOP
      NOP
      NOP
      DJNZ R7,RLP
      NOP
      RET

;读取从机应答位子程序
RACK:
      SETB SDA
      NOP
      NOP
      SETB SCL
      CLR ACK
      NOP
      NOP
      MOV C,SDA
      JC ACKEND
      SETB ACK

ACKEND:
      NOP
      CLR SCL
      NOP
      RET

DELAY:
      MOV R4,#5
D1:
      MOV R5,#100
D2:
      DJNZ R5,D2
      DJNZ R4,D1
      RET
TABLE: 	DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H
        DB 7FH,6FH,77H,7CH,39H,5EH,79H,71H
        DB 0F6H,0F3H,00H
END

结语:

有了AD/DA转换其他都很简单多加几个传感器可以完成很多天马行空的东西。本文只是基础中的基础。

你可能感兴趣的:(单片机,嵌入式硬件)