完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一. 串口通信简介
串口通信的原理网上教程一大堆了,入坑单片机的必会串口,这里就不多说了。唯一值得一提的就是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灯的驱动。
三. 五个串口发送与中断接收例程 串口驱动代码 新建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("rn"); memset(data, 0, sizeof(data)); flag = 0; } else { times++; if(times%200==0)printf("请输入数据,以回车键结束rn"); if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行. delay_ms(10); } } } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1561 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1501 浏览 1 评论
933 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
665 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1555 浏览 2 评论
1847浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
609浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
503浏览 3评论
507浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
488浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-10 12:02 , Processed in 0.647839 second(s), Total 78, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号