基于PCF8591设计的数字电压表.docx

上传人:b****7 文档编号:26577639 上传时间:2023-06-20 格式:DOCX 页数:23 大小:255.76KB
下载 相关 举报
基于PCF8591设计的数字电压表.docx_第1页
第1页 / 共23页
基于PCF8591设计的数字电压表.docx_第2页
第2页 / 共23页
基于PCF8591设计的数字电压表.docx_第3页
第3页 / 共23页
基于PCF8591设计的数字电压表.docx_第4页
第4页 / 共23页
基于PCF8591设计的数字电压表.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

基于PCF8591设计的数字电压表.docx

《基于PCF8591设计的数字电压表.docx》由会员分享,可在线阅读,更多相关《基于PCF8591设计的数字电压表.docx(23页珍藏版)》请在冰豆网上搜索。

基于PCF8591设计的数字电压表.docx

基于PCF8591设计的数字电压表

学习情境1-数字电压表的设计

之基于PCF8591设计的数字电压表

☆点名,复习

1、ADC0832的引脚及其功能,以及与单片机的硬件连接?

2、ADC0808的引脚及其功能,以及与单片机的硬件连接?

引言:

PCF8591是一个单片集成、单独供电、低功耗、8-bitCMOS数据获取器件。

PCF8591具有4个模拟输入、1个模拟输出和1个串行I²C总线接口。

PCF8591的3个地址引脚A0,A1和A2可用于硬件地址编程,允许在同一个I²C总线上接入8个PCF8591器件,而无需额外的硬件。

在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I²C总线以串行的方式进行传输。

☆新课讲授

3.3基于PCF8591设计的数字电压表

3.3.1PCF8591简介

PCF8591的功能包括多路模拟输入、置跟踪保持、8-bit模数转换和8-bit数模转换。

PCF8591的最大转化速率由I²C总线的最大速率决定。

1、主要技术指标和特性

单独供电

∙PCF8591的操作电压围2.5V-6V

∙低待机电流

∙通过I2C总线串行输入/输出

∙PCF8591通过3个硬件地址引脚寻址

∙PCF8591的采样率由I2C总线速率决定

∙4个模拟输入可编程为单端型或差分输入

∙自动增量频道选择

∙PCF8591的模拟电压围从Vss到VDD

∙PCF8591置跟踪保持电路

∙8-bit逐次逼近A/D转换器

∙通过1路模拟输出实现DAC增益

2、PCF8591引脚功能图3-3-1PCF8591引脚图

AIN0~AIN3:

模拟信号输入端。

A0~A3:

引脚地址端。

VDD、VSS:

电源端。

(2.5~6V)

SDA、SCL:

I2C总线的数据线、时钟线。

OSC:

外部时钟输入端,部时钟输出端。

EXT:

部、外部时钟选择线,使用部时钟时EXT接地。

AGND:

模拟信号地。

AOUT:

D/A转换输出端。

VREF:

基准电源端。

3、PCF8591部结构图

图3-3-2PCF8591部结构图

4功能描述

(1)地址

IIC总线系统中的每一片PCF8591通过发送有效地址到该地址器件来激活。

该地址包括固定部分和可编程部分。

可编程部分必需根据地址引脚A0、A1和A2来设置。

在IIC总线协议中地址必需是起始条件后作为第一个字节发送。

地址字节的最后一位是用于设置以后数据传输方向的读/写。

1

0

0

1

A0

A1

A2

R/

固定部分可编程部分

(2)控制字

控制字节用于实现器件的各种功能,如模拟信号由哪几个通道输入等。

控制字节存放在控制寄存器中。

总线操作时为主控器发送的第二字节。

其格式如下所示:

 

其中:

D1、D0两位是A/D通道编号:

00通道0,01通道1,10通道2,11通道3

       D2 自动增益选择(有效位为1)

       D5、D4模拟量输入选择:

00为四路单端数入、01为三路差分输入、10为单端与差分配合输入、11为模拟输出允许有效

   当系统为A/D转换时,模拟输出允许为0。

模拟量输入选择位取值由输入方式决定:

四路单端输入时取00,三路差分输入时取01,单端与差分输入时取10,二路差分输入时取11。

最低两位时通道编号位,当对0通道的模拟信号进行A/D转换时取00,当对1通道的模拟信号进行A/D转换时取01,当对2通道的模拟信号进行A/D转换时取10,当对3通道的模拟信号进行A/D转换时取11。

  在进行数据操作时,首先是主控器发出起始信号,然后发出读寻址字节,被控器做出应答后,主控器从被控器读出第一个数据字节,主控器发出应答,主控器从被控器读出第二个数据字节,主控器发出应答…一直到主控器从被控器中读出第n个数据字节,主控器发出非应答信号,最后主控器发出停止信号。

