嵌入式跨芯片通用项目框架设计方案
·
嵌入式跨芯片通用项目框架设计方案
一、框架核心设计思想
上层业务逻辑与底层硬件完全隔离:
- 应用层:不关心芯片型号,换芯片完全不动
- 硬件抽象层:统一接口封装,换芯片只改这一层
- 中间件层:承上启下,屏蔽芯片差异
二、项目框架目录结构
Project/
├── 01_App/ # 应用层(核心业务,100%复用)
│ ├── main.c # 主程序入口
│ ├── app_task.c # 业务任务
│ └── app_cfg.h # 项目配置
│
├── 02_Middleware/ # 中间件层(通用组件)
│ ├── protocol/ # 通信协议
│ ├── utils/ # 工具函数
│ └── sys_ctrl/ # 系统控制
│
├── 03_HAL/ # 硬件抽象层(换芯片只改这里)
│ ├── chip_port/ # 芯片适配层
│ │ ├── stm32/ # STM32适配
│ │ ├── gd32/ # GD32适配
│ │ └── chip_port.h # 统一抽象接口
│ └── board/ # 板级驱动
│
├── 04_ChipLib/ # 芯片原厂库(不修改)
└── 05_Output/ # 编译输出
三、统一硬件接口标准(chip_port.h)
// 03_HAL/chip_port/chip_port.h
#ifndef __CHIP_PORT_H
#define __CHIP_PORT_H
#include <stdint.h>
#include <stdbool.h>
/*************** GPIO 统一接口 ***************/
void gpio_init(void);
void gpio_set(uint8_t pin, uint8_t level);
uint8_t gpio_read(uint8_t pin);
void gpio_toggle(uint8_t pin);
/*************** UART 统一接口 ***************/
void uart_init(uint32_t baudrate);
void uart_send(uint8_t *data, uint16_t len);
uint16_t uart_recv(uint8_t *data, uint16_t max_len);
void uart_irq_handler(void); // 中断统一入口
/*************** 定时器统一接口 ***************/
void timer_init(uint32_t period_ms);
void timer_start(void);
void timer_stop(void);
#endif
四、芯片适配层实现(以USART为例)
STM32 适配实现
// 03_HAL/chip_port/stm32/chip_port_uart.c
// 哪个串口
uint32_t usartx = USART1;
uint32_t usartx_rcu = RCC_APB2Periph_USART1;
uint32_t usartx_irq = USART1_IRQn;
// 波特率
uint32_t usartx_p_baudrate = 115200;
// TX引脚配置
uint32_t usartx_tx_port_rcu = RCC_APB2Periph_GPIOA;
uint32_t usartx_tx_port = GPIOA;
uint32_t usartx_tx_pin = GPIO_Pin_9;
uint32_t usartx_tx_af = GPIO_AF_USART1;
// RX引脚配置
uint32_t usartx_rx_port_rcu = RCC_APB2Periph_GPIOA;
uint32_t usartx_rx_port = GPIOA;
uint32_t usartx_rx_pin = GPIO_Pin_10;
uint32_t usartx_rx_af = GPIO_AF_USART1;
/*************** GPIO 初始化 ***************/
// TX
rcu_periph_clock_enable(usartx_tx_port_rcu);
gpio_mode_set(usartx_tx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_tx_pin);
gpio_af_set(usartx_tx_port, usartx_tx_af, usartx_tx_pin);
gpio_output_options_set(usartx_tx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_tx_pin);
// RX
rcu_periph_clock_enable(usartx_rx_port_rcu);
gpio_mode_set(usartx_rx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_rx_pin);
gpio_af_set(usartx_rx_port, usartx_rx_af, usartx_rx_pin);
/*************** USART 初始化 ***************/
rcu_periph_clock_enable(usartx_rcu);
usart_deinit(usartx);
usart_baudrate_set(usartx, usartx_p_baudrate);
usart_parity_config(usartx, USART_PM_NONE);
usart_word_length_set(usartx, USART_WL_8BIT);
usart_stop_bit_set(usartx, USART_STB_1BIT);
usart_data_first_config(usartx, USART_MSBF_LSB);
usart_transmit_config(usartx, USART_TRANSMIT_ENABLE);
usart_receive_config(usartx, USART_RECEIVE_ENABLE);
nvic_irq_enable(usartx_irq, 2, 2);
usart_interrupt_enable(usartx, USART_INT_RBNE);
usart_interrupt_enable(usartx, USART_INT_IDLE);
usart_enable(usartx);
GD32 适配实现(换芯片只改这部分)
// 03_HAL/chip_port/gd32/chip_port_uart.c
// 哪个串口
uint32_t usartx = USART0;
uint32_t usartx_rcu = RCU_USART0;
uint32_t usartx_irq = USART0_IRQn;
// 波特率
uint32_t usartx_p_baudrate = 115200;
// TX引脚配置
uint32_t usartx_tx_port_rcu = RCU_GPIOA;
uint32_t usartx_tx_port = GPIOA;
uint32_t usartx_tx_pin = GPIO_PIN_9;
uint32_t usartx_tx_af = GPIO_AF_7;
// RX引脚配置
uint32_t usartx_rx_port_rcu = RCU_GPIOA;
uint32_t usartx_rx_port = GPIOA;
uint32_t usartx_rx_pin = GPIO_PIN_10;
uint32_t usartx_rx_af = GPIO_AF_7;
/*************** GPIO 初始化 ***************/
// TX
rcu_periph_clock_enable(usartx_tx_port_rcu);
gpio_mode_set(usartx_tx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_tx_pin);
gpio_af_set(usartx_tx_port, usartx_tx_af, usartx_tx_pin);
gpio_output_options_set(usartx_tx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_tx_pin);
// RX
rcu_periph_clock_enable(usartx_rx_port_rcu);
gpio_mode_set(usartx_rx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_rx_pin);
gpio_af_set(usartx_rx_port, usartx_rx_af, usartx_rx_pin);
/*************** USART 初始化 ***************/
rcu_periph_clock_enable(usartx_rcu);
usart_deinit(usartx);
usart_baudrate_set(usartx, usartx_p_baudrate);
usart_parity_config(usartx, USART_PM_NONE);
usart_word_length_set(usartx, USART_WL_8BIT);
usart_stop_bit_set(usartx, USART_STB_1BIT);
usart_data_first_config(usartx, USART_MSBF_LSB);
usart_transmit_config(usartx, USART_TRANSMIT_ENABLE);
usart_receive_config(usartx, USART_RECEIVE_ENABLE);
nvic_irq_enable(usartx_irq, 2, 2);
usart_interrupt_enable(usartx, USART_INT_RBNE);
usart_interrupt_enable(usartx, USART_INT_IDLE);
usart_enable(usartx);
五、统一接口封装(上层调用)
// 03_HAL/chip_port/chip_port_uart.c(统一对外接口)
#include "chip_port.h"
static uint8_t uart_rx_buffer[256];
static uint16_t uart_rx_index = 0;
void uart_init(uint32_t baudrate)
{
// 调用具体芯片的初始化代码(上面实现的)
// 这里直接复用上面的USART配置代码
}
void uart_send(uint8_t *data, uint16_t len)
{
for(uint16_t i = 0; i < len; i++)
{
while(usart_flag_get(usartx, USART_FLAG_TBE) == RESET);
usart_data_transmit(usartx, data[i]);
}
}
uint16_t uart_recv(uint8_t *data, uint16_t max_len)
{
// 从环形缓冲区读取数据
// 具体实现略
}
void uart_irq_handler(void)
{
if(usart_interrupt_flag_get(usartx, USART_INT_FLAG_RBNE) != RESET)
{
uint8_t rx_data = usart_data_receive(usartx);
// 存入环形缓冲区
}
}
六、应用层代码(完全芯片无关)
// 01_App/app_task.c
#include "chip_port.h"
void led_task(void)
{
gpio_set(LED_PIN, 1); // 不管STM32/GD32,代码一模一样
delay_ms(500);
gpio_set(LED_PIN, 0);
delay_ms(500);
}
void uart_task(void)
{
uint8_t tx_buf[] = "Hello World\r\n";
uart_send(tx_buf, sizeof(tx_buf) - 1);
}
七、换芯片操作流程
- 复制整个项目框架文件夹
- 替换
04_ChipLib原厂库 - 在
03_HAL/chip_port新增芯片适配文件 - 实现统一抽象接口(GPIO/UART/SPI等)
- 上层
01_App+02_Middleware一行不改 - 编译下载,直接运行
八、核心优势
| 场景 | 传统方式 | 本框架方式 |
|---|---|---|
| 换芯片 | 1周 | 1天(只改HAL层) |
| 换项目 | 从头搭建 | 复制框架 + 改配置 |
| 换人开发 | 需理解全部代码 | 按分层定位,快速上手 |
| 代码复用率 | < 30% | ≥ 80% |
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)