
STM32F429第十五篇之串口实验详解二
系统初始化:调用HAL_Init(), SystemClock_Config(), GpioInit(), UartInit()完成系统和串口的基本配置 串口初始化消息输出:通过重新定义printf函数实现串口输出 数据接收与发送:接收数据后直接控制寄存器实现快速发送 流水灯控制:通过位带操作控制流水灯的开关状态 忽略系统情况:避免对系统本身进行复杂处理 头文件管理:尽量减少头文件的包含,提高可移植性 程序简洁化:通过位带操作和宏定义优化代码结构
发布日期:2021-05-14 11:31:29
浏览次数:23
分类:精选文章
本文共 8971 字,大约阅读时间需要 29 分钟。
STM32 HAL库优化与串口通信改进
本文主要讨论了对STM32 HAL库中的串口通信进行优化,以及对系统文件夹中的程序进行简化的实现。通过构建一个新的工程,简化了串口工作流程,并对正点原子原有的system文件夹中的程序进行了优化。最终实现了一个高效的串口通信方案,并对相关系统配置进行了详细说明。
文章目录
- 1. 系统初始化与配置
- 2. 串口通信实现
- 3. 流水灯控制
- 4. 系统文件夹优化
- 5. 相关库文件实现
前言
通过上一篇博客已经详细梳理了串口在HAL库中的工作过程,但该过程流程复杂且实时性较差。本文通过构建一个新的工程,简化了串口工作流程,并对正点原子原有的system文件夹中的程序进行了优化。完整的工程文件可在GitHub上找到。
主函数实现
主函数的实现流程如下:
system文件夹优化
本文对system文件夹中的程序进行了以下优化:
sys库实现
sys库包含了系统初始化和位带操作的实现。
/** ****************************************************************************** * @file sys.h * @author zhy * @version 1.0 * @date 2021-01-22 * @brief 系统初始化相关的头文件 ****************************************************************************** */#ifndef _SYS_H#define _SYS_H#include typedef struct{ unsigned int bit0 : 1; unsigned int bit1 : 1; unsigned int bit2 : 1; unsigned int bit3 : 1; unsigned int bit4 : 1; unsigned int bit5 : 1; unsigned int bit6 : 1; unsigned int bit7 : 1; unsigned int bit8 : 1; unsigned int bit9 : 1; unsigned int bit10 : 1; unsigned int bit11 : 1; unsigned int bit12 : 1; unsigned int bit13 : 1; unsigned int bit14 : 1; unsigned int bit15 : 1; unsigned int rsv : 16;} BitBand __attribute__((bitband)); extern BitBand PAin;extern BitBand PBin;extern BitBand PCin;extern BitBand PDin;extern BitBand PEin;extern BitBand PFin;extern BitBand PGin;extern BitBand PHin;extern BitBand PIin;extern BitBand PAout;extern BitBand PBout;extern BitBand PCout;extern BitBand PDout;extern BitBand PEout;extern BitBand PFout;extern BitBand PGout;extern BitBand PHout;extern BitBand PIout;extern void SystemClock_Config(void); //时钟系统配置
延迟实现
延迟实现采用时钟窃取法,确保延时函数的高效性。
/** ****************************************************************************** * @name delay.h * @author zhy * @version 1.0 * @date 2020.11.11 * @brief 提供延时函数的对外接口。 ****************************************************************************** */#ifndef __DELAY_H#define __DELAY_H#include extern void delay_us(uint32_t nus );extern void delay_ms( uint16_t nms );#endif
/** ****************************************************************************** * @name delay.c * @author zhy * @version 1.0 * @date 2020.11.11 * @brief 通过时钟窃取法,得到延时时钟的功能。 ****************************************************************************** */#include "stm32f4xx.h" //包含该头文件不会出现引用错误#include "delay.h"/** * @brief 延时函数微秒 * @note None * @param nus:延时的微秒数,0~2^32/fac_us * @retval None */void delay_us(uint32_t nus){ uint32_t fac_us = HAL_RCC_GetSysClockFreq() / 1e6; //us延时倍乘数 uint32_t ticks; //存储需要节拍数 uint32_t told, tnow, tcnt = 0; //told:上一次存储的时间,tnow:当前时间;tcnt:累计的时间差 uint32_t reload = SysTick->LOAD; //读取sysTick装载值 ticks = nus * fac_us; //需要的节拍数 told = SysTick->VAL; //读取当前计数值 while (1) { tnow = SysTick->VAL; if (tnow != told) { /*获得上一次记录的时间和当前时间之间的差值*/ if (tnow < told) tcnt += told - tnow; else tcnt += reload - tnow + told; /*将当前时间记录下来*/ told = tnow; if (tcnt >= ticks) break; //时间超过/等于要延迟的时间,则退出. } }}/** * @brief 延时函数毫秒 * @note None * @param nms:延时的毫秒数 * @retval None */void delay_ms(uint16_t nms){ uint32_t i; for (i = 0; i < nms; i++) delay_us(1000);}
队列实现
队列实现采用环形结构,支持高效的数据接收和发送。
/** ****************************************************************************** * @file queue.h * @author zhy * @version 1.0 * @date 2021-01-25 * @brief 与队列相关的结构体 ****************************************************************************** */#ifndef __QUEUE_H__#define __QUEUE_H__#include typedef struct Queue{ uint8_t mem[256]; //255个长度的队列 uint8_t *front; //队首 uint8_t *rear; //队尾} Queue; /** * @brief 判断队列是否为空 * @note 注意括号的使用 * @param q:队列指针 * @retval 0:队列非空,1:队列空 */#define isQueueEmpty(q) ((q)->front == (q)->rear)extern void InitQueue(Queue *q);extern void InQueue(Queue *q, uint8_t item);extern uint8_t DeQueue(Queue *q, uint8_t *item);#endif
/** ****************************************************************************** * @file queue.c * @author zhy * @version 1.0 * @date 2021-01-25 * @brief 对队列相关的函数 ****************************************************************************** */#include "queue.h"/** * @brief 初始化队列 * @note 无 * @param {Queue} *q 被初始化队列的指针 * @retval 无 */void InitQueue(Queue *q){ q->front = q->mem; q->rear = q->mem;} /** * @brief 进队列 * @note 无 * @param {Queue} *q 进入的队列 * @param {uint8_t} item 进入的元素 * @retval 无 */void InQueue(Queue *q, uint8_t item){ *(q->front) = item; //将值写入队头 q->front = q->mem + ((q->front + 1 - q->mem) & 0xff); //队头自增 if (q->front == q->rear) //若队头和队尾相等——队列满,队尾被覆盖 { q->rear = q->mem + ((q->rear + 1 - q->mem) & 0xff); //队尾自增 }} /** * @brief 出队列 * @note 无 * @param {Queue} *q 从该队列出 * @param {uint8_t} *item 获得的数据 * @retval 队伍状态 */uint8_t DeQueue(Queue *q, uint8_t *item){ if (q->front != q->rear) //队伍不空 { *item = *(q->rear); //获得队尾值 q->rear = q->mem + ((q->rear + 1 - q->mem) & 0xff); //队尾自增 return 1; //正确得到数据 } return 0; //队伍空}
串口UART实现
串口实现采用中断驱动模式,支持高效的数据传输。
/** ****************************************************************************** * @file usart.h * @author zhy * @version 1.0 * @date 2021-01-22 * @brief 与串口相关配置,USART1 ****************************************************************************** */#ifndef __USART_H__#define __USART_H__ /* 外部结构体类型声明 */typedef struct Queue Queue;/* 对外接口 */extern void UartInit(void);extern Queue queueRx; //串口接收队列#endif
/** ****************************************************************************** * @file usart.h * @author zhy * @version 1.0 * @date 2021-01-22 * @brief 这是与串口相关的C文件。 * 主要实现了重构printf函数。 * 串口1的配置 ****************************************************************************** */#include "usart.h"#include "stm32f4xx.h"#include "queue.h"/* 全局变量区 */Queue queueRx; //串口接收队列/** * @brief 重构函数 * @note 在printf中自动调用 * @param {int} ch 发送的数据 * @param {FILE} *f 此处用不到 * @retval 当前发送值 */int fputc(int ch, FILE *f){ while ((USART1->SR & USART_SR_TXE) == 0) ; //判断是否发送完成 USART1->DR = (uint8_t)ch; //发送数据 return ch;} /** * @brief 串口初始化 * @note * @param 无 * @retval 无 */void UartInit(void){ /* 1.启动时钟 */ __HAL_RCC_USART1_CLK_ENABLE(); //开启串口1时钟 /* 2.配置外设相关参数 */ UART_HandleTypeDef huart; //串口句柄 huart.Instance = USART1; //串口1 huart.Init.BaudRate = 115200; //波特率 huart.Init.WordLength = UART_WORDLENGTH_8B; //字长 huart.Init.StopBits = UART_STOPBITS_1; //1位停止位 huart.Init.Parity = UART_PARITY_NONE; //非校验 huart.Init.HwFlowCtl = UART_HWCONTROL_NONE; //无硬件控制 huart.Init.Mode = UART_MODE_TX_RX; //收发模式 huart.Init.OverSampling = UART_OVERSAMPLING_8; //8倍过采样 HAL_UART_Init(&huart); //串口1初始化 /* 3.接收中断相关 */ __HAL_UART_ENABLE_IT(&huart, UART_IT_RXNE); //使能接收中断} /** * @brief 串口底层初始化 * @note 此函数会在HAL_UART_Init中被调用 * @param {UART_HandleTypeDef} *huart 串口句柄 * @retval 无 */void HAL_UART_MspInit(UART_HandleTypeDef *huart){ if (USART1 == huart->Instance) //若是串口1 { /* 1.启动底层时钟 */ __HAL_RCC_GPIOA_CLK_ENABLE(); /* 2.配置gpio底层 */ GPIO_InitTypeDef gpioInit; gpioInit.Pin = GPIO_PIN_9 | GPIO_PIN_10; gpioInit.Mode = GPIO_MODE_AF_PP; gpioInit.Pull = GPIO_PULLUP; gpioInit.Speed = GPIO_SPEED_FAST; gpioInit.Alternate = GPIO_AF7_USART1; HAL_GPIO_Init(GPIOA, &gpioInit); /* 3.配置接收中断 */ InitQueue(&queueRx); //使能接收队列 HAL_NVIC_EnableIRQ(USART1_IRQn); //使能中断 HAL_NVIC_SetPriority(USART1_IRQn, 3, 3); //设置抢断优先级与子优先级 }} /** * @brief 串口1中断服务函数 * @note 在此处,只开放接收中断。那么当中断触发时,必然是接收中断。 * 因为中断函数时间越短越好,采用直接操作寄存器的方式。 * @param {*}无 * @retval 无 */void USART1_IRQHandler(void){ if ((USART1->SR & USART_SR_RXNE) && (USART1->CR1 & USART_CR1_RXNEIE)) //当接收中断置位且有中断标记 { InQueue(&queueRx, USART1->DR); //将接收的内容放入队列,读取寄存器,自动清除中断标记位 }}
总结
本文通过对HAL库中的串口通信流程进行优化,实现了一个高效的串口通信方案。同时,对系统文件夹中的程序进行了简化,提高了代码的可移植性和运行效率。通过重新定义位带操作和优化延迟函数,确保了系统的实时性和稳定性。未来将继续优化相关库文件,提升系统性能。
发表评论
最新留言
哈哈,博客排版真的漂亮呢~
[***.90.31.176]2025年05月02日 05时32分59秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
pair的用法
2019-03-09
SQL基本操作命令
2019-03-09
C# WinForm程序退出的方法
2019-03-09
onFailure unexpected end of stream
2019-03-09
Flex 布局的自适应子项内容过长导致其被撑大问题
2019-03-09
PL/SQL 动态Sql拼接where条件
2019-03-09
Lua-table 一种更少访问的安全取值方式
2019-03-09
虚函数
2019-03-09
斐波那契数列两种算法的时间复杂度
2019-03-09
【自学Flutter】4.1 Material Design字体图标的使用(icon)
2019-03-09
C++清空队列(queue)方法
2019-03-09
【换行符】什么时候用cin.get()吃掉输入流中的换行符
2019-03-09
【二叉树】已知后序与中序求先序
2019-03-09
解决Nginx 404 not found问题
2019-03-09
广东外语外贸大学第三届网络安全大赛Writeup
2019-03-09
VS2019 报错: LINK Error 无法找到 MSCOREE.lib的解决办法
2019-03-09
2021-04-23
2019-03-09
hadoop 分布式文件系统的计算和高可用
2019-03-09
【Linux】VMware Workstation 不可恢复错误: (vcpu-0)
2019-03-09