(3)A/D转换

A/D转换器采用逐次逼近转换技术。

在A/D转换周期将临时使用片上转换器和高增益比较器。

一个A/D转换周期总是开始于发送一个有效读模式地址给PCF8591之后。

A/D转换周期子在应答时钟脉冲的后延被触发。

并在传输前一次转换结果时执行(见图3-3-3)

图3-3-3A/D转换

一旦一个转换周期被触发,所选通的输入电压采样将保存到芯片并被转换为对应的8位二进制码,取自差分输入的采样将被转换为8位二进制补码

转换结果被保存在ADC数据寄存器等待传输。

如果自动增量标志被置1,将选择下一个通道。

在读周期传输的第一个字节包含前一次读周期的转换结果代码,以上电复位之后读取的第一个字节是0x80。

最高A/D转换速率取决于实际的IIC总线速度。

(4)D/A转换

发送给PCF8591的第三个字节被存储到DAC数据存储器,并使用片D/A转换器转换成对应的模拟电压。

这个D/A转换器由连接到外部参考电压的具有256个接头的电阻分压电路和选择开关组成。

接头译码器切换一个接头至DAC输出线。

模拟输出电压由自动清零单位增益放大器缓冲。

这个缓冲放大器可通过设置控制寄存器的模拟输出允许标志来打开或关闭。

在激活状态,输出电压将保持到新的数据字节被发送。

提供给模拟输出AOUT的输出电压由下式给出。

D/A转换顺序的波形图如图3-3-5

=

+

图3-3-4D/A转换

(5)振荡器

片上振荡器产生A/D转换周期和刷新自动清零缓冲放大器需要的时钟信号。

在使用这个振荡器时EXT引脚必须连接到VSS。

在OSC引脚振荡频率是可用的。

如果EXT引脚被连接到VDD,振荡输出OSC将切换到高阻态以允许用户连接外部时钟信号至OSC。

6I2C总线特性

I2C总线是不同的IC或模块之间的双向两线通信,这两条线是串行数据线(SDA)和串行时钟线(SCL),这两条线必须通过上拉电阻连接至正电源。

数据传输只能是在总线不忙时启动。

(1)位传输

一个数据位在每一个时钟脉冲期间传输。

SDA线上的数据必须在时钟脉冲的高电平期间保持稳定。

这个期间数据线上的改变被当作控制信号。

图3-3-5位传输

(2)开始或停止条件

数据和时钟线在总不忙时保持高电平。

在时钟为高电平时,数据线上的一个由高到低的变化被定义为开始条件。

时钟为高电平时,数据线上的一个由低到高的变化被定义为停止条件。

图3-3-6开始和停止条件

(3)系统配置

产生信息的器件称作“发送机”,接收信息的器件称作“接收机”。

控制信息的器件称作“主机”,被控制的器件称作“从机”。

图3-3-7系统配置

(4)应答

在开始和停止条件之间从发送机传输到接收机的数据字节数是没有限制的。

每个8位数据字节之后紧跟着一个应答位。

应答位是由发送机放在总线的一个高电平,而主机也产生一个额外的与应答有关的时钟脉冲。

地址匹配的从接收机必须在接收每一个字节后产生一个应答。

在应答时钟脉冲期间,应答的器件必须将SDA线拉低。

因此在应答相应的时钟脉冲的高电平期间,SDA线必须保持稳定的低电平。

在由从机终止的最后一个字节,主接收机必须通过产生一个低电平应答向发送机发送一个数据结束信号,这样发送机必须将数据线SDA拉高以允许主机产生停止条件。

图3-3-8I2C总线应答

(5)总线协议

在开始条件后一个有效的硬件地址必须发送至PCF8591。

读/写位定义了以后单个或多个字节数据传输的方向。

开始条件、停止条件和应答位的格式应定时参考I2C总线特性。

在写模式数据传输通过发送下一个数据的停止条件或开始条件来约束。

图3-3-9写模式的总线协议,D/A转换

图3-3-10读模式的总线协议,A/D转换

3.3.2系统硬件设计

硬件电路主要包含单片机最小系统、PCF8591电压数据采集模块电路、LCD1602显示模块。

它们之间的具体连接如图6-3-11所示。

图3-3-11系统硬件连接图

3.2.3系统软件设计

本项目在软件设计方面主要有三个源程序:

PCF8591.C、LCD1602.C和MAIN.C。

在此我们主要介绍PCF8591.C源程序的设计。

根据对PCF8591芯片的详细分析,PCF8591.C源程序由以下8个子程序构成:

1、启动I2C总线子程序

voidIIC_Start(void)

