本框架为了合宙Air780E开发,主要用来连接TCP服务器,通过透明传输进行数据交互。
硬件使用STM32H723ZGT6,通过UART7与4G模块进行交互。串口使用。软件使用Freertos。通过空闲中断+DMA方式进行接收并压入消息队列。
#ifndef BSP_AT_H_
#define BSP_AT_H_
#include "main.h"
#include "string.h"
// AT步骤定义(需与指令表序号对应)
typedef enum {
STEP_AT, // 0: 测试模块
STEP_SIM, // 1: 测试SIM
STEP_ECHO_OFF, // 2: 关闭回显
STEP_CGATT, // 3: 注册网络
STEP_CSTT, // 4: 配置数据网络
STEP_CIICR, // 5: 激活数据网络
STEP_CIPMUX, // 6:设置单链接
STEP_CIPMODE, // 7:开启透明传输
STEP_CIPSTART, // 8:建立TCP连接
STEP_TRANSMIT, // 9:透传数据
STEP_MAX // a:步骤总数(不可删除)
} AT_STEP_t;
typedef struct{
const char* desc; // 步骤描述(用于打印)
const char* cmd; // AT指令(NULL表示无指令)
const char* success_flag; // 成功标志(字符串匹配)
AT_STEP_t next_step; // 成功后跳转的步骤
} AT_CMD_TABLE_t;
void at_callback_fun(void);
#endif
#include "bsp_at.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include <string.h>
#include <stdio.h>
uint8_t air780_rec_buf[100] = {0};
uint8_t tcp_rec_buf[100] = {0};
QueueHandle_t At_Message_Queue = NULL; /* AT消息队列句柄 */
QueueHandle_t Tcp_Raw_Message_Queue = NULL; /* TCP透传接消息队列句柄 */
void Ykc_Task(void const *argument)
{
Tcp_Raw_Message_Queue = xQueueCreate(10, 100);
for(;;)
{
if (xQueueReceive(Tcp_Raw_Message_Queue, &tcp_rec_buf, 10) == pdPASS)
{
printf("data:%s\r\n",tcp_rec_buf);
}
vTaskDelay(1);
}
}
// 任务参数
#define STEP_TIMEOUT_MS 5000
#define SERVER_IP "112.125.89.8"
#define SERVER_PORT 34673
// AT指令表(核心修改区:增减步骤只需修改此表)
const AT_CMD_TABLE_t at_cmd_table[STEP_MAX] = {
{"测试模块通信", "AT", "OK", STEP_SIM},
{"测试SIM模块", "AT+CPIN?", "+CPIN: READY", STEP_ECHO_OFF},
{"关闭回显", "ATE0", "OK", STEP_CGATT},
{"注册网络", "AT+CGATT?", "+CGATT: 1", STEP_CIPMUX},
{"设置单链接模式", "AT+CIPMUX=0", "OK", STEP_CSTT},
{"配置数据网络", "AT+CSTT", "OK", STEP_CIICR},
{"激活数据网络", "AT+CIICR", "OK", STEP_CIPMODE},
{"开启透明传输模式", "AT+CIPMODE=1", "OK", STEP_CIPSTART},
{"建立TCP连接", NULL, "CONNECT", STEP_TRANSMIT},
{"透传数据传输", NULL, NULL, STEP_TRANSMIT}
};
// 全局变量
AT_STEP_t current_step = STEP_AT; // 当前步骤(初始为第一步)
TickType_t step_start_time; // 步骤开始时间戳
// 串口发送AT命令
void AT_Send(const char* cmd) {
if (cmd && strlen(cmd) > 0) {
HAL_UART_Transmit(&huart7, (uint8_t*)cmd, strlen(cmd), 1000);
HAL_UART_Transmit(&huart7, (uint8_t*)"\r\n", 2, 1000);
}
}
// 启动指定步骤(含日志打印)
void step_start(AT_STEP_t step) {
if (step >= STEP_MAX) return;
current_step = step;
step_start_time = xTaskGetTickCount();
const AT_CMD_TABLE_t* entry = &at_cmd_table[step];
printf("[AT] 开始步骤 %d: %s\n", step, entry->desc);
if (entry->cmd) {
AT_Send(entry->cmd); // 固定指令直接发送
} else if (step == STEP_CIPSTART) {
char cmd[64];
sprintf(cmd, "AT+CIPSTART=\"TCP\",\"%s\",%d", SERVER_IP, SERVER_PORT);
AT_Send(cmd);
}
}
// AT Task - 二维数组指令表驱动
void At_Task(void const* argument) {
uint8_t at_rx_msg[100];
At_Message_Queue = xQueueCreate(10, 100);
step_start(STEP_AT);
for (;;) {
// 超时检测(透传模式下关闭)
if (current_step != STEP_TRANSMIT &&
(xTaskGetTickCount() - step_start_time) > pdMS_TO_TICKS(STEP_TIMEOUT_MS)) {
printf("[ERR] 步骤 %d 超时! 重发当前命令\n", current_step);
step_start(current_step); // 超时重发当前步骤
}
// 接收AT回复并处理
if (xQueueReceive(At_Message_Queue, &at_rx_msg, 10) == pdPASS) {
const AT_CMD_TABLE_t* entry = &at_cmd_table[current_step];
if (current_step == STEP_TRANSMIT) {
xQueueSend(Tcp_Raw_Message_Queue, at_rx_msg, 0);
} else if (entry->success_flag && strstr((char*)at_rx_msg, entry->success_flag)) {
step_start(entry->next_step);
}
}
}
}
// UART7空闲中断回调(放队列)
void at_callback_fun() {
uint8_t temp;
if (__HAL_UART_GET_FLAG(&huart7, UART_FLAG_IDLE) != RESET) {
HAL_UART_DMAStop(&huart7);
__HAL_UART_CLEAR_IDLEFLAG(&huart7);
__HAL_UART_CLEAR_OREFLAG(&huart7);
temp = __HAL_DMA_GET_COUNTER(&hdma_uart7_rx);
HAL_UART_Receive_DMA(&huart7, air780_rec_buf, 100);
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(At_Message_Queue, air780_rec_buf, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
memset(air780_rec_buf, 0x00, 100);
}
}

