手把手教你用STM32F103和ESP8266 DIY一个带RFID刷卡和手机APP的智能充电桩(附完整代码)

Aowandowski

从零打造智能充电桩: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,但完全能满足一般充电桩的需求。

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的组合,兼具图形化配置和命令行灵活性:

  1. 安装STM32CubeIDE(自带HAL库)
  2. 在VS Code中安装PlatformIO插件
  3. 创建新项目时选择"STM32F103C8"板型
  4. 添加所需库依赖:
    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. 功能扩展思路

基础版本完成后,可以考虑以下增强功能:

  1. 手机蓝牙控制

    • 添加HC-05模块
    • 开发简易APP(MIT App Inventor)
    • 实现近场控制和参数设置
  2. 能量回收显示

    c复制void calculate_energy_saving() {
        float total = get_total_energy();
        float green = get_solar_energy();
        printf("绿色能源占比: %.1f%%\n", green/total*100);
    }
    
  3. 语音提示功能

    • 加入SYN6288语音模块
    • 在关键操作时播放提示音
    • 支持多语言切换
  4. 离线支付系统

    • 集成ATGM336H GPS模块
    • 记录充电位置信息
    • 支持离线扣费和数据补传

在完成所有功能测试后,建议进行72小时连续老化测试,重点关注:

  • 继电器触点是否氧化
  • 无线模块的稳定性
  • 计量精度随时间的变化
  • 外壳在高温下的形变情况

内容推荐

