STM32控制PCF8591数字模拟转换器程序
一、硬件连接和头文件定义
1.1 硬件连接
PCF8591引脚 → STM32引脚
1 (AIN0) → 外部模拟输入0(可选)
2 (AIN1) → 外部模拟输入1(可选)
3 (AIN2) → 外部模拟输入2(可选)
4 (AIN3) → 外部模拟输入3(可选)
5 (A0) → GND(地址引脚0)
6 (A1) → GND(地址引脚1)
7 (A2) → GND(地址引脚2)
8 (VSS) → GND
9 (SDA) → PB7(I2C1_SDA)
10 (SCL) → PB6(I2C1_SCL)
11 (OSC) → NC(悬空)
12 (EXT) → NC(悬空)
13 (AGND) → GND
14 (VREF) → 3.3V(参考电压)
15 (AOUT) → 模拟输出
16 (VDD) → 3.3V
1.2 头文件定义 (pcf8591.h)
#ifndef __PCF8591_H
#define __PCF8591_H
#include "stm32f1xx_hal.h"
#include <stdint.h>
#include <string.h>
// PCF8591默认地址(A0=A1=A2=GND)
#define PCF8591_ADDR_WRITE 0x90 // 写地址
#define PCF8591_ADDR_READ 0x91 // 读地址
// 控制寄存器位定义
#define PCF8591_CTRL_ANALOG_OUT_ENABLE 0x40 // 模拟输出使能
#define PCF8591_CTRL_AUTO_INCREMENT 0x04 // 自动增量
#define PCF8591_CTRL_CHANNEL_MASK 0x03 // 通道选择掩码
// 通道定义
typedef enum {
PCF8591_CHANNEL_0 = 0x00, // 通道0
PCF8591_CHANNEL_1 = 0x01, // 通道1
PCF8591_CHANNEL_2 = 0x02, // 通道2
PCF8591_CHANNEL_3 = 0x03, // 通道3
} PCF8591_Channel;
// 输入模式定义
typedef enum {
PCF8591_MODE_SINGLE_ENDED = 0x00, // 单端输入
PCF8591_MODE_DIFF_0_1 = 0x10, // 差分输入0-1
PCF8591_MODE_DIFF_2_3 = 0x20, // 差分输入2-3
PCF8591_MODE_SINGLE_MIXED = 0x30, // 单端和差分混合
} PCF8591_InputMode;
// 工作模式定义
typedef enum {
PCF8591_MODE_NORMAL = 0x00, // 正常模式
PCF8591_MODE_THREE_DIFF = 0x10, // 三个差分输入
PCF8591_MODE_SINGLE_DIFF = 0x20, // 一个单端+一个差分
PCF8591_MODE_TWO_DIFF = 0x30, // 两个差分输入
} PCF8591_WorkMode;
// PCF8591结构体
typedef struct {
I2C_HandleTypeDef* hi2c; // I2C句柄
uint8_t dev_addr; // 设备地址
float vref; // 参考电压(V)
uint8_t auto_increment; // 自动增量标志
uint8_t channel_count; // 通道数量
PCF8591_Channel current_channel; // 当前通道
} PCF8591_HandleTypeDef;
// 函数声明
// 初始化函数
void PCF8591_Init(PCF8591_HandleTypeDef* hpcf, I2C_HandleTypeDef* hi2c, float vref);
uint8_t PCF8591_IsReady(PCF8591_HandleTypeDef* hpcf);
// 模拟输出函数
void PCF8591_SetAnalogOutput(PCF8591_HandleTypeDef* hpcf, uint8_t value);
void PCF8591_SetVoltage(PCF8591_HandleTypeDef* hpcf, float voltage);
void PCF8591_SetAnalogOutputPercent(PCF8591_HandleTypeDef* hpcf, float percent);
// 模拟输入函数
uint8_t PCF8591_ReadADC(PCF8591_HandleTypeDef* hpcf, PCF8591_Channel channel);
float PCF8591_ReadVoltage(PCF8591_HandleTypeDef* hpcf, PCF8591_Channel channel);
float PCF8591_ReadADCPercent(PCF8591_HandleTypeDef* hpcf, PCF8591_Channel channel);
// 多通道读取
void PCF8591_ReadAllChannels(PCF8591_HandleTypeDef* hpcf, uint8_t* data);
void PCF8591_ReadAllVoltages(PCF8591_HandleTypeDef* hpcf, float* voltages);
// 高级功能
void PCF8591_SetInputMode(PCF8591_HandleTypeDef* hpcf, PCF8591_InputMode mode);
void PCF8591_SetWorkMode(PCF8591_HandleTypeDef* hpcf, PCF8591_WorkMode mode);
void PCF8591_EnableAutoIncrement(PCF8591_HandleTypeDef* hpcf, uint8_t enable);
// 波形生成函数
void PCF8591_GenerateSineWave(PCF8591_HandleTypeDef* hpcf, float freq, float amplitude, uint16_t samples);
void PCF8591_GenerateSquareWave(PCF8591_HandleTypeDef* hpcf, float freq, float amplitude, uint16_t samples);
void PCF8591_GenerateTriangleWave(PCF8591_HandleTypeDef* hpcf, float freq, float amplitude, uint16_t samples);
void PCF8591_GenerateSawtoothWave(PCF8591_HandleTypeDef* hpcf, float freq, float amplitude, uint16_t samples);
// DAC校准函数
void PCF8591_CalibrateDAC(PCF8591_HandleTypeDef* hpcf);
void PCF8591_SetCalibration(PCF8591_HandleTypeDef* hpcf, float gain, float offset);
// 调试和测试
void PCF8591_SelfTest(PCF8591_HandleTypeDef* hpcf);
void PCF8591_PrintStatus(PCF8591_HandleTypeDef* hpcf);
#endif /* __PCF8591_H */
二、核心驱动实现
2.1 初始化函数 (pcf8591.c)
#include "pcf8591.h"
#include <math.h>
// 内部变量
typedef struct {
float gain_correction; // 增益校正
float offset_correction; // 偏置校正
} PCF8591_Calibration;
static PCF8591_Calibration calib = {1.0f, 0.0f};
// 初始化PCF8591
void PCF8591_Init(PCF8591_HandleTypeDef* hpcf, I2C_HandleTypeDef* hi2c, float vref) {
if (hpcf == NULL || hi2c == NULL) return;
hpcf->hi2c = hi2c;
hpcf->dev_addr = PCF8591_ADDR_WRITE;
hpcf->vref = vref;
hpcf->auto_increment = 0;
hpcf->channel_count = 4;
hpcf->current_channel = PCF8591_CHANNEL_0;
// 设置默认模式:单端输入,通道0
uint8_t ctrl_byte = PCF8591_CTRL_ANALOG_OUT_ENABLE; // 使能模拟输出
HAL_I2C_Master_Transmit(hpcf->hi2c, hpcf->dev_addr, &ctrl_byte, 1, 100);
// 初始化输出为0
PCF8591_SetAnalogOutput(hpcf, 0);
}
// 检查设备是否就绪
uint8_t PCF8591_IsReady(PCF8591_HandleTypeDef* hpcf) {
if (hpcf == NULL || hpcf->hi2c == NULL) return 0;
HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(hpcf->hi2c, hpcf->dev_addr, 1, 10);
return (status == HAL_OK);
}
2.2 模拟输出函数
// 设置模拟输出(原始值 0-255)
void PCF8591_SetAnalogOutput(PCF8591_HandleTypeDef* hpcf, uint8_t value) {
if (hpcf == NULL || hpcf->hi2c == NULL) return;
// 应用校准
int16_t calibrated_value = (int16_t)(value * calib.gain_correction + calib.offset_correction);
// 限制在0-255范围内
if (calibrated_value < 0) calibrated_value = 0;
if (calibrated_value > 255) calibrated_value = 255;
uint8_t buffer[2];
// 控制字节:使能模拟输出
buffer[0] = PCF8591_CTRL_ANALOG_OUT_ENABLE;
// 数据字节
buffer[1] = (uint8_t)calibrated_value;
// 发送数据
HAL_I2C_Master_Transmit(hpcf->hi2c, hpcf->dev_addr, buffer, 2, 100);
}
// 设置输出电压(单位:伏特)
void PCF8591_SetVoltage(PCF8591_HandleTypeDef* hpcf, float voltage) {
if (hpcf == NULL) return;
// 计算DAC值
// DAC值 = (电压 / 参考电压) * 255
float dac_value_f = (voltage / hpcf->vref) * 255.0f;
// 限制范围
if (dac_value_f < 0.0f) dac_value_f = 0.0f;
if (dac_value_f > 255.0f) dac_value_f = 255.0f;
uint8_t dac_value = (uint8_t)dac_value_f;
PCF8591_SetAnalogOutput(hpcf, dac_value);
}
// 设置输出电压百分比(0.0 - 1.0)
void PCF8591_SetAnalogOutputPercent(PCF8591_HandleTypeDef* hpcf, float percent) {
if (hpcf == NULL) return;
// 限制百分比范围
if (percent < 0.0f) percent = 0.0f;
if (percent > 1.0f) percent = 1.0f;
uint8_t dac_value = (uint8_t)(percent * 255.0f);
PCF8591_SetAnalogOutput(hpcf, dac_value);
}
2.3 模拟输入函数
// 读取ADC原始值(0-255)
uint8_t PCF8591_ReadADC(PCF8591_HandleTypeDef* hpcf, PCF8591_Channel channel) {
if (hpcf == NULL || hpcf->hi2c == NULL) return 0;
uint8_t buffer[2] = {0};
uint8_t ctrl_byte = channel; // 选择通道
if (hpcf->auto_increment) {
ctrl_byte |= PCF8591_CTRL_AUTO_INCREMENT;
}
// 发送控制字节,选择通道
if (HAL_I2C_Master_Transmit(hpcf->hi2c, hpcf->dev_addr, &ctrl_byte, 1, 100) != HAL_OK) {
return 0;
}
// 读取转换结果
// 注意:PCF8591在发送控制字节后会进行一次转换
// 需要读取两次,第一次是上一次的转换结果
HAL_I2C_Master_Receive(hpcf->hi2c, PCF8591_ADDR_READ, buffer, 2, 100);
// 返回第二次转换的结果
return buffer[1];
}
// 读取输入电压(单位:伏特)
float PCF8591_ReadVoltage(PCF8591_HandleTypeDef* hpcf, PCF8591_Channel channel) {
if (hpcf == NULL) return 0.0f;
uint8_t adc_value = PCF8591_ReadADC(hpcf, channel);
// 电压 = (ADC值 / 255) * 参考电压
float voltage = ((float)adc_value / 255.0f) * hpcf->vref;
return voltage;
}
// 读取输入电压百分比(0.0 - 1.0)
float PCF8591_ReadADCPercent(PCF8591_HandleTypeDef* hpcf, PCF8591_Channel channel) {
if (hpcf == NULL) return 0.0f;
uint8_t adc_value = PCF8591_ReadADC(hpcf, channel);
return (float)adc_value / 255.0f;
}
2.4 多通道读取函数
// 读取所有通道的原始值
void PCF8591_ReadAllChannels(PCF8591_HandleTypeDef* hpcf, uint8_t* data) {
if (hpcf == NULL || hpcf->hi2c == NULL || data == NULL) return;
uint8_t buffer[5] = {0}; // 控制字节 + 4个通道数据
uint8_t ctrl_byte = PCF8591_CTRL_AUTO_INCREMENT; // 使能自动增量
// 发送控制字节
if (HAL_I2C_Master_Transmit(hpcf->hi2c, hpcf->dev_addr, &ctrl_byte, 1, 100) != HAL_OK) {
return;
}
// 读取5个字节(包含一个无效字节)
HAL_I2C_Master_Receive(hpcf->hi2c, PCF8591_ADDR_READ, buffer, 5, 100);
// 保存4个通道的数据(跳过第一个无效字节)
for (int i = 0; i < 4; i++) {
data[i] = buffer[i + 1];
}
}
// 读取所有通道的电压值
void PCF8591_ReadAllVoltages(PCF8591_HandleTypeDef* hpcf, float* voltages) {
if (hpcf == NULL || voltages == NULL) return;
uint8_t adc_values[4];
PCF8591_ReadAllChannels(hpcf, adc_values);
for (int i = 0; i < 4; i++) {
voltages[i] = ((float)adc_values[i] / 255.0f) * hpcf->vref;
}
}
三、波形生成功能
3.1 波形生成函数 (pcf8591_waveform.c)
#include "pcf8591.h"
#include <math.h>
// 生成正弦波
void PCF8591_GenerateSineWave(PCF8591_HandleTypeDef* hpcf, float freq, float amplitude, uint16_t samples) {
if (hpcf == NULL || freq <= 0 || samples == 0) return;
// 计算周期
float period_us = 1000000.0f / freq; // 周期(微秒)
float sample_interval_us = period_us / samples;
// 计算幅度系数
float amplitude_factor = amplitude / hpcf->vref;
if (amplitude_factor > 0.5f) amplitude_factor = 0.5f; // 限制幅度
for (uint16_t i = 0; i < samples; i++) {
// 计算正弦波值
float angle = 2.0f * 3.1415926f * (float)i / (float)samples;
float sine_value = 0.5f + amplitude_factor * sinf(angle); // 偏移到0-1范围
// 转换为DAC值
uint8_t dac_value = (uint8_t)(sine_value * 255.0f);
// 设置输出
PCF8591_SetAnalogOutput(hpcf, dac_value);
// 延时
Delay_us((uint32_t)sample_interval_us);
}
}
// 生成方波
void PCF8591_GenerateSquareWave(PCF8591_HandleTypeDef* hpcf, float freq, float amplitude, uint16_t samples) {
if (hpcf == NULL || freq <= 0 || samples == 0) return;
float period_us = 1000000.0f / freq;
float half_period_us = period_us / 2.0f;
// 计算DAC值
float amplitude_factor = amplitude / hpcf->vref;
if (amplitude_factor > 0.5f) amplitude_factor = 0.5f;
uint8_t high_value = (uint8_t)((0.5f + amplitude_factor) * 255.0f);
uint8_t low_value = (uint8_t)((0.5f - amplitude_factor) * 255.0f);
while (1) { // 持续生成
// 高电平
PCF8591_SetAnalogOutput(hpcf, high_value);
Delay_us((uint32_t)half_period_us);
// 低电平
PCF8591_SetAnalogOutput(hpcf, low_value);
Delay_us((uint32_t)half_period_us);
}
}
// 生成三角波
void PCF8591_GenerateTriangleWave(PCF8591_HandleTypeDef* hpcf, float freq, float amplitude, uint16_t samples) {
if (hpcf == NULL || freq <= 0 || samples == 0) return;
float period_us = 1000000.0f / freq;
float sample_interval_us = period_us / samples;
float amplitude_factor = amplitude / hpcf->vref;
if (amplitude_factor > 0.5f) amplitude_factor = 0.5f;
while (1) { // 持续生成
// 上升沿
for (uint16_t i = 0; i < samples / 2; i++) {
float value = 0.5f - amplitude_factor + (2.0f * amplitude_factor * i) / (samples / 2.0f);
uint8_t dac_value = (uint8_t)(value * 255.0f);
PCF8591_SetAnalogOutput(hpcf, dac_value);
Delay_us((uint32_t)sample_interval_us);
}
// 下降沿
for (uint16_t i = 0; i < samples / 2; i++) {
float value = 0.5f + amplitude_factor - (2.0f * amplitude_factor * i) / (samples / 2.0f);
uint8_t dac_value = (uint8_t)(value * 255.0f);
PCF8591_SetAnalogOutput(hpcf, dac_value);
Delay_us((uint32_t)sample_interval_us);
}
}
}
// 生成锯齿波
void PCF8591_GenerateSawtoothWave(PCF8591_HandleTypeDef* hpcf, float freq, float amplitude, uint16_t samples) {
if (hpcf == NULL || freq <= 0 || samples == 0) return;
float period_us = 1000000.0f / freq;
float sample_interval_us = period_us / samples;
float amplitude_factor = amplitude / hpcf->vref;
if (amplitude_factor > 0.5f) amplitude_factor = 0.5f;
while (1) { // 持续生成
for (uint16_t i = 0; i < samples; i++) {
float value = 0.5f - amplitude_factor + (2.0f * amplitude_factor * i) / samples;
uint8_t dac_value = (uint8_t)(value * 255.0f);
PCF8591_SetAnalogOutput(hpcf, dac_value);
Delay_us((uint32_t)sample_interval_us);
}
}
}
四、校准和高级功能
4.1 校准函数 (pcf8591_calibration.c)
#include "pcf8591.h"
// DAC校准
void PCF8591_CalibrateDAC(PCF8591_HandleTypeDef* hpcf) {
if (hpcf == NULL) return;
// 测量实际输出电压
// 需要外部高精度电压表连接到AOUT
// 步骤1:输出0V
PCF8591_SetAnalogOutput(hpcf, 0);
// 这里应该读取实际输出电压(需要外部测量)
// float measured_0v = 0.0f; // 从外部设备读取
// 步骤2:输出满量程
PCF8591_SetAnalogOutput(hpcf, 255);
// float measured_255 = hpcf->vref; // 从外部设备读取
// 计算增益和偏置误差
// float ideal_slope = hpcf->vref / 255.0f;
// float actual_slope = (measured_255 - measured_0v) / 255.0f;
// calib.gain_correction = ideal_slope / actual_slope;
// calib.offset_correction = -measured_0v / actual_slope;
}
// 设置校准参数
void PCF8591_SetCalibration(PCF8591_HandleTypeDef* hpcf, float gain, float offset) {
calib.gain_correction = gain;
calib.offset_correction = offset;
}
// 设置输入模式
void PCF8591_SetInputMode(PCF8591_HandleTypeDef* hpcf, PCF8591_InputMode mode) {
if (hpcf == NULL) return;
// 读取当前控制寄存器
uint8_t ctrl_byte = 0;
// 注意:PCF8591没有直接的寄存器读取功能
// 通常我们会保存当前的控制字节状态
// 设置输入模式
ctrl_byte = mode | PCF8591_CTRL_ANALOG_OUT_ENABLE;
HAL_I2C_Master_Transmit(hpcf->hi2c, hpcf->dev_addr, &ctrl_byte, 1, 100);
}
// 设置工作模式
void PCF8591_SetWorkMode(PCF8591_HandleTypeDef* hpcf, PCF8591_WorkMode mode) {
if (hpcf == NULL) return;
uint8_t ctrl_byte = mode | PCF8591_CTRL_ANALOG_OUT_ENABLE;
HAL_I2C_Master_Transmit(hpcf->hi2c, hpcf->dev_addr, &ctrl_byte, 1, 100);
}
// 使能/禁用自动增量
void PCF8591_EnableAutoIncrement(PCF8591_HandleTypeDef* hpcf, uint8_t enable) {
if (hpcf == NULL) return;
hpcf->auto_increment = enable;
}
五、主程序示例
5.1 基本输出示例 (main_basic.c)
#include "main.h"
#include "pcf8591.h"
// 全局变量
I2C_HandleTypeDef hi2c1;
PCF8591_HandleTypeDef hpcf;
// 系统时钟配置
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// 配置HSE
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
// 配置系统时钟
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}
// GPIO初始化
static void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 使能GPIO时钟
__HAL_RCC_GPIOB_CLK_ENABLE();
// 配置I2C引脚
GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
// I2C初始化
static void MX_I2C1_Init(void) {
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000; // 100kHz
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(&hi2c1);
}
// 串口初始化(调试用)
void MX_USART1_UART_Init(void) {
// 串口1初始化代码...
}
// 延时函数
void Delay_ms(uint32_t ms) {
HAL_Delay(ms);
}
void Delay_us(uint32_t us) {
uint32_t delay = us * (SystemCoreClock / 1000000) / 5;
while(delay--) {
__NOP();
}
}
// 示例1:基本输出电压控制
void Example_BasicOutput(void) {
printf("PCF8591 Basic Output Test\n");
printf("==========================\n");
// 初始化PCF8591
PCF8591_Init(&hpcf, &hi2c1, 3.3f); // 参考电压3.3V
if (PCF8591_IsReady(&hpcf)) {
printf("PCF8591 Initialized Successfully!\n");
} else {
printf("PCF8591 Initialization Failed!\n");
return;
}
// 测试输出电压
printf("\nTesting Output Voltages:\n");
// 输出0V
PCF8591_SetVoltage(&hpcf, 0.0f);
printf("Output: 0.0V\n");
Delay_ms(1000);
// 输出1.65V
PCF8591_SetVoltage(&hpcf, 1.65f);
printf("Output: 1.65V\n");
Delay_ms(1000);
// 输出3.3V
PCF8591_SetVoltage(&hpcf, 3.3f);
printf("Output: 3.3V\n");
Delay_ms(1000);
// 输出斜坡电压
printf("\nGenerating Ramp Voltage...\n");
for (uint8_t i = 0; i <= 255; i++) {
PCF8591_SetAnalogOutput(&hpcf, i);
Delay_ms(10);
}
}
// 示例2:读取模拟输入
void Example_ReadInputs(void) {
printf("PCF8591 Analog Input Test\n");
printf("==========================\n");
// 读取所有通道
uint8_t adc_values[4];
float voltages[4];
while (1) {
PCF8591_ReadAllChannels(&hpcf, adc_values);
PCF8591_ReadAllVoltages(&hpcf, voltages);
printf("ADC Values: ");
for (int i = 0; i < 4; i++) {
printf("CH%d: %3d ", i, adc_values[i]);
}
printf("\n");
printf("Voltages: ");
for (int i = 0; i < 4; i++) {
printf("CH%d: %.3fV ", i, voltages[i]);
}
printf("\n\n");
Delay_ms(500);
}
}
// 示例3:生成波形
void Example_GenerateWaveform(void) {
printf("PCF8591 Waveform Generation\n");
printf("===========================\n");
// 生成正弦波
printf("Generating Sine Wave (1kHz, 1.5Vpp)\n");
PCF8591_GenerateSineWave(&hpcf, 1000.0f, 1.5f, 100);
// 生成方波
printf("Generating Square Wave (500Hz, 2Vpp)\n");
PCF8591_GenerateSquareWave(&hpcf, 500.0f, 2.0f, 100);
}
int main(void) {
// HAL库初始化
HAL_Init();
// 系统时钟配置
SystemClock_Config();
// 外设初始化
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
printf("STM32 PCF8591 Control Program\n");
printf("==============================\n\n");
// 运行示例
Example_BasicOutput();
// Example_ReadInputs();
// Example_GenerateWaveform();
return 0;
}
六、高级应用示例
6.1 电压监控和报警系统
// 电压监控结构体
typedef struct {
float lower_threshold; // 下限阈值
float upper_threshold; // 上限阈值
uint8_t alarm_enabled; // 报警使能
void (*alarm_callback)(uint8_t channel, float voltage); // 报警回调
} VoltageMonitor;
VoltageMonitor monitors[4];
// 初始化电压监控
void VoltageMonitor_Init(void) {
for (int i = 0; i < 4; i++) {
monitors[i].lower_threshold = 0.5f;
monitors[i].upper_threshold = 2.5f;
monitors[i].alarm_enabled = 1;
monitors[i].alarm_callback = NULL;
}
}
// 电压监控任务
void VoltageMonitor_Task(PCF8591_HandleTypeDef* hpcf) {
float voltages[4];
// 读取所有通道电压
PCF8591_ReadAllVoltages(hpcf, voltages);
// 检查每个通道
for (int i = 0; i < 4; i++) {
if (monitors[i].alarm_enabled) {
if (voltages[i] < monitors[i].lower_threshold) {
// 低于下限阈值
printf("ALARM: CH%d voltage LOW: %.3fV\n", i, voltages[i]);
if (monitors[i].alarm_callback) {
monitors[i].alarm_callback(i, voltages[i]);
}
} else if (voltages[i] > monitors[i].upper_threshold) {
// 高于上限阈值
printf("ALARM: CH%d voltage HIGH: %.3fV\n", i, voltages[i]);
if (monitors[i].alarm_callback) {
monitors[i].alarm_callback(i, voltages[i]);
}
}
}
}
}
// 报警回调示例
void Alarm_Callback(uint8_t channel, float voltage) {
// 可以控制LED闪烁、蜂鸣器报警等
printf("Channel %d alarm: %.2fV\n", channel, voltage);
}
6.2 PID电压控制
// PID控制器结构体
typedef struct {
float kp; // 比例系数
float ki; // 积分系数
float kd; // 微分系数
float setpoint; // 设定点
float integral; // 积分项
float prev_error; // 上次误差
float output_min; // 输出最小值
float output_max; // 输出最大值
} PIDController;
// 初始化PID控制器
void PID_Init(PIDController* pid, float kp, float ki, float kd, float setpoint) {
pid->kp = kp;
pid->ki = ki;
pid->kd = kd;
pid->setpoint = setpoint;
pid->integral = 0.0f;
pid->prev_error = 0.0f;
pid->output_min = 0.0f;
pid->output_max = 3.3f;
}
// PID计算
float PID_Calculate(PIDController* pid, float measured, float dt) {
float error = pid->setpoint - measured;
// 比例项
float proportional = pid->kp * error;
// 积分项
pid->integral += error * dt;
float integral = pid->ki * pid->integral;
// 微分项
float derivative = pid->kd * (error - pid->prev_error) / dt;
pid->prev_error = error;
// 计算输出
float output = proportional + integral + derivative;
// 输出限幅
if (output < pid->output_min) output = pid->output_min;
if (output > pid->output_max) output = pid->output_max;
return output;
}
// PID电压控制示例
void Example_PIDControl(void) {
PIDController pid;
PID_Init(&pid, 1.0f, 0.1f, 0.01f, 2.0f); // 目标电压2.0V
float measured_voltage = 0.0f;
float control_voltage = 0.0f;
while (1) {
// 读取当前电压(通道0)
measured_voltage = PCF8591_ReadVoltage(&hpcf, PCF8591_CHANNEL_0);
// 计算PID输出
control_voltage = PID_Calculate(&pid, measured_voltage, 0.1f); // dt=0.1s
// 设置输出电压
PCF8591_SetVoltage(&hpcf, control_voltage);
printf("Measured: %.3fV, Output: %.3fV, Error: %.3fV\n",
measured_voltage, control_voltage, pid.setpoint - measured_voltage);
Delay_ms(100);
}
}
七、调试和测试功能
7.1 自检和状态显示
// 自检函数
void PCF8591_SelfTest(PCF8591_HandleTypeDef* hpcf) {
printf("PCF8591 Self Test\n");
printf("=================\n");
// 检查设备是否就绪
if (PCF8591_IsReady(hpcf)) {
printf("✓ I2C Communication: OK\n");
} else {
printf("✗ I2C Communication: FAILED\n");
return;
}
// 测试DAC输出
printf("\nTesting DAC Output...\n");
// 测试几个关键点
float test_voltages[] = {0.0f, 0.825f, 1.65f, 2.475f, 3.3f};
for (int i = 0; i < 5; i++) {
PCF8591_SetVoltage(hpcf, test_voltages[i]);
printf("Set Voltage: %.3fV\n", test_voltages[i]);
Delay_ms(500);
}
// 返回0V
PCF8591_SetVoltage(hpcf, 0.0f);
// 测试ADC输入(需要外部连接)
printf("\nTesting ADC Input...\n");
printf("Connect test voltages to AIN0-AIN3\n");
printf("Press any key to continue...\n");
// 等待按键
while (!serial_available());
serial_read();
float voltages[4];
PCF8591_ReadAllVoltages(hpcf, voltages);
for (int i = 0; i < 4; i++) {
printf("Channel %d: %.3fV\n", i, voltages[i]);
}
printf("\nSelf Test Complete!\n");
}
// 打印状态信息
void PCF8591_PrintStatus(PCF8591_HandleTypeDef* hpcf) {
printf("PCF8591 Status\n");
printf("==============\n");
printf("I2C Address: 0x%02X\n", hpcf->dev_addr);
printf("Reference Voltage: %.2fV\n", hpcf->vref);
printf("Auto Increment: %s\n", hpcf->auto_increment ? "Enabled" : "Disabled");
printf("Channel Count: %d\n", hpcf->channel_count);
printf("Current Channel: %d\n", hpcf->current_channel);
}
八、实用工具函数
8.1 电压表功能
// 简易数字电压表
void DigitalVoltmeter(PCF8591_HandleTypeDef* hpcf, PCF8591_Channel channel) {
printf("Digital Voltmeter - Channel %d\n", channel);
printf("Press 'q' to quit\n");
char key = 0;
while (key != 'q') {
float voltage = PCF8591_ReadVoltage(hpcf, channel);
// 显示电压条
printf("Voltage: %6.3fV [", voltage);
int bars = (int)(voltage * 20 / hpcf->vref); // 20个字符宽度
for (int i = 0; i < 20; i++) {
if (i < bars) {
printf("█");
} else {
printf(" ");
}
}
printf("]\r");
Delay_ms(100);
// 检查按键
if (serial_available()) {
key = serial_read();
}
}
printf("\n");
}
参考代码 stm32控制PCF8591输出电压程序 www.youwenfan.com/contentcnv/71693.html
九、项目文件结构
PCF8591_Project/
├── Core/
│ ├── Src/
│ │ ├── main.c # 主程序
│ │ ├── stm32f1xx_it.c # 中断服务程序
│ │ └── stm32f1xx_hal_msp.c # HAL MSP文件
│ └── Inc/
│ ├── main.h
│ ├── stm32f1xx_it.h
│ └── stm32f1xx_hal_conf.h
├── Drivers/
│ ├── STM32F1xx_HAL_Driver/
│ └── CMSIS/
├── PCF8591/
│ ├── pcf8591.c # 主驱动文件
│ ├── pcf8591.h # 头文件
│ ├── pcf8591_waveform.c # 波形生成
│ └── pcf8591_calibration.c # 校准功能
├── Middlewares/
└── README.md
十、使用注意事项
-
电源要求:
- VDD: 2.5V-6V
- VREF: ≤ VDD
- AGND和VSS必须连接在一起
-
I2C时序:
- 最大时钟频率:100kHz(标准模式)
- 需要上拉电阻(4.7kΩ-10kΩ)
-
模拟输出:
- 输出阻抗:约1kΩ
- 建立时间:约100µs
- 输出电流:最大3mA
-
模拟输入:
- 输入阻抗:极高
- 转换时间:约100µs
- 输入电压范围:0-VREF
-
PCB布局:
- 模拟和数字地分开
- VREF引脚需要去耦电容(0.1µF)
- 信号线远离高频噪声源

浙公网安备 33010602011771号