# 嵌入式调试开发指南 ## 项目简介 本项目旨在实现基于 STM32F103 的嵌入式开发,支持通过 TCP/IP 协议进行数据传输。以下内容将详细介绍如何配置和使用相关功能。 --- ## 环境准备 ### 硬件需求 - STM32F103 开发板 - USB 转串口模块 - 连接线 ### 软件需求 - 串口调试工具(如 XCOM 或 SecureCRT) - TCP 测试软件 --- ## 配置步骤 ### 1. 串口配置 1. 选择实际的串口号(如 COM4)。 2. 设置波特率为 `115200`。 ### 2. AT 指令操作 #### 配置 Wi-Fi ```bash AT+CWMODE=1 # 设置工作模式为 STA AT+CWJAP="ssid","password" # 配置 Wi-Fi ``` #### 连接服务器 ```bash AT+CIPSTART="TCP","192.168.1.101",3456 # 连接服务器,IP 为电脑的 IP,端口为 3456 AT+SAVETRANSLINK=1,"192.168.1.101",3456,"TCP" # 保存连接信息,开机后自动连接 AT+CIPMODE=1 # 设置为透传模式 AT+CIPSEND # 发送数据 HELLOWORLD # 示例数据 ``` #### 退出透传模式 进入自动透传模式后,如需重新配置(如更换 IP),需退出透传模式: 1. 在串口助手中发送 `+++`。 2. 注意: - 不要勾选“发送新行”。 - 发送 `+++` 后,停顿 1 秒以上不要发送任何数据。 3. 模块返回 `OK` 后,即可重新进入命令模式。 --- ## 测试与验证 ### 1. 启动服务器 使用 TCP 测试软件创建服务器并启动。 ### 2. 实际连接与发送测试 通过串口助手发送数据,验证数据是否成功传输。 --- ## 连接示意图 ![连接线示意图](image.png) --- ## 常见问题 ### 1. 无法连接服务器 - 检查 IP 和端口是否正确。 - 确保 Wi-Fi 配置无误。 ### 2. 透传模式无法退出 - 确保发送 `+++` 时未勾选“发送新行”。 - 确保发送后停顿 1 秒以上。 --- ## 附录 ### 相关工具截图 #### TCP 测试软件 ![TCP 测试软件](image-2.png) #### 创建服务器 ![创建服务器](image-3.png) #### 启动服务器 ![启动服务器](image-4.png) #### 实际连接发送测试 ![实际连接发送测试](image-5.png) --- ## 串口重定向 使用以下函数,用于串口重定向: ```c #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif PUTCHAR_PROTOTYPE { HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, HAL_MAX_DELAY); return ch; } ``` 该函数用于将 `printf` 输出重定向到串口。 --- ## TCP 接收与发送 ### 接收数据 使用空闲中断接收 TCP 数据,开启了 DMA 接收: ```c void UART_IDLE_Callback(UART_HandleTypeDef *huart) { /* 仅处理 USART1 的实例 */ if (huart == NULL || huart->Instance != USART1) return; /* 清除空闲中断标志位(HAL库宏) */ __HAL_UART_CLEAR_IDLEFLAG(huart); /* 停止 DMA 以便安全读取计数器并更新状态 */ HAL_UART_DMAStop(huart); /* 计算接收到的字节数:总缓冲区长度 - DMA 剩余传输计数 */ uint16_t recv_len = UART1_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart->hdmarx); if (recv_len > 0 && recv_len < UART1_RX_BUF_SIZE) { uart1_rx_len = recv_len; uart1_rx_buf[recv_len] = '\0'; /* 添加字符串结束符,方便后续字符串处理 */ uart1_rx_flag = 1; /* 置位标志,通知应用层新消息到达 */ /* 仅供调试:在中断中打印接收到的数据(注意:printf 可能会影响实时性) */ elog_raw("UART1 Received: %s\r\n", (char *)uart1_rx_buf); } /* 重新启动新一轮的 DMA 接收 */ HAL_UART_Receive_DMA(&huart1, uart1_rx_buf, UART1_RX_BUF_SIZE); } ``` ### 发送数据 封装了发送函数,只需填入数据即可发送: ```c const char *message = "Hello, ESP12F! This is a test message."; HAL_StatusTypeDef status = ESP12F_TCP_SendMessage(message); ``` 这些是上位机发送的指令: 按照这些来写代码 这是一个基于 TCP/IP 局域网通信的物流小车控制指令协议设计方案。 为了方便调试和开发,本协议采用 **ASCII 文本格式**(类似于 Modbus ASCII 或简单的串口透传格式),而不是二进制格式。这样你可以直接使用网络调试助手(如 NetAssist)手动发送字符串来测试小车,而无需编写专门的上位机软件。 --- ### 📡 通信基础参数 - **通信方式**:TCP Client (上位机) 连接 TCP Server (单片机/小车) - **数据格式**:ASCII 字符串 - **换行符**:建议使用 `\r\n` (回车+换行) 作为每条指令的结束标志,以便单片机解析。 - **字节序**:N/A (文本协议不涉及大小端问题) --- ### 📦 指令帧结构 每条指令由以下几个部分组成,字段之间用英文冒号 `:` 分隔: `[帧头][命令字][数据内容][校验和][帧尾]` - **帧头**:固定为 `LOGI` (代表 Logistics),用于快速识别有效数据包。 - **命令字**:2位字符,代表具体操作(如 `GS` 代表去站点)。 - **数据内容**:具体的参数,长度可变。 - **校验和**:2位十六进制数,用于验证数据完整性(防止丢包或乱码)。 - **帧尾**:固定为 `#`。 --- ### 📝 具体控制指令定义 以下是针对你提出的四个需求(去站点、停止、启动、速度)的具体指令格式。 #### 1. 去往指定站点 - **功能**:指示小车移动到编号为 N 的站点。 - **指令格式**:`LOGI:GS:NNN:CS#` - **参数说明**: - `GS`: 命令字 (Go to Station)。 - `NNN`: 站点编号,3位数字,不足补0。例如:1号站写为 `001`,12号站写为 `012`。 - `CS`: 校验和。 - **示例**: - 去往 **5号站点**:`LOGI:GS:005:15#` (假设校验和计算结果为15) #### 2. 启动运行 - **功能**:让处于停止或待机状态的小车开始执行任务或继续运行。 - **指令格式**:`LOGI:ST:RUN:CS#` - **参数说明**: - `ST`: 命令字 (Start/Status)。 - `RUN`: 固定参数,表示启动。 - **示例**: - 启动小车:`LOGI:ST:RUN:2A#` #### 3. 紧急停止/暂停 - **功能**:立即停止小车的运动,通常用于急停或到达站点后的确认暂停。 - **指令格式**:`LOGI:ST:STOP:CS#` - **参数说明**: - `STOP`: 固定参数,表示停止。 - **示例**: - 停止小车:`LOGI:ST:STOP:32#` #### 4. 设置运行速度 - **功能**:动态调整小车的行驶速度。 - **指令格式**:`LOGI:SP:VVV:CS#` - **参数说明**: - `SP`: 命令字 (Set Speed)。 - `VVV`: 速度值,3位数字 (000-100),代表百分比或具体PWM占空比等级。 - `000`: 停止 - `050`: 50% 速度 - `100`: 全速 - **示例**: - 设置速度为 **80%**:`LOGI:SP:080:04#` --- ### 🧮 校验和算法 为了防止无线信号干扰导致指令错误,我们需要一个简单的校验和。 - **算法**:将 **帧头** 到 **数据内容** 结束的所有字符的 ASCII 码值相加,然后对 256 取余,最后转换为 2位十六进制字符串。 - **公式**:`Sum = (Byte1 + Byte2 + ... + ByteN) % 256` **举例计算 (去往 1 号站点):** 1. 原始字符串:`LOGI:GS:001` 2. ASCII 码值相加: - 'L'(76) + 'O'(79) + 'G'(71) + 'I'(73) + ':'(58) + 'G'(71) + 'S'(83) + ':'(58) + '0'(48) + '0'(48) + '1'(49) - 总和 = 614 3. 取余:`614 % 256 = 102` 4. 转十六进制:`102` -> `66` 5. 最终发送指令:`LOGI:GS:001:66#` --- ### 💬 小车回复机制 (可选但推荐) 单片机执行指令后,应向上位机返回执行结果,以便上位机显示状态。 **回复格式**:`[命令字]:[状态码]:[描述]#` - **状态码定义**: - `OK`: 指令接收正确并执行。 - `ERR`: 指令格式错误或校验失败。 - `BUSY`: 小车正在忙,无法执行新指令。 **示例回复**: - 成功去往站点:`GS:OK:Arrived#` - 速度设置成功:`SP:OK:SpeedSet#` - 校验错误:`CMD:ERR:CheckSum#` --- ### 📌 总结清单 你可以直接将下表发给单片机开发人员: | 功能 | 指令模板 | 示例 (假设校验和为 XX) | 说明 | | :--- | :--- | :--- | :--- | | **去站点** | `LOGI:GS:NNN:XX#` | `LOGI:GS:003:XX#` | NNN为3位站点号 | | **启动** | `LOGI:ST:RUN:XX#` | `LOGI:ST:RUN:XX#` | 开始运动 | | **停止** | `LOGI:ST:STOP:XX#` | `LOGI:ST:STOP:XX#` | 立即停止 | | **设速度** | `LOGI:SP:VVV:XX#` | `LOGI:SP:050:XX#` | VVV为0-100 | 我创建了 处理解析指令的任务和传递消息的消息队列。 ![指令处理任务和队列](image-6.png)