实例PCF8591

依旧是借着蓝桥杯的机会,来学习一些模块,和软件模拟一些通信方式。

今天学习的模块是PCF8591,一款AD\DA转换器,使用IIC通信方式。

芯片的内部框图如下所示:
在这里插入图片描述

各引脚作用如下表所示:
在这里插入图片描述

仍旧和之前DS1302的使用相似,对于这款芯片的使用,依旧是按照先寻地址,再读写相应寄存器的步骤。

PCF8591芯片所能接收的地址包含固定部分和可编程部分。可编程部分必须根据地址引脚A0,A1,和A2来设置,在IIC总线协议中地址必须是起始条件后作为第一个字节发送,地址字节的最后一位用来设置对目标地址的读或写。地址字节格式如下所示:在这里插入图片描述

第一个字节是地址字节,那么第二个字节就是控制字节,控制字节发送到PCF8591的控制寄存器中,用于控制器件的功能,控制字格式如下所示:

在这里插入图片描述

其中BIT7和BIT3必须设置为0,BIT6是模拟输出允许位,BIT4和BIT5用于定义模拟输入的方式,有单端和差分输入两种方式。最后三位用于选择模拟输入的通道。

接着就到了第三个字节,如果是D\A转换,发送的第三个字节被存储到DAC数据寄存器,使用D\A转换器转换成相应的模拟电压。

如果是A\D转换,在一个有效模式地址传给PCF8591之后,一个A\D转换周期便开始了,所选通道的采样电压被转换成相应的8位二进制码。

前面说过,单片机与PCF8591之间采用的是IIC的通信方式,所以在这里我想写一下如何用51软件模拟IIC通信。

我这里有蓝桥杯官方给出的IIC库,所以我就配合官方代码来理解IIC通信。

/首先是IIC的启动,启始条件:必须在所有命令之前发送,时钟线保持高电平期间,数据线电平从高到低的跳变作为IIC总线的启动信号。而下面这个函数IIC_Start()就是模拟这个过程/

void IIC_Start(void)

{
SDA = 1;
SCL = 1;
somenop;
SDA = 0;
somenop;
SCL = 0;
}

/类似地,停止条件:时钟线保持高电平期间,数据线电平从低到高的跳变作为IIC总线的停止信号。/

void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
somenop;
SDA = 1;
}

IIC总线协议规定,每传送一个字节数据后,都要有一个应答信号,以确定数据传送是否被对方收到,应答信号由接收设备产生,在SCL为高电平期间,接收设备将SDA拉为低电平表示数据传输正确,即产生了应答。

但当主机为接收设备时,主机对最后一个字节不应答,以向发送设备表示数据传送结束。

void IIC_Ack(unsigned char ackbit) //当ackbit为1时,表示单片机对从设备发送来数据的应答

{ //当ackbit为0时,表示主机接收了最后一个字节,因此不再应答,结束通信
if(ackbit)
{
SDA = 0;
}
else
{
SDA = 1;
}
somenop;
SCL = 1;
somenop;
SCL = 0;
SDA = 1;
somenop;
}

bit IIC_WaitAck(void)
{
SDA = 1;
somenop;
SCL = 1;
somenop;
if(SDA) //在SCL为高电平期间,因为接收设备未将SDA拉低,所以默认未接收到应答,结束IIC通信
{
SCL = 0;
IIC_Stop();
return 0;
}
else //接收到应答,返回1,继续下一个数据字节的传输
{
SCL = 0;
return 1;
}

}

//IIC传送一个字节的函数,高位在前,应当注意的是IIC进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定

void IIC_SendByte(unsigned char byt)

{
unsigned char i;
for(i=0;i<8;i++)
{
if(byt&0x80)
{
SDA = 1;
}
else
{
SDA = 0;
}
somenop;
SCL = 1;
byt <<= 1;
somenop;
SCL = 0;
}
}

//IIC接收字节函数,原理同发送

