当前位置: 首页 > news >正文

MCU 通用AT指令处理框架

文章目录

    • 设计原理与架构图
      • 类图表示
      • 序列图: AT命令发送流程
      • 序列图: URC处理流程
    • 头文件: `at_client.h`
    • 源文件: `at_client.c`
    • 使用示例

​ 本文描述了一个基于RTOS的通用AT指令处理框架设计,适用于各类嵌入式MCU系统。该框架提供了完整的AT指令通信能力,包括命令发送、响应处理、URC事件处理和数据透传模式。

设计原理与架构图

类图表示

URC注册表
1
*
命令状态
1
1
at_client_t
- int uart_port
- uint32_t baudrate
- uint32_t default_timeout
- at_cmd_state_t cmd_state
- bool in_data_mode
- bool cmd_in_progress
- data_receive_cb_t data_cb
- void* data_context
- urc_entry_t* urc_table
- size_t urc_table_size
- size_t urc_count
- SemaphoreHandle_t mutex
- SemaphoreHandle_t resp_sem
- TaskHandle_t task_handle
+at_status_t(*send_command)
+void(*register_urc)
+void(*enter_data_mode)
+void(*exit_data_mode)
+size_t(*send_data)
urc_entry_t
- const char* prefix
- urc_handler_t handler
- void* context
at_cmd_state_t
- const char* expect
- uint32_t timeout
- char* resp_buf
- size_t buf_size
- size_t resp_len

序列图: AT命令发送流程

应用程序AT客户端UART驱动RTOS内核send_command("AT+CSQ", "+CSQ:", 2000, buffer, 128)获取互斥锁锁成功发送"AT+CSQ\r\n"等待响应信号量(2000ms)超时释放互斥锁AT_TIMEOUT接收到"+CSQ:24,99"匹配到期望响应发送响应信号量信号量到达释放互斥锁AT_OKalt[超时][收到响应]应用程序AT客户端UART驱动RTOS内核

序列图: URC处理流程

UART驱动AT客户端应用程序接收到"+CMT: +8613800138000,Hello"检查URC表调用注册的URC处理函数处理短信通知vUART驱动AT客户端应用程序

头文件: at_client.h

#ifndef AT_CLIENT_H
#define AT_CLIENT_H#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>// RTOS头文件 (根据实际RTOS选择)
#ifdef USE_FREERTOS
#include "FreeRTOS.h"
#include "semphr.h"
#else
// 其他RTOS适配
#endif// AT指令执行状态
typedef enum {AT_OK = 0,      // 执行成功AT_ERROR,       // 执行失败AT_TIMEOUT,     // 超时AT_BUSY,        // 模块忙AT_MEM_ERR,     // 内存错误AT_PARAM_ERR    // 参数错误
} at_status_t;// URC处理函数类型
typedef void (*urc_handler_t)(void* context, const char* urc);// 数据接收回调类型
typedef void (*data_receive_cb_t)(void* context, uint8_t* data, size_t len);// URC注册项
typedef struct {const char* prefix;         // URC前缀urc_handler_t handler;      // 处理函数void* context;              // 上下文指针
} urc_entry_t;// AT命令状态
typedef struct {const char* expect;         // 期望响应uint32_t timeout;           // 超时时间 (RTOS ticks)char* resp_buf;             // 响应缓冲区size_t buf_size;            // 缓冲区大小size_t resp_len;            // 已接收长度
} at_cmd_state_t;// AT客户端对象
typedef struct at_client {// 配置参数int uart_port;              // UART端口号uint32_t baudrate;          // 波特率uint32_t default_timeout;   // 默认超时(ms)// 内部状态at_cmd_state_t cmd_state;   // 命令状态bool in_data_mode;          // 数据模式标志bool cmd_in_progress;       // 命令执行中标志// 回调函数data_receive_cb_t data_cb;  // 数据接收回调void* data_context;         // 数据回调上下文// URC处理urc_entry_t* urc_table;     // URC注册表size_t urc_table_size;      // URC表大小size_t urc_count;           // 已注册URC数量// RTOS资源#ifdef USE_FREERTOSSemaphoreHandle_t mutex;    // 互斥锁SemaphoreHandle_t resp_sem; // 响应信号量TaskHandle_t task_handle;   // 任务句柄#endif// 方法指针at_status_t (*send_command)(struct at_client* self, const char* cmd, const char* expect, uint32_t timeout, char* resp_buf, size_t buf_size);void (*register_urc)(struct at_client* self, const char* prefix, urc_handler_t handler, void* context);void (*enter_data_mode)(struct at_client* self, data_receive_cb_t cb, void* context);void (*exit_data_mode)(struct at_client* self);size_t (*send_data)(struct at_client* self, const uint8_t* data, size_t len);
} at_client_t;// 创建AT客户端实例
at_client_t* at_client_create(int uart_port, uint32_t baudrate, uint32_t default_timeout);// 销毁AT客户端实例
void at_client_destroy(at_client_t* client);// 启动AT服务任务
bool at_client_start(at_client_t* client);// 停止AT服务任务
void at_client_stop(at_client_t* client);#endif // AT_CLIENT_H