{

//EA=0;//时钟保持高,数据线从高到低一次跳变,I2C通信开始

SDA=1;

SCL=1;

delay4us();//延时5us

SDA=0;

delay4us();

SCL=0;

}

2、停止I2C总线子程序

voidIIC_Stop(void)

{

SDA=0;//时钟保持高,数据线从低到高一次跳变,I2C通信停止

SCL=1;

delay4us();

SDA=1;

delay4us();

SCL=1;

}

3、从机发送应答子程序

voidSlave_ACK(void)

{

SDA=0;

SCL=1;

delay4us();

SCL=0;

SDA=1;

}

4、从机发送非应答子程序

voidSlave_NOACK(void)

{

SDA=1;

SCL=1;

delay4us();

SDA=0;

SCL=0;

}

5、主机应答位检查子程序

voidcheck_ACK(void)

{

SDA=1;//将p1.0设置成输入,必须先向端口写1

SCL=1;

F0=0;

if(SDA==1)//若SDA=1表明非应答,置位非应答标志F0

F0=1;

SCL=0;

}

6、发送一个字节子程序

voidIIC_SendByte(ucharch)

{

ucharidatan=8;//向SDA上发送一位数据字节,共八位

while(n--)

{

if((ch&0x80)==0x80)//若要发送的数据最高位为1则发送位1

{

SDA=1;//传送位1

SCL=1;

delay4us();

SDA=0;

SCL=0;

}

else

{

SDA=0;//否则传送位0

SCL=1;

delay4us();

SCL=0;

}

ch=ch<<1;//数据左移一位

}

}

7、接收一个字节子程序

ucharIIC_ReceiveByte(void)

{

uchari,rd=0x00;

for(i=0;i<8;i++)

{

SCL=1;

rd<<=1;

rd|=SDA;

delay4us();

SCL=0;

delay4us();

}

//SCL=1;

delay4us();

returnrd;

}

8、A/D转换子程序

voidADC_PCF8591(ucharcontrolbyte)

{

ucharidatareceive_data,i=0;

IIC_Start();

IIC_SendByte(PCF8591_WRITE);//控制字

check_ACK();

if(F0==1)

{

IIC_Error=1;

return;

}

IIC_SendByte(controlbyte);//控制字

check_ACK();

if(F0==1)

{

IIC_Error=1;

return;

}

IIC_Start();//重新发送开始命令

IIC_SendByte(PCF8591_READ);//控制字

check_ACK();

if(F0==1)

{

IIC_Error=1;

return;

}

while(i<4)

{

receive_data=IIC_ReceiveByte();

receive_buf[i++]=receive_data;

Slave_ACK();//收到一个字节后发送一个应答位

}

Slave_NOACK();//收到最后一个字节后发送一个非应答位

IIC_Stop();

}

9、D/A转换子程序

voidDAC_PCF8591(ucharcontrolbyte,ucharwdata)

{

IIC_Start();//启动I2C

IIC_SendByte(PCF8591_WRITE);//发送地址位

check_ACK();//检查应答位

if(F0==1)

{

IIC_Error=1;

return;//若非应答表明器件错误或已坏,置错误标志位SystemError

}

IIC_SendByte(controlbyte&0x77);//Controlbyte

check_ACK();//检查应答位

if(F0==1)

{

IIC_Error=1;

return;//若非应答表明器件错误或已坏,置错误标志位SystemError

}

IIC_SendByte(wdata);//databyte

check_ACK();//检查应答位

if(F0==1)

{

IIC_Error=1;

return;//若非应答表明器件错误或已坏,置错误标志位SystemError

}

IIC_Stop();//全部发完则停止

delay4us();

delay4us();

delay4us();

delay4us();

}

需要注意的是,在PROTEUS7.5仿真条件下无法把4路模拟通道的效果仿真出来,只有AINO通道有效。

但在PROTEUS7.8仿真有效。

☆课堂小结

本节课主要详细介绍了pcf8591芯片的有关技术资料和具体用法,重点分析了PCF8591.C源程序的设计。

☆完整程序代码

1、MAIN.C源程序

#include

#include

#defineucharunsignedchar

#defineuintunsignedint

uintDisp_Voltage[]={'0','0','0'};

ucharLCD_Line1[]={"1-.V2-.v"};

ucharLCD_Line2[]={"3-.V4-.v"};

externucharidatareceive_buf[];//数据接收缓冲区

externvoidInitialize_LCD1602();//液晶初始化函数

externvoidADC_PCF8591(ucharcontrolbyte);//连续读入4路通道的A/D转换结果到receive_buf[]

externvoidDAC_PCF8591(ucharcontrolbyte,ucharwdata);

externvoidLCD_Display(ucharp,uchar*str);//在LCD上显示字符串

