# 实现逻辑详解 ## 1. 系统工作流程 ### 1.1 主程序流程图 ``` ┌─────────────────┐ │ 系统初始化 │ ├─────────────────┤ │ 硬件模块初始化 │ ├─────────────────┤ │ WiFi连接尝试 │ ├─────────────────┤ │ TCP连接建立 │ ├─────────────────┤ │ 设备注册发送 │ ├─────────────────┤ │ 主循环处理 │ └─────────────────┘ ``` ### 1.2 详细工作流程 #### 第一阶段:系统初始化 (main.c:32-50) ```c // 1. 中断优先级配置 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 2. 硬件模块初始化顺序 led_init(); // LED状态指示 beep_init(); // 蜂鸣器控制 systick_init(); // 系统时钟 usart1_init(115200); // 调试串口 eeprom_init(); // 配置存储 oled_init(); // 显示屏 dht11_init(); // 温湿度传感器 adc1_init(); // ADC采集 ``` **初始化逻辑说明**: - LED初始关闭,避免误触发 - 串口初始化为115200波特率,用于调试输出 - OLED显示屏初始化后立即准备显示数据 #### 第二阶段:网络连接 (main.c:52-79) ```c // WiFi连接逻辑 if (esp8266_connect_wifi(WIFI_SSID, WIFI_PASS)) { printf("Connected to WiFi\r\n"); // TCP连接逻辑 if (esp8266_tcp_connect(SERVER_IP, SERVER_PORT)) { tcp_connected = 1; // 设备注册消息 char reg_msg[128]; int reg_len = snprintf(reg_msg, sizeof(reg_msg), "{\"type\":\"register\",\"device_id\":\"%s\",\"action\":\"connect\"}\n", DEVICE_ID); } } ``` **连接策略**: - 先建立WiFi连接,再尝试TCP连接 - 连接成功后发送设备注册消息 - 失败时设置tcp_connected=0,进入重连机制 ## 2. 主循环实现逻辑 ### 2.1 数据采集与显示 (main.c:95-112) ```c // 传感器数据采集 u8 value[5]; dht11_get_values(value); // 获取温湿度数据 // OLED显示更新 sprintf(buf, "\xce\xc2\xb6\xc8: %5.1f \xa1\xe6", (float)value[2]); // 温度 oled_draw_text16(8, 8, buf); sprintf(buf, "\xca\xaa\xb6\xc8: %5.1f%%", (float)value[0]); // 湿度 oled_draw_text16(8, 24, buf); sprintf(buf, "ADC Value: %04d", adc1_get_value(10)); // ADC oled_draw_text8(8, 40, buf); sprintf(buf, "LED(0): %3s", led_get_status(0) ? "ON" : "OFF"); // LED状态 oled_draw_text8(8, 48, buf); oled_refresh_framebuffer(); // 刷新显示 ``` **实现细节**: - DHT11数据格式:`value[0-1]`湿度,`value[2-3]`温度,`value[4]`校验和 - OLED使用GBK编码显示中文 - 显示区域划分:温度(8,8),湿度(8,24),ADC(8,40),LED状态(8,48) ### 2.2 网络重连机制 (main.c:116-148) ```c static int reconnect_counter = 0; int reconnect_threshold = RECONNECT_PERIOD_MS / SEND_INTERVAL_MS; if (!tcp_connected) { if (reconnect_counter >= reconnect_threshold) { reconnect_counter = 0; // 尝试重连 if (esp8266_tcp_connect(SERVER_IP, SERVER_PORT)) { tcp_connected = 1; // 重连后重新注册 char reg_msg[128]; int reg_len = snprintf(reg_msg, sizeof(reg_msg), "{\"type\":\"register\",\"device_id\":\"%s\",\"action\":\"reconnect\"}\n", DEVICE_ID); } } else { printf("Not connected to TCP server, skipping send\r\n"); delay_ms(SEND_INTERVAL_MS); continue; // 跳过本次循环的数据发送 } } ``` **重连策略**: - 每5秒尝试一次重连(RECONNECT_PERIOD_MS = 5000ms) - 重连成功后发送"reconnect"类型的注册消息 - 连接断开期间跳过数据发送,避免错误 ### 2.3 数据发送逻辑 (main.c:150-169) ```c // JSON数据构造 char json[256]; int msg_len = snprintf(json, sizeof(json), "{\"device_id\":\"%s\",\"temp\":%.1f,\"humidity\":%.1f,\"buzzer\":%d,\"led0\":%d,\"led1\":%d,\"led2\":%d}\n", DEVICE_ID, (float)value[2], // 温度 (float)value[0], // 湿度 beep_get_status(), // 蜂鸣器状态 led_get_status(0), // LED0状态 led_get_status(1), // LED1状态 led_get_status(2)); // LED2状态 // 发送数据 esp8266_clear_read_buf(); // 清空接收缓冲区 int sent = esp8266_write(json, (uint16_t)msg_len); ``` **数据格式说明**: - 发送频率:200ms一次(SEND_INTERVAL_MS) - 数据格式:JSON,以换行符结束 - 包含设备ID、传感器数据、执行器状态 ### 2.4 控制命令接收与解析 (main.c:171-218) ```c // 主动请求控制命令 if (tcp_connected) { char getcmd[64]; snprintf(getcmd, sizeof(getcmd), "GET control %s\n", DEVICE_ID); int gsent = esp8266_write(getcmd, (uint16_t)strlen(getcmd)); } // 接收并解析控制命令 char inbuf[256]; int rlen = esp8266_read(inbuf, sizeof(inbuf)); if (rlen > 0) { inbuf[rlen] = '\0'; printf("Control recv: %s\r\n", inbuf); // 解析蜂鸣器控制 char *p = strstr(inbuf, "\"buzzer\""); if (p) { p = strchr(p, ':'); if (p && sscanf(p+1, "%d", &val) == 1) { if (val) { beep_on(); } else { beep_off(); } } } // 解析LED控制 (led0, led1, led2) for (int i = 0; i < 3; i++) { char key[16]; sprintf(key, "\"led%d\"", i); p = strstr(inbuf, key); if (p) { p = strchr(p, ':'); if (p && sscanf(p+1, "%d", &val) == 1) { led_set_status(i, val ? 1 : 0); } } } } ``` **控制协议解析**: - 使用轮询模式主动获取控制命令 - 支持的控制命令:`{"buzzer":1,"led0":1,"led1":0,"led2":0}` - 实时应用控制命令到硬件设备 ## 3. 关键算法实现 ### 3.1 DHT11时序控制算法 (dht11.c) ```c int dht11_get_values(u8 buf[5]) { // 1. 发送起始信号 DHT11_DATA_OUT = 0; // 拉低数据线 delay_ms(20); // 保持18ms以上 DHT11_DATA_OUT = 1; // 拉高数据线 delay_us(30); // 等待20-40us // 2. 等待传感器响应 while(DHT11_DATA_IN && timeout < 20) { delay_us(2); timeout++; } // 3. 读取40位数据 for(int i = 0; i < 5; i++) { for(int bit = 0; bit < 8; bit++) { // 等待50us低电平 while(!DHT11_DATA_IN); // 等待高电平结束 delay_us(40); if(DHT11_DATA_IN) { data_bit = 1; // '1'位 } else { data_bit = 0; // '0'位 } // 等待高电平结束 while(DHT11_DATA_IN); // 组装字节 buf[i] <<= 1; buf[i] |= data_bit; } } return 1; } ``` **时序要点**: - 起始信号:拉低18ms,拉高20-40us - 数据位判断:40us后检测电平状态 - 完整数据:40位(5字节),包含校验和 ### 3.2 ESP8266 AT指令控制 (esp8266.c) ```c int esp8266_connect_wifi(const char *ssid, const char *passwd) { char cmd[128]; // 1. 设置WiFi模式 usart2_send_string("AT+CWMODE=1\r\n"); if(!esp8266_wait_response("OK", 2000)) return 0; // 2. 连接WiFi sprintf(cmd, "AT+CWJAP=\"%s\",\"%s\"\r\n", ssid, passwd); usart2_send_string(cmd); if(!esp8266_wait_response("OK", 10000)) return 0; return 1; } int esp8266_tcp_connect(const char *ip, uint16_t port) { char cmd[64]; sprintf(cmd, "AT+CIPSTART=\"TCP\",\"%s\",%d\r\n", ip, port); usart2_send_string(cmd); return esp8266_wait_response("CONNECT", 5000); } ``` **AT指令流程**: - 设置WiFi模式为Station模式 - 连接指定WiFi网络(最长等待10秒) - 建立TCP连接到服务器 ### 3.3 OLED显示驱动 (oled.c) ```c void oled_refresh_framebuffer(void) { // 1. 设置列地址范围 OLED_write_command(0x21); // 列地址设置命令 OLED_write_command(0); // 起始列 OLED_write_command(127); // 结束列 // 2. 设置页地址范围 OLED_write_command(0x22); // 页地址设置命令 OLED_write_command(0); // 起始页 OLED_write_command(7); // 结束页 // 3. 发送帧缓冲区数据 for(int i = 0; i < 1024; i++) { OLED_write_data(OLED_FrameBuffer[i]); } } ``` **显示原理**: - 使用1024字节帧缓冲区(128×64÷8) - SSD1306支持页寻址模式,每页8行 - 批量发送整个帧缓冲区内容 ## 4. 错误处理与容错机制 ### 4.1 网络错误处理 ```c // 发送失败处理 int sent = esp8266_write(json, (uint16_t)msg_len); if (sent > 0) { printf("Sent: %s\r\n", json); } else { printf("Send failed\r\n"); tcp_connected = 0; // 标记连接断开 } ``` ### 4.2 传感器读取异常处理 ```c u8 dht11_data[5]; if (dht11_get_values(dht11_data)) { // 数据校验 u8 checksum = dht11_data[0] + dht11_data[1] + dht11_data[2] + dht11_data[3]; if (checksum != dht11_data[4]) { printf("DHT11 checksum error\r\n"); // 使用上一次的有效数据或默认值 } } ``` ### 4.3 内存保护机制 ```c // 缓冲区溢出保护 int msg_len = snprintf(json, sizeof(json), "..."); if (msg_len >= sizeof(json)) { msg_len = sizeof(json) - 1; // 截断过长数据 json[msg_len] = '\0'; } ``` ## 5. 性能优化策略 ### 5.1 时间片调度 - 数据采集:每次循环执行 - 网络发送:200ms间隔 - 显示刷新:每次循环执行 - 控制请求:每次循环执行 ### 5.2 资源使用优化 - 静态内存分配,避免动态内存碎片 - 字符串缓冲区复用 - 中断驱动的外设操作 ### 5.3 网络通信优化 - 批量发送JSON数据 - 清空接收缓冲区避免数据累积 - 连接断开时跳过发送操作 --- **文档版本**: v1.0 **最后更新**: 2025-11-16 **作者**: STM32项目组