含PD协议通信、电池管理、充电控制和状态显示等功能。
1#include <reg52.h> 2#include <intrins.h> 3 4// 硬件引脚定义 5sbit USB_CC1 = P1^0; // Type-C CC1检测引脚 6sbit USB_CC2 = P1^1; // Type-C CC2检测引脚 7sbit USB_DM = P1^2; // USB D- 引脚 8sbit USB_DP = P1^3; // USB D+ 引脚 9sbit LED_RED = P2^0; // 红色LED指示灯 10sbit LED_GREEN = P2^1; // 绿色LED指示灯 11sbit LED_BLUE = P2^2; // 蓝色LED指示灯 12sbit CHG_EN = P3^0; // 充电使能控制 13sbit DIS_EN = P3^1; // 放电使能控制 14sbit KEY = P3^2; // 功能按键 15 16// ADC通道定义 17#define ADC_BAT_VOLT 0 // 电池电压检测通道 18#define ADC_BAT_TEMP 1 // 电池温度检测通道 19#define ADC_OUT_VOLT 2 // 输出电压检测通道 20#define ADC_OUT_CURR 3 // 输出电流检测通道 21 22// PD协议相关定义 23#define PD_SOURCE_CAPABILITIES 0x01 24#define PD_REQUEST 0x02 25#define PD_ACCEPT 0x03 26#define PD_REJECT 0x04 27#define PD_PS_RDY 0x05 28 29// 电压档位定义 (单位: 0.1V) 30#define VOLT_5V 50 31#define VOLT_9V 90 32#define VOLT_12V 120 33#define VOLT_15V 150 34#define VOLT_20V 200 35 36// 全局变量 37unsigned char pd_voltage = VOLT_5V; // 当前输出电压档位 38unsigned char battery_level = 0; // 电池电量百分比 39unsigned char pd_connected = 0; // PD设备连接状态 40unsigned char charging_state = 0; // 充电状态 41 42// 函数声明 43void System_Init(void); 44void Timer0_Init(void); 45void ADC_Init(void); 46void PD_Protocol_Handler(void); 47void Battery_Management(void); 48void Charging_Control(void); 49void LED_Display(void); 50unsigned int Read_ADC(unsigned char channel); 51void Delay_ms(unsigned int ms); 52void UART_Send_Byte(unsigned char dat); 53void UART_Send_String(char *s); 54 55// 主函数 56void main(void) 57{ 58 System_Init(); // 系统初始化 59 Timer0_Init(); // 定时器初始化 60 ADC_Init(); // ADC初始化 61 62 EA = 1; // 开启总中断 63 64 UART_Send_String("PD Power Bank Started\r\n"); 65 66 while(1) 67 { 68 PD_Protocol_Handler(); // PD协议处理 69 Battery_Management(); // 电池管理 70 Charging_Control(); // 充放电控制 71 LED_Display(); // LED状态显示 72 } 73} 74 75// 系统初始化 76void System_Init(void) 77{ 78 // 设置IO方向 79 P1 = 0xFF; // P1口输入 80 P2 = 0x00; // P2口输出 81 P3 = 0x04; // P3.2为输入,其他输出 82 83 // 初始状态 84 CHG_EN = 0; // 充电禁用 85 DIS_EN = 0; // 放电禁用 86 LED_RED = 0; 87 LED_GREEN = 0; 88 LED_BLUE = 0; 89} 90 91// 定时器0初始化 (用于1ms定时) 92void Timer0_Init(void) 93{ 94 TMOD |= 0x01; // 定时器0,模式1 95 TH0 = 0xFC; // 1ms定时 96 TL0 = 0x66; 97 ET0 = 1; // 允许定时器0中断 98 TR0 = 1; // 启动定时器0 99} 100 101// ADC初始化 102void ADC_Init(void) 103{ 104 P1ASF = 0x0F; // 设置P1.0-P1.3为模拟输入 105 ADC_RES = 0; 106 ADC_CONTR = 0x80; // 开启ADC电源,ADC转换速度设为最慢 107} 108 109// 定时器0中断服务函数 110void Timer0_ISR() interrupt 1 111{ 112 static unsigned int timer_count = 0; 113 114 TH0 = 0xFC; // 重装初值 115 TL0 = 0x66; 116 117 timer_count++; 118 119 // 每100ms执行一次 120 if(timer_count >= 100) 121 { 122 timer_count = 0; 123 124 // 检测按键 125 if(KEY == 0) 126 { 127 Delay_ms(20); // 消抖 128 if(KEY == 0) 129 { 130 // 循环切换电压档位 131 if(pd_voltage == VOLT_5V) pd_voltage = VOLT_9V; 132 else if(pd_voltage == VOLT_9V) pd_voltage = VOLT_12V; 133 else if(pd_voltage == VOLT_12V) pd_voltage = VOLT_15V; 134 else if(pd_voltage == VOLT_15V) pd_voltage = VOLT_20V; 135 else pd_voltage = VOLT_5V; 136 137 UART_Send_String("Voltage Changed: "); 138 UART_Send_Byte(pd_voltage/10 + '0'); 139 UART_Send_Byte('.'); 140 UART_Send_Byte(pd_voltage%10 + '0'); 141 UART_Send_String("V\r\n"); 142 143 // 等待按键释放 144 while(KEY == 0); 145 } 146 } 147 } 148} 149 150// PD协议处理 151void PD_Protocol_Handler(void) 152{ 153 static unsigned char last_cc1, last_cc2; 154 unsigned char current_cc1, current_cc2; 155 156 // 读取CC引脚状态 157 current_cc1 = USB_CC1; 158 current_cc2 = USB_CC2; 159 160 // 检测连接状态变化 161 if((current_cc1 != last_cc1) || (current_cc2 != last_cc2)) 162 { 163 last_cc1 = current_cc1; 164 last_cc2 = current_cc2; 165 166 // 判断连接状态 167 if((current_cc1 == 0) || (current_cc2 == 0)) 168 { 169 pd_connected = 1; 170 UART_Send_String("PD Device Connected\r\n"); 171 172 // 发送电源能力信息 173 PD_Send_Source_Capabilities(); 174 } 175 else 176 { 177 pd_connected = 0; 178 DIS_EN = 0; // 禁用放电 179 UART_Send_String("PD Device Disconnected\r\n"); 180 } 181 } 182 183 // 如果已连接,处理PD通信 184 if(pd_connected) 185 { 186 // 模拟PD通信(实际应用中需使用专用PD芯片或软件实现) 187 if(PD_Receive_Message()) 188 { 189 // 处理接收到的PD消息 190 PD_Process_Message(); 191 } 192 } 193} 194 195// 发送电源能力信息 196void PD_Send_Source_Capabilities(void) 197{ 198 // 实际应用中需通过USB PD物理层发送 199 UART_Send_String("Sending Source Capabilities\r\n"); 200 UART_Send_String("5V/3A, 9V/3A, 12V/3A, 15V/3A, 20V/3A\r\n"); 201} 202 203// 接收PD消息(模拟) 204unsigned char PD_Receive_Message(void) 205{ 206 // 简化的模拟接收 207 static unsigned char counter = 0; 208 209 if(counter++ > 100) 210 { 211 counter = 0; 212 return 1; // 模拟接收到消息 213 } 214 return 0; 215} 216 217// 处理PD消息 218void PD_Process_Message(void) 219{ 220 // 模拟处理PD消息 221 UART_Send_String("Received PD Request\r\n"); 222 223 // 发送接受响应 224 UART_Send_String("Sending PD Accept\r\n"); 225 226 // 发送电源准备好消息 227 UART_Send_String("Sending Power Ready\r\n"); 228 229 // 使能放电 230 DIS_EN = 1; 231 UART_Send_String("Output Enabled\r\n"); 232} 233 234// 电池管理 235void Battery_Management(void) 236{ 237 unsigned int bat_voltage, bat_temp; 238 static unsigned char bat_counter = 0; 239 240 // 每100ms读取一次电池参数 241 if(bat_counter++ >= 10) 242 { 243 bat_counter = 0; 244 245 // 读取电池电压 (单位: mV) 246 bat_voltage = Read_ADC(ADC_BAT_VOLT) * 10; // 假设ADC值对应mV 247 248 // 读取电池温度 (单位: 0.1℃) 249 bat_temp = Read_ADC(ADC_BAT_TEMP); 250 251 // 计算电池电量 (简化算法) 252 if(bat_voltage > 4200) battery_level = 100; 253 else if(bat_voltage > 4100) battery_level = 90; 254 else if(bat_voltage > 4000) battery_level = 80; 255 else if(bat_voltage > 3900) battery_level = 70; 256 else if(bat_voltage > 3800) battery_level = 60; 257 else if(bat_voltage > 3700) battery_level = 50; 258 else if(bat_voltage > 3600) battery_level = 40; 259 else if(bat_voltage > 3500) battery_level = 30; 260 else if(bat_voltage > 3400) battery_level = 20; 261 else if(bat_voltage > 3300) battery_level = 10; 262 else battery_level = 0; 263 264 // 电池保护 265 if(bat_voltage < 3200) // 过放保护 266 { 267 DIS_EN = 0; // 禁用放电 268 CHG_EN = 1; // 强制充电 269 UART_Send_String("Battery Under Voltage! Charging Enabled\r\n"); 270 } 271 272 if(bat_temp > 500) // 温度过高 (50℃) 273 { 274 DIS_EN = 0; // 禁用放电 275 CHG_EN = 0; // 禁用充电 276 UART_Send_String("Battery Over Temperature! Charging/Discharging Disabled\r\n"); 277 } 278 } 279} 280 281// 充放电控制 282void Charging_Control(void) 283{ 284 unsigned int out_voltage, out_current; 285 static unsigned char charge_counter = 0; 286 287 // 每200ms读取一次输出参数 288 if(charge_counter++ >= 20) 289 { 290 charge_counter = 0; 291 292 // 读取输出电压 (单位: mV) 293 out_voltage = Read_ADC(ADC_OUT_VOLT) * 10; 294 295 // 读取输出电流 (单位: mA) 296 out_current = Read_ADC(ADC_OUT_CURR) * 10; 297 298 // 过压保护 299 if(out_voltage > (pd_voltage * 100 + 500)) // 超过设定值0.5V 300 { 301 DIS_EN = 0; // 禁用放电 302 UART_Send_String("Output Over Voltage! Discharging Disabled\r\n"); 303 } 304 305 // 过流保护 306 if(out_current > 3500) // 超过3.5A 307 { 308 DIS_EN = 0; // 禁用放电 309 UART_Send_String("Output Over Current! Discharging Disabled\r\n"); 310 } 311 312 // 短路保护 313 if(out_voltage < 1000 && out_current > 3000) // 电压低于1V且电流大于3A 314 { 315 DIS_EN = 0; // 禁用放电 316 UART_Send_String("Short Circuit Detected! Discharging Disabled\r\n"); 317 } 318 } 319} 320 321// LED状态显示 322void LED_Display(void) 323{ 324 static unsigned char led_counter = 0; 325 326 // LED显示状态 327 if(led_counter++ >= 50) // 每500ms更新一次 328 { 329 led_counter = 0; 330 331 // 充电状态 332 if(charging_state) 333 { 334 // 充电中 - 呼吸灯效果 335 static unsigned char pwm_val = 0; 336 static bit dir = 0; 337 338 if(dir == 0) 339 { 340 if(++pwm_val == 100) dir = 1; 341 } 342 else 343 { 344 if(--pwm_val == 0) dir = 0; 345 } 346 347 // 红色LED呼吸效果 348 if(led_counter < pwm_val) LED_RED = 1; 349 else LED_RED = 0; 350 351 LED_GREEN = 0; 352 LED_BLUE = 0; 353 } 354 else 355 { 356 // 电量显示 357 if(battery_level > 70) 358 { 359 LED_RED = 0; 360 LED_GREEN = 1; // 绿色 - 电量充足 361 LED_BLUE = 0; 362 } 363 else if(battery_level > 30) 364 { 365 LED_RED = 0; 366 LED_GREEN = 0; 367 LED_BLUE = 1; // 蓝色 - 电量中等 368 } 369 else 370 { 371 LED_RED = 1; // 红色 - 电量低 372 LED_GREEN = 0; 373 LED_BLUE = 0; 374 } 375 } 376 377 // PD输出状态 378 if(pd_connected && DIS_EN) 379 { 380 // 输出中 - 蓝色LED闪烁 381 static bit blink = 0; 382 blink = !blink; 383 LED_BLUE = blink; 384 } 385 } 386} 387 388// 读取ADC值 389unsigned int Read_ADC(unsigned char channel) 390{ 391 unsigned int result; 392 393 ADC_CONTR = 0x80 | (channel & 0x07); // 选择通道并启动转换 394 _nop_(); _nop_(); _nop_(); // 等待转换完成 395 396 while(!(ADC_CONTR & 0x10)); // 等待转换完成 397 ADC_CONTR &= ~0x10; // 清除完成标志 398 399 result = ADC_RES; 400 result = (result << 2) | (ADC_RESL & 0x03); // 10位ADC 401 402 return result; 403} 404 405// 延时函数 406void Delay_ms(unsigned int ms) 407{ 408 unsigned int i, j; 409 for(i=0; i<ms; i++) 410 for(j=0; j<120; j++); 411} 412 413// UART发送一个字节 414void UART_Send_Byte(unsigned char dat) 415{ 416 SBUF = dat; 417 while(!TI); 418 TI = 0; 419} 420 421// UART发送字符串 422void UART_Send_String(char *s) 423{ 424 while(*s) 425 { 426 UART_Send_Byte(*s++); 427 } 428} 429
程序功能说明
1. PD协议处理
1void PD_Protocol_Handler(void) 2{ 3 // 检测CC引脚状态变化 4 // 发送电源能力信息 5 // 处理PD请求和响应 6 // 控制输出使能 7} 8
2. 电池管理
1void Battery_Management(void) 2{ 3 // 监测电池电压和温度 4 // 计算电池电量百分比 5 // 实现过放保护和过温保护 6} 7
3. 充放电控制
1void Charging_Control(void) 2{ 3 // 监测输出电压和电流 4 // 实现过压、过流和短路保护 5 // 控制充放电状态 6} 7
4. LED状态显示
1void LED_Display(void) 2{ 3 // 显示电池电量状态 4 // 充电状态呼吸灯效果 5 // PD输出状态指示 6} 7
参考 针对PD协议移动电源进行开发的51单片机控制程序 youwenfan.com/contentcsl/70937.html
硬件连接说明
1. 电源部分
1电池组 + --------[MOSFET]-----+------ USB-C VBUS 2 | | 3电池组 - --------+ | 4 | | 5 +--[升降压电路]--+ 6
2. 控制部分
1STC89C52RC/STC12C5A60S2 2 P1.0 ---- USB CC1 3 P1.1 ---- USB CC2 4 P1.2 ---- USB D- 5 P1.3 ---- USB D+ 6 P1.4 ---- ADC 电池电压检测 7 P1.5 ---- ADC 电池温度检测 8 P1.6 ---- ADC 输出电压检测 9 P1.7 ---- ADC 输出电流检测 10 11 P2.0 ---- LED_RED 12 P2.1 ---- LED_GREEN 13 P2.2 ---- LED_BLUE 14 15 P3.0 ---- CHG_EN (充电使能) 16 P3.1 ---- DIS_EN (放电使能) 17 P3.2 ---- KEY (功能按键) 18
3. PD协议实现方案
由于51单片机本身不支持USB PD协议,本设计采用以下两种方案之一:
方案1:软件模拟PD协议(简化版)
- 通过CC引脚检测连接状态
- 使用UART模拟PD通信
- 支持基本电压档位切换
方案2:专用PD协议芯片
1+-----------------+ +-----------------+ 2| 51 单片机 | I2C | PD协议芯片 | 3| |<-------->| (如CH236D) | 4| | | | 5+--------+--------+ +--------+--------+ 6 | | 7 | | 8 | | 9+--------+--------+ +--------+--------+ 10| 电池管理电路 | | USB-C接口 | 11| 升降压电路 | | | 12| | | | 13+-----------------+ +-----------------+ 14
关键算法详解
1. 电池电量计算
1// 基于电压的简化电量计算 2if(bat_voltage > 4200) battery_level = 100; 3else if(bat_voltage > 4100) battery_level = 90; 4... 5
2. 充电状态呼吸灯
1// 呼吸灯效果实现 2if(dir == 0) { 3 if(++pwm_val == 100) dir = 1; 4} else { 5 if(--pwm_val == 0) dir = 0; 6} 7 8if(led_counter < pwm_val) LED_RED = 1; 9else LED_RED = 0; 10
3. 保护机制
1// 过压保护 2if(out_voltage > (pd_voltage * 100 + 500)) { 3 DIS_EN = 0; 4} 5 6// 过流保护 7if(out_current > 3500) { 8 DIS_EN = 0; 9} 10 11// 短路保护 12if(out_voltage < 1000 && out_current > 3000) { 13 DIS_EN = 0; 14} 15
系统工作流程
- 初始状态
- 所有LED熄灭
- 充放电均禁用
- 检测USB连接
- 设备连接
- 检测CC引脚状态变化
- 发送电源能力信息
- 协商输出电压
- 放电模式
- 使能放电电路
- 监测输出电压电流
- 显示电池电量
- 充电模式
- 检测输入电源
- 使能充电电路
- 实现恒流/恒压充电
- 保护机制
- 电池过放/过温保护
- 输出过压/过流保护
- 短路保护
优化建议
1. 增加快充协议支持
1// 添加QC协议支持 2void QC_Protocol_Handler(void) 3{ 4 // 检测D+/D-电压 5 // 发送QC电压请求 6 // 切换升降压电路输出 7} 8
2. 增加电量计功能
1// 库仑计实现 2void Coulomb_Counter(void) 3{ 4 // 测量充放电电流 5 // 积分计算电量 6 // 更新剩余容量 7} 8
3. 添加OLED显示
1// OLED显示函数 2void OLED_Display(void) 3{ 4 // 显示输出电压电流 5 // 显示电池电量 6 // 显示温度信息 7 // 显示工作状态 8} 9
4. 低功耗优化
1// 休眠模式 2void Enter_Sleep_Mode(void) 3{ 4 // 禁用不需要的外设 5 // 设置IO状态 6 // 进入空闲/掉电模式 7 // 定时唤醒检测 8} 9
测试与调试
1. PD协议测试
- 连接PD充电器,验证5V输出
- 按键切换电压档位,验证9V/12V/15V/20V输出
- 断开连接,验证自动关闭输出
2. 保护功能测试
- 输出端短路,验证短路保护
- 连接大功率负载,验证过流保护
- 电池过放测试,验证充电强制启用
3. 性能测试
- 测量转换效率(输入功率 vs 输出功率)
- 测试输出电压纹波
- 测量不同负载下的电压稳定性
完整系统框架
1+------------------+ 2| 51单片机 | 3| +-----------+ | 4| | PD协议处理 | | 5| +-----------+ | 6| +-----------+ | 7| | 电池管理 | | 8| +-----------+ | 9| +-----------+ | 10| | 充放电控制 | | 11| +-----------+ | 12| +-----------+ | 13| | 状态显示 | | 14| +-----------+ | 15+------------------+ 16 | 17 | 控制信号 18 | 19+------------------+ 20| 电源管理电路 | 21| +-------------+ | 22| | 升降压电路 | | 23| +-------------+ | 24| +-------------+ | 25| | 保护电路 | | 26| +-------------+ | 27+------------------+ 28 | 29 | USB-C 30 | 31+------------------+ 32| 外部设备 | 33+------------------+ 34
这个程序实现了基于51单片机的PD协议移动电源核心控制功能,包括PD协议处理、电池管理、充放电控制和状态显示。程序采用模块化设计,可根据实际硬件进行调整和扩展。
《基于51单片机的PD协议移动电源控制程序》 是转载文章,点击查看原文。