//函数申明

voidConvert_To_Voltage(ucharresult);//将模数转换结果得到的数值分解后放入缓冲数组中

voidRefesh_LCD();//显示刷新函数,把ADC转换结果送入显示缓冲数组

//------------------------------------------------------------

//函数名称:

main

//函数功能:

主程序

//-------------------------------------------------------------

voidmain()

{

Initialize_LCD1602();

while

(1)

{

ADC_PCF8591(0x04);

Refesh_LCD();

//液晶2行显示4个通道的转换结果

LCD_Display(0x00,LCD_Line1);

LCD_Display(0x40,LCD_Line2);

//将0通道模拟转换后的结果重新转换为模拟量并从Aout引脚输出

//结果通过LED的亮度表现出来,在真实的硬件上该函数调用才有效,在Proteus中看不到效果

DAC_PCF8591(0x40,receive_buf[0]);

}

}

//-----------------------------------------------------------------

//函数名称:

Convert_To_Voltage()__

//将模数转换结果得到的数值分解后放入缓冲数组中

//------------------------------------------------------------------

voidConvert_To_Voltage(ucharresult)

{

uchartemp;

//最大值为255,对应5V,255/5=51

Disp_Voltage[2]=result/51+'0';//整数部分

temp=result%51*10;//第1位小数

Disp_Voltage[1]=temp/51+'0';

temp=temp%51*10;//第2位小数

Disp_Voltage[0]=temp/51+'0';

}

//---------------------------------------------------------

//显示刷新函数,把ADC转换结果送入显示缓冲数组

//---------------------------------------------------------

voidRefesh_LCD()

{

//将4个模拟通道模数转换结果放入LCD显示缓冲LCD_Line1和LCD_Line2

Convert_To_Voltage(receive_buf[0]);

LCD_Line1[2]=Disp_Voltage[2];

LCD_Line1[4]=Disp_Voltage[1];

LCD_Line1[5]=Disp_Voltage[0];

Convert_To_Voltage(receive_buf[1]);

LCD_Line1[11]=Disp_Voltage[2];

LCD_Line1[13]=Disp_Voltage[1];

LCD_Line1[14]=Disp_Voltage[0];

Convert_To_Voltage(receive_buf[2]);

LCD_Line2[2]=Disp_Voltage[2];

LCD_Line2[4]=Disp_Voltage[1];

LCD_Line2[5]=Disp_Voltage[0];

Convert_To_Voltage(receive_buf[3]);

LCD_Line2[11]=Disp_Voltage[2];

LCD_Line2[13]=Disp_Voltage[1];

LCD_Line2[14]=Disp_Voltage[0];

}

2、PCF8591.C源程序

//----------------------------------------------------------------

//pcf8591驱动程序

//----------------函数声明,变量定义-------------------------------

#include

#include

#defineucharunsignedchar

#defineuintunsignedint

sbitSDA=P1^1;//将p1.0口设置为模拟数据口

sbitSCL=P1^0;//将p1.1口设置为模拟时钟口

#definedelay4us();{_nop_();_nop_();_nop_();_nop_();_nop_();};

bitbdataIIC_Error;//从机错误标志位

//PCF8591专用变量定义----------------------------------------

#definePCF8591_WRITE0x90

#definePCF8591_READ0x91

#defineNUM4//接收和发送缓存区的深度

ucharidatareceive_buf[NUM];//数据接收缓冲区

//-----------------------------------------------------------------

具体函数参见本文正文。

3、LCD1602.C源程序

//液晶控制与显示驱动程序

#include

#include

#include

#defineucharunsignedchar

#defineuintunsignedint

#definedelay4us(){_nop_();_nop_();_nop_();_nop_();}

sbitRS=P2^0;

sbitRW=P2^1;

sbitE=P2^2;

//延时

voidDelay(uintX)

{

uchari;

while(X--)for(i=0;i<120;i++)delay4us()

}

//---------------忙检查-------------------//

ucharLCD_Busy_Check()

{

ucharLCD_Status;

RS=0;

RW=1;

E=1;

delay4us();

LCD_Status=P0;

E=0;

returnLCD_Status;

}

//--------------向LCD写入命令--------------------//

voidWrite_LCD_mand(ucharcmd)

{

while((LCD_Busy_Check()&0x80)==0x80);//忙等待

RS=0;

RW=0;

E=0;

P0=cmd;

delay4us();

E=1;

delay4us();

E=0;

}

//-----------向LCD写入一个字节的数据函数-----------------*/

voidWrite_LCD_Data(uchardat)

{

while((LCD_Busy_Check()&0x80)==0x80);

RS=1;

RW=0;

E=0;

P0=dat

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 军事

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1