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

嵌入式分层架构下的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指令模块设计方法,具有以下优点:

  1. 低耦合:各层之间通过定义良好的接口通信,降低模块间依赖
  2. 高可移植性:硬件相关代码隔离在HAL层,移植时只需实现HAL接口
  3. 可维护性:模块职责清晰,易于测试和维护
  4. 可扩展性:易于添加新的硬件平台或AT指令功能

这种设计方法不仅适用于AT指令模块,也可以推广到其他嵌入式外设的驱动开发中,为嵌入式系统提供更加灵活和可靠的软件架构。

http://www.dtcms.com/a/354219.html

相关文章:

  • 使用Nginx搭建图片传输服务:配置与优化指南
  • Content-Type是application/x-www-form-urlencoded表示从前端到后端提交的是表单的形式
  • 微服务的编程测评系统17-判题功能-代码沙箱
  • 除自身以外数组的乘积是什么意思
  • 算法刷题常见错误
  • Linux 打包及压缩基础知识总结
  • 车间生产管理遇到的问题及改善方案有哪些?
  • 在 Windows 上部署 Go 语言开发环境
  • Go语言与Docker 开发的核心应用领域
  • 源码分析unexpected EOF on client connection with an open transaction
  • 分治法——二分答案
  • 深入探索Vue:前端开发的强大框架
  • Android10 音频系统之AudioPlaybackConfiguration
  • JVM之CMS、G1|ZGC详解以及选型对比
  • SynClub-百度在海外推出的AI社交产品
  • A-Level物理课程全解析:知识点、学习计划与培训机构推荐
  • 网络编程-连接、发送、接收数据学习
  • React Hooks 完全指南:从基础到高级的实战技巧
  • C++ 由 std::thread 初始化想到的
  • TencentOS Server 4.4 下创建mysql容器无法正常运行的问题
  • wireshark解析FLV插件分享
  • 嵌入式Linux(Exynos 4412)笔记
  • 3459. 最长 V 形对角线段的长度
  • 设计模式理解
  • Nishang PowerShell工具:原理详解+使用方法+渗透实战
  • Go+Gdal 完成高性能GIS数据空间分析
  • 深度学习:常用的损失函数的使用
  • “java简单吗?”Java的“简单”与PHP的挑战:编程语言哲学-优雅草卓伊凡
  • 白话FNN、RNN、Attention和self-attention等
  • 《从有限元到深度学习:我的金属疲劳研究进阶之路》