2026-08-09 10:07:21 +08:00
|
|
|
|
/* feed_scale.c - 485 喂料秤控制
|
|
|
|
|
|
*
|
|
|
|
|
|
* 硬件: USART2 接 RS485 磅秤传感器,PA2(TX), PA3(RX),9600-8N1
|
|
|
|
|
|
* 协议: 查询命令 {0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0xC4, 0x0B}
|
|
|
|
|
|
* 应答: 9 字节(地址1 + 功能码1 + 字节数1 + 数据4 + CRC2),重量值在数据字节[3..6],小端 float,单位 KG。
|
|
|
|
|
|
* 业务: 平台下发单次投喂量 onceWt(0.1KG 单位),继电器 1 吸合开始投喂,
|
|
|
|
|
|
* 当 起始剩余重量 - 当前重量 >= 单次投喂量 时停止。
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "feed_scale.h"
|
|
|
|
|
|
#include "relay.h"
|
|
|
|
|
|
#include "uart.h"
|
|
|
|
|
|
#include "log.h"
|
|
|
|
|
|
#include "network.h"
|
|
|
|
|
|
#include "24c02.h"
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
|
|
/* 查询秤的 Modbus 命令 */
|
|
|
|
|
|
static const uint8_t RS485_WEIGHT_CMD[8] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0xC4, 0x0B};
|
|
|
|
|
|
|
|
|
|
|
|
/* 运行状态 */
|
|
|
|
|
|
static FeedScaleState feed_state = FEED_IDLE;
|
|
|
|
|
|
static uint16_t once_weight = 0; /* 单次投喂量,0.1KG 单位,从 EEPROM 读取 */
|
|
|
|
|
|
static uint16_t start_weight = 0; /* 本次投喂开始时的剩余重量 */
|
|
|
|
|
|
static uint16_t last_weight = 0; /* 最近一次有效净重(已去皮) */
|
|
|
|
|
|
static uint16_t last_raw_weight = 0; /* 最近一次 485 原始毛重(未去皮) */
|
|
|
|
|
|
static uint16_t reduced_weight = 0; /* 本次投喂减少的重量 */
|
|
|
|
|
|
static uint16_t zero_weight = 0; /* 去皮重量,EEPROM 掉电保持 */
|
|
|
|
|
|
|
|
|
|
|
|
/* 轮询计时 */
|
|
|
|
|
|
static uint32_t last_query_tick = 0;
|
|
|
|
|
|
static uint32_t feed_start_tick = 0; /* 投喂开始时刻,用于超时保护 */
|
|
|
|
|
|
static uint8_t first_query_sent = 0; /* 首次上电查询已发送 */
|
|
|
|
|
|
static uint8_t first_query_reported = 0; /* 首次上电有效重量已上报 */
|
|
|
|
|
|
|
|
|
|
|
|
/* 重量异常增加计数 */
|
|
|
|
|
|
static uint8_t add_weight_count = 0;
|
|
|
|
|
|
#define FEED_ADD_WEIGHT_LIMIT 20u /* 连续约 10s 重量反而增加,结束投喂 */
|
|
|
|
|
|
|
|
|
|
|
|
/* 单次投喂超时 10 分钟 */
|
|
|
|
|
|
#define FEED_TIMEOUT_MS (10u * 60u * 1000u)
|
|
|
|
|
|
|
|
|
|
|
|
/* EEPROM 中保存去皮重量和单次投喂量的偏移(在 MqttInfoStr 之外) */
|
|
|
|
|
|
#define FEED_SCALE_ZERO_ADDR 120u
|
|
|
|
|
|
#define FEED_SCALE_ONCEWT_ADDR 122u
|
|
|
|
|
|
#define FEED_SCALE_INIT_FLAG_ADDR 124u
|
|
|
|
|
|
#define FEED_SCALE_INIT_FLAG 0xA5u
|
|
|
|
|
|
|
|
|
|
|
|
/* 本地 CRC16 校验 (Modbus) */
|
|
|
|
|
|
static uint16_t crc16_modbus(const uint8_t *data, uint16_t len)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint16_t crc = 0xFFFF;
|
|
|
|
|
|
for (uint16_t i = 0; i < len; i++) {
|
|
|
|
|
|
crc ^= data[i];
|
|
|
|
|
|
for (uint8_t j = 0; j < 8; j++) {
|
|
|
|
|
|
if (crc & 0x0001) {
|
|
|
|
|
|
crc = (crc >> 1) ^ 0xA001;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
crc >>= 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return crc;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 从 485 应答中解析重量,应答 9 字节: 01 03 04 41 97 30 33 0B F6 */
|
|
|
|
|
|
static int feed_scale_parse_weight(const uint8_t *buf, uint16_t len, uint16_t *weight_100g)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (len < 9) {
|
|
|
|
|
|
log_warn("> FEED: 485 帧长度过短, len=%d", (int)len);
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t calc_crc = crc16_modbus(buf, 7); /* 前 7 字节参与 CRC 计算 */
|
|
|
|
|
|
uint16_t recv_crc = (uint16_t)buf[8] << 8 | buf[7]; /* 最后两字节为 CRC */
|
|
|
|
|
|
if (calc_crc != recv_crc) {
|
|
|
|
|
|
log_warn("> FEED: 485 CRC 校验错误, calc=0x%04X recv=0x%04X", calc_crc, recv_crc);
|
|
|
|
|
|
return -2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 大端 float: 数据字节[3]=MSB, [6]=LSB,参考 APP12 解析方式 */
|
|
|
|
|
|
float fweight;
|
|
|
|
|
|
uint8_t *p = (uint8_t *)&fweight;
|
|
|
|
|
|
p[0] = buf[6];
|
|
|
|
|
|
p[1] = buf[5];
|
|
|
|
|
|
p[2] = buf[4];
|
|
|
|
|
|
p[3] = buf[3];
|
|
|
|
|
|
|
|
|
|
|
|
/* 转成 0.1KG 整数单位,限制范围 */
|
|
|
|
|
|
int32_t wt = (int32_t)(fweight * 10.0f);
|
|
|
|
|
|
if (wt < 0) wt = 0;
|
|
|
|
|
|
if (wt > FEED_SCALE_WEIGHT_MAX) wt = FEED_SCALE_WEIGHT_MAX;
|
|
|
|
|
|
*weight_100g = (uint16_t)wt;
|
|
|
|
|
|
log_info("> FEED: 485 原始毛重=%.1fKG (0.1kg=%d)", fweight, *weight_100g);
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 通过 USART2 发送 485 查询命令 */
|
|
|
|
|
|
static void feed_scale_send_query(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
HAL_UART_Transmit(&huart2, (uint8_t *)RS485_WEIGHT_CMD, sizeof(RS485_WEIGHT_CMD), 100);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 读取 485 返回帧 */
|
|
|
|
|
|
static int feed_scale_read_frame(uint8_t *buf, uint16_t max_len)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint16_t len = USART2_GetFrame(buf, max_len);
|
|
|
|
|
|
if (len == 0) return 0;
|
|
|
|
|
|
return (int)len;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 上报当前状态到平台: 开关、重量、单次投料量、去皮重量 */
|
|
|
|
|
|
static void feed_scale_report_weight(const char *header)
|
|
|
|
|
|
{
|
|
|
|
|
|
(void)header;
|
|
|
|
|
|
/* 云平台字段映射:把剩余料重放到 zero 字段,空载重量放到 weight 字段 */
|
|
|
|
|
|
/* sw1 与 feeding 均上报继电器 1 状态,平台两个开关都能同步刷新 */
|
|
|
|
|
|
NET_publish_status(
|
|
|
|
|
|
MqttInfoStr.Relay_State[1] ? 1 : 0,
|
|
|
|
|
|
MqttInfoStr.Relay_State[1] ? 1 : 0,
|
|
|
|
|
|
MqttInfoStr.Relay_State[2] ? 1 : 0,
|
|
|
|
|
|
MqttInfoStr.Relay_State[3] ? 1 : 0,
|
|
|
|
|
|
MqttInfoStr.Relay_State[4] ? 1 : 0,
|
|
|
|
|
|
(float)zero_weight / 10.0f,
|
|
|
|
|
|
(float)once_weight / 10.0f,
|
|
|
|
|
|
(float)last_weight / 10.0f);
|
|
|
|
|
|
log_info("> FEED: 净重=%.1fKG 单次投料=%.1fKG 去皮=%.1fKG",
|
|
|
|
|
|
(float)last_weight / 10.0f,
|
|
|
|
|
|
(float)once_weight / 10.0f,
|
|
|
|
|
|
(float)zero_weight / 10.0f);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void feedScaleInit(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t tmp[2] = {0};
|
|
|
|
|
|
|
|
|
|
|
|
/* 检测是否是空白/新刷机单片机,是则强制写入默认 1.0KG */
|
|
|
|
|
|
eepromReadData(FEED_SCALE_INIT_FLAG_ADDR, tmp, 1);
|
|
|
|
|
|
if (tmp[0] != FEED_SCALE_INIT_FLAG) {
|
|
|
|
|
|
tmp[0] = FEED_SCALE_INIT_FLAG;
|
|
|
|
|
|
eepromWriteData(FEED_SCALE_INIT_FLAG_ADDR, tmp, 1);
|
|
|
|
|
|
|
|
|
|
|
|
zero_weight = 10; /* 默认去皮 1.0KG */
|
|
|
|
|
|
once_weight = 10; /* 默认单次投料 1.0KG */
|
|
|
|
|
|
|
|
|
|
|
|
tmp[0] = (uint8_t)(zero_weight & 0xFF);
|
|
|
|
|
|
tmp[1] = (uint8_t)(zero_weight >> 8);
|
|
|
|
|
|
eepromWriteData(FEED_SCALE_ZERO_ADDR, tmp, 2);
|
|
|
|
|
|
|
|
|
|
|
|
tmp[0] = (uint8_t)(once_weight & 0xFF);
|
|
|
|
|
|
tmp[1] = (uint8_t)(once_weight >> 8);
|
|
|
|
|
|
eepromWriteData(FEED_SCALE_ONCEWT_ADDR, tmp, 2);
|
|
|
|
|
|
|
|
|
|
|
|
log_info("> FEED: 首次初始化, 设置默认 去皮=1.0KG, 单次投料=1.0KG");
|
|
|
|
|
|
} else {
|
|
|
|
|
|
eepromReadData(FEED_SCALE_ZERO_ADDR, tmp, 2);
|
|
|
|
|
|
zero_weight = (uint16_t)tmp[0] | ((uint16_t)tmp[1] << 8);
|
|
|
|
|
|
if (zero_weight == 0 || zero_weight > FEED_SCALE_WEIGHT_MAX) {
|
|
|
|
|
|
zero_weight = 10; /* 默认去皮 1.0KG */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
eepromReadData(FEED_SCALE_ONCEWT_ADDR, tmp, 2);
|
|
|
|
|
|
once_weight = (uint16_t)tmp[0] | ((uint16_t)tmp[1] << 8);
|
|
|
|
|
|
if (once_weight == 0 || once_weight > FEED_SCALE_WEIGHT_MAX) {
|
|
|
|
|
|
once_weight = 10; /* 默认单次投料 1.0KG */
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-09 10:18:47 +08:00
|
|
|
|
#if !FEED_SCALE_DISABLED
|
2026-08-09 10:07:21 +08:00
|
|
|
|
log_info("> FEED: 初始化, 去皮=%.1fKG, 单次投料=%.1fKG",
|
|
|
|
|
|
(float)zero_weight / 10.0f, (float)once_weight / 10.0f);
|
2026-08-09 10:18:47 +08:00
|
|
|
|
#endif
|
2026-08-09 10:07:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void feedScaleSetZero(uint16_t zero_100g)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (zero_100g > FEED_SCALE_WEIGHT_MAX) return;
|
|
|
|
|
|
zero_weight = zero_100g;
|
|
|
|
|
|
|
|
|
|
|
|
/* 平台下发新空载重量后,用最新原始毛重重新计算剩余料重 */
|
|
|
|
|
|
if (last_raw_weight >= zero_weight) {
|
|
|
|
|
|
last_weight = last_raw_weight - zero_weight;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
last_weight = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t tmp[2] = { (uint8_t)(zero_weight & 0xFF), (uint8_t)(zero_weight >> 8) };
|
|
|
|
|
|
eepromWriteData(FEED_SCALE_ZERO_ADDR, tmp, 2);
|
|
|
|
|
|
log_info("> FEED: 设置去皮=%.1fKG, 重算净重=%.1fKG",
|
|
|
|
|
|
(float)zero_weight / 10.0f, (float)last_weight / 10.0f);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void feedScaleSetOnceWeight(uint16_t once_wt_100g)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (once_wt_100g > FEED_SCALE_WEIGHT_MAX) return;
|
|
|
|
|
|
once_weight = once_wt_100g;
|
|
|
|
|
|
uint8_t tmp[2] = { (uint8_t)(once_weight & 0xFF), (uint8_t)(once_weight >> 8) };
|
|
|
|
|
|
eepromWriteData(FEED_SCALE_ONCEWT_ADDR, tmp, 2);
|
|
|
|
|
|
log_info("> FEED: 设置单次投料=%.1fKG", (float)once_weight / 10.0f);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t feedScaleGetOnceWeight(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
return once_weight;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t feedScaleGetWeight(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
return last_weight;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t feedScaleGetZero(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
return zero_weight;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 获取最近一次 485 原始毛重(未去皮,0.1KG 单位) */
|
|
|
|
|
|
uint16_t feedScaleGetRawWeight(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
return last_raw_weight;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FeedScaleState feedScaleGetState(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
return feed_state;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t feedScaleGetReduced(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
return reduced_weight;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void feedScaleStart(uint16_t once_wt_100g)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (once_wt_100g < FEED_SCALE_ONCEWT_MIN || once_wt_100g > FEED_SCALE_ONCEWT_MAX) {
|
|
|
|
|
|
log_warn("> FEED: 单次投料量无效=%.1fKG", (float)once_wt_100g / 10.0f);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (feed_state == FEED_RUNNING) {
|
|
|
|
|
|
log_warn("> FEED: 正在投喂中, 忽略本次请求");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (first_query_reported == 0) {
|
|
|
|
|
|
log_warn("> FEED: 秤未就绪, 无法开始投喂");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (last_weight == 0) {
|
|
|
|
|
|
log_warn("> FEED: 剩余重量为 0, 无法开始投喂");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
once_weight = once_wt_100g;
|
|
|
|
|
|
start_weight = last_weight; /* 取最近一次重量作为起始重量 */
|
|
|
|
|
|
reduced_weight = 0;
|
|
|
|
|
|
add_weight_count = 0;
|
|
|
|
|
|
feed_start_tick = HAL_GetTick();
|
|
|
|
|
|
feed_state = FEED_RUNNING;
|
|
|
|
|
|
|
|
|
|
|
|
relaySet(1, 1);
|
|
|
|
|
|
eepromWriteData(102, &MqttInfoStr.Relay_State[0], 7);
|
|
|
|
|
|
log_info("> FEED: 开始投喂 单次=%.1fKG, 起始=%.1fKG, 继电器1=开",
|
|
|
|
|
|
(float)once_weight / 10.0f, (float)start_weight / 10.0f);
|
|
|
|
|
|
|
|
|
|
|
|
/* 投喂开始时立即上报一次状态 */
|
|
|
|
|
|
feed_scale_report_weight("iot.prop.post");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void feedScaleStop(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (feed_state == FEED_IDLE) return;
|
|
|
|
|
|
relaySet(1, 0);
|
|
|
|
|
|
eepromWriteData(102, &MqttInfoStr.Relay_State[0], 7);
|
|
|
|
|
|
feed_state = FEED_DONE;
|
|
|
|
|
|
log_info("> FEED: 停止投喂, 已减少=%.1fKG", (float)reduced_weight / 10.0f);
|
|
|
|
|
|
relayRequestReport();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void feed_scale_finish_error(const char *reason)
|
|
|
|
|
|
{
|
|
|
|
|
|
relaySet(1, 0);
|
|
|
|
|
|
eepromWriteData(102, &MqttInfoStr.Relay_State[0], 7);
|
|
|
|
|
|
feed_state = FEED_ERROR;
|
|
|
|
|
|
log_warn("> FEED: 异常停止, %s", reason);
|
|
|
|
|
|
relayRequestReport();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void feedScaleProcess(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
#if FEED_SCALE_DISABLED
|
|
|
|
|
|
return;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t rx_buf[32];
|
|
|
|
|
|
int len;
|
|
|
|
|
|
uint16_t cur_weight;
|
|
|
|
|
|
int32_t diff;
|
|
|
|
|
|
|
|
|
|
|
|
/* 触发 USART2 帧超时自动提交 */
|
|
|
|
|
|
USART2_Tick();
|
|
|
|
|
|
|
|
|
|
|
|
/* 空闲时 10s 查询一次; 投喂时 1s 查询一次;
|
|
|
|
|
|
不累计无响应计数,手动测试时漏回也不会一直刷超时 */
|
|
|
|
|
|
uint32_t query_interval = (feed_state == FEED_RUNNING) ? FEED_SCALE_QUERY_RUN_MS : FEED_SCALE_QUERY_IDLE_MS;
|
|
|
|
|
|
|
|
|
|
|
|
if (first_query_sent == 0 || (HAL_GetTick() - last_query_tick) >= query_interval) {
|
|
|
|
|
|
last_query_tick = HAL_GetTick();
|
|
|
|
|
|
feed_scale_send_query();
|
|
|
|
|
|
if (first_query_sent == 0) {
|
|
|
|
|
|
first_query_sent = 1;
|
|
|
|
|
|
log_info("> FEED: 首次查询已发送");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 读取 485 返回 */
|
|
|
|
|
|
len = feed_scale_read_frame(rx_buf, sizeof(rx_buf));
|
|
|
|
|
|
if (len > 0) {
|
|
|
|
|
|
if (feed_scale_parse_weight(rx_buf, len, &cur_weight) == 0) {
|
|
|
|
|
|
last_raw_weight = cur_weight; /* 保存原始毛重 */
|
|
|
|
|
|
last_weight = cur_weight > zero_weight ? (cur_weight - zero_weight) : 0; /* 净重 */
|
|
|
|
|
|
if (!first_query_reported) {
|
|
|
|
|
|
/* 首次上电: 查询到一次有效重量后上报平台 */
|
|
|
|
|
|
first_query_reported = 1;
|
|
|
|
|
|
feed_scale_report_weight("iot.prop.post");
|
|
|
|
|
|
log_info("> FEED: 首次重量已上报");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (feed_state == FEED_RUNNING) {
|
|
|
|
|
|
/* 投喂期间:每次有效重量都上报平台,保证实时 */
|
|
|
|
|
|
feed_scale_report_weight("iot.prop.post");
|
|
|
|
|
|
|
|
|
|
|
|
/* 计算减少量,去零后比较 */
|
|
|
|
|
|
diff = (int32_t)start_weight - (int32_t)last_weight;
|
|
|
|
|
|
if (diff < 0) diff = -diff;
|
|
|
|
|
|
reduced_weight = (uint16_t)diff;
|
|
|
|
|
|
log_info("> FEED: 投喂中 起始=%.1f 当前=%.1f 已减=%.1f 单次=%.1f",
|
|
|
|
|
|
(float)start_weight / 10.0f, (float)last_weight / 10.0f,
|
|
|
|
|
|
(float)reduced_weight / 10.0f, (float)once_weight / 10.0f);
|
|
|
|
|
|
|
|
|
|
|
|
/* 条件1: 达到/超过单次投喂量,停止 */
|
|
|
|
|
|
if (reduced_weight >= once_weight) {
|
|
|
|
|
|
log_info("> FEED: 达到目标投喂量, 停止");
|
|
|
|
|
|
feedScaleStop();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 条件2: 重量反而增加,可能有人在加料,连续超过阈值后结束 */
|
|
|
|
|
|
if (last_weight > start_weight) {
|
|
|
|
|
|
add_weight_count++;
|
|
|
|
|
|
if (add_weight_count >= FEED_ADD_WEIGHT_LIMIT) {
|
|
|
|
|
|
feed_scale_finish_error("重量反增");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
add_weight_count = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 条件3: 投喂超时 5 分钟 */
|
|
|
|
|
|
if (HAL_GetTick() - feed_start_tick > FEED_TIMEOUT_MS) {
|
|
|
|
|
|
feed_scale_finish_error("投喂超时");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 清理已完成状态,让外部模块在下一循环前处理 */
|
|
|
|
|
|
if (feed_state == FEED_DONE || feed_state == FEED_ERROR) {
|
|
|
|
|
|
/* 状态保持一次,由 relay 状态机上报 */
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|