1.摘要:
使用trae solo,排查代码,并按照给出的建议进行代码优化,代码评分由35分,优化到80分
2.背景:
我是一名STM32的开发工程师,原本程序能够正常,运行,但是由于理解不到位出现了很多隐患和代码不清晰的地方,现在使用traesolo,进行代码的评分和优化,实现了代码的优化,将本来1周左右的工作缩短到1-2天即可完成,大大提高了效率
3.实践过程
通读代码,给出项目分析及结构
然后让solo给出代码评分
并给出优化建议和步骤
按照优化步骤进行优化
优化后再次给出评分
然后让solo持续优化,评分不低于80分
项目分析如下
# ProCubeZsce04_dalindun 代码分析与优化建议
## 1. 项目概述
**项目名称**: ProCubeZsce04_dalindun (智能放风机控制器)
**硬件平台**: STM32F103RBTx (ARM Cortex-M3, 64MHz)
**软件平台**: STM32CubeIDE + FreeRTOS (协作式调度, configUSE_PREEMPTION=0)
**版本**: V2.08 (2025-10-15)
-–
## 2. 系统架构
### 2.1 硬件层次
```
┌─────────────────────────────────────────────────────────────┐
│ STM32F103RBTx │
├─────────────────────────────────────────────────────────────┤
│ USART1 (4G模块EC600N) │ USART2 (调试串口) │
│ I2C1 (AT24C02 EEPROM) │ TIM1 (行程计数) │
│ GPIO (按键/LED/继电器) │ IWDG (看门狗) │
└─────────────────────────────────────────────────────────────┘
```
### 2.2 软件层次
```
┌─────────────────────────────────────────────────────────────┐
│ 应用层 (Application) │
│ my_zsce_fun.c | my_motor.c | ec600n.c | my_key.c │
├─────────────────────────────────────────────────────────────┤
│ 驱动层 (HAL Drivers) │
│ usart.c | i2c.c | gpio.c | tim.c | rtc.c │
├─────────────────────────────────────────────────────────────┤
│ 硬件抽象层 (CMSIS/HAL) │
├─────────────────────────────────────────────────────────────┤
│ FreeRTOS Kernel │
└─────────────────────────────────────────────────────────────┘
```
-–
## 3. 业务流程
### 3.1 系统启动流程
```
main()
├─ HAL_Init()
├─ SystemClock_Config() // 64MHz PLL
├─ MX_GPIO_Init()
├─ MX_I2C1_Init()
├─ MX_IWDG_Init()
├─ MX_RTC_Init()
├─ MX_USART1_UART_Init() // 4G模块
├─ MX_USART2_UART_Init() // 调试串口
├─ MX_TIM1_Init()
├─ fun_init() // 用户初始化
│ ├─ fun_ring_off()
│ ├─ fun_ec600n_init() // 4G模块初始化
│ ├─ fun_led_link_on_off(0)
│ ├─ fun_load_para() // 从AT24C02加载参数
│ ├─ fun_load_user_cs() // 加载用户策略
│ ├─ fun_sth_power_on() // 温湿度传感器上电
│ ├─ fun_motor_init() // 电机初始化
│ └─ Init_DSLED() // 数码管初始化
├─ MX_FREERTOS_Init()
└─ osKernelStart() // 启动RTOS调度
```
### 3.2 任务调度 (协作式, 10ms轮转)
```
┌─────────────────────────────────────────────────────────────┐
│ FreeRTOS Tasks │
├─────────────────────────────────────────────────────────────┤
│ defaultTask (256栈) │ StartDefaultTask → fun_main_loop │
│ EC600Task (640栈) │ vEC600Task → fun_e600_loop │
│ pingShowTask (256栈) │ vPingShowTask → fun_show_loop │
│ keepTask (128栈, idle)│ KeepTask → 监控/重启崩溃线程 │
└─────────────────────────────────────────────────────────────┘
```
### 3.3 各任务核心逻辑
#### defaultTask → fun_main_loop() [1s周期]
```c
void fun_main_loop() {
// 1. MCU运行指示灯 (1s翻转)
fun_mcu_run();
// 2. 4G连接超时检测
if (fun_out_time_change_to_auto()) {
s_status.get_conn = 0;
fun_led_link_on_off(LED_OFF);
}
// 3. 行程计数保存 (每5秒)
fun_counter_save();
// 4. 温湿度采集 (每2秒)
get_dsp_temp_humi(&s_status);
// 5. 自动控制 (每5秒)
auto_control();
// 6. 行程传感器扫描 (每100ms, 位点模式)
if (md_mode == MD_AC_POINT || MD_DC_POINT) {
fun_ac_loop();
incounter_err_fuc();
fun_e03_loop();
}
// 7. 状态更新
update_status(&s_status);
// 8. 电机控制
fun_loop_start();
fun_tim_stop();
// 9. 按键处理
fun_key_loop();
// 10. 喂狗
fun_watchdog_fresh();
}
```
#### EC600Task → fun_e600_loop() [1s周期]
```c
void fun_e600_loop() {
// 1. 4G模块拨号/连接
if (flag_ec600 == 1) {
ec600n_start();
connect_server(&s_uart_1);
http_get_para();
fun_4g_alive();
}
// 2. 串口数据处理
fun_uart_rec_treate();
// 3. 告警检测与上报
if (is_connect_server()) {
if (flag_getconfig && flag_getusercs) {
fun_alarm(s_status.f_temp, s_status.f_humi);
send_alarm();
send_current_to_server();
send_version_to_server();
}
}
}
```
#### pingShowTask → fun_show_loop() [500ms周期]
```c
void fun_show_loop() {
// 1. 版本号显示 (首次)
if (show_first == 0) {
fun_show_num(HARDWARE_VER\*100 + SOFTWARE_VER);
show_first = 1;
}
// 2. 主显示刷新 (每500ms)
fun_show_main();
// 3. LED状态指示
// - 电机正转: LED_SWA 500ms闪烁
// - 电机反转: LED_SWA 100ms闪烁
// - 电机停止: LED_SWA 常亮/常灭 (根据模式)
fun_led_mode(s_status.flag_SMODE == 0 ? 1 : 0);
fun_led_humi(...);
}
```
### 3.4 温湿度自动控制 (auto_control)
#### 控制策略匹配
```
时间窗口匹配 → 找到对应用户策略 → single_user_cs_control()
策略类型:
├─ AUTO_CONTROL_FORCE (mode=0) 强制控制 (直接设置开口CM)
└─ AUTO_CONTROL_WENDU (mode=1) 范围控制 (温度区间控制)
```
#### 温度控制逻辑 (范围控制)
```
温度 < (下限-0.5°C) → fun_close_all() 全关
温度 在[下限±0.5°C] → fun_open_hold() 保持搭边
温度 在[中心±AUTO_WENDU] → fun_close_step() / fun_open_step() 步进
温度 > 上限 → fun_open_step() 步进打开
```
### 3.5 4G通信流程 (EC600N模块)
```
连接服务器步骤:
1. AT+CSQ 获取信号强度
2. AT+QCCID 获取SIM卡号
3. AT+QIFGCNT 配置前置端口
4. AT+QIMODE 透传模式
5. AT+QITCFG 数据格式
6. AT+QIOPEN 连接TCP服务器
7. 发送LOGIN指令 登录认证
```
-–
## 4. 代码结构分析
### 4.1 核心文件
| 文件 | 职责 | 规模 |
|------|------|------|
| my_zsce_fun.c | 主业务逻辑: 参数加载/存储, 自动控制, 告警 | ~2600行 |
| my_motor.c | 电机驱动: 正转/反转/停止, 行程计数, 位点控制 | ~970行 |
| ec600n.c | 4G模块通信: AT指令, TCP连接, 透传数据处理 | ~1400行 |
| my_key.c | 按键处理: 模式切换, 参数设置, 电机控制 | ~1050行 |
| STH3x.c | 温湿度传感器驱动: SHT3x I2C通信 | ~330行 |
| DSLED.c | 数码管显示驱动: TM1629控制 | ~680行 |
| my_uart.c | 串口封装: 接收/发送/命令解析 | ~490行 |
| file_at24c_rw.c | AT24C02 EEPROM读写 | ~94行 |
### 4.2 关键数据结构
```c
// 设备参数 (存储于AT24C02)
struct_device {
u8 store_sn; // 设备序号
u8 smartCover; // 压膜宽度 (搭边距离)
u16 smartScopeLimitUp; // 行程上限 (CM)
u8 smartGear; // 钢管档位 (1/2/3)
u8 control_mode; // 0=自动, 1=手动
u8 emergency_enable; // 应急控制使能
u8 emergency_low/high; // 应急温度阈值
u8 auto_cm; // 每次步进开口 (CM)
u8 auto_stop_time; // 开风口间隔 (秒)
u8 auto_stop_time_close; // 关风口间隔 (秒)
u8 baoliu_start/stop; // 保留风口时间段
...
};
// 用户控制策略 (最多12条)
struct_user_cs {
u16 start_time; // 启动时间 (HHMM)
u16 end_time; // 结束时间 (HHMM)
u8 control_mode_enable; // bit7\~4使能, bit3\~0控制模式
u16 range_low_or_scope; // 强制:开口CM / 范围:下限温度
u16 range_high; // 上限温度
u8 run_time; // 运行时长
u8 stop_time; // 间隔时间
};
// 系统状态
struct_status {
int f_temp; // 温度值 (放大10倍)
u16 f_humi; // 湿度值 (放大10倍)
short data_cm; // 当前行程 (圈数)
u8 status; // 状态字节 (电机方向+传感器状态)
u8 direction; // 1=正转, 2=反转, 3=停止
u8 flag_SMODE; // 0=远程模式, 1=本地模式
u32 time_stop; // 停止时刻
u32 time_server_connect; // 服务器心跳
...
};
// 电机控制
struct_control {
u8 control_mode; // 0=网络, 1=按键
u8 control_flag; // 0=停止, 1=启动
u16 control_cm; // 目标位置 (圈数)
u8 flag_process; // 处理标志
};
```
### 4.3 通信协议
```
AT24C02地址映射 (0x00~0xFF, 256字节):
├─ 0x00~0x08: 网关ID/出厂日期
├─ 0x09: 设备序号
├─ 0x0A~0x10: 压膜宽度/档位/行程/温湿度校准
├─ 0x11: 自动/手动模式
├─ 0x12~0x22: 应急控制/风口保持参数
├─ 0x24~0x79: 用户策略存储 (12条x6字节)
└─ 0x9D~: 历史数据
串口协议 (RS485):
帧格式: [网关ID(5B)] [长度] [命令] [数据] [CRC16高] [CRC16低]
命令: 0x01=读出厂, 0x03=读状态, 0x04=电机控制, 0x05=参数设置
```
-–
## 5. 优化建议
### 5.1 内存与栈溢出风险 [高优先级]
**问题**: 多处代码在中断或临界区使用大数组
```c
// ec600n.c:1404
char c_send[500] = { 0 }; // 栈上分配500字节
// my_zsce_fun.c:730
u8 cmd01_data[50] = { 0 }; // 频繁分配
```
**建议**: 将大数组改为static或全局变量,避免栈溢出
### 5.2 I2C EEPROM写入延迟阻塞 [中优先级]
**问题**: `file_at24c_rw.c:54`使用阻塞式HAL_Delay(10)
```c
void AT24CXX_Write(…) {
HAL_I2C_Mem_Write(...);
HAL_Delay(10); // 阻塞10ms!
}
```
**建议**: 改用DMA+中断方式,或至少使用osDelay替代HAL_Delay避免阻塞RTOS调度
### 5.3 魔法数字与硬编码 [中优先级]
**问题**: 代码中大量未定义的魔法数字
```c
// my_motor.c:624
if ((HAL_GetTick() - tick_fd) >= E03_OUT_TIMES*1000) // E03_OUT_TIMES=30
// my_zsce_fun.c:1800
limit1 = low - 5; // 为什么是5度?
// my_key.c:895
if ((HAL_GetTick() - s_key_mode.tick_pressed) >= 1000) // 长按1秒
```
**建议**: 统一宏定义, 避免重复计算
```c
#define AUTO_WENDU_RANGE 5 // 已在my_struct.h定义
#define KEY_LONG_PRESS_MS 1000
#define E03_TIMEOUT_SEC 30
```
### 5.4 重复代码片段 [中优先级]
**问题**: `extract_num_from_str`与`extract_num_from_str_line`逻辑高度相似
```c
// my_tools.c:262 vs 342
u8 extract_num_from_str(…) {
// 大约80行相似逻辑
}
u8 extract_num_from_str_line(…) {
// 几乎完全相同的80行
}
```
**建议**: 提取公共函数,添加参数区分
### 5.5 sprintf/float格式化开销 [中优先级]
**问题**: 嵌入式环境下sprintf和float运算开销大
```c
// ec600n.c:1151
sprintf(arr_value, “%.1f”, alarm_value / 10.0f); // float除法+格式化
```
**建议**: 使用整数运算替代
```c
sprintf(arr_value, “%d.%d”, alarm_value/10, alarm_value%10);
```
### 5.6 冗余的HAL_Delay调用 [低优先级]
**问题**: `my_motor.c`中多处使用osDelay(1000)进行电机延时
```c
// my_motor.c:499
osDelay(2000); // 电机停止后等待2秒
```
**建议**: 考虑使用状态机替代阻塞延时,提高响应性
### 5.7 中断与临界区处理 [低优先级]
**问题**: `my_uart.c:390`在UART中断中禁用全局中断
```c
void fun_usart_treate(…) {
if (s_uart->flag_rec == 1) {
HAL_NVIC_DisableIRQ(USART2_IRQn); // 禁用所有中断!
...
HAL_NVIC_EnableIRQ(USART2_IRQn);
}
}
```
**建议**: 使用RTOS临界区或仅禁用特定UART中断
### 5.8 调试输出未统一管理 [低优先级]
**问题**: printf分散在多处,debug_show标志冗余
```c
extern u8 debug_show; // 在多个文件中重复声明
if (debug_show == 1) {
printf(...);
}
```
**建议**: 统一调试级别宏定义
```c
#define DEBUG_LEVEL 0 // 0=关闭, 1=错误, 2=Info, 3=Debug
#define debug_printf(level, fmt, …) do { if(level <= DEBUG_LEVEL) printf(fmt, ##_VA_ARGS_); } while(0)
```
### 5.9 看门狗喂狗分布不合理 [低优先级]
**问题**: 喂狗代码分散在每个任务的循环中,每10ms一次
```c
// freertos.c:178,198,218,264
fun_watchdog_fresh(); // 在每个任务中调用
```
**建议**: 考虑在看门狗硬件定时器中断中统一喂狗,或减少喂狗频率
### 5.10 代码注释语言不一致 [低优先级]
**问题**: 注释中英文混杂
```c
// 出厂信息的回复
// response 01 command
// 回应07命令
```
**建议**: 统一为英文或中文
-–
## 6. 已知问题与局限
1. **协作式调度限制**: 所有任务必须主动osDelay(10)让出CPU,长时间阻塞操作会饿死其他任务
2. **浮点数依赖**: 代码中多处使用float进行温度/湿度计算,STM32F1无FPU,效率较低
3. **栈空间紧张**: EC600Task 640字节栈在4G通信处理时可能接近上限
4. **缺乏OTA**: 固件更新依赖外部工具
5. **RTC精度**: 使用外部32.768kHz晶振,误差约±2分钟/天
-–
## 7. 测试建议
1. **边界测试**: 温度-45°C~125°C, 行程0~999cm
2. **通信超时**: 4G模块断网后60秒自动切应急控制
3. **电机堵转**: E03告警触发(30秒无位点变化)
4. **掉电恢复**: EEPROM参数正确加载, 行程数据不丢失
5. **并发测试**: 4G数据和按键同时操作的响应