从零打造智能充电桩:STM32F103+ESP8266实战指南
1. 项目规划与硬件选型
在开始动手之前,我们需要明确项目的核心需求和功能模块。这个智能充电桩需要实现刷卡启动、电量计量、安全保护和远程监控四大核心功能。经过多次方案对比和成本考量,我最终选择了以下硬件组合:
核心控制器:STM32F103C8T6(蓝色pill开发板)
- 72MHz Cortex-M3内核,64KB Flash,20KB RAM
- 丰富的外设接口(USART、SPI、I2C、ADC)
- 性价比极高(约15元/片),社区资源丰富
无线通信模块:ESP8266-01S
- 支持802.11 b/g/n WiFi协议
- 内置TCP/IP协议栈
- 通过AT指令或直接编程控制
- 价格仅需10元左右
RFID读卡器:RC522模块
- 支持ISO14443A协议
- 工作频率13.56MHz
- 读取距离约3-5cm
- SPI接口,配套白卡成本低廉
电力监测方案对比:
| 传感器类型 | 型号 | 精度 | 接口 | 成本 | 适用场景 |
|---|---|---|---|---|---|
| 霍尔传感器 | ACS712 | ±1% | 模拟量 | 中 | 中等精度直流测量 |
| 电流芯片 | INA226 | ±0.1% | I2C | 高 | 高精度电能计量 |
| 分流电阻 | 75mV/50A | ±2% | 模拟量 | 低 | 大电流低成本方案 |
考虑到DIY项目的成本因素,我选择了ACS712+分压电阻的方案,虽然精度稍逊于INA226,但完全能满足一般充电桩的需求。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 硬件电路设计与组装
2.1 电源系统设计
充电桩的电源系统需要为各模块提供稳定工作电压:
code复制[220V AC] → [开关电源] → [12V DC] → [LM2596] → 5V → [AMS1117] → 3.3V
↓
[继电器控制端]
关键元件选型:
- 主继电器:选用30A容量的HFD4系列,带灭弧设计
- 保险丝:在AC输入端串联10A玻璃管保险
- 防反接保护:在DC侧加入SS34肖特基二极管
注意:强电部分务必做好绝缘处理,建议使用热缩管和端子排,避免裸露导线。
2.2 核心模块连接
STM32与各模块的连接方式如下:
c复制// RC522 (SPI1)
#define RFID_CS_PIN PA4
#define RFID_RST_PIN PA3
#define RFID_SCK_PIN PA5
#define RFID_MISO_PIN PA6
#define RFID_MOSI_PIN PA7
// ESP8266 (USART2)
#define ESP_TX_PIN PA2
#define ESP_RX_PIN PA3
// ACS712 (ADC1)
#define VOLTAGE_ADC PA0
#define CURRENT_ADC PA1
// 继电器控制
#define RELAY_PIN PC13
实际焊接时,我推荐使用杜邦线先搭建原型,验证无误后再用焊锡固定。特别要注意的是:
- ESP8266的CH_PD引脚需要上拉至3.3V
- RC522的天线区域不要被金属物体遮挡
- ACS712的VCC和GND要并联0.1μF去耦电容
3. 软件开发环境搭建
3.1 工具链配置
我选择的是STM32CubeIDE + PlatformIO的组合,兼具图形化配置和命令行灵活性:
- 安装STM32CubeIDE(自带HAL库)
- 在VS Code中安装PlatformIO插件
- 创建新项目时选择"STM32F103C8"板型
- 添加所需库依赖:
ini复制lib_deps = miguelbalboa/MFRC522@^1.4.10 bblanchon/ArduinoJson@^6.19.4
3.2 FreeRTOS任务划分
系统软件架构采用多任务设计,各任务优先级如下:
| 任务名称 | 优先级 | 堆栈大小 | 功能描述 |
|---|---|---|---|
| SafetyMonitor | 4 | 256 | 实时监测电压电流温度 |
| RFIDHandler | 3 | 512 | 处理刷卡事件和计费逻辑 |
| NetworkManager | 2 | 1024 | MQTT通信和云端数据同步 |
| UIDisplay | 1 | 384 | 刷新OLED界面 |
任务间通信采用FreeRTOS的队列机制:
c复制// 定义事件消息结构体
typedef struct {
uint8_t event_type;
union {
float sensor_value;
uint8_t card_uid[10];
char mqtt_msg[64];
} data;
} EventMessage_t;
// 创建全局事件队列
QueueHandle_t xEventQueue = xQueueCreate(10, sizeof(EventMessage_t));
4. 核心功能代码实现
4.1 电力监测与安全保护
电压电流的采集需要特别注意滤波处理:
c复制#define SAMPLE_COUNT 20
float read_filtered_voltage(void) {
static float buffer[SAMPLE_COUNT];
static uint8_t index = 0;
// 原始ADC读取
float raw = (float)adc_read(VOLTAGE_ADC) * 3.3 / 4096.0;
// 转换为实际电压(分压比11:1)
float voltage = raw * 11.0;
// 移动平均滤波
buffer[index] = voltage;
index = (index + 1) % SAMPLE_COUNT;
float sum = 0;
for(int i=0; i<SAMPLE_COUNT; i++) {
sum += buffer[i];
}
return sum / SAMPLE_COUNT;
}
void SafetyMonitor_Task(void *pvParameters) {
const TickType_t xFrequency = pdMS_TO_TICKS(100);
TickType_t xLastWakeTime = xTaskGetTickCount();
for(;;) {
float v = read_filtered_voltage();
float i = read_filtered_current();
float t = read_temperature();
if(v > OVER_VOLTAGE || i > OVER_CURRENT) {
HAL_GPIO_WritePin(RELAY_GPIO_Port, RELAY_Pin, GPIO_PIN_RESET);
EventMessage_t msg = { .event_type = EVENT_FAULT };
xQueueSend(xEventQueue, &msg, 0);
}
vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
}
4.2 RFID计费系统实现
刷卡逻辑需要考虑防重入和异常处理:
c复制void RFID_Task(void *pvParameters) {
MFRC522 mfrc;
MFRC522_Init(&mfrc, hspi1, RFID_CS_PIN, RFID_RST_PIN);
for(;;) {
if(MFRC522_Check(&mfrc)) {
uint8_t uid[10];
MFRC522_GetUID(&mfrc, uid);
EventMessage_t msg;
msg.event_type = EVENT_CARD;
memcpy(msg.data.card_uid, uid, 10);
if(xQueueSend(xEventQueue, &msg, 100) != pdPASS) {
printf("RFID: Queue full!\n");
}
// 防抖延时
vTaskDelay(pdMS_TO_TICKS(500));
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}
计费算法支持时间和电量两种模式:
c复制typedef enum {
MODE_TIME, // 按时计费
MODE_ENERGY // 按电量计费
} ChargeMode;
typedef struct {
uint8_t uid[10];
float balance;
time_t start_time;
float start_energy;
ChargeMode mode;
} UserCard;
float calculate_charge(UserCard *card) {
float amount = 0;
time_t now = time(NULL);
if(card->mode == MODE_TIME) {
float hours = (now - card->start_time) / 3600.0;
amount = hours * TIME_RATE;
} else {
float energy = get_current_energy() - card->start_energy;
amount = energy * ENERGY_RATE;
}
return amount;
}
4.3 ESP8266联网功能
MQTT通信采用异步处理方式:
c复制void mqtt_callback(char* topic, byte* payload, unsigned int length) {
char msg[length+1];
memcpy(msg, payload, length);
msg[length] = '\0';
if(strcmp(topic, "charge/cmd") == 0) {
if(strstr(msg, "stop")) {
emergency_stop();
}
}
}
void Network_Task(void *pvParameters) {
WiFiClient espClient;
PubSubClient client(espClient);
client.setServer(MQTT_SERVER, 1883);
client.setCallback(mqtt_callback);
for(;;) {
if(!client.connected()) {
reconnect_mqtt(&client);
}
client.loop();
// 每5秒上报数据
static uint32_t last_report = 0;
if(HAL_GetTick() - last_report > 5000) {
report_status(&client);
last_report = HAL_GetTick();
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}
数据上报采用JSON格式:
json复制{
"voltage": 54.2,
"current": 8.5,
"power": 460,
"energy": 1.2,
"status": "charging",
"card": "A1B2C3D4"
}
5. 调试技巧与问题排查
在开发过程中,我遇到了几个典型问题及解决方案:
问题1:ESP8266频繁断连
- 现象:MQTT连接每10分钟左右断开
- 排查:用串口监视器发现WiFi信号强度波动大
- 解决:在代码中添加WiFi信号检测和自动重连逻辑
c复制void check_wifi_strength() { int8_t rssi = WiFi.RSSI(); if(rssi < -80) { WiFi.reconnect(); } }
问题2:RFID读卡不稳定
- 现象:有时需要刷多次才能识别
- 排查:用逻辑分析仪发现SPI时钟不稳定
- 解决:调整SPI时钟分频系数,并优化天线匹配电路
c复制
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
问题3:计量误差偏大
- 现象:电量计量与实际相差约8%
- 排查:发现ACS712存在零点漂移
- 解决:增加自动校准功能
c复制void calibrate_current_sensor() { float sum = 0; for(int i=0; i<100; i++) { sum += adc_read(CURRENT_ADC); HAL_Delay(10); } zero_offset = sum / 100; }
6. 外壳设计与安装建议
为了让项目更接近产品形态,我使用3D打印制作了防护外壳:
结构设计要点:
- 分体式设计:前盖可拆卸,方便维护
- 散热孔:在继电器和电源模块上方开孔
- 防水处理:接缝处加装橡胶密封条
- 固定孔位:兼容标准86盒安装
材料选择对比:
| 材料类型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| PLA | 易打印 | 耐温性差 | 室内原型 |
| ABS | 强度高 | 需要加热床 | 一般户外 |
| PETG | 耐候性好 | 价格较高 | 严苛环境 |
最终我选择了PETG材料,虽然打印温度需要控制在230-250℃,但长期户外使用不易变形开裂。
7. 功能扩展思路
基础版本完成后,可以考虑以下增强功能:
-
手机蓝牙控制:
- 添加HC-05模块
- 开发简易APP(MIT App Inventor)
- 实现近场控制和参数设置
-
能量回收显示:
c复制void calculate_energy_saving() { float total = get_total_energy(); float green = get_solar_energy(); printf("绿色能源占比: %.1f%%\n", green/total*100); } -
语音提示功能:
- 加入SYN6288语音模块
- 在关键操作时播放提示音
- 支持多语言切换
-
离线支付系统:
- 集成ATGM336H GPS模块
- 记录充电位置信息
- 支持离线扣费和数据补传
在完成所有功能测试后,建议进行72小时连续老化测试,重点关注:
- 继电器触点是否氧化
- 无线模块的稳定性
- 计量精度随时间的变化
- 外壳在高温下的形变情况
