Files
BR_YKC/Doc/README.md
2026-05-21 14:05:46 +08:00

25 KiB
Raw Permalink Blame History

BR_YKC 充电桩网关

基于 STM32H743 + AIR724 4G模块 的充电桩网关方案,对接云快充平台,支持通过4G TCP以太网UDP双通道通信。

stm32工程采用EIDE插件开发请在vscode中安装EIDE插件,然后在插件界面点击打开项目,选择\Core\MDK-ARM\IPort.code-workspace,即可编译下载项目。默认选择DAP下载。


目录


硬件架构

┌──────────────────────────────────────────────┐
│                 STM32H743                    │
│                                              │
│  UART1 ─── 4G模块(AIR724) ──→ 云快充平台 (TCP)│
│  UART3 ─── RS485                             │
│  ETH  ──── LAN (UDP, 桩1~6 + 上位机)          │
│  UART6 ─── 调试串口(printf)                   │
└──────────────────────────────────────────────┘
外设 用途
UART1 (115200) 与AIR724 4G模块通信
UART3 RS485接口
ETH (LWIP) 以太网桩1~6 UDP通信 + 上位机
UART6 printf调试输出

软件架构

  Os/            任务/队列/信号量/定时器管理
  ├─ os_task.c       5个任务的创建
  ├─ os_queue.c      3个消息队列
  ├─ os_timer.c      软件定时器
  └─ os_semaphore.c  信号量/互斥量

  App/            应用层任务
  ├─ task_air724  4G下行数据解析任务
  ├─ task_udp     UDP收发 + 解析任务
  ├─ task_ykc     云快充核心状态机任务
  └─ task_sys     系统任务(心跳指示、喂狗)

  Driver/         驱动层
  ├─ drv_air724   AIR724命令收发 + 响应解析
  ├─ drv_usart    串口收发(含互斥锁)
  ├─ drv_flash    通用Flash读写框架
  └─ flash_config 应用层Flash配置

  Network/        网络层
  ├─ udp_manager  UDP报文发送
  └─ udp_router   UDP路由分发

  Protocol/       协议层
  ├─ Point/       南向(充电桩JSON)
  ├─ Host Computer/ 上位机JSON通信
  └─ Ykc/         北向(云快充字节协议)
     ├─ charger_to_server  上行帧
     ├─ server_to_charger  下行帧
     ├─ server_common      公共(组包/解包/CRC)
     └─ ykc_router         帧类型路由分发

  Global/         全局数据
  ├─ g_dcpile     桩/枪 结构体 + 管理器
  ├─ g_init       全局初始化
  ├─ g_runtime    运行时统计
  └─ board_config 板级配置IP/端口)

  4G/             4G模块Lua固件
  ├─ core/main.lua       入口:初始化+串口+网络
  ├─ core/cmd.lua        命令解析+分发
  └─ core/linksocket.lua 多路TCP socket管理

通信拓扑

                   云快充服务器(TCP)
                        ↑
                        │ 4G
                   AIR724模块
                        ↑ UART1
              ┌─────────┴──────────┐
              │   STM32H743 网关   │
              │    (协议转换器)     │
              └─────────┬──────────┘
                   UDP │ 以太网
          ┌─────────────┼─────────────┐
          │             │             │
       桩1~6         上位机        RS485设备
     (10.12.19.101~106)  (107)       (触摸屏等)

数据路径:

  • 云快充 → 桩云快充TCP → 4G → UART1 → STM32解析 → 填充数据到桩结构体
  • 桩上报 → 云快充:桩 → UDP → STM32 → 打包Ykc帧 → UART1 → 4G → TCP → 云快充
  • 上位机查询:上位机 → UDP → STM32 → 查询桩数据 → 回复

三层状态机

task_ykc.c 实现了 桩层 + 枪层 两层非阻塞时间片状态机:

桩层初始化桩0~2通用只做一次

step 0 ── 等待桩UDP上电 → 连接4G通道(i+1)
  ↓  (socket_connected[i] == true)
step 1 ── 发送云快充登录(0x01)
  ↓  (is_online == true)
step 2 ── 发送计费模型验证(0x05) + 请求(0x09)
  ↓  (get_model == true)
step 3 ── 进入枪层运行态

枪层运行(每把枪独立)

gun_step 0 ── 每5秒上传实时数据(0x13) + 主动上报到上位机
              如有账单(is_get_bill==true),上传交易记录(0x3B)

非阻塞机制

所有 osDelay() 已被替换为时间戳轮询

now = HAL_GetTick();
if (now < pile->step_tick)  // 时间没到,立即跳过,不阻塞
    continue;

// 执行动作
pile->step_tick = now + 5000;  // 设定5秒后的下次超时

6个桩每轮循环只需微秒级完成互不阻塞。


通信协议

南向协议(网关 ↔ 桩)

  • 传输:以太网 UDP
  • 端口Server=6001, Stake=6001, App=6002
  • 桩IP10.12.19.101 ~ 106
  • 格式JSON

路由表 udp_router.c

cmd 桩ID来源 处理函数 说明
online 桩1~6 point_callback_power_on 上电,设置 is_udp_online
heartbeat 桩1~6 point_callback_heartbeat 心跳
start charging 桩1~6 point_callback_start_charging 开始充电反馈
end charging 桩1~6 point_callback_end_charging 停止充电反馈
realtime data 桩1~6 point_callback_realtime_data 实时数据
settlement bill 桩1~6 point_callback_settlement_bill 结算账单
proactive end charging 桩1~6 point_callback_proactive_end_charging 桩主动停止
charge process real 桩1~6 point_callback_charge_process BMS需求
bms info real 桩1~6 point_callback_bms_info BMS信息

桩未上电拦截:除 online 外,所有桩指令都会检查 is_udp_online,未上电的桩指令将被静默丢弃。

上位机协议(网关 ↔ 上位机APP

  • 传输:以太网 UDP同一通道
  • 端口Server=6001, App=6002
  • 上位机ID7
  • 格式JSONrequest_id + success

指令表 host_computer_protocol.h

cmd 功能 处理函数 回复字段
server_login 登录 host_computer_on_login success
server_get_status 获取所有桩状态 host_computer_on_get_status piles[].serial/is_online/guns[].status
server_reboot 重启网关 host_computer_on_reboot 无(立即重启)
gateway_get_info 查询网关信息 host_computer_on_get_gw_info device_id, software_ver, hardware_ver, uptime
gateway_get_4g_status 查询4G状态 host_computer_on_get_4g_status iccid, net_status, signal, isp
gateway_get_cloud_config 查询云配置 host_computer_on_get_cloud_config host, port
gateway_set_cloud_config 设置云配置 host_computer_on_set_cloud_config host, port触发重连
gateway_get_net_config 查询网络配置 host_computer_on_get_net_config ip, mask, gateway, dns
gateway_set_net_config 设置网络配置 host_computer_on_set_net_config success重启生效
server_get_pile_info 查询单个桩信息 host_computer_on_get_pile_info serial, type, gun_num, protocol_ver, software_ver, sim

北向协议(网关 ↔ 云快充)

  • 传输4G TCP
  • 数据格式字节流含CRC16校验
  • 封装55 AA 01 socketId len [ykc_frame] AA 55

YKC帧格式

┌────────┬──────┬────────┬─────────┬────────┬──────────┬──────┐
│ 0x68   │ len  │ serial │encrypt  │type    │ data     │ crc │
│ (起始) │(1字节)│ (2字节)│ (1字节) │(1字节) │ (n字节)  │2字节│
└────────┴──────┴────────┴─────────┴────────┴──────────┴──────┘

帧类型(上行 → 云快充)

type 函数 说明
0x01 charger_to_server_0X01 登录认证
0x03 charger_to_server_0X03 心跳
0x05 charger_to_server_0X05 计费模型验证
0x09 charger_to_server_0X09 计费模型请求
0x13 charger_to_server_0X13 实时监测数据
0x19 charger_to_server_0X19 充电结束
0x33 charger_to_server_0X33 远程启动回复
0x35 charger_to_server_0X35 远程停机回复
0x3B charger_to_server_0X3B 交易记录
0x57 charger_to_server_0x57 计费模型应答

帧类型(下行 ← 云快充)

type 处理函数 说明
0x02 on_cmd_frame_type_0X02 登录认证应答
0x04 on_cmd_frame_type_0X04 心跳应答
0x06 on_cmd_frame_type_0X06 计费模型验证应答
0x0A on_cmd_frame_type_0X0A 获取计费模型
0x58 on_cmd_frame_type_0X58 计费模型设置
0x34 on_cmd_frame_type_0X34 平台启动充电
0x36 on_cmd_frame_type_0X36 平台控制停止充电
0x40 on_cmd_frame_type_0X40 交易记录确认

4G链路协议STM32 ↔ AIR724

AIR724模块内部运行Lua脚本 cmd.lua + linksocket.lua

55 AA mainCmd subCmd [payload] AA 55
mainCmd subCmd 功能
0x01 socketId 数据发送到指定Socket
0x02 - 系统重启
0x03 0x01/0x02 连接/断开Socket
0x04 0x00 设置服务器地址
0x05 0x01~0x03 查询ICCID/IMSI/IMEI
0x06 0x00 查询信号强度
0x07 0x00 查询链路状态

上行响应4G → STM32

mainCmd subCmd 含义
0x83 0x01 TCP已连接
0x83 0x02 TCP已断开
0x83 0x03 TCP连接失败
0x84 0x01~0x03 SIM信息ICCID/IMSI/IMEI
0x85 - 信号强度
0x86 - 链路状态

上位机 C# 客户端

C# 上位机客户端项目位于 C:\Users\Administrator\PycharmProjects\PythonProject\C#\YKC,基于 .NET Framework 4.7.2 + WPF 框架开发,通过 UDP 与网关通信。

项目结构

YKC/
├── App.xaml(.cs)          程序入口
├── MainWindow.xaml(.cs)   主窗口(导航框架)
├── LoginWindow.xaml(.cs)  登录窗口
├── Config.cs              配置参数 + 指令字典
├── UdpClient.cs           UDP通信客户端同步/异步)
├── PilesDataStore.cs      充电桩历史数据存储(含图表数据)
│
├── Pages/
│   ├── DashboardPage.xaml(.cs)   总览页面
│   ├── RealtimePage.xaml(.cs)    实时监控含OxyPlot图表
│   ├── ChargerPage.xaml(.cs)     充电桩管理
│   └── GatewayPage.xaml(.cs)     网关管理
│
├── bin/Debug/
│   ├── OxyPlot.dll                  波形图库
│   ├── OxyPlot.Wpf.dll
│   ├── OxyPlot.Wpf.Shared.dll
│   └── Newtonsoft.Json.dll          JSON库
│
└── Properties/              项目属性

