目录
一 前言
二 引言
三 PCF8591介绍
(1)I2C通信
(2)原理图中的8591
四 代码层面
(1)根据题目所给的示范代码,实现ADC
1 为什么需要返回值,同时返回值是unsigned char?
2 为什么发送地址是0x90?
(2)根据题目所给的示范代码,实现DAC
main.c
为什么需要转化成unsigned int?
一 前言
本次关于PCF8591的学习,我们主要学ADC和DAC板块,主要的目标是通过旋转蓝桥杯板子上的旋钮(电压采集)和边上的光敏电阻,来实现PCK8591_ADC板块的转换,本次也会教DAC的转换,但并不写相关代码调试
二 引言
我们知道,在电路中传输的信号只有两种,分别是数字信号和模拟信号,模拟信号更像一个个具体的数值,数字信号只由0和1构成。将模拟信号转换为数字信号,我们把这个过程称之为ADC转化,A表示模拟信号,D表示数字信号,所衍生出来了两种技术:模拟-数字转换ADC技术、数字-模拟转换DAC技术,一般来说,我们用模拟-数字转换ADC技术用的比较多,我也会着重去讲ADC技术。(大家不要把ADC想成王者荣耀里面的射手位置啊!!)
三 PCF8591介绍
(1)I2C通信
在蓝桥杯比赛中提供的板子原理图中,上面这张照片就是PCF8591的原理图,大家仔细观察本章图片的右下角位置,你会发现:P20、P21后面的SCL和SDA,这两个线就是I2C的核心线,I2C需知道的相关底层知识点,如若不理解I2C通信,推荐大家去哔哩哔哩看这个博主的视频
【4分钟看懂!I2C通讯协议 最简单的总线通讯!】 https://www.bilibili.com/video/BV1dg4y1H773/?share_source=copy_web
1 SDA:提供信息通道 SCL:提供精确的频率 GND:接地线
2 当SCL为高电平时:(1)SDA从高到低的跳变为开始信号(2)SDA从低到高的跳变为结束信号
3 主机每次发送信息只能发送八个二进制数(1字节byte)
4 先写在读
大家先对上面这张图片有所印象,我会在后面结合比赛给提供的代码中进行添加代码讲解,因为比赛所提供的范例代码已经包含上面这个过程了
(2)原理图中的8591
现在我们观察左上角的这个几个位置,这几个位置是决定着PCF8591该作用到那个地方,例如下图(从原理图中摘出来的部分)+对应功能的地址(代码要写对应的地址):
地址 | 对应的功能 | |
---|---|---|
AIN1 | 0x41 | 光敏电阻 |
AIN3 | 0x43 | 滑动变阻器 |
四 代码层面
(1)根据题目所给的示范代码,实现ADC
我们先看一下范例代码给我们提供了什么:
static void I2C_Delay(unsigned char n);//延时函数
void I2CStart(void); //开始信号
void I2CStop(void); //停止信号
void I2CSendByte(unsigned char byt);//发送一个字节
unsigned char I2CReceiveByte(void); //接收一个字节
unsigned char I2CWaitAck(void);//等待响应
void I2CSendAck(unsigned char ackbit);//发送应答位
我们根据上面比赛提供的代码进行ADC转换,由于我们知道在板子上ADC有两个,分别是光敏电阻和滑动变阻器,所以我们需要在代码书写的时候要进行选择,引入入口参数channel_num,再在对应的.h文件中,将两个参数进行宏定义,我们如果想要用哪个功能只需要给对应的函数进行更换入口参数即可。
#define Photo_Res_Channel 0x41 //光敏电阻
#define Adj_Res_Channel 0x43 //滑动变阻器
在官方给的IIC.c文件中的最下面添加相应的代码:
unsigned char Pcf8591_Adc(unsigned char channel_num_contrl)
{unsigned char temp;I2CStart();//发送开启信号I2CSendByte(0x90);//选择PCF8591芯片,确定写的模式I2CWaitAck();//等待PCF8591反馈I2CSendByte(channel_num_contrl);//确定要转换的通道(顺便,使能DA转换)I2CWaitAck();//等待PCF8591反馈 I2CStart();//发送开启信号I2CSendByte(0x91);//选择PCF8591芯片,确定读的模式I2CWaitAck();//等待PCF8591反馈 temp = I2CReceiveByte();//接收数据I2CSendAck(1);//选择不应答I2CStop();//停止发送return temp;}
1 为什么需要返回值,同时返回值是unsigned char?
函数内部通过 IIC 总线从 PCF8591 读取的数据(存储在 temp中),temp是转换结果,必须通过返回值返回给用户,否则无法获取 ADC 结果
PCF8591 是一个 8 位 ADC(模数转换器)
2 为什么发送地址是0x90?
0x90 = 1001 0000,高四位分别是1001,1001的意思就是PCF8591,然后最后一位决定着读还是写,0是写,1是读,再看上面PCF8591的原理图的A1 2 3部分,他们仨是接地的,所以0x90的意思就是我PCF8591要写数据了,若不理解,就背下来!!!
整体的一个代码过程就是:
开始信号 -> 写 -> 等待应答
告诉单片机对应的通道 -> 等待应答
开始信号 -> 读 - > 等待应答
将接受到的数据给temp -> 8591告诉单片机不应答 -> 停止信号
(2)根据题目所给的示范代码,实现DAC
同样,在iic.c文件中,继续添加相应的DAC转换代码:
void Pcf8591_Dac(unsigned char trans_dat)
{I2CStart();//发送开启信号I2CSendByte(0x90);//选择PCF8591芯片,确定写的模式I2CWaitAck();//等待PCF8591反馈I2CSendByte(0x41);//使能DA转换(随便写通道编号,不影响,主要的功能是使能DA)I2CWaitAck();//等待PCF8591反馈 I2CSendByte(trans_dat);//将待转换的数据发送出去I2CWaitAck();//等待PCF8591反馈 I2CStop();//停止发送 }
注意:
这里和上面ADC很多地方不一样,这里不用接收信号函数 I2CReceiveByte(),以及不用引用其他变量
main.c
在main.c中,仅需添加一种新的情况,全部代码我就不写了,和本专题前面的main文件中的代码类似,请大家认真阅读曾经的文章
case 4:sprintf(seg_string,"%4d%4d",(unsigned int)PCF8591_ADC(Photo_Res_Channel ),(unsigned int)PCF8591_ADC(Adjust_Channel));//为什么最后显示的是左边是光敏电阻,右边是光敏电阻break;
这里面我们也需要将ADC读取的光敏电阻传到数码管上,需要利用上面这行代码
为什么需要转化成unsigned int?
因为PCF8591_ADC,这个函数的返回值是unsigned char,数码管显示不了字符型(char),所以我们需要将返回值强行转化成unsigned int类型