嵌入式分层架构下的AT指令模块设计与实现
概述
在嵌入式系统开发中,良好的软件架构设计能够显著提高代码的可维护性和可移植性。本文将以STM32系列微控制器为例,介绍如何通过分层抽象和函数指针实现一个低耦合、高可移植性的AT指令模块。
设计思想
1. 分层架构
我们将系统分为三个主要层次:
- 硬件抽象层(HAL):隔离底层硬件差异
- 驱动层(Driver):实现AT指令核心逻辑
- 应用层(Application):业务逻辑实现
2. 面向接口编程
通过结构体和函数指针实现接口抽象,使各层之间通过定义良好的接口进行通信,降低模块间的耦合度。
实现代码
硬件抽象层(HAL)部分代码
// hal_uart.h
#ifndef __HAL_UART_H__
#define __HAL_UART_H__#include <stdint.h>
#include <stddef.h>// UART配置结构体
typedef struct {uint32_t baudrate;uint8_t data_bits;uint8_t stop_bits;uint8_t parity;
} uart_config_t;// UART操作接口
typedef struct {int (*init)(void *handle, uart_config_t *config);int (*deinit)(void *handle);int (*send)(void *handle, const uint8_t *data, size_t length);int (*recv)(void *handle, uint8_t *buffer, size_t length, uint32_t timeout);int (*set_rx_callback)(void *handle, void (*callback)(uint8_t data));
} uart_ops_t;// UART设备结构体
typedef struct {void *handle;uart_ops_t ops;
} uart_device_t;// 外部声明具体UART设备的实现
extern uart_device_t uart1_device;#endif /* __HAL_UART_H__ */
// hal_uart_stm32f1.c
#include "hal_uart.h"
#include "stm32f1xx_hal.h"// STM32F1系列UART实现
static UART_HandleTypeDef huart1;static int uart1_init(void *handle, uart_config_t *config) {// 初始化代码实现huart1.Instance = USART1;huart1.Init.BaudRate = config->baudrate;// 其他配置...return HAL_UART_Init(&huart1) == HAL_OK ? 0 : -1;
}static int uart1_send(void *handle, const uint8_t *data, size_t length) {return HAL_UART_Transmit(&huart1, (uint8_t *)data, length, 1000) == HAL_OK ? 0 : -1;
}// 其他函数实现...// 定义UART1设备
uart_device_t uart1_device = {.handle = &huart1,.ops = {.init = uart1_init,.send = uart1_send,// 其他操作...}
};
AT指令驱动层
// at_driver.h
#ifndef __AT_DRIVER_H__
#define __AT_DRIVER_H__#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>// AT指令响应回调类型
typedef void (*at_response_callback_t)(const char *response, void *user_data);// AT指令驱动结构体
typedef struct at_driver at_driver_t;// AT驱动操作接口
typedef struct {int (*send_cmd)(at_driver_t *drv, const char *cmd, at_response_callback_t callback, void *user_data,uint32_t timeout);int (*send_data)(at_driver_t *drv, const uint8_t *data, size_t length,at_response_callback_t callback, void *user_data,uint32_t timeout);int (*process)(at_driver_t *drv);int (*set_receive_callback)(at_driver_t *drv, at_response_callback_t callback, void *user_data);
} at_driver_ops_t;// AT驱动结构体
struct at_driver {void *uart_device;at_driver_ops_t ops;// 其他内部状态...
};// 创建AT驱动实例
at_driver_t *at_driver_create(void *uart_device);
void at_driver_destroy(at_driver_t *drv);#endif /* __AT_DRIVER_H__ */
// at_driver.c
#include "at_driver.h"
#include "hal_uart.h"
#include <stdlib.h>
#include <string.h>// AT驱动私有数据结构
typedef struct {at_response_callback_t response_callback;void *user_data;char response_buffer[256];size_t buffer_index;// 其他状态变量...
} at_driver_priv_t;static int at_send_cmd(at_driver_t *drv, const char *cmd, at_response_callback_t callback, void *user_data,uint32_t timeout) {uart_device_t *uart = (uart_device_t *)drv->uart_device;at_driver_priv_t *priv = (at_driver_priv_t *)drv->priv;// 保存回调信息priv->response_callback = callback;priv->user_data = user_data;priv->buffer_index = 0;// 发送AT指令return uart->ops.send(uart->handle, (const uint8_t *)cmd, strlen(cmd));
}static void uart_rx_callback(uint8_t data) {// 处理接收到的数据// 这里简化处理,实际应实现状态机解析响应
}static int at_set_receive_callback(at_driver_t *drv, at_response_callback_t callback, void *user_data) {uart_device_t *uart = (uart_device_t *)drv->uart_device;at_driver_priv_t *priv = (at_driver_priv_t *)drv->priv;priv->response_callback = callback;priv->user_data = user_data;// 设置UART接收回调return uart->ops.set_rx_callback(uart->handle, uart_rx_callback);
}// 其他函数实现...at_driver_t *at_driver_create(void *uart_device) {at_driver_t *drv = malloc(sizeof(at_driver_t));if (!drv) return NULL;at_driver_priv_t *priv = malloc(sizeof(at_driver_priv_t));if (!priv) {free(drv);return NULL;}memset(priv, 0, sizeof(at_driver_priv_t));drv->uart_device = uart_device;drv->priv = priv;drv->ops.send_cmd = at_send_cmd;drv->ops.set_receive_callback = at_set_receive_callback;// 初始化其他操作...return drv;
}void at_driver_destroy(at_driver_t *drv) {if (drv) {free(drv->priv);free(drv);}
}
应用层实现
// application.c
#include "at_driver.h"
#include "hal_uart.h"
#include <stdio.h>static void gsm_response_callback(const char *response, void *user_data) {printf("Received: %s\n", response);// 处理AT指令响应
}int main(void) {// 初始化硬件hardware_init();// 创建UART设备uart_config_t uart_config = {.baudrate = 115200,.data_bits = 8,.stop_bits = 1,.parity = 0};uart1_device.ops.init(uart1_device.handle, &uart_config);// 创建AT驱动at_driver_t *gsm_driver = at_driver_create(&uart1_device);if (!gsm_driver) {return -1;}// 设置接收回调gsm_driver->ops.set_receive_callback(gsm_driver, gsm_response_callback, NULL);// 发送AT指令gsm_driver->ops.send_cmd(gsm_driver, "AT+CSQ\r\n", gsm_response_callback, NULL, 1000);while (1) {// 处理AT驱动gsm_driver->ops.process(gsm_driver);// 其他应用逻辑...}at_driver_destroy(gsm_driver);return 0;
}
移植到新平台
当需要将代码移植到新的硬件平台时,只需实现硬件抽象层的接口:
// hal_uart_new_platform.c
#include "hal_uart.h"
#include "new_platform_uart.h"static int new_platform_uart_init(void *handle, uart_config_t *config) {// 新平台的UART初始化实现return 0;
}static int new_platform_uart_send(void *handle, const uint8_t *data, size_t length) {// 新平台的UART发送实现return 0;
}// 实现其他操作...// 定义新平台的UART设备
uart_device_t uart1_device_new_platform = {.handle = NULL, // 根据需要设置句柄.ops = {.init = new_platform_uart_init,.send = new_platform_uart_send,// 其他操作...}
};
应用层和驱动层代码无需修改,只需在创建AT驱动时传入新的UART设备:
// 创建AT驱动时使用新平台的UART设备
at_driver_t *gsm_driver = at_driver_create(&uart1_device_new_platform);
总结
基于分层架构和函数指针的AT指令模块设计方法,具有以下优点:
- 低耦合:各层之间通过定义良好的接口通信,降低模块间依赖
- 高可移植性:硬件相关代码隔离在HAL层,移植时只需实现HAL接口
- 可维护性:模块职责清晰,易于测试和维护
- 可扩展性:易于添加新的硬件平台或AT指令功能
这种设计方法不仅适用于AT指令模块,也可以推广到其他嵌入式外设的驱动开发中,为嵌入式系统提供更加灵活和可靠的软件架构。