STM32实战:基于STM32F103的智能共享充电宝管理系统

文章目录

    • 一、前言
      • [1.1 技术背景](#1.1 技术背景)
      • [1.2 应用场景](#1.2 应用场景)
      • [1.3 读者收获](#1.3 读者收获)
      • [1.4 技术栈](#1.4 技术栈)
    • 二、环境准备
      • [2.1 硬件准备](#2.1 硬件准备)
      • [2.2 软件安装](#2.2 软件安装)
    • 三、系统架构设计
      • [3.1 系统总体架构](#3.1 系统总体架构)
      • [3.2 机柜硬件结构](#3.2 机柜硬件结构)
      • [3.3 硬件连接](#3.3 硬件连接)
    • 四、核心代码实现
      • [4.1 系统配置文件](#4.1 系统配置文件)
      • [4.2 电磁锁控制模块](#4.2 电磁锁控制模块)
      • [4.3 仓位检测模块](#4.3 仓位检测模块)
      • [4.4 租借流程控制](#4.4 租借流程控制)
      • [4.5 主程序](#4.5 主程序)
    • 五、故障排查与问题解决
    • 六、测试验证
      • [6.1 功能测试](#6.1 功能测试)
    • 七、总结
      • [7.1 核心知识点回顾](#7.1 核心知识点回顾)
      • [7.2 扩展方向](#7.2 扩展方向)

一、前言

1.1 技术背景

共享充电宝作为移动互联网时代的新兴服务,已广泛应用于商场、餐厅、车站等公共场所。传统充电宝租借设备存在管理效率低、计费不精准、用户体验差等问题。基于STM32的智能充电宝管理系统通过集成多种传感器、实现精准计费、提供友好的用户交互,能够大幅提升运营效率和用户体验。

STM32F103微控制器凭借其丰富的外设接口、可靠的性能和低成本优势,非常适合用于共享充电宝机柜的控制核心。

1.2 应用场景

本系统适用于以下场景:

  • 商场/购物中心充电宝租借点
  • 餐厅/咖啡厅桌面充电站
  • 车站/机场候机楼充电柜
  • 景区/公园便民充电点

1.3 读者收获

完成本教程后,你将能够:

  • 掌握电磁锁控制与状态检测
  • 实现充电宝在位检测与电量监测
  • 设计扫码租借与归还流程
  • 掌握OLED显示和语音播报控制
  • 实现4G/WiFi联网与云端通信

1.4 技术栈

硬件平台:

  • 主控芯片:STM32F103C8T6
  • 锁控模块:电磁锁 × 6(6仓位机柜)
  • 检测模块:霍尔传感器(仓位检测)
  • 电量检测:ADC分压电路(充电宝电量)
  • 显示模块:OLED 128x64
  • 语音模块:JQ8400语音播报模块
  • 通信模块:ESP8266 WiFi / Air724 4G模块
  • 扫码模块:二维码扫描头(可选)

软件工具:

  • 开发环境:Keil MDK-ARM 5
  • 固件库:STM32标准外设库
  • 编程语言:C语言

二、环境准备

2.1 硬件准备

核心模块:

  • STM32F103C8T6最小系统板 × 1
  • ST-Link V2下载器 × 1

锁控与检测:

  • 电磁锁(5V/2A)× 6
  • 霍尔传感器(A3144)× 6
  • MOSFET驱动电路(IRF540N)× 6

交互模块:

  • 0.96寸OLED显示屏 × 1
  • JQ8400语音模块 × 1
  • 按键 × 2(租借/归还)
  • LED指示灯 × 6(仓位状态)

通信模块:

  • ESP8266-01S WiFi模块 × 1
  • 或 Air724 4G模块 × 1

2.2 软件安装

Keil MDK-ARM 安装:

  1. 下载并安装Keil MDK-ARM 5.38
  2. 安装STM32F1系列Device Family Pack

三、系统架构设计

3.1 系统总体架构

通信层
设备层
云平台
用户层
手机APP/小程序
扫码租借
在线支付
订单管理
计费系统
设备监控
数据分析
STM32F103主控
电磁锁控制
仓位检测
电量检测
OLED显示
语音播报
LED指示
4G/WiFi模块
仓位1
仓位2
仓位6

3.2 机柜硬件结构

复制代码
┌─────────────────────────────────────┐
│         共享充电宝机柜               │
│  ┌─────┐ ┌─────┐ ┌─────┐           │
│  │  1  │ │  2  │ │  3  │  ← 仓位   │
│  │ 🔋  │ │ 🔋  │ │ 🔒  │           │
│  └─────┘ └─────┘ └─────┘           │
│  ┌─────┐ ┌─────┐ ┌─────┐           │
│  │  4  │ │  5  │ │  6  │           │
│  │ 🔋  │ │ 🔒  │ │ 🔋  │           │
│  └─────┘ └─────┘ └─────┘           │
│                                     │
│  [OLED显示屏]  [租借] [归还]        │
│                                     │
└─────────────────────────────────────┘

🔋 = 有充电宝  🔒 = 空仓

3.3 硬件连接

STM32F103引脚分配:

功能模块 引脚分配 说明
电磁锁1-6 PB0-PB5 锁控输出
霍尔传感器1-6 PA0-PA5 仓位检测
电量检测1-6 ADC1_IN6-IN11 电量采集
OLED_SDA PB7 I2C数据
OLED_SCL PB6 I2C时钟
语音模块TX PA9 USART1
语音模块RX PA10 USART1
WiFi_TX PA2 USART2
WiFi_RX PA3 USART2
按键租借 PB8 输入
按键归还 PB9 输入
LED1-6 PC0-PC5 状态指示

四、核心代码实现

4.1 系统配置文件

📄 创建文件:system_config.h

c 复制代码
/**
 * @file system_config.h
 * @brief 共享充电宝系统配置文件
 */

#ifndef __SYSTEM_CONFIG_H
#define __SYSTEM_CONFIG_H

#include "stm32f10x.h"

/* ==================== 硬件参数 ==================== */

#define SLOT_COUNT              6       // 仓位数量
#define LOCK_OPEN_TIME          3000    // 开锁保持时间(ms)
#define LOCK_PWM_FREQ           1000    // 锁控PWM频率

/* ==================== 引脚定义 ==================== */

// 电磁锁控制引脚
#define LOCK1_PIN       GPIO_Pin_0
#define LOCK2_PIN       GPIO_Pin_1
#define LOCK3_PIN       GPIO_Pin_2
#define LOCK4_PIN       GPIO_Pin_3
#define LOCK5_PIN       GPIO_Pin_4
#define LOCK6_PIN       GPIO_Pin_5
#define LOCK_PORT       GPIOB

// 霍尔传感器引脚
#define HALL1_PIN       GPIO_Pin_0
#define HALL2_PIN       GPIO_Pin_1
#define HALL3_PIN       GPIO_Pin_2
#define HALL4_PIN       GPIO_Pin_3
#define HALL5_PIN       GPIO_Pin_4
#define HALL6_PIN       GPIO_Pin_5
#define HALL_PORT       GPIOA

// ADC通道(电量检测)
#define ADC_BAT1        ADC_Channel_6
#define ADC_BAT2        ADC_Channel_7
#define ADC_BAT3        ADC_Channel_8
#define ADC_BAT4        ADC_Channel_9
#define ADC_BAT5        ADC_Channel_10
#define ADC_BAT6        ADC_Channel_11

/* ==================== 数据结构 ==================== */

/**
 * @brief 仓位状态枚举
 */
typedef enum {
    SLOT_EMPTY = 0,         // 空仓
    SLOT_OCCUPIED,          // 有充电宝
    SLOT_LOCKED,            // 锁定中
    SLOT_FAULT              // 故障
} SlotState_t;

/**
 * @brief 仓位信息结构体
 */
typedef struct {
    uint8_t slot_id;                // 仓位编号
    SlotState_t state;              // 当前状态
    uint16_t battery_voltage;       // 充电宝电压(mV)
    uint8_t battery_percent;        // 电量百分比
    uint8_t is_rented;              // 是否已租借
    uint32_t lock_open_time;        // 开锁时间
    char order_id[32];              // 订单号
} SlotInfo_t;

/**
 * @brief 系统状态结构体
 */
typedef struct {
    SlotInfo_t slots[SLOT_COUNT];
    uint8_t available_count;        // 可用仓位数
    uint8_t total_count;            // 总仓位数
    uint8_t system_status;          // 系统状态
    uint32_t total_rentals;         // 总租借次数
} PowerBankSystem_t;

/* ==================== 全局变量 ==================== */

extern PowerBankSystem_t g_system;
extern volatile uint32_t g_tick_ms;

#endif /* __SYSTEM_CONFIG_H */

4.2 电磁锁控制模块

📄 创建文件:modules/lock_control.c

c 复制代码
/**
 * @file lock_control.c
 * @brief 电磁锁控制模块
 */

#include "lock_control.h"

// 锁控引脚表
static const uint16_t s_lock_pins[SLOT_COUNT] = {
    LOCK1_PIN, LOCK2_PIN, LOCK3_PIN,
    LOCK4_PIN, LOCK5_PIN, LOCK6_PIN
};

/**
 * @brief 电磁锁初始化
 */
void Lock_Control_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    // 配置PB0-PB5为推挽输出
    GPIO_InitStruct.GPIO_Pin = LOCK1_PIN | LOCK2_PIN | LOCK3_PIN |
                               LOCK4_PIN | LOCK5_PIN | LOCK6_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(LOCK_PORT, &GPIO_InitStruct);
    
    // 初始状态:全部锁定(低电平)
    for (int i = 0; i < SLOT_COUNT; i++) {
        GPIO_ResetBits(LOCK_PORT, s_lock_pins[i]);
    }
}

/**
 * @brief 打开指定仓位锁
 * @param slot_id 仓位编号(0-5)
 * @return 0=成功,-1=失败
 */
int Lock_Control_Open(uint8_t slot_id)
{
    if (slot_id >= SLOT_COUNT) return -1;
    
    // 高电平开锁
    GPIO_SetBits(LOCK_PORT, s_lock_pins[slot_id]);
    
    // 记录开锁时间
    g_system.slots[slot_id].lock_open_time = g_tick_ms;
    g_system.slots[slot_id].state = SLOT_LOCKED;
    
    return 0;
}

/**
 * @brief 关闭指定仓位锁
 * @param slot_id 仓位编号(0-5)
 */
void Lock_Control_Close(uint8_t slot_id)
{
    if (slot_id >= SLOT_COUNT) return;
    
    // 低电平锁定
    GPIO_ResetBits(LOCK_PORT, s_lock_pins[slot_id]);
}

/**
 * @brief 自动锁管理(超时自动锁定)
 */
void Lock_Control_Auto_Manage(void)
{
    for (int i = 0; i < SLOT_COUNT; i++) {
        if (g_system.slots[i].state == SLOT_LOCKED) {
            uint32_t elapsed = g_tick_ms - g_system.slots[i].lock_open_time;
            
            // 超过开锁时间自动锁定
            if (elapsed >= LOCK_OPEN_TIME) {
                Lock_Control_Close(i);
                
                // 根据霍尔传感器状态更新仓位状态
                // TODO: 读取霍尔传感器
            }
        }
    }
}

4.3 仓位检测模块

📄 创建文件:modules/slot_detector.c

c 复制代码
/**
 * @file slot_detector.c
 * @brief 仓位检测模块
 */

#include "slot_detector.h"

// 霍尔传感器引脚表
static const uint16_t s_hall_pins[SLOT_COUNT] = {
    HALL1_PIN, HALL2_PIN, HALL3_PIN,
    HALL4_PIN, HALL5_PIN, HALL6_PIN
};

// ADC通道表
static const uint8_t s_adc_channels[SLOT_COUNT] = {
    ADC_BAT1, ADC_BAT2, ADC_BAT3,
    ADC_BAT4, ADC_BAT5, ADC_BAT6
};

/**
 * @brief 仓位检测初始化
 */
void Slot_Detector_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    ADC_InitTypeDef ADC_InitStruct;
    
    // 初始化霍尔传感器GPIO
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    
    GPIO_InitStruct.GPIO_Pin = HALL1_PIN | HALL2_PIN | HALL3_PIN |
                               HALL4_PIN | HALL5_PIN | HALL6_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;  // 上拉输入
    GPIO_Init(HALL_PORT, &GPIO_InitStruct);
    
    // 初始化ADC
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);
    
    ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStruct.ADC_ScanConvMode = ENABLE;
    ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStruct.ADC_NbrOfChannel = SLOT_COUNT;
    ADC_Init(ADC1, &ADC_InitStruct);
    
    // 配置ADC通道
    for (int i = 0; i < SLOT_COUNT; i++) {
        ADC_RegularChannelConfig(ADC1, s_adc_channels[i], i + 1, 
                                 ADC_SampleTime_239Cycles5);
    }
    
    ADC_Cmd(ADC1, ENABLE);
    ADC_ResetCalibration(ADC1);
    while (ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while (ADC_GetCalibrationStatus(ADC1));
    
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

/**
 * @brief 检测仓位是否有充电宝
 * @param slot_id 仓位编号
 * @return 1=有充电宝,0=空仓
 */
uint8_t Slot_Detector_Check_Occupied(uint8_t slot_id)
{
    if (slot_id >= SLOT_COUNT) return 0;
    
    // 读取霍尔传感器(低电平表示有磁铁,即充电宝在位)
    return (GPIO_ReadInputDataBit(HALL_PORT, s_hall_pins[slot_id]) == Bit_RESET);
}

/**
 * @brief 读取充电宝电量
 * @param slot_id 仓位编号
 * @return 电压值(mV)
 */
uint16_t Slot_Detector_Read_Voltage(uint8_t slot_id)
{
    // 读取ADC值并转换为电压
    // 假设使用分压电阻,3.7V锂电池分压到ADC量程内
    // 转换公式:Voltage = ADC * 3300 / 4095 * 分压比
    
    // 这里简化处理,实际需要根据硬件电路计算
    uint16_t adc_value = ADC_GetConversionValue(ADC1);
    uint16_t voltage = (uint16_t)((uint32_t)adc_value * 3300 / 4095 * 2);
    
    return voltage;
}

/**
 * @brief 计算电量百分比
 * @param voltage 电压(mV)
 * @return 电量百分比(0-100)
 */
uint8_t Slot_Detector_Calc_Percent(uint16_t voltage)
{
    // 锂电池电压范围:3.0V-4.2V
    // 3.0V = 0%, 4.2V = 100%
    
    if (voltage <= 3000) return 0;
    if (voltage >= 4200) return 100;
    
    return (uint8_t)((voltage - 3000) * 100 / 1200);
}

/**
 * @brief 更新所有仓位状态
 */
void Slot_Detector_Update_All(void)
{
    uint8_t available = 0;
    
    for (int i = 0; i < SLOT_COUNT; i++) {
        uint8_t occupied = Slot_Detector_Check_Occupied(i);
        
        if (occupied) {
            g_system.slots[i].state = SLOT_OCCUPIED;
            g_system.slots[i].battery_voltage = Slot_Detector_Read_Voltage(i);
            g_system.slots[i].battery_percent = 
                Slot_Detector_Calc_Percent(g_system.slots[i].battery_voltage);
        } else {
            g_system.slots[i].state = SLOT_EMPTY;
            g_system.slots[i].battery_percent = 0;
        }
        
        if (g_system.slots[i].state == SLOT_EMPTY) {
            available++;
        }
    }
    
    g_system.available_count = available;
}

4.4 租借流程控制

📄 创建文件:modules/rental_manager.c

c 复制代码
/**
 * @file rental_manager.c
 * @brief 租借管理模块
 */

#include "rental_manager.h"

/**
 * @brief 处理租借请求
 * @param order_id 订单号
 * @return 分配的仓位编号,-1表示失败
 */
int Rental_Manager_Process_Rent(const char* order_id)
{
    // 查找可用仓位
    int slot_id = -1;
    for (int i = 0; i < SLOT_COUNT; i++) {
        if (g_system.slots[i].state == SLOT_EMPTY) {
            slot_id = i;
            break;
        }
    }
    
    if (slot_id < 0) {
        // 无可用仓位
        Voice_Play(VOICE_NO_AVAILABLE);
        return -1;
    }
    
    // 保存订单信息
    strncpy(g_system.slots[slot_id].order_id, order_id, 31);
    g_system.slots[slot_id].order_id[31] = '\0';
    g_system.slots[slot_id].is_rented = 1;
    
    // 打开电磁锁
    Lock_Control_Open(slot_id);
    
    // 语音播报
    Voice_Play(VOICE_PLEASE_TAKE);
    
    // 上报云端
    // TODO: 发送租借记录到服务器
    
    g_system.total_rentals++;
    
    return slot_id;
}

/**
 * @brief 处理归还请求
 * @return 归还的仓位编号,-1表示失败
 */
int Rental_Manager_Process_Return(void)
{
    // 等待用户放入充电宝
    // 检测哪个仓位从空变为有充电宝
    
    for (int i = 0; i < SLOT_COUNT; i++) {
        if (g_system.slots[i].state == SLOT_EMPTY) {
            // 检测该仓位是否有充电宝放入
            if (Slot_Detector_Check_Occupied(i)) {
                // 锁定仓位
                Lock_Control_Close(i);
                
                // 清除租借状态
                g_system.slots[i].is_rented = 0;
                memset(g_system.slots[i].order_id, 0, 32);
                
                // 语音播报
                Voice_Play(VOICE_RETURN_SUCCESS);
                
                // 上报云端
                // TODO: 发送归还记录到服务器
                
                return i;
            }
        }
    }
    
    return -1;
}

4.5 主程序

📄 创建文件:main.c

c 复制代码
/**
 * @file main.c
 * @brief 共享充电宝主程序
 */

#include "system_config.h"
#include "lock_control.h"
#include "slot_detector.h"
#include "rental_manager.h"

PowerBankSystem_t g_system = {0};
volatile uint32_t g_tick_ms = 0;

void SysTick_Handler(void) { g_tick_ms++; }
uint32_t Get_Tick(void) { return g_tick_ms; }
void Delay_ms(uint32_t ms) {
    uint32_t start = g_tick_ms;
    while ((g_tick_ms - start) < ms);
}

void System_Init(void)
{
    SysTick_Config(SystemCoreClock / 1000);
    
    Lock_Control_Init();
    Slot_Detector_Init();
    
    g_system.total_count = SLOT_COUNT;
    
    printf("Power Bank System Started!\r\n");
}

int main(void)
{
    System_Init();
    
    while (1) {
        // 更新仓位状态
        Slot_Detector_Update_All();
        
        // 自动锁管理
        Lock_Control_Auto_Manage();
        
        // TODO: 处理扫码租借/归还
        // TODO: 更新显示
        // TODO: 与云端通信
        
        Delay_ms(100);
    }
}

五、故障排查与问题解决

5.1 电磁锁问题

问题1:电磁锁无法打开

原因分析:

  • 电源功率不足
  • MOSFET驱动电路故障
  • 电磁锁机械卡死

解决方案:

复制代码
电源要求:
- 电磁锁启动电流:2-3A
- 需要独立5V/10A电源供电
- STM32只输出控制信号,不直接驱动

驱动电路:
STM32 GPIO → 光耦隔离 → MOSFET驱动 → 电磁锁

六、测试验证

6.1 功能测试

测试1:仓位检测测试

c 复制代码
void Test_Slot_Detection(void) {
    printf("Slot Detection Test\r\n");
    for (int i = 0; i < SLOT_COUNT; i++) {
        uint8_t occupied = Slot_Detector_Check_Occupied(i);
        uint16_t voltage = Slot_Detector_Read_Voltage(i);
        printf("Slot %d: %s, Voltage: %dmV\r\n", 
               i + 1, occupied ? "Occupied" : "Empty", voltage);
    }
}

七、总结

7.1 核心知识点回顾

通过本教程,我们学习了:

  1. 电磁锁控制:大功率负载的驱动方法
  2. 传感器应用:霍尔传感器和ADC电量检测
  3. 租借流程设计:完整的借还业务逻辑
  4. 物联网通信:设备与云端的交互
  5. 商业产品设计:可靠性、安全性考虑

7.2 扩展方向

功能扩展:

  • 添加广告屏显示
  • 集成POS机支付
  • 会员积分系统
  • 故障自动上报

学习资源:

相关推荐
点灯师2 小时前
基于单片机的智能家居智能雨水自动关窗控制系统设计
单片机·嵌入式硬件·毕业设计·智能家居·课程设计·期末大作业
Smart-佀2 小时前
涨薪秘技:智能家居中的BLE协议与实现
网络·arm开发·嵌入式硬件·microsoft
LCG元3 小时前
STM32嵌入式开发:基于LD3320的智能语音识别系统
stm32·语音识别·xcode
freeinlife'4 小时前
onenet云平台下发数据到单片机并且OLED屏显示
单片机·嵌入式硬件
硅农深芯5 小时前
为什么有的芯片电源pin叫VCC,有的叫VDD?
单片机·嵌入式硬件·vcc·vdd·vee·vss
d111111111d6 小时前
STM32-UART封装问题解析
笔记·stm32·单片机·嵌入式硬件·学习·算法
国产化创客7 小时前
龙芯 2K0300-- 实现工业网关监控仪表盘项目
嵌入式硬件·物联网·数据可视化
项目題供诗7 小时前
STM32-OLED显示屏(六)
stm32·单片机·嵌入式硬件
jllllyuz7 小时前
STM32F10x MQ-2烟雾传感器驱动程序
stm32·单片机·嵌入式硬件