V1.5: 产品模式改运行时可切(EEPROM172+蓝牙SCALE/SCALE0/SCALE1命令,切换自动重启);OLED欢迎页改'继电器控制终端'

This commit is contained in:
helei 2026-08-15 07:36:39 +08:00
parent b81958535d
commit 0c2020ddfb
8 changed files with 91 additions and 33 deletions

View File

@ -131,6 +131,26 @@ static void feed_scale_report_weight(const char *header)
(float)zero_weight / 10.0f);
}
uint8_t g_feed_scale_on = 0;
/* 加载产品模式EEPROM 空白时用编译宏做默认值 */
void feed_scale_load_mode(void)
{
uint8_t v = 0xFF;
eepromReadData(FEED_SCALE_MODE_ADDR, &v, 1);
if (v > 1) v = PRODUCT_WITH_FEED_SCALE;
g_feed_scale_on = v;
log_info("> 产品模式: %s", v ? "称重投料(带秤)" : "四路继电器(无秤)");
}
/* 蓝牙命令切换产品模式:写 EEPROM重启后完全生效 */
void feed_scale_set_mode(uint8_t on)
{
on = on ? 1 : 0;
g_feed_scale_on = on;
eepromWriteData(FEED_SCALE_MODE_ADDR, &on, 1);
}
void feedScaleInit(void)
{
uint8_t tmp[2] = {0};
@ -167,10 +187,10 @@ void feedScaleInit(void)
}
}
#if !FEED_SCALE_DISABLED
log_info("> FEED: 놓迦뺏, 혼튄=%.1fKG, 데늴尻죕=%.1fKG",
(float)zero_weight / 10.0f, (float)once_weight / 10.0f);
#endif
if (g_feed_scale_on) {
log_info("> FEED: 初始化, 去皮=%.1fKG, 单次投料=%.1fKG",
(float)zero_weight / 10.0f, (float)once_weight / 10.0f);
}
}
void feedScaleSetZero(uint16_t zero_100g)
@ -287,9 +307,7 @@ static void feed_scale_finish_error(const char *reason)
void feedScaleProcess(void)
{
#if FEED_SCALE_DISABLED
return;
#endif
if (!g_feed_scale_on) return;
uint8_t rx_buf[32];
int len;

View File

@ -9,10 +9,16 @@
#define FEED_SCALE_ONCEWT_MAX 5000 /* 500.0 KG */
#define FEED_SCALE_WEIGHT_MAX 5000 /* 500.0 KG */
/* 磅秤接入控制:由 main.h 的 PRODUCT_WITH_FEED_SCALE 决定,此处做反向映射。
* 1=()feeding 1
* 0=()使 */
#define FEED_SCALE_DISABLED (!PRODUCT_WITH_FEED_SCALE)
/* 产品形态运行时可切换EEPROM(偏移172) 存 0/1空白(0xFF) 时用
* main.h PRODUCT_WITH_FEED_SCALE
* 1=()
* 0=()feeding 1
* SCALE SCALE0/SCALE1 */
extern uint8_t g_feed_scale_on;
void feed_scale_load_mode(void); /* app_init 早期调用,加载产品模式 */
void feed_scale_set_mode(uint8_t on); /* 写 EEPROM 并更新全局(重启后完全生效) */
#define FEED_SCALE_MODE_ADDR 172 /* EEPROM 产品模式字节164~171 为电能累计脉冲) */
/* Ͷι״̬ */
typedef enum {

View File

@ -12,6 +12,7 @@
#include "network.h"
#include "net_wifi.h"
#include "hlw8032.h"
#include "feed_scale.h"
#include "net_wifi_ota.h"
#include "air780e.h"
#include "led.h"
@ -264,24 +265,24 @@ void NET_publish_status(int sw1, int feeding, int sw2, int sw3, int sw4,
* sw1 feeding */
/* 无秤模式PRODUCT_WITH_FEED_SCALE=0不上报 zero/onceWt 字段 */
if (s_backend == NET_BACKEND_4G) {
#if PRODUCT_WITH_FEED_SCALE
if (g_feed_scale_on) {
CAT1_printf("AT+MPUB=\"/iot/data/up/%s\",0,0,\"{\\22header\\22:\\22iot.prop.post\\22,\\22body\\22:{\\22ver\\22:%u,\\22weight\\22:%.1f,\\22onceWt\\22:%.1f,\\22zero\\22:%.1f,\\22sw1\\22:%d,\\22feeding\\22:%d,\\22sw2\\22:%d,\\22sw3\\22:%d,\\22sw4\\22:%d}}\"",
MqttInfoStr.ClientID, (unsigned)MqttInfoStr.Ver, zero_kg, once_wt_kg, weight_kg, sw1, feeding, sw2, sw3, sw4);
#else
} else {
CAT1_printf("AT+MPUB=\"/iot/data/up/%s\",0,0,\"{\\22header\\22:\\22iot.prop.post\\22,\\22body\\22:{\\22ver\\22:%u,\\22weight\\22:%.1f,\\22sw1\\22:%d,\\22feeding\\22:%d,\\22sw2\\22:%d,\\22sw3\\22:%d,\\22sw4\\22:%d,\\22energy\\22:%.2f}}\"",
MqttInfoStr.ClientID, (unsigned)MqttInfoStr.Ver, zero_kg, sw1, feeding, sw2, sw3, sw4, (double)hlw8032_get_energy_kwh());
#endif
}
} else {
char json[256];
#if PRODUCT_WITH_FEED_SCALE
if (g_feed_scale_on) {
snprintf(json, sizeof(json),
"{\"header\":\"iot.prop.post\",\"body\":{\"ver\":%u,\"weight\":%.1f,\"onceWt\":%.1f,\"zero\":%.1f,\"sw1\":%d,\"feeding\":%d,\"sw2\":%d,\"sw3\":%d,\"sw4\":%d}}",
(unsigned)MqttInfoStr.Ver, zero_kg, once_wt_kg, weight_kg, sw1, feeding, sw2, sw3, sw4);
#else
} else {
snprintf(json, sizeof(json),
"{\"header\":\"iot.prop.post\",\"body\":{\"ver\":%u,\"weight\":%.1f,\"sw1\":%d,\"feeding\":%d,\"sw2\":%d,\"sw3\":%d,\"sw4\":%d,\"energy\":%.2f}}",
(unsigned)MqttInfoStr.Ver, zero_kg, sw1, feeding, sw2, sw3, sw4, (double)hlw8032_get_energy_kwh());
#endif
}
net_wifi_publish_up(json);
}
net_at_unlock();

View File

@ -110,13 +110,13 @@ void relayInit(void)
* : 1 */
void relayRestoreState(void)
{
#if FEED_SCALE_DISABLED
if (!g_feed_scale_on) {
if (MqttInfoStr.Relay_State[1]) { Relay1_ON; log_info("SW1:开(恢复)"); }
else { Relay1_OFF; log_info("SW1:关(恢复)"); }
#else
} else {
MqttInfoStr.Relay_State[1] = 0;
Relay1_OFF; log_info("SW1:关(不恢复,投喂安全保护)");
#endif
}
if (MqttInfoStr.Relay_State[2]) { Relay2_ON; log_info("SW2:开(恢复)"); }
else { Relay2_OFF; log_info("SW2:关(恢复)"); }
@ -217,14 +217,14 @@ void relayAction(uint8_t *data)
/* 控制继电器前先读取反馈电平 */
fb_before = relayReadFb(ch);
#if !FEED_SCALE_DISABLED
if (g_feed_scale_on) {
/* 称重自动投喂模式下继电器 1 仅由 feeding 指令控制, sw1 直接忽略 */
if (ch == 1) {
log_warn("> 继电器: 称重投喂模式下忽略 sw1请用 feeding 指令");
NET_publish_response(CmdId, 0, "sw1 disabled, use feeding");
return;
}
#endif
}
relaySet(ch, (uint8_t)on);
log_info("> SW%d %s", ch, on ? "" : "");
} else if (strstr((char *)data, "\"feeding\"")) {
@ -239,7 +239,7 @@ void relayAction(uint8_t *data)
ch = 1;
fb_before = relayReadFb(ch);
#if FEED_SCALE_DISABLED
if (!g_feed_scale_on) {
if (value_true) {
relaySet(1, 1);
log_info("> 继电器: 手动投喂开(无秤)");
@ -247,7 +247,7 @@ void relayAction(uint8_t *data)
relaySet(1, 0);
log_info("> 继电器: 手动投喂关(无秤)");
}
#else
} else {
if (value_true) {
/* 首次上电查询到有效重量前不允许启动投喂 */
if (feedScaleGetWeight() == 0) {
@ -274,14 +274,14 @@ void relayAction(uint8_t *data)
log_info("> 继电器: 停止投喂");
feedScaleStop();
}
#endif
}
} else if (proto_locate((char *)data, "onceWt")) {
#if FEED_SCALE_DISABLED
if (!g_feed_scale_on) {
/* 无秤模式:无单次投喂量概念,拒绝设置 */
log_warn("> 继电器: 拒绝设置 onceWt无秤");
NET_publish_response(CmdId, 0, "no scale on this device");
return;
#else
} else {
/* 单独设置单次投喂量, 持久化到 EEPROM */
uint16_t once_wt_100g = 0;
proto_get_kg100((char *)data, "onceWt", &once_wt_100g);
@ -294,14 +294,14 @@ void relayAction(uint8_t *data)
NET_publish_response(CmdId, 1, "OK");
relayStatueUpdata();
return;
#endif
}
} else if (proto_locate((char *)data, "zero")) {
#if FEED_SCALE_DISABLED
if (!g_feed_scale_on) {
/* 无秤模式:无去皮/空载重量概念,拒绝设置 */
log_warn("> 继电器: 拒绝设置 zero无秤");
NET_publish_response(CmdId, 0, "no scale on this device");
return;
#else
} else {
/* 平台下发空载重量/去皮值,直接解析 value 并保存 */
uint16_t zero_100g = 0;
proto_get_kg100((char *)data, "zero", &zero_100g);
@ -314,7 +314,7 @@ void relayAction(uint8_t *data)
NET_publish_response(CmdId, 1, "OK");
relayStatueUpdata();
return;
#endif
}
} else {
log_warn("> 继电器: 未知指令(无 sw/feeding/zero");
return;

View File

@ -83,6 +83,9 @@ void app_init(void)
/* 继电器 GPIO控制输出 + 反馈输入) */
relayInit();
/* 产品模式(带秤/无秤EEPROM 可切,默认跟编译宏) */
feed_scale_load_mode();
/* RS485 喂料秤控制模块 */
feedScaleInit();
@ -98,7 +101,7 @@ void app_init(void)
/* OLED 屏幕128x64 + GB2312 字库 IC */
oled_init();
oled_locate(1, 0); oled_print("4路继电器控制终端");
oled_locate(1, 1); oled_print("继电器控制终端");
oled_locate(2, 2); oled_print("V" FIRMWARE_VERSION_STR " RTOS");
log_info("> OLED: 初始化完成");

View File

@ -21,6 +21,7 @@
#include "net_wifi.h"
#include "esp8266.h"
#include "reset_log.h"
#include "feed_scale.h"
/* 本地命令字符串不区分大小写比较 */
static int cmd_is(const char *a, const char *b)
@ -57,6 +58,25 @@ void process_usart1_command(void)
const char *cmd = USART1_GetCommand();
if (!cmd) return;
/* 产品模式查询/切换SCALE 查询SCALE0=四路继电器(无秤)SCALE1=称重投料(带秤),切换后自动重启生效 */
if (cmd_is(cmd, "SCALE")) {
log_info("> BT: 产品模式 %s", g_feed_scale_on ? "SCALE1 称重投料(带秤)" : "SCALE0 四路继电器(无秤)");
return;
}
if (cmd_is(cmd, "SCALE0") || cmd_is(cmd, "SCALE1")) {
uint8_t on = (cmd[5] == '1') ? 1 : 0;
if (on == g_feed_scale_on) {
log_info("> BT: 已是该模式,无需切换");
return;
}
feed_scale_set_mode(on);
log_warn("> BT: 产品模式已切到 %s重启生效...", on ? "称重投料(带秤)" : "四路继电器(无秤)");
reset_log_mark(RSN_CMD_RESET);
HAL_Delay(200);
NVIC_SystemReset();
return;
}
if (cmd_is(cmd, "RESET")) {
log_warn("> USART1: 收到 RESET 命令,正在重启...");
reset_log_mark(RSN_CMD_RESET);
@ -123,7 +143,7 @@ void process_usart1_command(void)
log_info("> BT: 当前日志等级 %s", lvs[(int)log_get_level()]);
}
else if (cmd_is(cmd, "HELP")) {
log_info("BT CMD: RESET, INFO, STATUS, R1ON/R1OFF~R4ON/R4OFF, ALLON, ALLOFF, OTA, RECOVERY, BLESET, LOG, LOGTRACE, LOGDEBUG, LOGINFO, LOGWARN, LOGERROR, LOGFATAL, HELP");
log_info("BT CMD: RESET, INFO, STATUS, R1ON/R1OFF~R4ON/R4OFF, ALLON, ALLOFF, OTA, RECOVERY, BLESET, SCALE, SCALE0, SCALE1, LOG, LOGTRACE, LOGDEBUG, LOGINFO, LOGWARN, LOGERROR, LOGFATAL, HELP");
}
else {
log_warn("> BT: 未知命令 %s", cmd);

View File

@ -317,6 +317,7 @@ W25Q64 外部 Flash8MB
| 132~157 | 26B | 蓝牙名称配置缓存(命中则开机跳过蓝牙 AT 设置流程) |
| 160 | 1B | 日志等级0~5TRACE/DEBUG/INFO/WARN/ERROR/FATAL |
| 164~171 | 8B | HLW8032 累计脉冲数uint64每攒 0.1kWh + 断电前写入) |
| 172 | 1B | 产品模式0=四路继电器(无秤)1=称重投料(带秤),空白时用 main.h 宏默认值(蓝牙 SCALE0/SCALE1 切换) |
| 250 | 1B | 探测字节(上电写 0xA5 回读,验证 I2C 通信) |
> 注意:改 `MqttInfo_Str` 结构体会改变上述偏移秤参数120+和联网方式130
@ -340,6 +341,10 @@ W25Q64 外部 Flash8MB
下行报文由 `m_app/proto.c` 按键名定位解析(`"sw2"` 不会误中 `"sw21"`,其他字段里的 true/false 不会造成误判)。
## 产品模式(带秤/无秤,运行时可切)
`PRODUCT_WITH_FEED_SCALE` 从纯编译宏改为**运行时可切换**:模式存 EEPROM(172),空白时用 main.h 宏做默认值。蓝牙命令:`SCALE` 查询,`SCALE0`=四路继电器(无秤)`SCALE1`=称重投料(带秤)**切换后自动重启生效**(初始化路径不同,必须重启)。影响范围:状态上报字段(zero/onceWt)、sw1/feeding 指令语义、继电器 1 断电记忆策略、秤轮询开关。
## 串口调试命令
通过 USART1蓝牙串口发送

View File

@ -121,3 +121,8 @@
- OLED 界面重构未联网只显示联网进度4G 各阶段中文提示 / WiFi 固定热点搜索倒计时 /
SmartConfig"请打开APP广播"倒计时),联网后才显示电能/开关/网络/运行时间;
开关状态改中文(开关:开开关关);防烧屏每 10s 内容右移 0/2/4px 轮换
- 产品模式 PRODUCT_WITH_FEED_SCALE 改为运行时可切EEPROM(172) 存 0/1空白用 main.h 宏默认),
蓝牙命令 SCALE 查询 / SCALE0=无秤四路继电器 / SCALE1=带秤称重投料,切换后自动重启生效;
原 9 处 #if 编译分支全部改运行时判断(状态上报字段/sw1·feeding 语义/继电器1记忆/秤轮询)
- OLED 欢迎页改"继电器控制终端 / V1.5.0 RTOS";修复 4G 阻塞建链期间屏幕不显示联网进度
bg_delay 挂调度器启动前的 500ms 刷新钩子)