STM32_HAL库_CubeMx实现STM32F1五个串口通信(单字节中断接收)
目录一. 串口通信简介二. STM32CubeMx实现STM32F103系列串口驱动三. 五个串口发送与中断接收例程一. 串口通信简介串口通信的原理网上教程一大堆了,入坑单片机的必会串口,这里就不多说了。唯一值得一提的就是STM32是有USART和UART之分的。UART就是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),是一种异步收发
一. 串口通信简介
串口通信的原理网上教程一大堆了,入坑单片机的必会串口,这里就不多说了。唯一值得一提的就是STM32是有USART和UART之分的。UART就是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),是一种异步收发传输器。USART是通用同步/异步串行接收/发送器(Universal Synchronous/Asynchronous Receiver/Transmitter)。USART是一个全双工通用同步/异步串行收发模块,该接口是一个高度灵活的串行通信设备。从名字上可以看出,USART在UART基础上增加了同步功能,即USART是UART的增强型。
当然,一般应用时我们都是使用的异步串行通信,此时两者是一样的用法。具体在写代码时就注意不要将UART写成了USART,比如STM32F1系列有五个串口,分别是USART1,USART2,USART3,UART4,UART5。在使用4和5号串口的时候不要写错了。
本教程在STM32F103系列上实现五个串口的驱动,全部使用中断接收方式。最后的功能是上位机通过串口调试助手向任何一个串口发送数据(以回车键结束),单片机都即时通过串口1返回接收的数据。使用原子哥的精英版子测试通过,当然任何一个最小系统板或其他板子都可以测试。
本例程上传到了CSDN,可以作为串口通信的驱动模板下载使用。
CSDN下载地址:https://download.csdn.net/download/qq_30267617/20244343
百度网盘下载地址:https://pan.baidu.com/s/1Olju-OqyXFi06wOkpaKklg
提取码:5232
二. STM32CubeMx实现STM32F103系列串口驱动
串口的配置还是相对简单的。使用STM32CubeMx很容易实现串口的驱动,这里我们在CubeMx中新建一个工程,实现五个串口和两个LED灯的驱动。
-
使能时钟RCC,使用高速外部时钟(HSE)
-
配置时钟,外部时钟源8MHz,配置系统时钟为72MHz。
-
配置GPIO,实现两个LED灯。
-
配置串口1,2,3
以串口1为例,设置为异步通信方式,使能全局中断,其他使用默认。
-
配置串口4和串口5
以串口4为例,设置为异步通信方式,使能全局中断,其他使用默认。
6. 设置调试模式为ST-debug
然后就可以Generate Code了。
但是我一般都是使用CubeMx生成驱动代码,然后摘到自己的工程里面,方便管理。 所以后面讲的就不是CubeMx的代码框架了。
三. 五个串口发送与中断接收例程
-
串口驱动代码
新建uart.c和uart.h文件。uart.c中存放驱动代码与中断处理代码。
void uart1_init(u32 bound)
{
//UART 初始化设置
huart1.Instance = USART1;
huart1.Init.BaudRate = bound;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
}
HAL_UART_Receive_IT(&huart1, (u8 *)aRxBuffer1, RXBUFFERSIZE);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量
}
void uart2_init(u32 bound)
{
//UART 初始化设置
huart2.Instance = USART2;
huart2.Init.BaudRate = bound;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
}
HAL_UART_Receive_IT(&huart2, (u8 *)aRxBuffer2, RXBUFFERSIZE);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量
}
void uart3_init(u32 bound)
{
huart3.Instance = USART3;
huart3.Init.BaudRate = bound;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart3) != HAL_OK)
{
}
HAL_UART_Receive_IT(&huart3, (u8 *)aRxBuffer3, RXBUFFERSIZE);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量
}
void uart4_init(u32 bound)
{
huart4.Instance = UART4;
huart4.Init.BaudRate = bound;
huart4.Init.WordLength = UART_WORDLENGTH_8B;
huart4.Init.StopBits = UART_STOPBITS_1;
huart4.Init.Parity = UART_PARITY_NONE;
huart4.Init.Mode = UART_MODE_TX_RX;
huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart4.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart4) != HAL_OK)
{
}
HAL_UART_Receive_IT(&huart4, (u8 *)aRxBuffer4, RXBUFFERSIZE);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量
}
void uart5_init(u32 bound)
{
huart5.Instance = UART5;
huart5.Init.BaudRate = bound;
huart5.Init.WordLength = UART_WORDLENGTH_8B;
huart5.Init.StopBits = UART_STOPBITS_1;
huart5.Init.Parity = UART_PARITY_NONE;
huart5.Init.Mode = UART_MODE_TX_RX;
huart5.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart5.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart5) != HAL_OK)
{
}
HAL_UART_Receive_IT(&huart5, (u8 *)aRxBuffer5, RXBUFFERSIZE);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量
}
//UART底层初始化,时钟使能,引脚配置,中断配置
//此函数会被HAL_UART_Init()调用
//huart:串口句柄
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStruct;
if (huart->Instance == USART1)
{
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 3, 3);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
else if (huart->Instance == USART2)
{
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART2 interrupt Init */
HAL_NVIC_SetPriority(USART2_IRQn, 2, 1);
HAL_NVIC_EnableIRQ(USART2_IRQn);
}
else if (huart->Instance == USART3)
{
__HAL_RCC_USART3_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**USART3 GPIO Configuration
PB10 ------> USART3_TX
PB11 ------> USART3_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USART3 interrupt Init */
HAL_NVIC_SetPriority(USART3_IRQn, 2, 2);
HAL_NVIC_EnableIRQ(USART3_IRQn);
}
if (huart->Instance == UART4)
{
__HAL_RCC_UART4_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**UART4 GPIO Configuration
PC10 ------> UART4_TX
PC11 ------> UART4_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* UART4 interrupt Init */
HAL_NVIC_SetPriority(UART4_IRQn, 3, 1);
HAL_NVIC_EnableIRQ(UART4_IRQn);
}
if (huart->Instance == UART5)
{
__HAL_RCC_UART5_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/**UART5 GPIO Configuration
PC12 ------> UART5_TX
PD2 ------> UART5_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* UART5 interrupt Init */
HAL_NVIC_SetPriority(UART5_IRQn, 3, 2);
HAL_NVIC_EnableIRQ(UART5_IRQn);
}
}
-
中断处理函数
中断函数里面处理接收数据,每一帧数据以回车符结束。每接收完一帧数据就把接收到的数据拷贝到预定义的数据中,等待主函数处理,同时标志位置1,标志着有新一帧数据,在主函数里面需要将标志位清零。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1) //如果是串口1
{
if ((USART1_RX_STA & 0x8000) == 0) //接收未完成
{
if (USART1_RX_STA & 0x4000) //接收到了0x0d
{
if (aRxBuffer1[0] != 0x0a)
USART1_RX_STA = 0; //接收错误,重新开始
else
USART1_RX_STA |= 0x8000; //接收完成了
}
else //还没收到0X0D
{
if (aRxBuffer1[0] == 0x0d)
USART1_RX_STA |= 0x4000;
else
{
USART1_RX_BUF[USART1_RX_STA & 0X3FFF] = aRxBuffer1[0];
USART1_RX_STA++;
if (USART1_RX_STA > (USART_REC_LEN - 1))
USART1_RX_STA = 0; //接收数据错误,重新开始接收
}
}
}
if (USART1_RX_STA & 0x8000)
{
flag = 1;
memcpy(data, USART1_RX_BUF, USART1_RX_STA & 0x3fff);
USART1_RX_STA = 0;
}
}
if (huart->Instance == USART2) //如果是串口1
{
if ((USART2_RX_STA & 0x8000) == 0) //接收未完成
{
if (USART2_RX_STA & 0x4000) //接收到了0x0d
{
if (aRxBuffer2[0] != 0x0a)
USART2_RX_STA = 0; //接收错误,重新开始
else
USART2_RX_STA |= 0x8000; //接收完成了
}
else //还没收到0X0D
{
if (aRxBuffer2[0] == 0x0d)
USART2_RX_STA |= 0x4000;
else
{
USART2_RX_BUF[USART2_RX_STA & 0X3FFF] = aRxBuffer2[0];
USART2_RX_STA++;
if (USART2_RX_STA > (USART_REC_LEN - 1))
USART2_RX_STA = 0; //接收数据错误,重新开始接收
}
}
}
if (USART2_RX_STA & 0x8000)
{
flag = 1;
memcpy(data, USART2_RX_BUF, USART2_RX_STA & 0x3fff);
USART2_RX_STA = 0;
}
}
if (huart->Instance == USART3) //如果是串口1
{
if ((USART3_RX_STA & 0x8000) == 0) //接收未完成
{
if (USART3_RX_STA & 0x4000) //接收到了0x0d
{
if (aRxBuffer3[0] != 0x0a)
USART3_RX_STA = 0; //接收错误,重新开始
else
USART3_RX_STA |= 0x8000; //接收完成了
}
else //还没收到0X0D
{
if (aRxBuffer3[0] == 0x0d)
USART3_RX_STA |= 0x4000;
else
{
USART3_RX_BUF[USART3_RX_STA & 0X3FFF] = aRxBuffer3[0];
USART3_RX_STA++;
if (USART3_RX_STA > (USART_REC_LEN - 1))
USART3_RX_STA = 0; //接收数据错误,重新开始接收
}
}
}
if (USART3_RX_STA & 0x8000)
{
flag = 1;
memcpy(data, USART3_RX_BUF, USART3_RX_STA & 0x3fff);
USART3_RX_STA = 0;
}
}
if (huart->Instance == UART4) //如果是串口1
{
if ((USART4_RX_STA & 0x8000) == 0) //接收未完成
{
if (USART4_RX_STA & 0x4000) //接收到了0x0d
{
if (aRxBuffer4[0] != 0x0a)
USART4_RX_STA = 0; //接收错误,重新开始
else
USART4_RX_STA |= 0x8000; //接收完成了
}
else //还没收到0X0D
{
if (aRxBuffer4[0] == 0x0d)
USART4_RX_STA |= 0x4000;
else
{
USART4_RX_BUF[USART4_RX_STA & 0X3FFF] = aRxBuffer4[0];
USART4_RX_STA++;
if (USART4_RX_STA > (USART_REC_LEN - 1))
USART4_RX_STA = 0; //接收数据错误,重新开始接收
}
}
}
if (USART4_RX_STA & 0x8000)
{
flag = 1;
memcpy(data, USART4_RX_BUF, USART4_RX_STA & 0x3fff);
USART4_RX_STA = 0;
}
}
if (huart->Instance == UART5) //如果是串口1
{
if ((USART5_RX_STA & 0x8000) == 0) //接收未完成
{
if (USART5_RX_STA & 0x4000) //接收到了0x0d
{
if (aRxBuffer5[0] != 0x0a)
USART5_RX_STA = 0; //接收错误,重新开始
else
USART5_RX_STA |= 0x8000; //接收完成了
}
else //还没收到0X0D
{
if (aRxBuffer5[0] == 0x0d)
USART5_RX_STA |= 0x4000;
else
{
USART5_RX_BUF[USART5_RX_STA & 0X3FFF] = aRxBuffer5[0];
USART5_RX_STA++;
if (USART5_RX_STA > (USART_REC_LEN - 1))
USART5_RX_STA = 0; //接收数据错误,重新开始接收
}
}
}
if (USART5_RX_STA & 0x8000)
{
flag = 1;
memcpy(data, USART5_RX_BUF, USART5_RX_STA & 0x3fff);
USART5_RX_STA = 0;
}
}
}
//串口1中断服务程序
void USART1_IRQHandler(void)
{
u32 timeout = 0;
#if SYSTEM_SUPPORT_OS //使用OS
OSIntEnter();
#endif
HAL_UART_IRQHandler(&huart1); //调用HAL库中断处理公用函数
timeout = 0;
while (HAL_UART_GetState(&huart1) != HAL_UART_STATE_READY) //等待就绪
{
timeout++; ////超时处理
if (timeout > HAL_MAX_DELAY)
break;
}
timeout = 0;
while (HAL_UART_Receive_IT(&huart1, (u8 *)aRxBuffer1, RXBUFFERSIZE) != HAL_OK) //一次处理完成之后,重新开启中断并设置RxXferCount为1
{
timeout++; //超时处理
if (timeout > HAL_MAX_DELAY)
break;
}
#if SYSTEM_SUPPORT_OS //使用OS
OSIntExit();
#endif
}
//串口2中断服务程序
void USART2_IRQHandler(void)
{
u32 timeout = 0;
HAL_UART_IRQHandler(&huart2); //调用HAL库中断处理公用函数
timeout = 0;
while (HAL_UART_GetState(&huart2) != HAL_UART_STATE_READY) //等待就绪
{
timeout++; ////超时处理
if (timeout > HAL_MAX_DELAY)
break;
}
timeout = 0;
while (HAL_UART_Receive_IT(&huart2, (u8 *)aRxBuffer2, RXBUFFERSIZE) != HAL_OK) //一次处理完成之后,重新开启中断并设置RxXferCount为1
{
timeout++; //超时处理
if (timeout > HAL_MAX_DELAY)
break;
}
}
//串口2中断服务程序
void USART3_IRQHandler(void)
{
u32 timeout = 0;
HAL_UART_IRQHandler(&huart3); //调用HAL库中断处理公用函数
timeout = 0;
while (HAL_UART_GetState(&huart3) != HAL_UART_STATE_READY) //等待就绪
{
timeout++; ////超时处理
if (timeout > HAL_MAX_DELAY)
break;
}
timeout = 0;
while (HAL_UART_Receive_IT(&huart3, (u8 *)aRxBuffer3, RXBUFFERSIZE) != HAL_OK) //一次处理完成之后,重新开启中断并设置RxXferCount为1
{
timeout++; //超时处理
if (timeout > HAL_MAX_DELAY)
break;
}
}
//串口4中断服务程序
void UART4_IRQHandler(void)
{
u32 timeout = 0;
HAL_UART_IRQHandler(&huart4); //调用HAL库中断处理公用函数
timeout = 0;
while (HAL_UART_GetState(&huart4) != HAL_UART_STATE_READY) //等待就绪
{
timeout++; ////超时处理
if (timeout > HAL_MAX_DELAY)
break;
}
timeout = 0;
while (HAL_UART_Receive_IT(&huart4, (u8 *)aRxBuffer4, RXBUFFERSIZE) != HAL_OK) //一次处理完成之后,重新开启中断并设置RxXferCount为1
{
timeout++; //超时处理
if (timeout > HAL_MAX_DELAY)
break;
}
}
//串口5中断服务程序
void UART5_IRQHandler(void)
{
u32 timeout = 0;
HAL_UART_IRQHandler(&huart5); //调用HAL库中断处理公用函数
timeout = 0;
while (HAL_UART_GetState(&huart5) != HAL_UART_STATE_READY) //等待就绪
{
timeout++; ////超时处理
if (timeout > HAL_MAX_DELAY)
break;
}
timeout = 0;
while (HAL_UART_Receive_IT(&huart5, (u8 *)aRxBuffer5, RXBUFFERSIZE) != HAL_OK) //一次处理完成之后,重新开启中断并设置RxXferCount为1
{
timeout++; //超时处理
if (timeout > HAL_MAX_DELAY)
break;
}
}
-
主函数处理接收数据
main函数内容如下。这样处理之后就实现无论哪个串口接收到了数据,都会在中断函数中将接收到的数据拷贝到data数组中,置位标志位flag,然后主函数中将data数组通过串口1输出,清空data数组,清零标志位,等待下一次接收。
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
int main(void)
{
u8 len;
u16 times=0;
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟,72M
delay_init(72); //初始化延时函数
uart1_init(115200); //初始化串口
uart2_init(115200); //初始化串口
uart3_init(115200); //初始化串口
uart4_init(115200); //初始化串口
uart5_init(115200); //初始化串口
LED_Init(); //初始化LED
KEY_Init(); //初始化按键
while(1)
{
if (flag)
{
HAL_UART_Transmit(&huart1,(uint8_t*)data,sizeof(data),1000); //发送接收到的数据
printf("\r\n");
memset(data, 0, sizeof(data));
flag = 0;
}
else
{
times++;
if(times%200==0)printf("请输入数据,以回车键结束\r\n");
if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
delay_ms(10);
}
}
}
工程文件上传到了百度网盘,提供免费下载。
下载地址:https://pan.baidu.com/s/1Olju-OqyXFi06wOkpaKklg
提取码:5232
更多推荐
所有评论(0)