[网友问答1]STM32驱动PCF8591模块,实现AD/DA转换
问题原由
粉丝提问,STM32如何驱动PCF8591?
时间赶趟,小哈哥必须安排。
模块外观
原理图
模块说明:
模块所用芯片为PCF8591T,贴片封装
支持4路模拟电压采集信号输入(电压输入范围0–5V)
模块带电源指示灯1个(D1)
模块带DA输出指示灯1个(D2),当DA输出电压达到一定值时,该指示灯亮,电压值越高,指示灯越亮
模块集成1路0–5V电压输入采集(通过蓝白电位器调节输入电压)
模块集成1路光敏电阻(型号:5537),可以通过AD采集环境光线强度
模块集成1路热敏电阻(型号:MF58),可以通过AD采集环境温度
PCF8591特点:
单电源供电;
正常工作电源电压范围为2.5V~6V;
通过I2C总线完成数据的输入/输出;
器件地址由3个地址引脚决定;
由上面的原理图可以看出A0、A1、A2与GND相连。
采样频率由I2C总线传输速率决定;
4路模拟量输入可编程为单端输入或差分输入;
可配置转换通道号自动增加功能;
模拟电压范围为VSS~VDD;
片上跟踪保持功能;
8位逐次逼近A/D转换;
带有一路模拟量输出的D/A转换。
接线说明:
模块输入引脚
PCF8591模块 | 含义 | STM32核心板 |
---|---|---|
SDA | IIC数据接口 | U3R PB11 |
SCL | IIC时钟接口 | U3T PB10 |
VCC | 电源正 | 3V3 |
GND | 电源负 | GND |
实际连接图
模块输出调试引脚
PCF8591模块 | 含义 |
---|---|
AOUT | 模块DA输出端口 |
AIN3 | 模拟输入信号接口3 |
AIN2 | 模拟输入信号接口2 |
AIN1 | 模拟输入信号接口1 |
AIN0 | 模拟输入信号接口0 |
GND | 模块的GND |
INPUT2 | 已连接至热敏电阻信号输入口 |
INPUT1 | 已连接至光敏电阻信号输入口 |
INPUT0 | 已连接至电位器信号输入口 |
跳线帽使用说明
AIN0与INPUT0 连接跳线帽时,选择电位器接入电路
AIN1与INPUT1 连接跳线帽时,选择光敏电阻接入电路
AIN2与INPUT2 连接跳线帽时,选择热敏电阻接入电路
需要外接模拟信号输入时,请断开跳线帽,将该模拟信号接入AIN0----AIN3
芯片手册
地址
从模块原理图得知A0,A1,A2接地,所以模块的地址为:1001000X,那么其地址就是0x90或者是0x91,看是读还是写来决定。
最后一位,当是0时,表示下一个字节往总线上写数据;
当是1时,表示下一个字节从总线上读取数据。
#define PCF8591Addr 0x90 //写操作地址PCF8591Addr|0x01 //读操作地址
1
2
1
2
控制字
控制字位说明:
bit0-bit1:AD转换通道选择,当值为00时,为AIN0;
bit2:自动增量使能
bit4-bit5:单端输入/差分输入选择,00为单端输入
bit6:为1时为允许模拟电压输出
假设我需要从通道0单端获得A/D转换数据,那么control byte就是01000000 = 0x40 。
所以我们获取四个通道ADC值的函数如下调用:
adcData[0] = PCF8591_ADC_Input(0x90 ,0x40);adcData[1] = PCF8591_ADC_Input(0x90 ,0x41);adcData[2] = PCF8591_ADC_Input(0x90 ,0x42);adcData[3] = PCF8591_ADC_Input(0x90 ,0x43);12341234
D/A转换时序
具体实现代码如下:
u8 PCF8591_DAC_Output(unsigned char WriteAddr,unsigned char c, unsigned char Val){ IIC_Start(); //启动总线 IIC_Send_Byte(WriteAddr); //发送写操作地址 IIC_Wait_Ack(); IIC_Send_Byte(c); //发送控制字 IIC_Wait_Ack(); IIC_Send_Byte(Val); //发送DAC的数值 IIC_Wait_Ack(); IIC_Stop(); //结束总线 return(1);}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
输出DAC的值参考下面换算关系计算:
简单理解就是,发送的DAC数值IIC_Send_Byte(Val);
,将Vref分成 0xFF 份,Vagnd 对应第一份;Vref对应最后一份。
A/D转换时序
u8 PCF8591_ADC_Input(unsigned char WriteAddr,unsigned char Channel){ u8 temp=0; IIC_Start(); //启动总线 IIC_Send_Byte(WriteAddr); //发送写操作地址 IIC_Wait_Ack(); IIC_Send_Byte(Channel); //写入控制字 IIC_Wait_Ack(); IIC_Stop(); //结束此次写操作,结束总线 IIC_Start(); IIC_Send_Byte(WriteAddr|0x01); //发送读操作地址 IIC_Wait_Ack(); temp=IIC_Read_Byte(0); // IIC_Stop(); //结束总线 return temp;}1234567891011121314151617181920212223242526272812345678910111213141516171819202122232425262728
若要完成一次AD转换,应严格按照时序图进行:开启总线-->发送写操作地址-->等待PCF8591的应答-->发送控制字-->等待PCF8591的应答-->结束总线-->重新开启总线-->发送读操作地址-->等待PCF8591的应答-->读取ADC数据(1字节)-->发送非应答信号-->停止总线
。
上面IIC_
开头的函数都与24C02那个例程中的函数一致,不需要修改。
移植过程
在网文: STM32 I2C通信操作24C02写数据、读数据 的实例代码基础上,完成移植,具体过程如下:
1. 将驱动文件拷贝到自己工程中HARDWARE目录下
2. 添加驱动文件所在文件夹至工程中
3. 添加.c文件至工程中
4. main函数中调用
成果展示
先旋转电位器,然后用手遮挡光敏电阻,串口助手中具体现象如下: