feat: 完善Mesh继电器OTA与地址协议
- 增加STM8 Bootloader工程及出厂固件恢复流程\n- 增加W25Q64外部Flash驱动和OTA分包接收、CRC16校验、断点续传状态管理\n- 增加固件版本查询、升级结果上报与主机确认机制\n- 将业务帧从55 AA帧头调整为发送方Mesh短地址+CMD+LEN+DATA+CRC16\n- 修正JDY-28M外层地址与业务发送方地址的职责划分,支持广播请求定向应答\n- 同步更新硬件引脚、存储分区、OTA流程和主机通信协议文档\n- 已使用SDCC重新编译,应用代码大小为5512字节,链接地址为0x8800
This commit is contained in:
@@ -20,6 +20,12 @@
|
||||
/** 释放 RESET 后等待模块启动完成的时间。 */
|
||||
#define JDY28M_RESET_STARTUP_WAIT_MS 1500ul
|
||||
|
||||
/** 当前主程序固件版本,高字节为主版本、低字节为次版本。发布新版本时必须增加版本号。
|
||||
* 0x0001:版本0.1
|
||||
* 0x0100:版本1.0
|
||||
* 0x0102:版本1.2 */
|
||||
#define FIRMWARE_VERSION 0x0100u
|
||||
|
||||
/** 默认电流阈值,单位为 mA。 */
|
||||
#define DEFAULT_CURRENT_THRESHOLD_MA 100u
|
||||
|
||||
@@ -38,10 +44,4 @@
|
||||
/** ACS712 采样建议使用的 RMS 窗口,单位为毫秒。 */
|
||||
#define CURRENT_RMS_WINDOW_MS 100ul
|
||||
|
||||
/** 业务协议帧头第一个字节。 */
|
||||
#define BUSINESS_FRAME_HEAD_0 0x55u
|
||||
|
||||
/** 业务协议帧头第二个字节。 */
|
||||
#define BUSINESS_FRAME_HEAD_1 0xAAu
|
||||
|
||||
#endif
|
||||
|
||||
+9
-2
@@ -3,7 +3,8 @@
|
||||
* @brief 蓝牙 Mesh 继电器硬件板级接口定义。
|
||||
*
|
||||
* 本阶段先提供稳定的硬件抽象接口,不在业务层直接操作 GPIO 寄存器。
|
||||
* PA1 的有效电平已经确认:高电平吸合、低电平断开;PD3 高电平点亮 LED3。
|
||||
* PA1 的有效电平已经确认:高电平吸合、低电平断开;PB5 为低电平点亮的
|
||||
* 蓝牙组网/故障指示灯,PD3 为高电平点亮的继电器状态灯。
|
||||
*/
|
||||
#ifndef BOARD_H
|
||||
#define BOARD_H
|
||||
@@ -22,9 +23,15 @@ uint8_t Board_GetRelay(void);
|
||||
/** 读取 JDY-28M STAT 状态,1 表示模块报告已组网。 */
|
||||
uint8_t Board_ReadMeshJoined(void);
|
||||
|
||||
/** 设置 LED3 点亮状态,1 表示点亮,0 表示熄灭。 */
|
||||
/** 设置蓝牙组网/故障指示灯,1表示点亮,0表示熄灭;硬件低电平点亮。 */
|
||||
void Board_SetLed3(uint8_t on);
|
||||
|
||||
/** 设置继电器状态灯,1表示点亮,0表示熄灭;硬件高电平点亮。 */
|
||||
void Board_SetRelayLed(uint8_t on);
|
||||
|
||||
/** 周期驱动PB4程序状态灯;正常运行500ms翻转,OTA期间100ms翻转。 */
|
||||
void Board_StatusLedTask(uint8_t ota_active);
|
||||
|
||||
/** 设置 PWRC:1 表示拉低进入 AT 窗口,0 表示恢复高电平通信。 */
|
||||
void Board_SetBluetoothAtWindow(uint8_t enabled);
|
||||
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
* @file business_protocol.h
|
||||
* @brief STM8 业务帧协议接口。
|
||||
*
|
||||
* 业务帧格式:0x55 0xAA | CMD | LEN | DATA | CRC16。
|
||||
* CRC 使用 CRC-16/MODBUS,计算范围为 CMD 至 DATA,低字节在前。
|
||||
* 业务帧格式:SRC_H SRC_L | CMD | LEN | DATA | CRC16_L CRC16_H。
|
||||
* SRC 为发送方的 Mesh 短地址;CRC 使用 CRC-16/MODBUS,计算范围为
|
||||
* SRC、CMD、LEN 和 DATA,线上低字节在前。
|
||||
*/
|
||||
#ifndef BUSINESS_PROTOCOL_H
|
||||
#define BUSINESS_PROTOCOL_H
|
||||
@@ -13,8 +14,8 @@
|
||||
/** 业务帧最大 DATA 长度,需为 JDY-28M 外层 20 字节限制预留空间。 */
|
||||
#define BUSINESS_MAX_DATA_LENGTH 4u
|
||||
|
||||
/** 业务帧头长度。 */
|
||||
#define BUSINESS_FRAME_HEADER_LENGTH 2u
|
||||
/** 发送方短地址字段长度。 */
|
||||
#define BUSINESS_SOURCE_ADDRESS_LENGTH 2u
|
||||
|
||||
/** 业务命令:继电器控制。 */
|
||||
#define CMD_RELAY_CONTROL 0x01u
|
||||
@@ -34,9 +35,22 @@
|
||||
/** 业务命令:电流阈值配置。 */
|
||||
#define CMD_THRESHOLD_CONFIG 0x06u
|
||||
|
||||
/** 查询当前主程序固件版本。 */
|
||||
#define CMD_FIRMWARE_VERSION_QUERY 0x0Eu
|
||||
|
||||
/** 查询固件版本应答。 */
|
||||
#define CMD_FIRMWARE_VERSION_RESPONSE \
|
||||
(CMD_FIRMWARE_VERSION_QUERY | CMD_RESPONSE_FLAG)
|
||||
|
||||
/** Bootloader升级结果主动上报。 */
|
||||
#define CMD_OTA_RESULT_REPORT 0x0Du
|
||||
|
||||
/** 应答命令基值,具体应答为请求命令加 0x80。 */
|
||||
#define CMD_RESPONSE_FLAG 0x80u
|
||||
|
||||
/** OTA升级结果上报应答命令。 */
|
||||
#define CMD_OTA_RESULT_ACK (CMD_OTA_RESULT_REPORT | CMD_RESPONSE_FLAG)
|
||||
|
||||
/** 通用错误应答命令。 */
|
||||
#define CMD_ERROR_RESPONSE 0xE0u
|
||||
|
||||
@@ -76,10 +90,13 @@ uint8_t BusinessProtocol_GetDataLength(void);
|
||||
/** 读取最近一帧合法业务帧的数据区;返回 0 表示下标越界。 */
|
||||
uint8_t BusinessProtocol_GetDataByte(uint8_t index, uint8_t *value);
|
||||
|
||||
/** 执行最近一帧已经通过校验的业务命令,并向源地址返回应答。 */
|
||||
void BusinessProtocol_HandleFrame(uint16_t source_address);
|
||||
/** 读取最近一帧合法业务帧携带的发送方 Mesh 短地址。 */
|
||||
uint16_t BusinessProtocol_GetSourceAddress(void);
|
||||
|
||||
/** CRC-16/MODBUS 计算函数,输入范围不包含业务帧头。 */
|
||||
/** 执行最近一帧已经通过校验的业务命令,并向源地址返回应答。 */
|
||||
void BusinessProtocol_HandleFrame(void);
|
||||
|
||||
/** CRC-16/MODBUS 计算函数,输入范围包含发送方地址字段。 */
|
||||
uint16_t BusinessProtocol_Crc16Modbus(const uint8_t *data, uint16_t length);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @file interrupt_control.h
|
||||
* @brief STM8 全局中断控制接口。
|
||||
*
|
||||
* STM8 的全局中断允许位位于 CPU 条件代码寄存器中,不能像 GPIO 或定时器
|
||||
* 那样通过普通 C 变量直接访问,因此由本模块统一封装 SDCC 内联汇编。
|
||||
*/
|
||||
#ifndef INTERRUPT_CONTROL_H
|
||||
#define INTERRUPT_CONTROL_H
|
||||
|
||||
/** 开启 STM8 全局中断,使 TIM4、UART 等中断可以进入。 */
|
||||
void Interrupts_Enable(void);
|
||||
|
||||
/** 关闭 STM8 全局中断,用于极短的不可打断临界区。 */
|
||||
void Interrupts_Disable(void);
|
||||
|
||||
#endif
|
||||
@@ -16,8 +16,8 @@ void MeshFrame_Init(void);
|
||||
/** 从 UART 接收并解析 JDY-28M 外层帧。 */
|
||||
void MeshFrame_Task(void);
|
||||
|
||||
/** 返回最近一帧合法数据的源短地址。 */
|
||||
uint16_t MeshFrame_GetLastSourceAddress(void);
|
||||
/** 返回最近一帧合法外层数据携带的目标短地址,仅用于诊断。 */
|
||||
uint16_t MeshFrame_GetLastTargetAddress(void);
|
||||
|
||||
/**
|
||||
* 封装并发送一帧 Mesh 业务数据。
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @file ota_manager.h
|
||||
* @brief 应用程序侧 OTA 管理接口。
|
||||
*
|
||||
* 应用程序负责通过 JDY-28M 接收 OTA 分包、校验业务帧并写入 W25Q64。
|
||||
* 下载完成后,应用程序只设置升级请求标志并复位;真正擦写片内程序
|
||||
* Flash 的工作由独立 Bootloader 完成。
|
||||
*/
|
||||
#ifndef OTA_MANAGER_H
|
||||
#define OTA_MANAGER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** 初始化 OTA 状态机和外部 Flash 接口。 */
|
||||
void OtaManager_Init(void);
|
||||
/** 周期性处理 OTA 状态机,不得长时间阻塞主循环。 */
|
||||
void OtaManager_Task(void);
|
||||
/** 处理一条已经通过 Mesh 外层解析的 OTA 业务命令。 */
|
||||
uint8_t OtaManager_HandleCommand(uint8_t command,
|
||||
const uint8_t *data,
|
||||
uint8_t length);
|
||||
/** 返回当前是否处于 OTA 下载模式。 */
|
||||
uint8_t OtaManager_IsActive(void);
|
||||
uint8_t OtaManager_GetExpectedOffset(uint16_t *offset);
|
||||
/**
|
||||
* 读取Bootloader写入的升级结果并准备由主程序主动上报。
|
||||
* @return 0表示没有待上报结果,非0表示升级结果码。
|
||||
*/
|
||||
uint8_t OtaManager_GetBootloaderResult(void);
|
||||
/** 主机确认升级结果后清除待上报状态。 */
|
||||
void OtaManager_AcknowledgeBootloaderResult(void);
|
||||
|
||||
#endif
|
||||
@@ -16,6 +16,11 @@
|
||||
#define GPIOA_DDR_ADDR 0x5002u
|
||||
#define GPIOA_CR1_ADDR 0x5003u
|
||||
#define GPIOA_CR2_ADDR 0x5004u
|
||||
#define GPIOB_ODR_ADDR 0x5005u
|
||||
#define GPIOB_IDR_ADDR 0x5006u
|
||||
#define GPIOB_DDR_ADDR 0x5007u
|
||||
#define GPIOB_CR1_ADDR 0x5008u
|
||||
#define GPIOB_CR2_ADDR 0x5009u
|
||||
#define GPIOC_ODR_ADDR 0x500Au
|
||||
#define GPIOC_IDR_ADDR 0x500Bu
|
||||
#define GPIOC_DDR_ADDR 0x500Cu
|
||||
@@ -26,6 +31,10 @@
|
||||
#define GPIOD_DDR_ADDR 0x5011u
|
||||
#define GPIOD_CR1_ADDR 0x5012u
|
||||
#define GPIOD_CR2_ADDR 0x5013u
|
||||
#define SPI1_CR1_ADDR 0x5200u
|
||||
#define SPI1_CR2_ADDR 0x5201u
|
||||
#define SPI1_SR_ADDR 0x5203u
|
||||
#define SPI1_DR_ADDR 0x5204u
|
||||
|
||||
/* UART1 寄存器地址。 */
|
||||
#define UART1_SR_ADDR 0x5230u
|
||||
@@ -63,6 +72,7 @@
|
||||
#define REG8(address) (*((volatile uint8_t *)(address)))
|
||||
|
||||
#define PA1_MASK 0x02u
|
||||
#define PA2_MASK 0x04u
|
||||
#define PC3_MASK 0x08u
|
||||
#define PC4_MASK 0x10u
|
||||
/** PC4 在 STM8S003F3P6 上对应 ADC1 的 AIN2 通道。 */
|
||||
@@ -72,5 +82,24 @@
|
||||
#define PD6_MASK 0x40u
|
||||
#define PC5_MASK 0x20u
|
||||
#define PC6_MASK 0x40u
|
||||
#define PC7_MASK 0x80u
|
||||
#define PD2_MASK 0x04u
|
||||
#define PD4_MASK 0x10u
|
||||
#define PB5_MASK 0x20u
|
||||
#define PB4_MASK 0x10u
|
||||
|
||||
#define SPI1_CR1 REG8(SPI1_CR1_ADDR)
|
||||
#define SPI1_CR2 REG8(SPI1_CR2_ADDR)
|
||||
#define SPI1_SR REG8(SPI1_SR_ADDR)
|
||||
#define SPI1_DR REG8(SPI1_DR_ADDR)
|
||||
#define SPI_CR1_SPE 0x40u
|
||||
#define SPI_CR1_MSTR 0x04u
|
||||
#define SPI_CR1_BR0 0x08u
|
||||
#define SPI_CR1_BR1 0x10u
|
||||
#define SPI_CR1_BR2 0x20u
|
||||
#define SPI_CR2_SSI 0x01u
|
||||
#define SPI_CR2_SSM 0x02u
|
||||
#define SPI_SR_RXNE 0x01u
|
||||
#define SPI_SR_TXE 0x02u
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/** @file w25q64_app.h @brief 主程序侧W25Q64结果读取接口。 */
|
||||
#ifndef W25Q64_APP_H
|
||||
#define W25Q64_APP_H
|
||||
#include <stdint.h>
|
||||
void W25Q64App_Init(void);
|
||||
uint8_t W25Q64App_ReadByte(uint32_t address, uint8_t *value);
|
||||
uint8_t W25Q64App_Read(uint32_t address, uint8_t *buffer, uint16_t length);
|
||||
uint8_t W25Q64App_EraseSector(uint32_t address);
|
||||
uint8_t W25Q64App_PageProgram(uint32_t address, const uint8_t *data,
|
||||
uint16_t length);
|
||||
uint8_t W25Q64App_ClearUpgradeResult(void);
|
||||
#endif
|
||||
Reference in New Issue
Block a user