STM32学习笔记 二基于STM32F103C8T6和STM32CubeMX实现UART串口通信数据收发
Posted 遗忘丶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32学习笔记 二基于STM32F103C8T6和STM32CubeMX实现UART串口通信数据收发相关的知识,希望对你有一定的参考价值。
系列文章目录
一、基于STM32F103C8T6最小系统板和STM32CubeMX实现LED灯循环闪烁
二、基于STM32F103C8T6和STM32CubeMX实现UART串口通信数据收发
文章目录
前言
这次我用的板子是一个用STM32F103C8T6作为主控芯片的一个数据采集卡,两个LED灯连接的引脚是PB3与PB4,TX与RX引脚分别是PA9和PA10。完整工程下载链接:
基于STM32F103C8T6(HAL库)和CubeMX实现UART串口通信数据收发.rar
相关基础概念:
基于STM32之UART串口通信协议(一)详解
一、配置CubeMX
1、新建工程;
2、配置时钟源,在RCC里面的HSE配置的是晶振时钟;
3、配置程序烧录引脚SYS为SWD模式;
4、配置GPIO口,配置一个LED灯(我的板子是PB3),起到串口成功接收到数据时的指示作用;
5、配置串口收发引脚
此处我们采用的通信方式为UART通信(异步全双工串口通信),PA9作为TX,PA10作为RX使用。直接在可视框图里点击相应的引脚进行配置。
配置到目前,效果图为:
可以发现,TX和RX两个引脚配置完之后是黄色的,代表还没有配置完毕,下面继续进行配置。
6、在左边的"Connectivity”里面的USART1模式里选择异步全双工通信模式asynchronous
⮚点击USATR1
⮚设置MODE为异步通信(Asynchronous)
⮚基础参数:波特率为115200 Bits/s。传输数据长度为8 Bit。奇偶检验无,停止位1,接收和发送都使能
⮚GPIO引脚设置 USART1_RX/USART_TX
⮚NVIC Settings 一栏使能接收中断
这里简单扩展一下:
STM32F103系列单片机共有5个串口,其中1-3是通用同步/异步串行接口USART(Universal Synchronous/Asynchronous Receiver/Transmitter),4,、5是通用异步串行接口UART(Universal Asynchronous Receiver/Transmitter)。
7、配置时钟树,我还是开到最高的72MHz
8、进行项目设置,最后生成代码,CubeMX部分就大功告成了
二、HAL库UART相关函数简介
2.1 串口发送/接收函数
HAL_UART_Transmit();//串口发送数据,使用超时管理机制
HAL_UART_Receive();//串口接收数据,使用超时管理机制
HAL_UART_Transmit_IT();//串口中断模式发送
HAL_UART_Receive_IT();//串口中断模式接收
HAL_UART_Transmit_DMA();//串口DMA模式发送
HAL_UART_Transmit_DMA();//串口DMA模式接收
这六个函数参数基本一致,发送/接收各挑一个常用的函数进行简单介绍:
串口发送数据:
HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
功能:
串口发送指定长度的数据。如果超时没发送完成,则不再发送,返回超时标志(HAL_TIMEOUT)。
参数:
⮚ UART_HandleTypeDef *huart UART的别名 如 : UART_HandleTypeDef huart1; 别名就是huart1
⮚ *pData 需要发送的数据
⮚ Size 发送的字节数
⮚ Timeout 最大发送时间,发送数据超过该时间退出发送
举例: HAL_UART_Transmit(&huart1, (uint8_t *)ZZX, 3, 0xffff); //串口发送三个字节数据,最大传输时间0xffff
串口接收数据:
HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
功能:
串口中断接收,以中断方式接收指定长度数据。
大致过程是,设置数据存放位置,接收数据长度,然后使能串口接收中断。接收到数据时,会触发串口中断。再然后,串口中断函数处理,直到接收到指定长度数据,而后关闭中断,进入中断接收回调函数,不再触发接收中断。(只触发一次中断)
参数:
⮚ UART_HandleTypeDef *huart UART的别名
⮚ *pData 接收到的数据存放地址
⮚ Size 接收的字节数
举例: HAL_UART_Receive_IT(&huart1,(uint8_t *)&value,1); //中断接收一个字符,存储到value中
2.2 串口中断函数
HAL_UART_IRQHandler(UART_HandleTypeDef *huart); //串口中断处理函数
HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); //串口发送中断回调函数
HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart); //串口发送一半中断回调函数(不常用)
HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //串口接收中断回调函数
HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//串口接收一半回调函数(不常用)
HAL_UART_ErrorCallback();//串口接收错误函数
串口接收中断回调函数:
HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
功能:
HAL库的中断进行完之后,并不会直接退出,而是会进入中断回调函数中,用户可以在其中设置代码,串口中断接收完成之后,会进入该函数,该函数为空函数,用户需自行修改。
参数:
⮚ UART_HandleTypeDef *huart UATR的别名
举例: HAL_UART_RxCpltCallback(&huart1) //用户设定的代码 //
串口中断处理函数:
HAL_UART_IRQHandler(UART_HandleTypeDef *huart);
功能:
对接收到的数据进行判断和处理,判断是发送中断还是接收中断,然后进行数据的发送和接收,在中断服务函数中使用。
如果接收数据,则会进行接收中断处理函数
/* UART in mode Receiver ---------------------------------------------------*/
if((tmp_flag != RESET) && (tmp_it_source != RESET))
UART_Receive_IT(huart);
如果发送数据,则会进行发送中断处理函数
/* UART in mode Transmitter ------------------------------------------------*/
if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
UART_Transmit_IT(huart);
return;
2.3 串口查询函数
HAL_UART_GetState(); 判断UART的接收是否结束,或者发送数据是否忙碌
举例:
while(HAL_UART_GetState(&huart4) == HAL_UART_STATE_BUSY_TX) //检测UART发送结束
三、逻辑代码部分
3.1 UART接收中断
因为中断接收函数只能触发一次接收中断,所以我们需要在中断回调函数中再调用一次中断接收函数。
具体流程:
1、初始化串口
2、在main中第一次调用接收中断函数
3、进入接收中断,接收完数据 进入中断回调函数
4、修改HAL_UART_RxCpltCallback中断回调函数,处理接收的数据,
5、回调函数中要调用一次HAL_UART_Receive_IT函数,使得程序可以重新触发接收中断
函数流程:
①HAL_UART_Receive_IT (中断接收函数) ->
②USART2_IRQHandler(void) (中断服务函数) ->
③HAL_UART_IRQHandler(UART_HandleTypeDef *huart) (中断处理函数) ->
④UART_Receive_IT(UART_HandleTypeDef *huart) (接收函数) ->
⑤HAL_UART_RxCpltCallback(huart) (中断回调函数)
HAL_UART_RxCpltCallback函数就是用户要重写在main.c里的回调函数。
代码实现:
在main.c中添加下列定义:
#include <string.h>
#define RxBuffer_MaxSize 256 //最大接收字节数
char RxBuffer[RxBuffer_MaxSize]; //接收数据
uint8_t aRxBuffer; //接收中断缓冲
uint8_t UART1_Rx_Cnt = 0; //接收缓冲计数
在main()主函数中,调用一次接收中断函数
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
/* USER CODE END 2 */
在main.c下方添加中断回调函数
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
UNUSED(huart);
if(UART1_Rx_Cnt >= 255) //溢出判断
UART1_Rx_Cnt = 0;
memset(RxBuffer,0x00,sizeof(RxBuffer));
HAL_UART_Transmit(&huart1, (uint8_t *)"数据溢出", 10,0xFFFF);
else
RxBuffer[UART1_Rx_Cnt++] = aRxBuffer; //接收数据转存
if((RxBuffer[UART1_Rx_Cnt-1] == 0x0A)&&(RxBuffer[UART1_Rx_Cnt-2] == 0x0D)) //判断结束位
//此处条件可以改写为if(RxBuffer[UART1_Rx_Cnt-1] == '\\n') 因为上面的条件就是表示回车
HAL_UART_Transmit(&huart1, (uint8_t *)&RxBuffer, UART1_Rx_Cnt,0xFFFF); //将收到的信息发送出去
while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);//检测UART发送结束
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_3);//LED指示灯状态翻转
UART1_Rx_Cnt = 0;
memset(RxBuffer,0x00,sizeof(RxBuffer)); //清空数组
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1); //再开启接收中断
/* USER CODE END 4 */
现象:
使用USB转TTL(CH340)进行数据发送,XCOM V2.6串口助手进行调试,发送“1”(这里要注意波特率等参数要设置的和之前配置的相同)
在debug模式下,将缓冲计数值UART1_Rx_Cnt加入监视器,串口接收到发来的数据后,计数值+1.
同时也可以看到LED灯状态翻转
3.2 UART发送
重新定义printf函数
在 stm32f1xx_hal.c中包含#include <stdio.h>
#include "stm32f1xx_hal.h"
#include <stdio.h>
extern UART_HandleTypeDef huart1; //声明串口
在 stm32f1xx_hal.c 中重写fget和fput函数
/**
* 函数功能: 重定向c库函数printf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fputc(int ch, FILE *f)
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
/**
* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE *f)
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
在main.c中添加
#define RxBuffer_MaxSize 256
char RxBuffer[RxBuffer_MaxSize];
while (1)
/* USER CODE END WHILE */
printf("你好,世界\\r\\n");//这里博主只写\\n的时候无法换行,百度了一下用\\r\\n就可以了,估计是编译系统的问题
HAL_Delay(1000);
/* USER CODE BEGIN 3 */
现象:
注意:
重定义printf后,必须在target里面勾选上MicroLIB,调用一下这个微型库,不然一直卡在里面。
以上是关于STM32学习笔记 二基于STM32F103C8T6和STM32CubeMX实现UART串口通信数据收发的主要内容,如果未能解决你的问题,请参考以下文章
STM32学习笔记 二基于STM32F103C8T6和STM32CubeMX实现UART串口通信数据收发
STM32学习笔记 一基于STM32F103C8T6最小系统板和STM32CubeMX实现板载LED灯循环闪烁
STM32学习笔记 一基于STM32F103C8T6最小系统板和STM32CubeMX实现LED灯循环闪烁
三实战小例程 基于STM32F103C8T6最小系统板和STM32CubeMX驱动WS2812B光立方