源文件: at_client.c

#include "at_client.h"
#include <string.h>
#include <stdio.h>// 模拟UART驱动接口
void uart_write(int port, const uint8_t* data, size_t len);
size_t uart_read(int port, uint8_t* data, size_t len, uint32_t timeout);// 内部函数声明
static void at_service_task(void* arg);
static void at_process_line(at_client_t* client, const char* line);
static at_status_t at_cmd_send_impl(at_client_t* self, const char* cmd, const char* expect, uint32_t timeout, char* resp_buf, size_t buf_size);static void register_urc_impl(at_client_t* self, const char* prefix, urc_handler_t handler, void* context);static void enter_data_mode_impl(at_client_t* self, data_receive_cb_t cb, void* context);static void exit_data_mode_impl(at_client_t* self);static size_t send_data_impl(at_client_t* self, const uint8_t* data, size_t len);// 创建AT客户端实例
at_client_t* at_client_create(int uart_port, uint32_t baudrate, uint32_t default_timeout) {at_client_t* client = malloc(sizeof(at_client_t));if (!client) return NULL;memset(client, 0, sizeof(at_client_t));// 初始化配置client->uart_port = uart_port;client->baudrate = baudrate;client->default_timeout = default_timeout;// 初始化状态client->cmd_in_progress = false;client->in_data_mode = false;// 初始化方法指针client->send_command = at_cmd_send_impl;client->register_urc = register_urc_impl;client->enter_data_mode = enter_data_mode_impl;client->exit_data_mode = exit_data_mode_impl;client->send_data = send_data_impl;// 创建URC表 (固定大小)client->urc_table_size = 10;client->urc_table = malloc(client->urc_table_size * sizeof(urc_entry_t));if (!client->urc_table) {free(client);return NULL;}memset(client->urc_table, 0, client->urc_table_size * sizeof(urc_entry_t));client->urc_count = 0;// 创建RTOS资源#ifdef USE_FREERTOSclient->mutex = xSemaphoreCreateMutex();client->resp_sem = xSemaphoreCreateBinary();if (!client->mutex || !client->resp_sem) {free(client->urc_table);free(client);return NULL;}#endifreturn client;
}// 销毁AT客户端实例
void at_client_destroy(at_client_t* client) {if (!client) return;// 停止服务任务at_client_stop(client);// 释放RTOS资源#ifdef USE_FREERTOSif (client->mutex) vSemaphoreDelete(client->mutex);if (client->resp_sem) vSemaphoreDelete(client->resp_sem);#endif// 释放URC表if (client->urc_table) free(client->urc_table);// 释放命令状态缓冲区if (client->cmd_state.resp_buf) free(client->cmd_state.resp_buf);free(client);
}// 启动AT服务任务
bool at_client_start(at_client_t* client) {#ifdef USE_FREERTOS// 创建服务任务BaseType_t result = xTaskCreate(at_service_task,        // 任务函数"AT_Service",           // 任务名configMINIMAL_STACK_SIZE * 4, // 堆栈大小client,                 // 参数tskIDLE_PRIORITY + 2,   // 优先级&client->task_handle    // 任务句柄);return (result == pdPASS);#else// 其他RTOS实现return true;#endif
}// 停止AT服务任务
void at_client_stop(at_client_t* client) {#ifdef USE_FREERTOSif (client->task_handle) {vTaskDelete(client->task_handle);client->task_handle = NULL;}#endif
}// AT服务任务实现
static void at_service_task(void* arg) {at_client_t* client = (at_client_t*)arg;uint8_t rx_buf[256];size_t rx_index = 0;while (1) {uint8_t c;// 从串口读取一个字节if (uart_read(client->uart_port, &c, 1, 10) != 1) {#ifdef USE_FREERTOSvTaskDelay(1); // 短暂延时避免忙等#endifcontinue;}// 处理回车符(忽略)if (c == '\r') {continue;}// 处理换行符(行结束)if (c == '\n') {if (rx_index > 0) {rx_buf[rx_index] = '\0'; // 确保字符串终止if (client->in_data_mode) {// 数据模式处理if (client->data_cb) {client->data_cb(client->data_context, rx_buf, rx_index);}} else {// 命令模式处理at_process_line(client, (const char*)rx_buf);}rx_index = 0;}continue;}// 处理普通字符if (rx_index < sizeof(rx_buf) - 1) {rx_buf[rx_index++] = c;} else {// 缓冲区溢出处理rx_index = 0; // 重置缓冲区}}
}// 处理接收行
static void at_process_line(at_client_t* client, const char* line) {// 1. 检查URCfor (size_t i = 0; i < client->urc_count; i++) {urc_entry_t* entry = &client->urc_table[i];if (strstr(line, entry->prefix) == line) {entry->handler(entry->context, line);return;}}// 2. 检查命令响应if (client->cmd_in_progress) {// 检查期望响应if (strstr(line, client->cmd_state.expect) != NULL) {// 成功响应#ifdef USE_FREERTOSxSemaphoreGive(client->resp_sem);#endif} // 检查错误响应else if (strstr(line, "ERROR") != NULL) {// 错误响应#ifdef USE_FREERTOSxSemaphoreGive(client->resp_sem);#endif}// 保存响应数据if (client->cmd_state.resp_buf && client->cmd_state.resp_len < client->cmd_state.buf_size) {int len = snprintf(client->cmd_state.resp_buf + client->cmd_state.resp_len,client->cmd_state.buf_size - client->cmd_state.resp_len,"%s\n", line);if (len > 0) {client->cmd_state.resp_len += len;}}}
}// AT命令发送实现
static at_status_t at_cmd_send_impl(at_client_t* self, const char* cmd, const char* expect, uint32_t timeout, char* resp_buf, size_t buf_size) {#ifdef USE_FREERTOS// 获取互斥锁if (xSemaphoreTake(self->mutex, pdMS_TO_TICKS(100)) != pdTRUE) {return AT_BUSY;}#endif// 检查是否已有命令在执行if (self->cmd_in_progress) {#ifdef USE_FREERTOSxSemaphoreGive(self->mutex);#endifreturn AT_BUSY;}// 设置命令状态self->cmd_in_progress = true;self->cmd_state.expect = expect ? expect : "OK";self->cmd_state.timeout = timeout ? timeout : self->default_timeout;self->cmd_state.resp_buf = resp_buf;self->cmd_state.buf_size = buf_size;self->cmd_state.resp_len = 0;// 发送命令uart_write(self->uart_port, (const uint8_t*)cmd, strlen(cmd));uart_write(self->uart_port, (const uint8_t*)"\r\n", 2);// 等待响应at_status_t status = AT_TIMEOUT;#ifdef USE_FREERTOSif (xSemaphoreTake(self->resp_sem, pdMS_TO_TICKS(self->cmd_state.timeout)) == pdTRUE) {status = AT_OK;}#endif// 清理命令状态self->cmd_in_progress = false;#ifdef USE_FREERTOSxSemaphoreGive(self->mutex);#endifreturn status;
}// 注册URC实现
static void register_urc_impl(at_client_t* self, const char* prefix, urc_handler_t handler, void* context) {if (!prefix || !handler) return;#ifdef USE_FREERTOSxSemaphoreTake(self->mutex, portMAX_DELAY);#endif// 检查是否已存在for (size_t i = 0; i < self->urc_count; i++) {if (strcmp(self->urc_table[i].prefix, prefix) == 0) {// 更新现有条目self->urc_table[i].handler = handler;self->urc_table[i].context = context;#ifdef USE_FREERTOSxSemaphoreGive(self->mutex);#endifreturn;}}// 添加新条目if (self->urc_count < self->urc_table_size) {urc_entry_t* entry = &self->urc_table[self->urc_count++];entry->prefix = prefix;entry->handler = handler;entry->context = context;}#ifdef USE_FREERTOSxSemaphoreGive(self->mutex);#endif
}// 进入数据模式实现
static void enter_data_mode_impl(at_client_t* self, data_receive_cb_t cb, void* context) {#ifdef USE_FREERTOSxSemaphoreTake(self->mutex, portMAX_DELAY);#endifself->in_data_mode = true;self->data_cb = cb;self->data_context = context;#ifdef USE_FREERTOSxSemaphoreGive(self->mutex);#endif
}// 退出数据模式实现
static void exit_data_mode_impl(at_client_t* self) {#ifdef USE_FREERTOSxSemaphoreTake(self->mutex, portMAX_DELAY);#endifself->in_data_mode = false;self->data_cb = NULL;self->data_context = NULL;#ifdef USE_FREERTOSxSemaphoreGive(self->mutex);#endif
}// 发送数据实现
static size_t send_data_impl(at_client_t* self, const uint8_t* data, size_t len) {#ifdef USE_FREERTOSxSemaphoreTake(self->mutex, portMAX_DELAY);#endifsize_t sent = 0;if (self->in_data_mode) {sent = uart_write(self->uart_port, data, len);}#ifdef USE_FREERTOSxSemaphoreGive(self->mutex);#endifreturn sent;
}

使用示例

#include "at_client.h"// URC处理函数
void sms_urc_handler(void* context, const char* urc) {printf("Received SMS: %s\n", urc);// 实际项目中解析短信内容
}// 数据接收回调
void data_receive_callback(void* context, uint8_t* data, size_t len) {printf("Received %zu bytes: %.*s\n", len, (int)len, data);
}int main() {// 创建AT客户端at_client_t* at_client = at_client_create(1, 115200, 2000);if (!at_client) {printf("Failed to create AT client\n");return -1;}// 注册URCat_client->register_urc(at_client, "+CMT:", sms_urc_handler, NULL);// 启动服务任务if (!at_client_start(at_client)) {printf("Failed to start AT service\n");at_client_destroy(at_client);return -1;}// 发送AT命令char resp_buffer[128];at_status_t status = at_client->send_command(at_client, "AT+CSQ", "+CSQ:", 2000, resp_buffer, sizeof(resp_buffer));if (status == AT_OK) {printf("Signal quality: %s\n", resp_buffer);} else {printf("Command failed: %d\n", status);}// 进入数据模式at_client->enter_data_mode(at_client, data_receive_callback, NULL);// 发送数据const char* data = "Hello, module!";at_client->send_data(at_client, (uint8_t*)data, strlen(data));// 保持运行...while(1) {// 主循环}// 清理资源at_client_stop(at_client);at_client_destroy(at_client);return 0;
http://www.lryc.cn/news/601471.html

相关文章:

  • PDF转图片实用指南:如何批量高效转换?
  • 创建的springboot工程java文件夹下还是文件夹而不是包
  • 内网服务器实现从公网穿透
  • 单片机ADC采集机理层面详细分析(二)
  • 零基础学习性能测试第五章:JVM性能分析与调优-多线程检测与瓶颈分析
  • 【C语言网络编程基础】TCP 服务器详解
  • Rust与Java DynamoDB、MySQL CRM、tokio-pg、SVM、Custors实战指南
  • 墨者:通过手动解决SQL手工注入漏洞测试(MySQL数据库)
  • Wireshark TS | 发送数据超出接收窗口
  • 双面15.6寸智能访客机硬件规格书及对接第三方接口说明
  • 力扣 hot100 Day57
  • 数据江湖的“三国演义”:数据仓库、数据湖与湖仓一体的全景对比
  • 区块链:工作量证明与联邦学习
  • 神经网络知识讨论
  • 【旧文】Adobe Express使用教程
  • 7月27日星期日今日早报简报微语报早读
  • 数据赋能(340)——技术平台——共享平台
  • Spring之【Bean的生命周期】
  • 视频转GIF工具,一键批量制作高清动图
  • GIt学习——分布式版本控制工具
  • Triton IR
  • Python折线图
  • Java面试新趋势:云原生与新兴框架实战解析
  • 零基础学习性能测试第五章:Tomcat的性能分析与调优-Tomcat原理,核心配置项,性能瓶颈分析,调优
  • MySQL ROUTER安装部署
  • Java面试实战:安全框架与大数据技术深度解析
  • 深度解析 inaSpeechSegmenter:高效音频语音分割与检测开源工具
  • 基于 LSTM 与 SVM 融合的时间序列预测模型:理论框架与协同机制—实践算法(1)
  • maven命令详解
  • Redis C++客户端——命令使用