单片机开发---分层架构设计

文章目录

  • 一、架构总览
      • 单片机程序分层架构总览
      • 详细分层说明
        • [1. 硬件抽象层 (Hardware Abstraction Layer - HAL)](#1. 硬件抽象层 (Hardware Abstraction Layer - HAL))
        • [2. 驱动层 (Driver Layer)](#2. 驱动层 (Driver Layer))
        • [3. 业务逻辑层 (Business Logic Layer - BLL) / 中间件层 (Middleware Layer)](#3. 业务逻辑层 (Business Logic Layer - BLL) / 中间件层 (Middleware Layer))
        • [4. 应用层 (Application Layer)](#4. 应用层 (Application Layer))
      • 总结与优势
  • 二、更详细一点的层
      • [1. **硬件抽象层(Hardware Abstraction Layer, HAL)**](#1. 硬件抽象层(Hardware Abstraction Layer, HAL))
      • [2. **驱动层(Driver Layer)**](#2. 驱动层(Driver Layer))
      • [3. **中间层(Middleware Layer)**](#3. 中间层(Middleware Layer))
      • [4. **接口层(Interface Layer)**](#4. 接口层(Interface Layer))
      • [5. **板级支持包(Board Support Package, BSP)**](#5. 板级支持包(Board Support Package, BSP))
      • 分层设计的优势

一、架构总览

一个结构良好的单片机程序通常会被划分为不同的层次,每一层都职责明确,从而提高代码的可读性、可维护性、可移植性和可测试性。

典型的单片机程序可以划分为以下四个核心层次,从最接近硬件的到最接近用户的逻辑。

单片机程序分层架构总览

下图清晰地展示了常见的四层架构及其依赖关系:
单片机程序分层架构 应用层
App Layer 业务逻辑层
BLL Layer 驱动层
Driver Layer 硬件抽象层
HAL Layer 单片机
MCU & 外设


详细分层说明

下面我们来详细解释每一层的职责、使用方法和示例。

1. 硬件抽象层 (Hardware Abstraction Layer - HAL)

职责 :这是最底层,直接与单片机寄存器和外设打交道。它的核心目标是将硬件操作封装成统一的函数接口,从而屏蔽不同型号单片机之间的寄存器操作差异。

使用

  • 对下 :直接操作单片机的特定外设寄存器(如 USART1->DR, GPIOA->ODR)。
  • 对上 :为驱动层提供标准化的、与硬件无关的API(如 void HAL_UART_WriteByte(uint8_t byte))。
  • 当更换单片机型号时,理论上只需要重写或替换这一层代码,上层代码几乎无需改动。

示例代码

c 复制代码
// hal_uart.h
#ifndef __HAL_UART_H
#define __HAL_UART_H

void HAL_UART_Init(uint32_t baudrate);
void HAL_UART_WriteByte(uint8_t byte);
uint8_t HAL_UART_ReadByte(void);

#endif

// hal_uart.c (针对特定MCU,如STM32)
#include "stm32f1xx.h"
#include "hal_uart.h"

void HAL_UART_Init(uint32_t baudrate) {
    // ... 复杂的寄存器配置,如使能时钟、设置波特率、数据位等
    USART1->BRR = ...; // 根据baudrate计算
    USART1->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; // 使能USART、发送、接收
}

void HAL_UART_WriteByte(uint8_t byte) {
    while (!(USART1->SR & USART_SR_TXE)); // 等待发送寄存器空
    USART1->DR = byte; // 写入数据寄存器
}
2. 驱动层 (Driver Layer)

职责 :在HAL的基础上,驱动具体的硬件模块或芯片。它不再关心单片机寄存器,而是关心如何操作一个完整的设备(如温湿度传感器、LCD屏幕、电机驱动芯片)。这一层会实现该设备特定的通信协议和控制逻辑。

使用

  • 对下:调用HAL提供的函数来控制GPIO、SPI、I2C、UART等。
  • 对上 :为业务逻辑层提供面向功能的API(如 DHT11_ReadTempHumidity)。

示例代码

c 复制代码
// dht11_driver.h
#ifndef __DHT11_DRIVER_H
#define __DHT11_DRIVER_H

typedef struct {
    float temperature;
    float humidity;
} DHT11_Data_t;

int DHT11_Init(void);
int DHT11_ReadTempHumidity(DHT11_Data_t *data);

#endif

// dht11_driver.c
#include "hal_gpio.h" // 使用HAL的GPIO函数
#include "hal_delay.h" // 使用HAL的延时函数
#include "dht11_driver.h"

// DHT11的通信时序(例如,拉低总线18ms启动信号)
int DHT11_ReadTempHumidity(DHT11_Data_t *data) {
    // 1. 调用HAL_GPIO_WritePin将数据线拉低
    // 2. 调用HAL_Delay_ms(18)
    // 3. 调用HAL_GPIO_ReadPin读取数据线,解析40位数据
    // 4. 将解析出的二进制数据转换为temperature和humidity,填入data结构体
    // 5. 返回成功或失败状态
}
3. 业务逻辑层 (Business Logic Layer - BLL) / 中间件层 (Middleware Layer)

职责 :这是系统的"大脑",实现具体的产品功能和应用逻辑。它协调多个驱动,完成复杂的任务。FreeRTOS、文件系统、网络协议栈等也常被视作这一层的一部分。

使用

  • 对下:调用驱动层提供的各种设备API。
  • 对上 :为应用层提供简洁的服务接口(如 CheckButtonAndControlMotor)。

示例代码

c 复制代码
// control_logic.h
#ifndef __CONTROL_LOGIC_H
#define __CONTROL_LOGIC_H

void ControlLogic_Init(void);
void ControlLogic_Run(void); // 主循环中调用

#endif

// control_logic.c
#include "dht11_driver.h"
#include "fan_driver.h"
#include "button_driver.h"
#include "control_logic.h"

void ControlLogic_Run(void) {
    DHT11_Data_t env_data;
    static uint32_t last_check_time = 0;

    // 每5秒检查一次温湿度
    if (HAL_GetTick() - last_check_time > 5000) {
        if (DHT11_ReadTempHumidity(&env_data) == SUCCESS) {
            // 业务逻辑:如果温度高于28度,则打开风扇
            if (env_data.temperature > 28.0f) {
                Fan_TurnOn();
            } else {
                Fan_TurnOff();
            }
        }
        last_check_time = HAL_GetTick();
    }

    // 处理按键事件
    if (Button_IsPressed()) {
        Fan_Toggle();
    }
}
4. 应用层 (Application Layer)

职责 :这是整个程序的**"总指挥",是程序的入口。它负责初始化所有下层模块、创建任务(如果使用RTOS)、启动调度器、并定义整个程序的执行框架**。这一层通常不实现复杂逻辑,只进行组织和调度。

使用

  • 对下:调用业务逻辑层的初始化函数和主循环函数。
  • 对外 :它是 main.c 的核心内容。

示例代码

c 复制代码
// main.c
#include "hal.h"     // 初始化硬件
#include "drivers.h" // 初始化所有驱动
#include "control_logic.h" // 业务逻辑
#include "FreeRTOS.h"
#include "task.h"

// 如果没有RTOS
int main(void) {
    // 1. 初始化所有底层硬件和驱动
    HAL_Init();
    SystemClock_Config();
    DHT11_Init();
    Fan_Init();
    Button_Init();

    // 2. 初始化业务逻辑
    ControlLogic_Init();

    // 3. 主循环(轮询架构)
    for (;;) {
        ControlLogic_Run(); // 在循环中执行业务逻辑
        // 可能还有其他任务...
    }
}

// 如果使用FreeRTOS
int main(void) {
    // 1. 硬件和基础驱动初始化
    HAL_Init();
    SystemClock_Config();

    // 2. 创建业务逻辑任务
    xTaskCreate(ControlLogic_Task, "ControlLogic", 128, NULL, 2, NULL);

    // 3. 启动RTOS调度器
    vTaskStartScheduler();

    // 4. 永远不会执行到这里
    for (;;);
}

总结与优势

层次 核心思想 依赖关系 变化影响
应用层 组织与调度 依赖BLL 产品功能改变时修改
业务逻辑层 功能与逻辑 依赖Driver 业务规则改变时修改
驱动层 设备与协议 依赖HAL 更换传感器/设备时修改
硬件抽象层 抽象与统一 依赖MCU硬件 更换单片机型号时修改

采用分层架构的优势:

  • 高内聚,低耦合:每一层只关注自己的职责。
  • 易于移植:换MCU?主要改HAL。换传感器?主要改Driver。
  • 易于协作与测试:可以模拟下层接口,对上层的业务逻辑进行单元测试。
  • 代码复用:为同一款MCU写的HAL和Driver,可以用在多个不同的项目中。

在实际项目中,根据系统复杂度,层次可能会合并或进一步细分(例如,在HAL和Driver之间再增加一个板级支持包BSP),但核心的"分层"思想是相通的。

二、更详细一点的层

在单片机项目开发中,为了提高代码的可维护性、复用性和模块化程度,通常会采用分层设计思想。除了直接实现业务逻辑的应用层,常见的分层还包括以下几层(不同项目可能有细微差异,核心是按功能职责划分):

1. 硬件抽象层(Hardware Abstraction Layer, HAL)

  • 核心作用:屏蔽底层硬件细节,提供统一的软件接口,使上层代码无需直接操作寄存器或硬件引脚。
  • 具体功能
    • 对单片机的外设(如GPIO、UART、SPI、I2C、ADC、定时器等)进行封装,提供标准化函数(如 gpio_init()uart_send())。
    • 处理硬件相关的初始化参数(如引脚定义、波特率、时钟频率),与具体芯片型号绑定。
  • 举例
    无论用STM32还是51单片机,上层调用 uart_send_data(buf, len) 即可发送数据,无需关心底层寄存器配置(如STM32的USART寄存器、51的SBUF寄存器)。

2. 驱动层(Driver Layer)

  • 核心作用:在HAL之上,针对具体外部硬件(如传感器、执行器、模块)编写专用驱动,实现硬件的控制逻辑。
  • 具体功能
    • 基于HAL提供的接口,实现特定硬件的初始化、数据读写、状态控制等(如OLED屏驱动、温湿度传感器DHT11驱动、电机驱动L298N)。
    • 处理硬件的时序要求、通信协议(如I2C协议的传感器驱动需实现起始/停止信号、数据收发逻辑)。
  • 与HAL的区别
    HAL针对单片机内部外设 (芯片自带功能),驱动层针对外部硬件模块(芯片外部的元器件)。

3. 中间层(Middleware Layer)

  • 核心作用:提供通用功能或协议支持,连接驱动层与应用层,解决跨模块的共性问题。
  • 常见模块
    • 通信协议栈:如Modbus、MQTT、蓝牙协议(BLE)、WiFi协议的封装,使应用层无需处理复杂协议细节。
    • 数据处理:如数据校验(CRC、校验和)、加密解密(AES)、JSON/XML解析。
    • 任务调度:在多任务系统(如FreeRTOS)中,封装任务创建、信号量、队列等接口,简化应用层的任务管理。
    • 通用工具:如内存管理、日志打印、延时函数等。

4. 接口层(Interface Layer)

(部分项目会单独划分,或融入中间层/HAL)

  • 核心作用:定义各层之间的接口标准,明确函数的输入输出、返回值和功能职责,实现"接口与实现分离"。
  • 具体形式
    通常用头文件(.h)定义函数声明、结构体、枚举等,而.c文件实现具体逻辑。例如,sensor_interface.h 定义传感器的通用接口(sensor_read()),不同传感器的驱动(DHT11、SHT30)分别实现该接口。

5. 板级支持包(Board Support Package, BSP)

(多见于复杂项目,可理解为"硬件抽象层+驱动层"的结合)

  • 核心作用:针对特定电路板(而非单一芯片)提供硬件支持,包含板载资源的初始化和控制。
  • 具体内容
    例如,某块开发板上有LED、按键、OLED屏、温湿度传感器,BSP层会统一初始化这些硬件,并提供 bsp_led_on()bsp_key_scan() 等接口,应用层直接调用即可,无需关心硬件在板上的具体连接(如LED接哪个GPIO引脚)。

分层设计的优势

  • 模块化:每层职责清晰,修改某一层(如更换传感器驱动)不影响其他层。
  • 可移植性:更换单片机型号时,只需修改HAL层,上层代码可复用。
  • 协作效率:多人开发时,可按层分工(如一人写驱动,一人写应用逻辑)。

实际项目中,分层并非绝对严格,简单项目可能只分"应用层+驱动层",复杂项目(如带操作系统的工业控制)则会细分更多层级。

相关推荐
国科安芯4 小时前
AS32S601ZIT2抗辐照MCU在商业卫星飞轮系统中的可靠性分析
服务器·网络·人工智能·单片机·嵌入式硬件·fpga开发·1024程序员节
优信电子4 小时前
电脑控制DFPlayer Mini MP3播放音乐
单片机·串口·嵌入式·mp3·语音播报·串口语音·mp3播报
点灯小铭6 小时前
基于单片机的±5V数字电压表设计
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
djarmy6 小时前
使用定时器14(GPIOF9复用映射到TIM14_CH1)控制LED0闪烁实验
stm32·单片机·嵌入式硬件
GilgameshJSS7 小时前
STM32H743-ARM例程29-HTTP
c语言·arm开发·stm32·单片机·http
学工科的皮皮志^_^7 小时前
锂电池充放电管理学习
经验分享·笔记·单片机·嵌入式硬件·学习·1024程序员节
点灯小铭7 小时前
基于单片机的滴速液位输液报警系统
单片机·毕业设计·课程设计·1024程序员节·期末大作业
CiLerLinux8 小时前
第三章 FreeRTOS 任务相关 API 函数
开发语言·单片机·物联网·c#
wanglong371314 小时前
STM32单片机PWM驱动无源蜂鸣器模块C语言程序
stm32·单片机·1024程序员节