本文最后更新于 2025-01-10T22:20:33+08:00
说明:
- 本文档由DuRuofu撰写,由DuRuofu负责解释及执行。
修订历史:
文档名称 |
版本 |
作者 |
时间 |
备注 |
STM32串口使用(HAL库) |
v1.0.0 |
DuRuofu |
2023-07-09 |
首次建立 |
|
|
|
|
|
STM32串口使用(HAL库)
一、工程创建
1.设置RCC
设置高速外部时钟HSE 选择外部时钟源
2.设置串口
- 点击USATR1
- 设置MODE为异步通信(Asynchronous)
- 基础参数:波特率为115200 Bits/s。传输数据长度为8 Bit。奇偶检验无,停止位1 接收和发送都使能
- GPIO引脚设置 USART1_RX/USART_TX
- NVIC Settings 一栏使能接收中断
3.设置时钟
我的是 外部晶振为8MHz
1选择外部时钟HSE 8MHz
2PLL锁相环倍频72倍
3系统时钟来源选择为PLL
4设置APB1分频器为 /2
4.项目文件设置
- 设置项目名称
- 设置存储路径
- 选择所用IDE
5.创建工程文件
然后点击GENERATE CODE 创建工程
配置下载工具
新建的工程所有配置都是默认的 我们需要自行选择下载模式,勾选上下载后复位运行
二、串口发送
1. 相关函数:
1 2 3 4 5 6
| HAL_UART_Transmit();串口发送数据,使用超时管理机制 HAL_UART_Receive();串口接收数据,使用超时管理机制 HAL_UART_Transmit_IT();串口中断模式发送 HAL_UART_Receive_IT();串口中断模式接收 HAL_UART_Transmit_DMA();串口DMA模式发送 HAL_UART_Transmit_DMA();串口DMA模式接收
|
串口发送数据函数:
1 2 3
| HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
|
2.以重新定义printf函数的方式发送
在生成的的usart.c里 中包含#include <stdio.h> 重写fget和fput函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
int fputc(int ch, FILE *f) { HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff); return ch; }
int fgetc(FILE *f) { uint8_t ch = 0; HAL_UART_Receive(&huart1, &ch, 1, 0xffff); return ch; }
|
也可以自己建立文件,引入自动生成的usart.c作为依赖,在自己的模块里添加,强烈建议这种方式。
3.使用
1 2 3 4 5 6 7 8
| while (1) { printf("duruofu测试\n"); HAL_Delay(1000); }
|
二、串口接收
这里使用中断接收:
只需要在接收中断回调函数里编写自己的代码即可:(下面这段代码也建议放在自己的模块里:)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1) { HAL_UART_Transmit(&huart1,&Uart1RX_Data,1,0xFFFF); HAL_UART_Receive_IT(&huart1,&Uart1RX_Data,1); } if(huart->Instance == USART2) { HAL_UART_Transmit(&huart2,&Uart2RX_Data,1,0xFFFF); HAL_UART_Receive_IT(&huart2,&Uart2RX_Data,1); } }
|
使用 if
语句判断是哪个串口接收到了数据。如果是 USART1,会执行相应的操作:
- 调用
HAL_UART_Transmit
函数将接收到的数据 Uart1RX_Data
发送出去,第三个参数表示要发送的数据长度为 1。
- 调用
HAL_UART_Receive_IT
函数开启 USART1 的连续接收中断,继续准备接收下一组数据。
这里需要注意:
若定长串口中断接收数据,数据溢出,将会产生数据溢出错误,中断不再接收数据
这和前面的开启接收中断有关:1 2 3 4
| __HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);
HAL_UART_Receive_IT(&huart1,&Uart1RX_Data,8);
|
超出缓冲区就会发生溢出,然后不能再接收
可以参考下面修改后的代码:
最后代码总结为:
serial_it_config.c
这段代码实现了串口接收中断相关的初始化和回调函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| #include "serial_it_config.h"
void USART_IT_Config(void)
{
Debug_Init();
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
UART1_RxCpltCallback(huart);
}
else if(huart->Instance == USART2)
{
}
else if(huart->Instance == USART3)
{
}
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
UART1_ErrorCallback(huart);
}
else if(huart->Instance == USART2)
{
}
else if(huart->Instance == USART3)
{
}
}
|
serial_it_config.h
1 2 3 4 5 6 7 8 9
| #include "main.h"
#include "debug.h" #ifndef __USART_CONFIG_H
#define __USART_CONFIG_H
void USART_IT_Config(void); #endif
|
debug.c
这段代码是用于在嵌入式系统中实现串口调试功能的代码。主要包含了串口初始化函数、接收完成回调函数、错误回调函数、发送字符串函数以及重定向c库函数printf和scanf到串口的功能。
代码中使用了名为UART_HANDLE
的宏来定义了串口句柄,指定了使用的是串口1。同时定义了接收缓冲区和接收缓冲计数变量。在串口初始化函数Debug_Init
中,使能了串口的接收中断,并设置连续接收中断并指定接收缓冲区的地址和长度。
接收完成回调函数UART1_RxCpltCallback
中,判断了接收缓冲区溢出的情况,并进行了处理。然后根据接收到的字符进行操作,例如当接收到字符’1’时,输出”发送1”;当接收到字符’2’时,输出”发送2”;以此类推。最后判断是否接收到结束标志位,并把接收到的信息发送出去。
错误回调函数UART1_ErrorCallback
用于清除溢出中断。发送字符串函数Usart_SendString
用于发送字符串。重定向c库函数printf和scanf到串口的功能分别在fputc
和fgetc
函数中实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
| #include "debug.h"
#include "string.h"
#define RXBUFFERSIZE 256
#define UART_HANDLE huart1
uint8_t RxBuffer[RXBUFFERSIZE];
uint8_t Uart_RxBuffer;
uint8_t Uart_Rx_Cnt = 0;
void Debug_Init(void)
{
__HAL_UART_ENABLE_IT(&UART_HANDLE,UART_IT_RXNE);
HAL_UART_Receive_IT(&UART_HANDLE,&Uart_RxBuffer,1);
}
void UART1_RxCpltCallback(UART_HandleTypeDef *huart)
{
UNUSED(huart);
if(Uart_Rx_Cnt >= 255)
{
Uart_Rx_Cnt = 0;
memset(RxBuffer,0x00,sizeof(RxBuffer));
HAL_UART_Transmit(&UART_HANDLE, (uint8_t *)"数据溢出", 10,0xFFFF);
}
else
{
RxBuffer[Uart_Rx_Cnt++] = Uart_RxBuffer;
if(Uart_RxBuffer == '1')
{
DEBUG_printf("发送1");
}
else if(Uart_RxBuffer == '2')
{
DEBUG_printf("发送2");
}
else if(Uart_RxBuffer == '3')
{
DEBUG_printf("发送3");
}
else if(Uart_RxBuffer == '4')
{
DEBUG_printf("发送4");
}
if((RxBuffer[Uart_Rx_Cnt-1] == 0x0A)&&(RxBuffer[Uart_Rx_Cnt-2] == 0x0D))
{
HAL_UART_Transmit(&UART_HANDLE, (uint8_t *)&RxBuffer, Uart_Rx_Cnt,0xFFFF);
Uart_Rx_Cnt = 0;
memset(RxBuffer,0x00,sizeof(RxBuffer));
}
}
HAL_UART_Receive_IT(&UART_HANDLE, (uint8_t *)&Uart_RxBuffer, 1);
}
void UART1_ErrorCallback(UART_HandleTypeDef *huart)
{
if(HAL_UART_ERROR_ORE)
{
uint32_t temp = huart->Instance->SR;
temp = huart->Instance->DR;
}
}
void Usart_SendString(uint8_t *str)
{
unsigned int k=0;
do
{
HAL_UART_Transmit(&UART_HANDLE,(uint8_t *)(str + k) ,1,1000);
k++;
} while(*(str + k)!='\0');
}
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&UART_HANDLE, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&UART_HANDLE, &ch, 1, 0xffff);
return ch;
}
|
debug.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #include <stdio.h>
#include "main.h"
#include "usart.h"
#ifndef __DEBUG_H
#define __DEBUG_H
#define DEBUG
#ifdef DEBUG
#define DEBUG_printf(format, ...) printf(format "\r\n", ##__VA_ARGS__)
#define DEBUG_info(tag,format, ...) printf("DEBUG_info["tag"]:" format "\r\n", ##__VA_ARGS__)
#define DEBUG_warnig(tag,format, ...) printf("DEBUG_warnig["tag"]:" format "\r\n", ##__VA_ARGS__)
#define DEBUG__error(tag,format, ...) printf("DEBUG__error["tag"]:" format "\r\n",##__VA_ARGS__)
#else #define DEBUG_printf(format, ...) printf(format "\r\n", ##__VA_ARGS__)
#define DEBUG_info(tag,format, ...)
#define DEBUG_warnig(tag,format, ...)
#define DEBUG__error(tag,format, ...)
#endif
void Debug_Init(void);
void UART1_RxCpltCallback(UART_HandleTypeDef *huart);
void UART1_ErrorCallback(UART_HandleTypeDef *huart);
#endif
|
参考链接
STM32CubeMX之串口使用(中断方式)
https://zhuanlan.zhihu.com/p/162732368
【STM32】HAL库——串口中断通信(二)
https://blog.csdn.net/weibo1230123/article/details/80596220