AVR智能充电器PID控制程序(基于ATmega16/ATmega328)
一、系统硬件架构
1. 硬件连接方案
AVR ATmega16
├── ADC0 (PC0) → 电池电压采样(分压电阻)
├── ADC1 (PC1) → 充电电流采样(分流电阻+运放)
├── OC1A (PB1) → PWM输出 → MOSFET驱动 → 充电控制
├── INT0 (PD2) → 过温保护(NTC热敏电阻)
├── PC4/PC5 → I2C接口 → OLED显示(可选)
└── PD0/PD1 → UART → 上位机监控(可选)
电源部分:
输入12V/2A适配器 → 同步Buck降压 → 锂电池/铅酸电池
2. 关键参数设计
| 参数 |
数值 |
说明 |
| 开关频率 |
31.25kHz |
PWM分频,降低开关损耗 |
| 电压采样 |
12位ADC |
分压比1/10,分辨率10mV |
| 电流采样 |
50mV/10A |
分流电阻0.005Ω,运放增益20 |
| 控制周期 |
10ms |
PID计算周期,响应速度适中 |
二、PID算法核心程序(整型PID,适合AVR)
1. PID结构体与初始化
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
// PID控制器结构体(整型,避免浮点运算)
typedef struct {
int16_t Kp; // 比例系数(放大100倍)
int16_t Ki; // 积分系数(放大10000倍)
int16_t Kd; // 微分系数(放大100倍)
int16_t setpoint; // 设定值(电压或电流)
int16_t feedback; // 反馈值
int32_t integral; // 积分项(扩大100倍防溢出)
int16_t prev_error; // 上次误差
int16_t output; // 输出值(0-1000对应0-100%占空比)
int16_t output_min; // 输出最小值
int16_t output_max; // 输出最大值
} PID_Controller_t;
// 系统状态
typedef enum {
CHARGE_STOP = 0, // 停止充电
CHARGE_CC, // 恒流充电
CHARGE_CV, // 恒压充电
CHARGE_TRICLE, // 涓流充电
CHARGE_COMPLETE // 充电完成
} ChargeState_t;
// 全局变量
PID_Controller_t voltage_pid; // 电压PID
PID_Controller_t current_pid; // 电流PID
ChargeState_t charge_state = CHARGE_STOP;
uint16_t battery_voltage = 0; // 电池电压(mV)
uint16_t charge_current = 0; // 充电电流(mA)
2. 整型PID计算函数(AVR友好)
// PID计算函数(整型版本,适合8位MCU)
int16_t PID_Calculate(PID_Controller_t *pid) {
int16_t error = pid->setpoint - pid->feedback;
int32_t output;
// 1. 比例项(Kp已放大100倍)
int32_t P = (int32_t)pid->Kp * error; // 结果放大100倍
// 2. 积分项(Ki放大10000倍,积分项放大100倍)
pid->integral += (int32_t)error * 100; // 积分累积
// 积分限幅(防止积分饱和)
if (pid->integral > (int32_t)pid->output_max * 10000 / pid->Ki)
pid->integral = (int32_t)pid->output_max * 10000 / pid->Ki;
if (pid->integral < -(int32_t)pid->output_max * 10000 / pid->Ki)
pid->integral = -(int32_t)pid->output_max * 10000 / pid->Ki;
int32_t I = (pid->Ki * pid->integral) / 10000; // 结果放大100倍
// 3. 微分项(Kd放大100倍)
int32_t D = (int32_t)pid->Kd * (error - pid->prev_error); // 放大100倍
pid->prev_error = error;
// 4. 计算总输出(所有项都放大100倍)
output = P + I + D;
output = output / 100; // 缩小100倍,得到实际占空比
// 5. 输出限幅
if (output > pid->output_max) output = pid->output_max;
if (output < pid->output_min) output = pid->output_min;
pid->output = (int16_t)output;
return pid->output;
}
3. ADC采样函数
// ADC初始化
void ADC_Init(void) {
// AVCC为参考电压,右对齐,ADC0通道
ADMUX = (1<<REFS0) | (0<<ADLAR);
// 使能ADC,128分频(16MHz/128=125kHz)
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
}
// 读取ADC值
uint16_t ADC_Read(uint8_t channel) {
ADMUX = (ADMUX & 0xF0) | (channel & 0x0F); // 选择通道
ADCSRA |= (1<<ADSC); // 启动转换
while (ADCSRA & (1<<ADSC)); // 等待转换完成
return ADC;
}
// 获取电池电压(单位:mV)
uint16_t Get_Battery_Voltage(void) {
uint16_t adc_value = ADC_Read(0); // ADC0读取电压
// 分压比1/10,Vref=5V,12位ADC
uint32_t voltage = (uint32_t)adc_value * 5000 / 1023; // 单位mV
return (uint16_t)voltage * 10; // 乘以分压比
}
// 获取充电电流(单位:mA)
uint16_t Get_Charge_Current(void) {
uint16_t adc_value = ADC_Read(1); // ADC1读取电流
// 分流电阻0.005Ω,运放增益20,Vref=5V
uint32_t current = (uint32_t)adc_value * 5000 / 1023; // mV
current = current * 1000 / (20 * 5); // mA = mV / (增益 * 分流电阻)
return (uint16_t)current;
}
4. PWM输出控制
// PWM初始化(Timer1,10位快速PWM)
void PWM_Init(void) {
// OC1A输出,快速PWM,10位模式
TCCR1A = (1<<COM1A1) | (1<<WGM11) | (1<<WGM10);
TCCR1B = (1<<WGM12) | (1<<CS11); // 8分频,31.25kHz PWM频率
OCR1A = 0; // 初始占空比0%
DDRB |= (1<<PB1); // PB1设为输出
}
// 设置PWM占空比(0-1000对应0-100%)
void PWM_SetDuty(uint16_t duty) {
if (duty > 1000) duty = 1000;
OCR1A = duty; // 10位PWM,0-1023
}
5. 智能充电状态机
// 充电状态机处理
void Charge_State_Machine(void) {
static uint16_t cc_current = 1000; // 恒流电流1000mA
static uint16_t cv_voltage = 4200; // 恒压电压4200mV(4.2V锂电)
static uint16_t trickle_current = 100; // 涓流电流100mA
switch (charge_state) {
case CHARGE_STOP:
PWM_SetDuty(0); // 关闭PWM
break;
case CHARGE_CC: // 恒流充电
// 使用电流PID控制
current_pid.setpoint = cc_current;
current_pid.feedback = charge_current;
PWM_SetDuty(PID_Calculate(¤t_pid));
// 当电压达到恒压值时,切换到CV模式
if (battery_voltage >= cv_voltage) {
charge_state = CHARGE_CV;
}
break;
case CHARGE_CV: // 恒压充电
// 使用电压PID控制
voltage_pid.setpoint = cv_voltage;
voltage_pid.feedback = battery_voltage;
PWM_SetDuty(PID_Calculate(&voltage_pid));
// 当电流降低到涓流阈值时,切换到涓流模式
if (charge_current <= trickle_current) {
charge_state = CHARGE_TRICLE;
}
break;
case CHARGE_TRICLE: // 涓流充电
// 小电流维持
PWM_SetDuty(50); // 5%占空比
// 充电完成判断(电流持续低于50mA 10分钟)
static uint16_t complete_counter = 0;
if (charge_current < 50) {
complete_counter++;
if (complete_counter >= 6000) { // 10分钟 * 600次/分钟
charge_state = CHARGE_COMPLETE;
}
} else {
complete_counter = 0;
}
break;
case CHARGE_COMPLETE:
PWM_SetDuty(0); // 充电完成,关闭输出
break;
}
}
6. 主函数
int main(void) {
// 初始化PID参数
voltage_pid.Kp = 800; // 比例系数8.0
voltage_pid.Ki = 200; // 积分系数0.02
voltage_pid.Kd = 100; // 微分系数1.0
voltage_pid.output_min = 0;
voltage_pid.output_max = 1000;
current_pid.Kp = 600; // 比例系数6.0
current_pid.Ki = 150; // 积分系数0.015
current_pid.Kd = 50; // 微分系数0.5
current_pid.output_min = 0;
current_pid.output_max = 1000;
// 初始化外设
ADC_Init();
PWM_Init();
// 充电开始
charge_state = CHARGE_CC;
while (1) {
// 1. 读取电池参数
battery_voltage = Get_Battery_Voltage();
charge_current = Get_Charge_Current();
// 2. 安全检查(过压、过流、过温)
if (battery_voltage > 4300 || charge_current > 1500) {
charge_state = CHARGE_STOP; // 安全保护
}
// 3. 执行充电状态机
Charge_State_Machine();
// 4. 延时10ms(100Hz控制频率)
_delay_ms(10);
}
}
三、参数整定指南
1. PID参数推荐值(锂电充电)
| 参数 |
恒流模式(CC) |
恒压模式(CV) |
说明 |
| Kp |
600-800 |
800-1000 |
决定响应速度 |
| Ki |
100-200 |
150-250 |
消除稳态误差 |
| Kd |
30-80 |
50-100 |
抑制超调震荡 |
2. 整定步骤
1. 先调CC模式:设置目标电流1000mA,逐步增大Kp直到电流快速跟随
2. 再加入Ki:消除电流稳态误差,避免积分饱和
3. 最后调CV模式:设置目标电压4200mV,用Kd抑制电压超调
4. 切换测试:验证CC→CV切换时的平滑性
参考代码 AVR智能充电器PID算法程序 www.youwenfan.com/contentcnt/123398.html
四、扩展功能
1. 温度补偿充电
// 根据电池温度调整充电电压
uint16_t Get_Temperature_Compensated_Voltage(uint16_t temp) {
// 锂电:-3mV/℃/cell,25℃基准
int16_t compensation = (25 - temp) * 3; // 温度补偿量
return 4200 + compensation; // 补偿后的目标电压
}
2. 电池类型识别
// 识别电池类型(锂电/铅酸)
BatteryType_t Identify_Battery(void) {
uint16_t voltage = Get_Battery_Voltage();
if (voltage < 2000) return BATTERY_LIION; // <2V:锂电池
else if (voltage < 3000) return BATTERY_LEAD_ACID; // 2-3V:铅酸电池
else return BATTERY_UNKNOWN;
}
五、调试建议
- 安全第一:先断开电池,用可调电阻模拟电池负载调试PID
- 分步验证:先验证PWM输出→再验证ADC采样→最后整定PID
- 保护测试:故意制造过压/过流条件,验证保护功能是否生效
- 散热设计:MOSFET和大电流路径要做好散热,避免热失控