编程模型 ------ 如何合理接收WIFI模块、4G模块等AT指令形式的数据
通信模块配置(比如设置连接服务器的IP和port)完之后分为透传接收和命令接收,先讨论透传接收:
前提:服务器发给通信模块的数据是一包一包的,每一包数据包含包头、包长和数据,比如一包数据位:AA AA 00 08 01 02 45 FA,其中AA AA表示包头,00 08是包长,01 02 45 FA表示数据(其中01 02是命令,45 FA是命令内容)。
方式一:
每接收到一个字节数据,进入接收中断,并在中断程序中判断是否接收到包头,如果不是包头,index清零;根据接收到的包长判断是否接收完一包数据,接收完进行相应记录,之后接收到的数据继续检测是否是包头。
优点:节省RAM资源,需要一个大数组按顺序接收每个包,一个二维数组记录每个包的起始结束位置。
缺点:中断程序稍微长点,要进行的判断比较多。
......
方法二:
需要用到接收中断、空闲中断。首先需要一个数组A循环接收收到的数据,接收中断程序只要把每字节数据放入数组A即可;空闲中断产生后发布一个信号读取数组A的数据,在读取数据函数中根据包头和包长把一个个数据包取出放入大数组中,并通过二维数组记录每个包的位置信息。
优点:中断函数程序较短。
缺点:多用些RAM资源,包括一个数组A、需要一个大数组按顺序接收每个包,一个二维数组记录每个包的起始结束位置。
接收中断程序:
if(huart == &_2_4G_UART) { __HAL_UNLOCK(&_2_4G_UART); g_from4G[g_from4G_index] = g_recv_4G_value; g_from4G_index++; g_from4G_cnt++; if(g_from4G_index >= FROM4G_SIZE) { g_from4G_index = 0; } HAL_UART_Receive_IT(&_2_4G_UART,(uint8_t *)&g_recv_4G_value,1); }
空闲中断函数
if(__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE) == 1) { __HAL_UART_CLEAR_IDLEFLAG(&huart3); g_from4G_index_tmp = g_from4G_cnt;//这两个变量只在命令模式有用到 xTaskNotifyFromISR( xTaskhandle_uartInt, 0x01, eSetBits, &xHigherPriorityTaskWoken ); }
空闲中断发出信号执行如下程序:
if(g_flag_4G_cmd_or_data == 1)/*现在是命令接收*/ { // g_from4G[g_from4G_index_tmp] = '\0'; //命令反馈 if(my_strstr((u8 *)g_from4G, g_from4G_index_tmp, "OK") != NULL) { xSemaphoreGive( xSemaphoreBinary_4G_cmd ); }else if(my_strstr((u8 *)g_from4G, g_from4G_index_tmp, "ERROR") != NULL) { xSemaphoreGive( xSemaphoreBinary_4G_cmd ); }//URC if(my_strstr((u8 *)g_from4G, g_from4G_index_tmp, "Unknown error") != NULL) { xTaskNotify( xTaskhandle_URC, g_URC_event[URC_UNKNOWN_ERROR], eSetBits ); } if(my_strstr((u8 *)g_from4G, g_from4G_index_tmp, "RDY") != NULL) { xSemaphoreGive( xSemaphoreBinary_4G_cmd ); } }else { u16 index = g_from4G_index; u16 data_length; if(g_from4G_index_after <= index) { data_length = index - g_from4G_index_after; }else { data_length = FROM4G_SIZE - g_from4G_index_after; data_length += index; } u16 tmp_index; static u16 packet_length = 0; static u16 tmp_offset = 0; for(i=0; i<data_length; i++) { if(g_from4G_index_after <= index) { g_serverPackageBuf[g_serverPackageBuf_index] = g_from4G[g_from4G_index_after+i]; }else { if(i < FROM4G_SIZE - g_from4G_index_after) { g_serverPackageBuf[g_serverPackageBuf_index] = g_from4G[g_from4G_index_after+i]; }else { g_serverPackageBuf[g_serverPackageBuf_index] = g_from4G[i-(FROM4G_SIZE - g_from4G_index_after)]; } } tmp_index = g_serverPackageBuf_index; g_serverPackageBuf_index++; if(g_serverPackageBuf_index >= SERVERBUF_SIZE) { g_serverPackageBuf_index = 0; } if(tmp_index == judge_server_index(4 + g_serverPackageBuf_packet_start_index))//长度字段 { if(g_serverPackageBuf[judge_server_index(g_serverPackageBuf_packet_start_index+4)] == 0x00) {//说明长度字段是4字节 tmp_offset = 8; }else { packet_length = g_serverPackageBuf[judge_server_index(g_serverPackageBuf_packet_start_index+4)]; tmp_offset = 5; } } if(tmp_offset == 8) { if(tmp_index == judge_server_index(7 + g_serverPackageBuf_packet_start_index)) { packet_length = (g_serverPackageBuf[judge_server_index(g_serverPackageBuf_packet_start_index+6)]<<8) | g_serverPackageBuf[judge_server_index(g_serverPackageBuf_packet_start_index+7)]; } } if(tmp_index == judge_server_index(0 + g_serverPackageBuf_packet_start_index))//包头第一字节 { if(g_serverPackageBuf[tmp_index] != 0xAA) { g_serverPackageBuf_index = g_serverPackageBuf_packet_start_index; } }else if(tmp_index == judge_server_index(1 + g_serverPackageBuf_packet_start_index))//包头第二字节 { if(g_serverPackageBuf[tmp_index] != 0xAA) { g_serverPackageBuf_index = g_serverPackageBuf_packet_start_index; } }else if(tmp_index == judge_server_index(2 + g_serverPackageBuf_packet_start_index))//包头第三字节 { if(g_serverPackageBuf[tmp_index] != 0xAA) { g_serverPackageBuf_index = g_serverPackageBuf_packet_start_index; } }else if(tmp_index == judge_server_index(3 + g_serverPackageBuf_packet_start_index))//包头第四字节 { if(g_serverPackageBuf[tmp_index] != 0xAA) { g_serverPackageBuf_index = g_serverPackageBuf_packet_start_index; } }else if(tmp_index == judge_server_index(packet_length + tmp_offset + g_serverPackageBuf_packet_start_index))//包尾第一字节 { if(g_serverPackageBuf[tmp_index] != 0xAB) { g_serverPackageBuf_index = g_serverPackageBuf_packet_start_index; } }else if(tmp_index == judge_server_index(packet_length + tmp_offset + 1 + g_serverPackageBuf_packet_start_index))//包尾第二字节 { if(g_serverPackageBuf[tmp_index] != 0xAB) { g_serverPackageBuf_index = g_serverPackageBuf_packet_start_index; } }else if(tmp_index == judge_server_index(packet_length + tmp_offset + 2 + g_serverPackageBuf_packet_start_index))//包尾第三字节 { if(g_serverPackageBuf[tmp_index] != 0xAB) { g_serverPackageBuf_index = g_serverPackageBuf_packet_start_index; } }else if(tmp_index == judge_server_index(packet_length + tmp_offset + 3 + g_serverPackageBuf_packet_start_index))//包尾第四字节 { if(g_serverPackageBuf[tmp_index] != 0xAB) { g_serverPackageBuf_index = g_serverPackageBuf_packet_start_index; }else //一个包接收完成 { g_serverPackageBuf_property[g_serverPackageBuf_packet_record][0] = g_serverPackageBuf_packet_start_index; g_serverPackageBuf_property[g_serverPackageBuf_packet_record][1] = judge_server_index(packet_length + tmp_offset + 3 + g_serverPackageBuf_packet_start_index); g_serverPackageBuf_packet_start_index = g_serverPackageBuf_index; g_serverPackageBuf_packet_record++; if(g_serverPackageBuf_packet_record >= SERVERBUF_PACKET_CAPACITY) { g_serverPackageBuf_packet_record = 0; } xTaskNotifyGive(xTaskhandle_server_communication); tmp_offset = 0; } } } g_from4G_index_after = index; }
现在讨论命令模式接收数据:
需要用到接收中断,空闲中断;处理接收到的数据时要考虑多个数据包一起发给单片机,但只产生一次空闲中断
接收中断程序:
if(huart == &_1_4G_UART) { __HAL_UNLOCK(&_1_4G_UART); g_from4G1[g_from4G1_index] = g_recv_4G1_value; g_from4G1_index_previous = g_from4G1_index; g_from4G1_index++; if(g_from4G1_index >= FROM4G1_SIZE) { g_from4G1_index = 0; } HAL_UART_Receive_IT(&_1_4G_UART,(uint8_t *)&g_recv_4G1_value,1); }
空闲中断程序:
if(__HAL_UART_GET_FLAG(&huart6, UART_FLAG_IDLE) == 1) { __HAL_UART_CLEAR_IDLEFLAG(&huart6); g_from4G1_index_tmp = g_from4G1_index; xTaskNotifyFromISR( xTaskhandle_UART_4G1, 0x01, eSetBits, &xHigherPriorityTaskWoken ); }
空闲中断发出信号执行如下程序:
if(g_flag_clear_semaphore == 1)//发送数据到4G模块,有回显,需要忽略掉回显的数据 { if(g_from4G1_index_tmp > g_cnt_send_to_gddServer_data_len) { remainning_len = g_from4G1_index_tmp - g_cnt_send_to_gddServer_data_len; new_buffer = (u8 *)(g_from4G1 + g_cnt_send_to_gddServer_data_len); }else { remainning_len = 0; new_buffer = (u8 *)g_from4G1; } }else { remainning_len = g_from4G1_index_tmp; new_buffer = (u8 *)g_from4G1; } again:; //URC u8 *p; p = my_strstr((u8 *)new_buffer, remainning_len, "+QIURC: \"recv\",0,"); if(p != NULL) { g_from4G1_index = 0; u8 index=0; u16 tmp; u16 len; tmp = remainning_len - (p - new_buffer);//表示从“+QIURC..."到结束的长度 for(i=18; i<tmp; i++) { if(p[i] == '\n') { index = i+1; break; } } u8 num_byte; num_byte = index-19; len = 0; for(i=0; i<num_byte; i++) { len = len*10 + (p[17+i]-'0'); } remainning_len = tmp - index - 2 - len; new_buffer = p + index + 2 + len; // len = tmp-index-2; p = p + index; printf("\r\n\r\n\r\n"); debug("recv gdd server data: <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"); debug_array((u8 *)p, len); u16 tmp_index; u16 data_length; for(i=0; i<len; i++) { g_gdd_serverPackageBuf[g_gdd_serverPackageBuf_index] = p[i]; tmp_index = g_gdd_serverPackageBuf_index; g_gdd_serverPackageBuf_index++; if(g_gdd_serverPackageBuf_index >= GDD_SERVERBUF_SIZE) { g_gdd_serverPackageBuf_index = 0; } data_length = (g_gdd_serverPackageBuf[judge_gdd_server_index(g_gdd_serverPackageBuf_packet_start_index+2)]<<8) | g_gdd_serverPackageBuf[judge_gdd_server_index(g_gdd_serverPackageBuf_packet_start_index+3)]; if(tmp_index == judge_gdd_server_index(0 + g_gdd_serverPackageBuf_packet_start_index)) { if(g_gdd_serverPackageBuf[tmp_index] != 0x01) { g_gdd_serverPackageBuf_index = g_gdd_serverPackageBuf_packet_start_index; } }else if(tmp_index == judge_gdd_server_index(1 + g_gdd_serverPackageBuf_packet_start_index)) { }else if(tmp_index == judge_gdd_server_index(2 + g_gdd_serverPackageBuf_packet_start_index)) { }else if(tmp_index == judge_gdd_server_index(data_length - 1 + g_gdd_serverPackageBuf_packet_start_index)) { g_gdd_serverPackageBuf_property[g_gdd_serverPackageBuf_packet_record][0] = g_gdd_serverPackageBuf_packet_start_index; g_gdd_serverPackageBuf_property[g_gdd_serverPackageBuf_packet_record][1] = judge_gdd_server_index(data_length - 1 + g_gdd_serverPackageBuf_packet_start_index); g_gdd_serverPackageBuf_packet_start_index = g_gdd_serverPackageBuf_index; g_gdd_serverPackageBuf_packet_record++; if(g_gdd_serverPackageBuf_packet_record >= GDD_SERVERBUF_PACKET_CAPACITY) { g_gdd_serverPackageBuf_packet_record = 0; } xTaskNotifyGive(xTaskhandle_gdd_server_communication); } } if(remainning_len > 0) { goto again; } }else { //命令反馈 if(my_strstr((u8 *)new_buffer, remainning_len, "SEND OK") != NULL) { debug("----------------------------------------------------------------------%d %s", remainning_len, "SEND OK"); xSemaphoreGive( xSemaphoreBinary_4G1_cmd ); }else if(my_strstr((u8 *)new_buffer, remainning_len, "ERROR") != NULL) { debug("----------------------------------------------------------------------%d %s", remainning_len, "ERROR"); xSemaphoreGive( xSemaphoreBinary_4G1_cmd ); }if(my_strstr((u8 *)new_buffer, remainning_len, "RDY") != NULL) { debug("----------------------------------------------------------------------%d %s", remainning_len, "RDY"); xSemaphoreGive( xSemaphoreBinary_4G1_cmd ); } p = my_strstr((u8 *)new_buffer, remainning_len, "+QIURC: \"closed\",0"); if(p != NULL) { debug("----------------------------------------------------------------------%d %s", remainning_len, "+QIURC: \"closed\",0"); g_from4G1_index = 0; // error("%s", p); error("gdd server close socket"); notify_URC_ENTER_SLEEP_GDD(); } }
4G模块发送数据的函数:
u8 LTE4G_send_data_cmd_gdd(u8 *buffer, u16 index, u16 length) { u16 i; if(exec_cmd_gdd_server("AT+QISTATE=1,0\r", 10) != 0) { error("not connect to server, close and reconnect"); return 1; } char cmd_send[100]; sprintf(cmd_send, "AT+QISEND=0,%d\r", length); if(exec_cmd_gdd_server(cmd_send, 10) != 0) { error("%s, revc > timeout", cmd_send); return 2; } g_from4G1_index = 0; g_flag_clear_semaphore = 1; g_cnt_send_to_gddServer_data_len = length; u8 *p = buffer + index; for(i=0; i<length; i++) { // *p = 0x3E; HAL_UART_Transmit(&LET4G_uart, p, 1, 1000); p++; } if(xSemaphoreTake( xSemaphoreBinary_4G1_cmd, pdMS_TO_TICKS( 1000*5 )) == pdPASS) { g_flag_clear_semaphore = 0; if(my_strstr((u8 *)g_from4G1, g_from4G1_index_tmp, "SEND OK") != NULL) { debug("SEND OK"); return 0; }else if(my_strstr((u8 *)g_from4G1, g_from4G1_index_tmp, "SEND FAIL") != NULL) { error("SEND FAIL"); return 4; }else if(my_strstr((u8 *)g_from4G1, g_from4G1_index_tmp, "ERROR") != NULL) { error("ERROR"); return 4; }else { error("unknow error, recv %.*s", g_from4G1_index_tmp, g_from4G1); return 4; } }else { g_flag_clear_semaphore = 0; error("AT+QISEND=0, recv SEND OK timeout"); return 3; } }
标签:
单片机
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
2016-05-19 RCC电路 - 自激式反激转换器