unsigned char IIC_RecByte(void)
{
unsigned char da;
unsigned char i;

for(i=0;i<8;i++)
{
SCL = 1;
somenop;
da <<= 1;
if(SDA)
da |= 0x01;
SCL = 0;
somenop;
}
return da;

}

以上就是蓝桥杯官方给出的全部IIC函数。

对于PCF8591的初始化与通信函数还需要我们自己编写。

初始化函数如下:

void init_pcf8591(void)
{
IIC_Start();

IIC_SendByte(0x90); //大家可以看看IAP15F2K61S2的原理图,就知道为什么是0x90了

IIC_WaitAck();
IIC_SendByte(0x03); //选择ADC通道3
IIC_WaitAck();
IIC_Stop();
}

//接收PCF8591转换过的采样电压值

unsigned char adc_pcf8591(void)
{
unsigned char temp;

IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
temp = IIC_RecByte();
IIC_Ack(0);
IIC_Stop();

return temp;

}

以上就是PCF8591的使用以及对IIC通信的理解,在IAP15F2K61S2上还有EEPROM—AT24C02,它用的也是IIC通信,原理相同,不再多说。

作者:汉月冰
来源:CSDN
原文:https://blog.csdn.net/qq_33656619/article/details/79560544
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于PCF8591芯片AD DA实验例程C51单片机KEIL源码工程文件5个合集: PCF8591 1602液晶显示 PCF8591 1路AD数码管显示 PCF8591 4路AD数码管显示 PCF8591 DA输出模拟 PCF8591 输出锯齿波 main() { unsigned char num=0,i; unsigned char temp[7];//定义显示区域临时存储数组 float Voltage; //定义浮点变量 LCD_Init(); //初始化液晶 DelayMs(20); //延时有助于稳定 LCD_Clear(); //清屏 while (1) //主循环 { for(i=0;i<5;i++)//连续读5次,取最后一次,以便读取稳定值 num=ReadADC(0); //读取第1路电压值,范围是0-255 Voltage=(float)num*5/256; //根据参考电源VREF算出时间电压,float是强制转换符号,用于将结果转换成浮点型 sprintf(temp,"V0 %3.2f ",Voltage);//格式输出电压值,%3.2f 表示浮点输出,共3位数,小数点后2位 LCD_Write_String(0,0,temp); for(i=0;i<5;i++) num=ReadADC(1); Voltage=(float)num*5/256; sprintf(temp,"V1 %3.2f ",Voltage); LCD_Write_String(8,0,temp); for(i=0;i<5;i++) num=ReadADC(2); Voltage=(float)num*5/256; sprintf(temp,"V2 %3.2f ",Voltage); LCD_Write_String(0,1,temp); for(i=0;i<5;i++) num=ReadADC(3); Voltage=(float)num*5/256; sprintf(temp,"V3 %3.2f ",Voltage); LCD_Write_String(8,1,temp); //主循环中添加其他需要一直工作的程序 DelayMs(200); } } /*------------------------------------------------ 读AD转值程序 输入参数 Chl 表示需要转换的通道,范围从0-3 返回值范围0-255 ------------------------------------------------*/ unsigned char ReadADC(unsigned char Chl) { unsigned char Val; Start_I2c(); //启动总线 SendByte(AddWr); //发送器件地址 if(ack==0)return(0); SendByte(0x40|Chl); //发送器件子地址 if(ack==0)return(0); Start_I2c(); SendByte(AddWr+1); if(ack==0)return(0); Val=RcvByte(); NoAck_I2c(); //发送非应位 Stop_I2c(); //结束总线 return(Val); } /*------------------------------------------------ 写入DA转换数值 输入参数:dat 表示需要转换的DA数值,范围是0-255 ------------------------------------------------*/ /*bit WriteDAC(unsigned char dat) { Start_I2c(); //启动总线 SendByte(AddWr); //发送器件地址 if(ack==0)return(0); SendByte(0x40); //发送器件子地址 if(ack==0)return
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值