STM32-UART抽象层封装

一. 封装UART前的准备工作


1. 数据接收与保存方式

  • 收到的数据需要保存,可以使用 buffer 或队列(操作系统支持)。
  • 提供统一接口给上层(如APP),避免直接依赖HAL库。
  • 如果更换芯片厂商或没有HAL库,直接使用HAL代码会带来维护困难。
  • 推荐自行封装,例如 libmodbus、AT指令等,应用程序可直接使用这些封装。
  • 串口连接WiFi模块时,AT指令层还可进一步封装,实现网络数据收发。


2. 软件层次结构的引入

  • 多层软件架构可减少因芯片变化导致的程序修改。
  • 保证程序的稳定性和可移植性,无需大幅调整代码。


推荐的层次结构

  1. 底层:HAL库
  2. 第二层:自定义封装
  3. 第三层:AT命令封装
  4. 第四层:APP封装
  5. 第五层:应用程序


3. 硬件连接示例

  • 假设STM32与WiFi模块通过串口连接。


4. 函数封装示例

  • 实现 AT_send() 函数时,通常会调用 HAL 库的串口发送函数,如:
    HAL_UART_Transmit(&huart1, data, len);
  • 直接写芯片相关代码会导致移植困难,建议对 HAL 库进行封装,提升代码复用性。


5. 封装函数参数设计

  • 自定义 UART 函数时应明确第一个参数表示串口,避免代码写死,增强通用性。


6. 封装的必要性

  • 过度依赖底层库函数会导致更换芯片时需要大幅修改代码。
  • 建议编写兼容多芯片的封装函数,提升代码适应性。


7. 第三方库兼容

  • 无论使用哪家厂商的库,均可通过封装实现第三方库的兼容调用。


8. 抽象硬件操作

  • 通常会将硬件操作抽象为结构体,便于管理和扩展。


9. 芯片自定义UART结构体

  • 可根据不同芯片实现各自的 UART_Derive 结构体,提升可移植性。

二. HAL库串口发送流程解析


1. STM32cubemx配置步骤

  • 打开 STM32cubemx,选择 STM32F103C8T6 并进行配置。


2. 启用外部调试


3. 开启UART1


  • 串口配置完成后即可显示相关信息。


4. 开启中断


  • 默认参数:115200波特率,8数据位,无校验位,1停止位。


5. 代码生成


  • 使用中断发送时,函数只使能中断,不判断发送完成状态。


6. 选择LIB库


  • 串口可正常发送数据,配置简单,代码仅需两行即可实现:
cs 复制代码
/* 使用中断方式发送数据 第一个参数是要用哪个串口 第二个是要发送的数据 第三个是数据长度 */ 
HAL_UART_Transmit_IT(&huart1, "100aks\r\n", 8); 
HAL_Delay(500); /* 等待发送完成 */

7. 数据接收与处理

  • 测试能否收到数据,使用中断触发接收,但不代表已接收完成。


  • 为便于观察,建议使用轮询方式。


  • 读取成功返回 OK,否则持续读取,成功后将数据发送出去,1ms即可:
cs 复制代码
/* 使用中断方式发送数据 第一个参数是要用哪个串口 第二个是要发送的数据 第三个是数据长度 */ 
HAL_UART_Transmit_IT(&huart1, "100aks\r\n", 8); 
HAL_Delay(500); /* 等待发送完成 */ 
/* 第一个是用哪个串口接收 第二个是接收后存在哪里 第三个是数据长度 第三个参数是超时时间 */
 while(HAL_UART_Receive(&huart1, &c, 1, 100) != HAL_OK); c++;
/* 累加后发送 */ 
/* 读取成功后发送出去 */ 
HAL_UART_Transmit_IT(&huart1, &c, 1);
 HAL_Delay(1); /* 等待发送完成 */

  • 累加后进行发送,增加程序趣味性。


  • 输入1得到2,发送a得到b,直接使用库函数操作简单。


8. 应用程序需求与问题

  • 要求:打印100ask,收到字符后累加并输出。
  • 存在问题:
  1. 更换芯片需修改相关函数。
  2. 更换串口也需修改相关函数。
  • 需改动地方较多,建议进行程序封装。

三. 添加FreeRTOS功能

cs 复制代码
/* 使用中断方式发送数据 第一个参数是要用哪个串口 第二个是要发送的数据 第三个是数据长度 */ HAL_UART_Transmit_IT(&huart1, "100aks\r\n", 8);
 HAL_Delay(100);
 /* 等待发送完成 */ 
/* 第一个是用哪个串口接收 第二个是接收后存在哪里 第三个是数据长度 第三个参数是超时时间 */ while(HAL_OK != HAL_UART_Receive(&huart1, &c, 1, 100)); 
c++;/* 累加后发送 */ 
/* 读取成功后发送出去 */ 
HAL_UART_Transmit_IT(&huart1, &c, 1); HAL_Delay(1); /* 等待发送完成 */

  • 复制代码,准备添加 FreeRTOS 功能。


1. FreeRTOS配置流程

  • 打开 cubemx,选择中间键 -> freertos。


  • 选择接口,参数默认即可,确保可抢占。


  • 若使用 FreeRTOS,建议 HAL 库时钟基准不再用 system tick。
  • 若 FreeRTOS 使用 system tick,需将 HAL 库延时等基准时钟切换为 TIM1。


  • 修改 HAL 库时钟为 TIM1,生成代码。


2. main.c代码注意事项

  • 开启 RTOS 后,main.c 的 while(1) 不再输出内容。


  • 原因:main.c 只执行到调度器启动,后续代码不会执行。


  • 需将代码写入默认任务中,编译运行后可看到结果。


  • 结果可正常输出。


  • 建议备份程序,便于后续维护。

相关推荐
yi0115 小时前
LeetCode 219:存在重复元素 II——哈希表记录“最近一次出现的位置”
数据结构·人工智能·笔记·python·算法·leetcode·哈希表
志尊宝6 小时前
Vue3 零基础每日笔记(073):keep-alive 页面缓存实战——列表页返回不丢状态
vue.js·笔记·缓存·#vue #前端 #前端开发·#javascript·#vue.js
Jason_zhao_MR7 小时前
Linux与实时控制如何兼得
linux·嵌入式硬件·机器人·工业控制
BSD_CGQ7 小时前
FSR传感器STM32 DMA高速采样工程实现(高精度、低CPU占用)
stm32·单片机·嵌入式硬件·压力传感器·源头工厂·柔性薄膜压力传感器·可变电阻压力传感器
李日华大战鸡红8 小时前
FOC状态空间方程模型推导(学习记录)
python·学习·线性代数
weixin_448119948 小时前
Datawhale Easy Data × AI:笔记1 已重做,看新的笔记
笔记
要开心吖ZSH9 小时前
MySQL 慢 SQL 排查操作手册-个人笔记版
java·笔记·sql·mysql·慢查询
kkkkkkkkkk_Z9 小时前
新手自学嵌入式 | 学习日记:异常与中断基础、i.MX6ULL裸机开发环境搭建、GPIO模块与点灯原理
学习
咖啡忍者10 小时前
【SAP】程制造生产计划PP-PI(Production Planning for Process Industries)
笔记
芯岭技术郦10 小时前
32 位 ARM® Cortex®-M0+ 内核MCU普冉MS32C001-C
单片机·嵌入式硬件