【避坑指南】Tessy 单元测试实战:高频导入难题与排查策略精讲
本文深入解析Tessy单元测试中的高频导入难题,包括头文件路径设置、编码格式问题及递归导入技巧。提供环境配置、接口设置与桩函数实战经验,帮助开发者有效排查和解决常见错误,提升嵌入式C项目的测试效率。
YOLOv5/v8自定义数据集时,你的anchors真的设对了吗?一个实验讲清楚
本文深入探讨了YOLOv5/v8在自定义数据集中anchors设置的重要性,通过实验验证了合理设置anchors对模型性能的显著提升。文章详细介绍了K-means聚类方法计算最佳anchors的步骤,并提供了YOLO内置工具的实际操作指南。实验结果显示,自定义anchors可使mAP提升12.5%,训练时间减少25%,特别适用于工业缺陷检测等特定场景。
CMT2380F32低功耗项目实战:手把手教你搞定LPT长定时与RTC时钟源切换
本文详细介绍了CMT2380F32低功耗项目实战,重点讲解LPT长定时与RTC时钟源切换的实现方法。通过寄存器级操作和混合定时器架构设计,解决射频模块占用外部晶振时的RTC稳定性问题,并突破16位LPT定时器限制,实现小时级超低功耗定时。文章还提供了功耗优化实测数据和可复用的代码框架,助力物联网边缘设备开发。
告别CPU搬运工:手把手教你用Exynos 4412的PL330 DMA实现内存到串口的高速传输
本文详细介绍了如何在Exynos 4412处理器上使用PL330 DMA控制器实现内存到串口的高速数据传输。通过寄存器配置、DMA微指令编程和性能优化技巧,开发者可以显著提升嵌入式系统的数据传输效率,降低CPU负载。文章还提供了UART高速传输的完整实现流程和性能对比测试,展示了DMA技术在嵌入式开发中的实际应用价值。
保姆级教程:小米AX3600路由器刷回旧固件1.0.17,一步步开启SSH权限
本文提供小米AX3600路由器降级至1.0.17固件并开启SSH权限的详细教程。通过实测步骤,帮助用户解决新版固件功能限制问题,获取完整系统权限,适用于技术爱好者进行深度定制和第三方插件安装。
【管理运筹学】运输问题最优解判定:从闭回路到对偶位势的实战解析
本文深入解析运输问题最优解判定的两种核心方法——闭回路法和位势法,帮助读者掌握物流配送和供应链管理中的关键运筹技术。通过实战案例和常见错误分析,详细介绍了闭回路构建技巧、检验数计算要点以及位势法的数学原理与应用场景,为管理运筹学学习者提供实用指导。
告别手动合并!用R包TCGAbiolinks一键搞定TCGA新版突变数据(SNP/MAF)
本文详细介绍了如何使用R包TCGAbiolinks自动化处理TCGA新版突变数据(SNP/MAF),解决手动合并数百个样本文件的繁琐问题。通过一站式数据查询、下载和格式转换,显著提升癌症基因组研究的效率,并与maftools无缝集成进行下游分析。特别适合需要处理大规模TCGA突变数据的研究者。
C++实战指南:解锁STL无序容器unordered_set、unordered_map、unordered_multiset、unordered_multimap的高效应用
本文深入探讨C++ STL无序容器(unordered_set、unordered_map、unordered_multiset、unordered_multimap)的高效应用,通过实战案例展示哈希表在百万级数据处理中的性能优势。文章涵盖从基础原理到高级优化技巧,包括自定义哈希函数、负载因子调优和线程安全方案,帮助开发者提升C++程序性能。
逆向学习神器:用ApkAnalyzer拆解夸克浏览器,看看大厂APP里藏了哪些好东西
本文详细介绍了如何使用Android Studio内置的ApkAnalyzer工具逆向分析夸克浏览器,揭示大厂APP的技术选型和架构设计。通过实战演示,读者可以学习到APK文件结构解析、第三方库依赖分析、安全策略及性能优化技巧,为Android开发提供宝贵参考。
如果你是19世纪的工程师:手把手复盘AC/DC之争中的关键技术与商业决策
本文深度复盘19世纪AC/DC电流战争中的关键技术对比与商业决策,揭示交流电最终胜出的系统原因。从输电效率、设备可靠性到商业模式成本结构,详细分析西屋电气如何通过高压交流输电技术实现电力平民化,并探讨爱迪生团队在舆论战与专利布局中的得失。为现代工程师提供基础设施技术选型的历史镜鉴。
告别盲调!手把手教你用CAPL脚本的on message事件精准捕获CAN报文数据(附完整代码)
本文详细介绍了如何使用CAPL脚本的on message事件精准捕获CAN报文数据,包括环境准备、实战技巧和高级应用。通过示例代码和避坑指南,帮助工程师快速掌握CAN测试中的关键技能,提升车载网络测试效率。
ClickHouse 实战(从入门到精通)
本文详细介绍了ClickHouse从入门到精通的实战指南,包括安装部署、表设计、数据导入、高效查询、性能优化、集群部署及监控运维等内容。通过电商数据分析案例,展示了ClickHouse在处理海量数据实时分析方面的卓越性能,帮助开发者快速掌握这一列式数据库的核心技术。
手把手教你用微软官方工具制作Win10安装U盘(含VMD/IRST驱动问题解决)
本文详细介绍了使用微软官方工具制作Win10安装U盘的完整流程,并针对12/13代酷睿平台常见的VMD/IRST驱动兼容性问题提供了解决方案。从准备工作到BIOS设置调整,再到手动加载驱动,手把手教你顺利完成Windows10系统安装,特别适合需要重装系统的用户。
从TNS配置到防火墙:一次彻底解决Oracle ORA-12541错误的完整排查指南
本文详细解析了Oracle数据库常见的ORA-12541错误,提供从TNS配置到防火墙设置的完整排查指南。通过系统性检查监听器状态、配置文件对比、网络连通性测试等方法,帮助DBA快速定位并解决监听器不可用的问题,同时建立长效预防机制。
手把手教你用C代码实现Autosar E2E Profile01的发送与校验(附完整工程)
本文详细介绍了如何使用C代码实现Autosar E2E Profile01的发送与校验,包括硬件级实现原理、发送端和接收端的完整方案,以及工程实践中的分层架构和性能优化技巧。通过深度调试指南和完整工程示例,帮助开发者构建符合ASIL等级要求的汽车电子通信保护方案。
告别远程更新焦虑:用Xilinx FPGA的Multiboot功能,给你的产品固件上‘双保险’
本文深入解析Xilinx FPGA的Multiboot技术,通过Golden Image+Update Image双镜像架构解决工业设备远程更新的可靠性问题。详细介绍了WBSTAR寄存器配置、看门狗超时机制等关键技术,帮助工程师构建具备自愈能力的固件更新方案,显著降低现场维护成本。
别再死记硬背了!用一张图搞懂SPI、IIC、UART、RS485的区别与选型
本文深入解析SPI、I2C、UART和RS485四种主流嵌入式通信协议的核心差异与选型策略。通过速度、距离、线数和拓扑结构等关键参数的对比,帮助工程师在实际项目中做出最优选择,并提供了硬件设计中的常见陷阱与解决方案,如I2C上拉电阻计算和SPI片选风暴问题。
Ubuntu20.04 ROS noetic下LIO-SAM实战:从编译到建图的全流程避坑指南
本文详细介绍了在Ubuntu20.04 ROS noetic环境下部署LIO-SAM的全流程,包括环境配置、依赖安装、编译调试、建图实战及性能优化。特别针对常见编译错误和运行问题提供了实用解决方案,帮助开发者快速掌握LIO-SAM在SLAM领域的应用技巧。
从网关超时到服务恢复:深入剖析HTTP 504错误的根源与实战修复指南
本文深入剖析HTTP 504 Gateway Timeout错误的根源与修复方法,涵盖网络层问题、网关配置、后端服务性能等六大常见原因,并提供实战诊断流程与预防体系搭建建议,帮助开发者快速定位和解决这一影响用户体验的关键错误。
避坑指南:Stata做交互效应图时,连续变量和分类变量到底该怎么标记?(c. vs i.)
本文详细解析了Stata中连续变量与分类变量在交互效应可视化中的正确标记方法,重点介绍了`c.`和`i.`前缀的使用场景及常见错误。通过logistic回归和交互项分析的实际案例,帮助用户避免可视化分析中的常见陷阱,提升统计建模的准确性。
已经到底了哦
精选内容
热门内容
最新内容
从社区到商业:解析国产主流操作系统的技术谱系与选型指南(优麒麟、开放麒麟、deepin、UOS、银河麒麟)
本文深入解析国产主流操作系统(优麒麟、开放麒麟、deepin、UOS、银河麒麟)的技术谱系与选型指南。从社区版到商业发行版,详细比较各系统的技术渊源、适用场景及优劣势,帮助开发者和企业根据硬件兼容性、软件生态、安全要求等维度做出明智选择。特别推荐优麒麟和deepin作为个人开发者的首选,UOS和银河麒麟则更适合企业级应用。
解锁RabbitMQ插件生态:从延迟队列到消息审计的实战指南
本文深入探讨RabbitMQ插件生态系统的实战应用,从延迟队列到消息审计的全面指南。通过详细解析插件分类、安装步骤及性能优化技巧,帮助开发者高效利用社区插件扩展RabbitMQ功能,提升消息处理能力与系统可靠性。重点介绍了延迟队列插件rabbitmq_delayed_message_exchange的实战案例与调优方案。
STM32 IAP升级避坑指南:从‘跳转就死’到‘丝滑切换’的完整配置流程(基于HAL库)
本文详细解析了STM32 IAP升级中常见的‘跳转就死’问题,提供了基于HAL库的完整解决方案。从时钟配置冲突、外设状态残留到内存管理陷阱,全面剖析问题根源,并给出五种主流跳转策略的实战分析。通过工业级配置流程和优化技巧,实现从故障频发到‘丝滑切换’的转变,特别适合需要稳定OTA升级的嵌入式开发者。
告别sudo!手把手教你用普通用户安全运行Docker(Rootless模式实战)
本文详细介绍了Docker Rootless模式的安装与配置方法,帮助普通用户无需sudo权限即可安全运行Docker容器。通过用户命名空间隔离和守护进程降权运行等核心安全机制,有效降低容器逃逸风险,同时保持大部分Docker功能的可用性。文章包含完整的安装步骤、使用限制及生产环境部署建议,是提升容器安全性的实用指南。
告别拉伸丑界面!Qt Designer布局实战:用Spacer和布局管理器搞定控件自适应
本文详细介绍了如何使用Qt Designer中的Spacer和布局管理器实现控件自适应,解决界面拉伸时的混乱问题。通过五种基础布局类型和Spacer的巧妙应用,帮助开发者打造专业级自适应界面,提升用户体验和开发效率。
WPF Grid布局实战:巧用Auto与*打造自适应界面
本文深入探讨WPF Grid布局中Auto与*属性的实战应用,帮助开发者打造自适应界面。通过详细解析Auto按内容自适应和*按比例分配空间的特性,结合Grid.ColumnSpan等高级技巧,实现复杂布局设计。文章包含多语言适配、比例分配调试等实用场景,是提升WPF界面开发效率的必备指南。
别再手动勾图了!用GEE的MODIS和Landsat数据,5分钟自动提取高精度农田边界(附完整代码)
本文介绍如何利用Google Earth Engine(GEE)平台,结合MODIS和Landsat数据,实现农田边界的全自动提取。通过高效的云计算能力和丰富的遥感数据集,将原本耗时数小时的手动勾绘工作缩短至5分钟内完成,大幅提升农业遥感与土地利用调查的效率。
【STM32篇】LCD动态显示GBK汉字(基于W25Q64字库缓存与SPI DMA优化)
本文详细介绍了在STM32项目中实现LCD动态显示GBK汉字的优化方案,重点讲解了基于W25Q64字库缓存与SPI DMA的技术实现。通过外部字库存储和DMA传输优化,有效解决了内部Flash空间不足和显示卡顿问题,适用于智能家居、嵌入式菜单等需要高效汉字显示的场合。
告别配对数据烦恼:用Zero-DCE无监督增强你的夜间照片(附PyTorch代码实战)
本文详细介绍了Zero-DCE技术在夜间照片无监督增强中的应用,通过PyTorch代码实战展示了其核心算法和实现步骤。Zero-DCE无需配对数据,通过自适应曲线体系和四重损失函数,显著提升低光照片的细节可视度,是夜间摄影的理想解决方案。
别再纠结高德SDK收费了!手把手教你用URI协议免费唤醒高德/百度地图(附uniapp完整代码)
本文详细介绍了如何通过URI协议免费唤醒高德/百度地图实现导航功能,特别适合预算有限的独立开发者和初创团队。文章对比了URI协议与官方SDK的优缺点,提供了UniApp跨平台实现代码,并解析了高德和百度地图的URI协议规范,帮助开发者快速集成基础导航功能。