页面功能

1. 登录页面 (LoginWindow)

  • 用户名/密码认证
  • 发送 server_login → 网关返回 success: true/false
  • 默认账号:admin / 123456

2. 总览页面 (DashboardPage)

  • 连接状态:显示网关在线/离线
  • 在线/充电统计:在线桩数、充电中枪数
  • 表格列表:每桩的序列号、在线状态、每枪状态
  • 5秒 自动轮询 server_get_status
枪状态 含义
0 离线
1 故障
2 空闲
3 充电中

3. 实时监控页面 (RealtimePage)

  • 选择桩号(1N) + 枪号(1N)
  • 实时显示:电流(A)、电压(V)、功率(kW)、电量(kWh)、总金额、SOC、累计时间、剩余时间
  • OxyPlot 实时曲线
    • 电流/电压/功率 折线图含时间轴最多300个点
    • 电费/服务费/总金额 柱状图
  • 2秒 自动轮询 report_data 主动上报数据来自PilesDataStore历史记录

4. 充电桩管理页面 (ChargerPage)

查询桩信息

  • 按桩索引查询
  • 回复显示:序列号、类型(直流/交流)、枪数、协议版本、软件版本、SIM

设置桩ID

  • 输入桩索引 + 14位HEX序列号

重启网关

  • 发送 server_reboot(确认弹窗)

5. 网关管理页面 (GatewayPage)

网关信息卡片

  • 设备ID、软件版本、硬件版本、运行时长
  • 调用 gateway_get_info

4G状态卡片

  • ICCID、网络状态、信号强度(dBm)、运营商
  • 调用 gateway_get_4g_status

云平台配置卡片

  • 查询(gateway_get_cloud_config) / 保存(gateway_set_cloud_config)
  • 保存时验证IP格式或域名格式端口 1~65535

网络配置卡片

  • IP/掩码/网关/DNS 查询 + 设置
  • 调用 gateway_get_net_config / gateway_set_net_config
  • 支持IP地址格式校验

通信机制

UDP通信封装在 UdpClient.cs

消息格式

{
  "id": 7,              // 固定ID=7上位机
  "cmd": "server_login",
  "request_id": "server_login_1700000000000",
  ...其他参数...
}

回复格式

{
  "request_id": "server_login_...",
  "success": true,
  ...其他数据...
}

两种发送模式

方法 说明
Send(payload, callback) 异步发送,通过回调接收回复
SendSync(payload, timeoutSec?) 同步发送阻塞等待回复或超时默认4秒

超时机制:异步请求启动定时器,超时后自动回调 { success: false, error: "timeout" }

