PCF8591 AD/DA转换模块学习笔记
1. 模块基础介绍
1.1 什么是PCF8591?
PCF8591是一款单电源、低功耗的8位CMOS数据采集器件,具有:
- 4路模拟输入(ADC) - 将模拟信号转换为数字信号
- 1路模拟输出(DAC) - 将数字信号转换为模拟信号
- 通过I2C总线 与单片机通信
1.2 硬件连接
#include <intrins.h> // 必须包含,用于_nop_()延时
sbit scl = P2 ^ 0; // I2C时钟线(连接到PCF8591的SCL引脚)
sbit sda = P2 ^ 1; // I2C数据线(双向,连接到PCF8591的SDA引脚)
1.3 I2C总线基础函数(官方提供)
I2C_Delay() // I2C延时函数
I2CStart() // 发送起始信号
I2CStop() // 发送停止信号
I2CSendByte() // 发送一个字节
I2CReceiveByte() // 接收一个字节
I2CWaitAck() // 等待应答信号
I2CSendAck() // 发送应答信号
2.1 地址计算原理
PCF8591的I2C设备地址由7位固定地址+1位读写位组成:
| 设备 | 固定地址 | R/W位 | 完整地址 |
|---|---|---|---|
| PCF8591 | 0x48 | 写=0, 读=1 | 写:0x90, 读:0x91 |
计算公式:
- 写地址 =
(0x48 << 1) | 0= 0x90 - 读地址 =
(0x48 << 1) | 1= 0x91
3. 控制寄存器详解
3.1 寄存器格式
PCF8591的控制寄存器(8位)格式如下:
位7 位6 位5 位4 位3 位2 位1 位0
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 0 │ 1 │ 0 │ 0 │ AI1│ AI0│ CH1│ CH0│
└────┴────┴────┴────┴────┴────┴────┴────┘
│ │ │ │ │ │ │ └── 通道选择位0
│ │ │ │ │ │ └───── 通道选择位1
│ │ │ │ │ └───────── 模拟输入模式位0
│ │ │ │ └───────────── 模拟输入模式位1
│ │ │ └────────────────── DA使能位(1=开启,0=关闭)
│ │ └─────────────────────── 固定为0
│ └──────────────────────────── 固定为1
└───────────────────────────────── 固定为0
4. DA转换(数字→模拟)
4.1 工作原理
数字值(0-255) → DAC转换 → 模拟电压(0-5V)
↓ ↓
单片机写入 PCF8591转换输出
4.2 DA转换函数
/**
* 功能: PCF8591 DA转换
* 描述: 向PCF8591的DA输出设置模拟量
* 设置范围: 0~255 (对应0~5V)
* 参数: dat - DA转换值(0~255)
*/
void Da_Write(unsigned char dat)
{
I2CStart(); // 发送起始信号
I2CSendByte(0x90); // 发送设备地址+写操作(0x90)
I2CWaitAck(); // 等待应答
I2CSendByte(0x41); // 发送控制字(开启DA输出,通道1)
I2CWaitAck(); // 等待应答
I2CSendByte(dat); // 发送DA值
I2CWaitAck(); // 等待应答
I2CStop(); // 发送停止信号
}
5. AD转换(模拟→数字)
5.1 工作原理
模拟电压(0-5V) → ADC转换 → 数字值(0-255)
↓ ↓
传感器输入 单片机读取
5.2 AD转换函数
/**
* 功能: PCF8591 AD转换
* 描述: 从PCF8591的指定通道读取AD转换值
* 读取范围: 0~255 (对应0~5V)
* 参数: addr - 控制字,指定通道和配置
* 0x41 - 通道1,开启DA(光照传感器)
* 0x43 - 通道3,开启DA(滑动变阻器)
* 返回值: AD转换结果(0~255)
*/
unsigned char Ad_Read(unsigned char addr)
{
unsigned char temp;
// 写操作阶段:选择通道
I2CStart(); // 发送起始信号
I2CSendByte(0x90); // 发送设备地址+写操作
I2CWaitAck(); // 等待应答
I2CSendByte(addr); // 发送控制字(选择通道)
I2CWaitAck(); // 等待应答
// 读操作阶段:获取数据
I2CStart(); // 重新发送起始信号
I2CSendByte(0x91); // 发送设备地址+读操作
I2CWaitAck(); // 等待应答
temp = I2CReceiveByte(); // 读取AD转换结果
I2CSendAck(1); // 发送非应答信号
I2CStop(); // 发送停止信号
return temp; // 返回AD转换结果
}
6. 应用层示例
6.1 数值换算
- 数字量 → 模拟电压 :
电压 = 数字量 ÷ 51 - 模拟电压 → 数字量 :
数字量 = 电压 × 51
注:255对应5V,所以换算系数为 255÷5 = 51
6.2 完整应用示例
// 全局变量
unsigned char AD_Slow_Down = 0; // 延时计数器
unsigned char AD_Light_Val_100x; // 光照值(放大100倍)
unsigned char AD_RB2_Val_100x; // 滑动变阻器值(放大100倍)
void AD_DA()
{
// 检查延时是否到达(80-160ms读取一次)
if (AD_Slow_Down < 80)
return;
AD_Slow_Down = 0;
// 读取光照传感器(通道1)并转换为百分比
AD_Light_Val_100x = Ad_Read(0x41) * 100 / 51;
// 读取滑动变阻器(通道3)并转换为百分比
AD_RB2_Val_100x = Ad_Read(0x43) * 100 / 51;
// 设置DA输出2V电压(2×51=102)
Da_Write(2 * 51);
}
7. 重要注意事项
7.1 读取延迟问题
问题现象 :连续读取时,下一次读取到的是上一次转换后的值。
解决方案 :使用"交换地址读取法"
// 交换地址读取(反读)
AD_Light_Val_100x = Ad_Read(0x43) * 100 / 51; // 实际读取的是RB2通道
AD_RB2_Val_100x = Ad_Read(0x41) * 100 / 51; // 实际读取的是光照传感器
7.2 常见问题排查
- 无响应 :检查I2C地址是否正确(0x90/0x91)
- 数据错误 :检查控制字(addr参数)是否正确
总结 :PCF8591是一款简单易用的AD/DA转换芯片,通过I2C接口与单片机通信,只需掌握地址计算、控制字设置和基本读写时序即可灵活使用。