【蓝桥杯】PCF8591AD转换模块

备赛目录

1、PCF8591模块简介

PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591具有4个模拟输入、1个模拟输出和1个串行I²C总线接口。
在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。
在这里插入图片描述

2、电路连接图

PCF8591电路连接图
在这里插入图片描述
AIN0~AIN3:模拟信号输入端。
A0~A2:器件地址的低3位。
VSS:电源负极。
SDA、SCL:I2C 总线的数据线、时钟线。
OSC:外部时钟输入端,内部时钟输出端。
EXT:内部/外部时钟选择线,使用内部时钟时EXT 接地。
AGND:模拟信号地。
VREF:基准电源端。
AOUT:D/A 转换输出端。
VDD:电源端。(2.5~6V)

我们只需要关注两个部分,一个是输入部分AIN0~AIN3,另一个是输出部分AOUT:D/A 转换输出端。

2.1A/D转换模块

1、什么是A/D转换??
简单来说,就是读取器件的电压值模拟量(0到5v),并转换成数字量(0到255)保存起来。

2、哪些引脚提供了该功能??
AIN0~AIN3是模拟信号输入端。也就是说,这四个引脚都有这个功能
在这里插入图片描述
3、这些引脚连接了什么??或者说测了什么??

——AIN0未连接器件,这个是留给咱自己支配的一个通道口。
在这里插入图片描述

——AIN1外接了一个光敏电阻和一个定值电阻,
在这里插入图片描述在这里插入图片描述
读取的是定值电阻两端的电压,因此,光照越强,光敏电阻阻值越小,即电压越小,然后R31电压增大,所以总的来看,读取到的电压是随光照增加而增大的。

——AIN2接的是啥东西我不知道,图是这样的
在这里插入图片描述在这里插入图片描述

——AIN3外接一个电位器RB2,读取到的是AIN3向接地部分的电阻,因此是随电阻增大,电压减小
在这里插入图片描述在这里插入图片描述

2.2D/A转换模块

1、什么是D/A转换??
与A/D相反的功能,该功能是把输入的数字量0到255转化为0到5v的电压输出。

2、那些引脚可以输出呢??

AOUT:D/A 转换输出端。
在这里插入图片描述在这里插入图片描述
可以看到只有一根,并且什么也没有接

3、可以拿它干嘛呢

它可以输出电压,当然我们得给它一个数字量。它才知道要输出多少!
比如我们可以这样玩,我给了它一个255的数字量,它输出了一个5v的电压,然后我么外接一个LED灯它就亮了,他的好处是这个电压是可以通过编程改变的,后面我们讲怎么改变!
在这里插入图片描述

4、我怎么知道我输出了多少呢

我们上面不是有一个AIN0啥也没干么!!!!
咱可以拿它测电压,拿一个跳线帽,将A/D和D/A连接起来就可以了!设计板子的时候就把它俩挨在一起了,这暗示的多明显啊!!

3、器件地址

1、啥是器件地址??
由于PCF8591与单片机的通信方式是IIC通信,所以必须有一个器件地址来指明这个器件的位置!!这个器件地址是一个8位的地址

2、我怎么知道它是多少呢

在这里插入图片描述
A0~A2:器件地址的低3位。前四位固定为1001。最后一位是方向位W/R, PCF8591的3个地址引脚A0,
A1和A2可用于硬件地址编程,也就是编写器件地址第2、3、4位。最后一位地址的最后一位为方向位R/W ,当主控器对A/D
器件进行读操作时为1,进行写操作时为0。前四位固定为1001,因此允许在同个I2C总线上接入8个PCF8591器件,而无需额外的硬件。
即0X90——写操作地址+器件地址 0X91——读操作地址+器件地址

4、编写AD转换函数

上面我们已经了解了它的功能和电路图,下面开始编写函数
1、我写这个函数要干嘛??
要对AIN0~AIN3这四个通道进行操作,咱要把它保存的数字量读取出来

2、我怎么读??
当然是单片机通过IIC告诉PCF8591我要读你的数据!!

——0x90是告诉PCF8591我要写东西给你
——0X00、0X01、0X02、0X03是告诉它我要读你哪个通道的值,也就是0、1、2、3
——0x91是告诉PCF8591我已经做好准备接收数据了,赶紧把数据交出来

这些命令都要通过IIC的通信规则来发送。具体的可以看我另外一篇博客IIC通信

3、开始编写,用到的底层通信官方都是会给的。我们直接用就好了

unsigned char read_rb(unsigned char channel)//选择通道,取值0、1、2、3
{
  unsigned char dat;
  IIC_Start();
  IIC_SendByte(0x90); //写
  IIC_WaitAck();
  IIC_SendByte(channel);
  IIC_WaitAck();
  IIC_Stop();
  
  IIC_Start();
  IIC_SendByte(0x91); //读
  IIC_WaitAck();
  dat = IIC_RecByte();
  IIC_SendAck(1);
  IIC_Stop();
  return dat;
}

5、DA转换功能

1、我写这玩意又要干嘛??
当然是操作AOUT这根引脚了!让它输出我们想要的值。只需要写一次,如果要一直变换输出,可以反复写不同的数字量

2、我要怎么写??
同样还是IIC通信

——0x90是告诉PCF8591我要写东西给你
——0x43是告诉PCF8591我要用你的输出功能,我稍后就告诉你要输出多大的电压

3、开始编写函数

void write_DAC(unsigned char x)
{
  IIC_Start();
  IIC_SendByte(0x90); //写
  IIC_WaitAck();
 
  IIC_SendByte(0x43); //允许输出
  IIC_WaitAck();
  IIC_SendByte(x);
  IIC_WaitAck();
  IIC_Stop();
 
}

6、PCF8591测量光敏电阻电压,并且输出5v电压实验

这个代码直接复制就能跑,冲冲冲

#include <STC15F2K60S2.H> 
#include "intrins.h"
#include <stdio.H> 
#define DELAY_TIME 5
#define u8 unsigned char
#define u16 unsigned int
//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

unsigned char buf[10],duanma[10];
int temp=0;
void Timer0Init(void)		//1毫秒@11.0592MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}

void IIC_Delay(unsigned char i)
{
    do{_nop_();}
    while(i--);        
}
//总线启动条件
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//发送应答
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//等待应答
bit IIC_WaitAck(void)
{
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

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

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)
    {   
    	SCL = 1;
	    IIC_Delay(DELAY_TIME);
	    da <<= 1;
	    if(SDA) da |= 1;
	    SCL = 0;
	    IIC_Delay(DELAY_TIME);
    }
    return da;    
}
unsigned char read_rb(unsigned char channel)//选择通道,取值0、1、2、3
{
  unsigned char dat;
  IIC_Start();
  IIC_SendByte(0x90); //写
  IIC_WaitAck();
  IIC_SendByte(channel);
  IIC_WaitAck();
   IIC_Stop();

  IIC_Start();
  IIC_SendByte(0x91); //读
  IIC_WaitAck();
  dat = IIC_RecByte();
  IIC_SendAck(1);
  IIC_Stop();
  return dat;
}
void write_DAC(unsigned char x)
{
  IIC_Start();
  IIC_SendByte(0x90); //写
  IIC_WaitAck();
 
  IIC_SendByte(0x43); //允许输出
  IIC_WaitAck();
  IIC_SendByte(x);
  IIC_WaitAck();
  IIC_Stop();
 
}
void Conversion(u8 *buf,u8 *duanma)
{
  u8 i,j=0,temp;
  for(i=0;i<8;i++,j++)
  {
    switch(buf[j])
	{
	  //根据要显示的字符获取共阳极数码管编码
			case '0': temp = 0xc0; break;
			case '1': temp = 0xf9; break;
			case '2': temp = 0xa4; break;
			case '3': temp = 0xb0; break;
			case '4': temp = 0x99; break;
			case '5': temp = 0x92; break;
			case '6': temp = 0x82; break;
			case '7': temp = 0xf8; break;
			case '8': temp = 0x80; break;
			case '9': temp = 0x90; break;
			case 'A': temp = 0x88; break;
			case 'B': temp = 0x83; break;
			case 'C': temp = 0xc6; break;
			case 'D': temp = 0xA1; break;
			case 'E': temp = 0x86; break;
			case 'F': temp = 0x8E; break;
			case 'H': temp = 0x89; break;
			case 'L': temp = 0xC7; break;
			case 'N': temp = 0xC8; break;
			case 'P': temp = 0x8c; break;
			case 'U': temp = 0xC1; break;
			case '-': temp = 0xbf; break;
			case ' ': temp = 0xff; break;
			default: temp = 0xff;
	}
	if(buf[j+1]=='.')
	{
	  temp = temp&0x7f;
	  j++;
	}
	duanma[i] = temp;
  }
}
void display(u8 *duanma,u8 position)
{
  P0 = 0XFF;//段码消影
  P2 = (P2&0X1F)|0XE0;//允许段码更新
  P2 &= 0X1F;
					 
  P0 = 1<<position;//送位码
  P2 = (P2&0X1F)|0XC0;
  P2 &= 0X1F;

  P0 = duanma[position]; //送段码
  P2 = P2 & 0x1F | 0xE0; //允许段码锁存器更新
  P2 &= 0x1F; //锁存段码锁存器
}
void main()
{
 
  Timer0Init();
  EA = 1;ET0 = 1;
  
  while(1)
  {      
	   sprintf(buf,"%8d",temp);
	   Conversion(&buf,&duanma);	   
  }
}
void Timer0() interrupt 1
{
  static unsigned char i,m;

  if(++i==8){i=0;}display(&duanma,i);
  if(++m==200){m=0;temp = read_rb(1);temp = read_rb(1);}
  write_DAC(255);
}

实验现象;

在这里插入图片描述
改变光照
在这里插入图片描述
每次读取的电压值是上次的哦,记得运行两次以获得现在的值,如果觉得文章代码有用,点个赞再走呗
备赛目录

版权声明:本文为CSDN博主「学到地中海」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/C_white_llj/article/details/122776829

生成海报
点赞 0

学到地中海

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

【蓝桥杯】串口通信详解附双串口代码

备赛目录 IAP15F2K61S2单片机拥有两个全双工串口通信接口(串口1和串口2)1、串口相关寄存器 每个串口都有2个数据缓冲器、一个移位寄存器、一个串行控制器和一个波特率发生器 1.1数据缓冲器SBUF 这是

【蓝桥杯】我的单片机备赛准备目录

知其然,更需知其所以然 1、客观题准备 蓝桥杯历届客观题及答案解析 2、模块化准备 2.1、LED灯及蜂鸣器 1、关闭蜂鸣器 2、LED灯的操作 2.2、数码管 万能数码管编写 2.3、按键 1、独立按键 2、矩阵

【蓝桥杯】AT24C02存储扩展

备赛目录 1、AT24C02简介 AT24C02芯片是一种EEPROM器件。EEPROM是电可擦除可编程只读存储器,是ROM的一种。它是只读存储器,即掉电可继续存储数据,而同时又可以在高于普通电压的作