主动上报接收OnActiveReport 事件监听 cmd == "report_data" / "pile_metrics" / "real_time_data",由 PilesDataStore 订阅存储。

监听端口Config.LocalPort = 6002,目标网关 Config.TargetIp:Config.TargetPort(默认 10.12.19.100:6001

数据存储

PilesDataStore.cs 单例模式管理:

  • 实时数据GetLatest(pile, gun) → 最新一条 JObject
  • 图表数据GetChartData(pile, gun)GunData 对象内含最多300个历史点的电流/电压/功率/电量/金额等序列
  • 历史清理超过300个点自动移除旧数据

配置参数

Config.cs

TargetIp   = "10.12.19.100";   // 网关IP
TargetPort = 6001;             // 网关UDP端口
LocalPort  = 6002;             // 本机监听端口
UdpTimeout = 3;                // 超时时间(秒)

指令字典(与网关 udp_router.c 路由表对应):

常量 cmd 对应网关处理函数
LOGIN server_login host_computer_on_login
GET_STATUS server_get_status host_computer_on_get_status
REBOOT server_reboot host_computer_on_reboot
GET_PILE_INFO server_get_pile_info host_computer_on_get_pile_info
GET_GW_INFO gateway_get_info host_computer_on_get_gw_info
GET_4G_STATUS gateway_get_4g_status host_computer_on_get_4g_status
GET_CLOUD_CONFIG gateway_get_cloud_config host_computer_on_get_cloud_config
SET_CLOUD_CONFIG gateway_set_cloud_config host_computer_on_set_cloud_config
GET_NET_CONFIG gateway_get_net_config host_computer_on_get_net_config
SET_NET_CONFIG gateway_set_net_config host_computer_on_set_net_config
SET_PILE_ID server_set_pile_id 待开发
REPORT_DATA report_data 主动上报(南向)

配置指南

修改桩编码(序列号)

修改 g_dcpile.c 中的 piles_serial 数组每个桩编码为7字节十六进制

/*充电桩序列号*/
const uint8_t piles_serial[6][7] = {
    {0x32, 0x01, 0x06, 0x01, 0x16, 0x92, 0x45},  // 桩1
    {0x32, 0x01, 0x06, 0x01, 0x16, 0x92, 0x44},  // 桩2
    {0x32, 0x01, 0x06, 0x01, 0x16, 0x92, 0x43},  // 桩3
    {0x32, 0x01, 0x06, 0x01, 0x16, 0x92, 0x42},  // 桩4
    {0x32, 0x01, 0x06, 0x01, 0x11, 0x15, 0x58},  // 桩5
    {0x32, 0x01, 0x06, 0x01, 0x11, 0x15, 0x54},  // 桩6
};

init_chargers() 中通过 memcpy(ctx->charger_serial, piles_serial[i], CHARGER_SERIAL_LENGTH) 加载。

序列号转换为字符串显示时表现为14位HEX码例如 32010601169244

修改桩数量

两步:

修改 g_dcpile.h 中的宏:

#define MAX_CHARGER_COUNT 2   // ← 改为实际桩数量

确保 g_dcpile.c 中的 piles_serial 数组有对应数量的序列号。

同时需要修改 udp_router.cROUTE_TABLE 的路由数量(如果新增桩路由),以及 task_ykc.c 中状态机的循环 for (int i = 0; i < g_charger_manager.charger_count; i++) 已自动适配。

桩1~6的UDP IP地址在 udp_manager.c 中硬编码:

static ip4_addr_t s_point_ip[6] = {
    IPADDR4_INIT_BYTES(10, 12, 19, 101), /* 桩1 */
    IPADDR4_INIT_BYTES(10, 12, 19, 102), /* 桩2 */
    ...
};

如果桩数量变化,需要同步更新此数组。

修改每桩枪数

修改 g_dcpile.h

#define MAX_GUN_PER_CHARGER 2   // ← 改为实际枪数

状态机中的枪循环已自动适配:

for (int g = 0; g < MAX_GUN_PER_CHARGER; g++)

配置云快充服务器地址

默认在 linksocket.lua 中:

local server_config = {
    ip = "129.211.170.245",
    port = 9002
}

可通过上位机指令 gateway_set_cloud_config 动态修改 s_cloud_host / s_cloud_port,修改后调用 drv_air724_set_server 触发AIR724重新连接。


Flash组件使用说明

Flash存储组件分为两层

框架层 drv_flash

drv_flash.h / drv_flash.c

提供通用Flash读写管理支持按帧类型存取、覆写模式、多帧管理。

帧格式

┌──────┬──────┬──────┬──────┬──────────┬──────┐
│ HEAD │ size_low │size_high│type│  DATA  │ TAIL │
│(0xA5)│ (2字节 小端) │(1字节)│(n字节) │(0x5A)│
└──────┴──────┴──────┴──────┴──────────┴──────┘

核心API

函数 说明
flash_manage_init(flash_manage_t *fm) 初始化遍历Flash重建可读帧表
flash_manage_read(fm, *pbuf, frame_type) 读取指定类型的帧数据
flash_manage_write(fm, *pbuf, size, frame_type) 写入指定类型的帧数据

flash_manage_t 配置

typedef struct {
    uint8_t align_num;                    // 地址对齐数STM32H7一般为32
    flash_write_read_mode_t flash_write_mode; // 写模式
    flash_write_read_mode_t flash_read_mode;  // 读模式
    uint32_t flash_start_address;         // 管理起始地址(按扇区对齐)
    uint32_t manage_sector_num;           // 管理的扇区数
    uint32_t sector_size;                 // 扇区大小H743=128KB
    void (*read_flash)(...);              // 读函数指针
    void (*write_flash)(...);             // 写函数指针
    uint8_t (*erase_sector)(...);         // 擦除函数指针
} flash_manage_t;

应用层 flash_config

flash_config.h / flash_config.c

基于框架层的封装提供开箱即用的API

// 单例,地址=0x081800001个Sector(128KB)32字节对齐
void stm_flash_init(void);

// 读取,传入缓冲区 + 帧类型成功返回1
int8_t stm_flash_read(uint8_t *pbuf, uint8_t frame_type);

// 写入,传入数据 + 大小 + 帧类型成功返回1
int8_t stm_flash_write(uint8_t *pbuf, uint16_t size, uint8_t frame_type);

注意STM32H743 Bank2 的 Sector 擦除规则:

  • 起始地址 0x08100000每Sector = 128KB
  • 写入必须 32字节对齐不满32字节补 0xFF
  • flash_config.c 使用 0x08180000Bank2的第4个Sector

使用示例

#include "flash_config.h"

// 初始化在main中调用一次
stm_flash_init();

// 写入配置数据
uint8_t config_data[] = {0x01, 0x02, 0x03, 0x04};
stm_flash_write(config_data, sizeof(config_data), 0x01);  // 帧类型1

// 读取配置数据
uint8_t read_buf[64] = {0};
if (stm_flash_read(read_buf, 0x01) == 1) {
    // 读取成功read_buf中为数据
} else {
    // 无数据
}

写模式

模式 说明
FLASH_NO_OVERWRITING_MODE 0x00 只追加,不覆盖旧帧
FLASH_OVERWRITING_MODE 0x01 将旧帧头置为无效,写新帧(默认)

读模式

模式 说明
FLASH_NO_CLEAR_MODE 0x02 读取后不清除(默认)
FLASH_CLEAR_MODE 0x03 读取后将帧标记为无效

任务列表

任务 函数 栈大小 优先级 说明
SysTask sys_task_function 128 Low 指示灯、蜂鸣器、喂狗
Air724RecvTask air724_recv_task_function 1024 AboveNormal 解析4G下行数据
UDPRecvTask udp_recv_task_function 1536 High UDP接收入队
UDPParseTask udp_parse_task_function 2048 AboveNormal UDP数据解析+路由分发
YkcTask ykc_task_function 1024 AboveNormal 云快充状态机+数据上报

消息队列

队列 长度 消息大小 用途
Air724_Message_Queue 20 512 4G接收数据
RS485_Message_Queue 5 256 RS485接收数据
UDP_Message_Queue 20 sizeof(UdpMsg_t) UDP接收数据

日志格式

[YKC Router] frame=0x02 │ stake=1 │  登录认证应答        ← 4G下行路由
[ UDP 接收路由 ] 指令: realtime data      │ 桩ID: 1 │  实时数据  ← 南向UDP
[ UDP 路由拦截 ] 桩ID: 2 未上电,忽略指令: heartbeat     ← 上电过滤
[ 北向 ] 对电桩 1 发送登录认证                               ← 4G上行
[ 北向 ] 对电桩 1 枪 1 上传交易记录(0x3B)电量0.00金额0.00  ← 4G上行
[ 4G ] 通道 1 连接成功                                         ← 4G链路通知
[ 上位机 ] get_status 回复已发送                                ← 上位机回复