HAL库-串口USART
勾选Enable
如果开启了多个中断的话建议去NVIC中去调节一下优先级
串口初始化函数
**MX_USART1_UART_Init();**
**void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;//波特率设置
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)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}**
位置:这个类型的初始化函数都会定义在对应的外设usart.c源文件中,简单看看它的代码(部分解释写在代码里面)
功能: 这个函数用于初始化串口的相关配置,他会按照你在CubeMX里面的配置,写好代码,自动生成,不用管
串口的HAL库函数(先说明总体的,常用的记录一下)
位置: 这些函数主要在**stm32f1xx_hal.c**
文件中定义,一般查看直接看这个**stm32f1xx_hal.h**
头文件
在其中执行要关注这几个函数
**//发送和接收函数
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_DMAPause(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_DMAResume(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart);
//中断处理函数
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart);
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);
void HAL_UART_AbortCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_AbortTransmitCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart);**
这些函数的具体使用可以参考STM的官网
这里基本介绍一下的几个函数,一般的项目用这几个就够了
**HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);**
串口发送函数-轮询模式
**HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout);**
功能:
使用实例和讲解:
**uint8_t test[] = "Hello,World";
HAL_UART_Transmit(&huart1,test,11,100);
//&huart1,数据类型UART_HandleTypeDef,&-取地址,huart1表示通过串口几
//test,数据类型uint8_t,要发送的变量的地址,test[]是数组-地址直接写数组名
/*11,数据类型uint16_t,要发送的数据字节长度,11就是发送一个有11个字节的数据,注意一个字节=8个位
'Hello,World'一共有11个字节*/
//100,数据类型uint32_t,发送的超时时间-ms,100就是100ms,当发送数据所花费的时间超过100ms就退出这个函数**
串口发送函数-中断模式
**HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);**
功能: 是一个用于以中断方式发送数据的函数,具体的工作流程是怎样的呢可以去查看KK的视频讲解;
过程: 这里简单的说明一下自己的理解,就是根据STM32的串口硬件结构可以发现,有一个发送移位寄存器和发送缓冲寄存器。每次发送一个字节之后发送缓冲寄存器中缓冲的数据就会传到发送移位寄存器中,这个时候发送缓冲寄存器就会空掉,这个时候UART外设将生成一个发送缓冲区为空中断,让CPU将下一个字节放进来(这个就是串口中断服务函数干的),然后CPU就去干别的了,UART自己去继续发送,等到下一次缓冲寄存器空掉,CPU再过来一下,当按照函数规定的数据长度发送完毕之后会再产生一个发送完成中断 (然后让串口发送完成中断回调函数来处理)。
使用实例和讲解:
**uint8_t test[] = "Hello,World";**
**HAL_UART_Transmit_IT(&huart1,test,11);
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
UART_HandleTypeDef *huart:这是一个指向UART_HandleTypeDef结构体的指针,它包含了有关UART外设的配置和状态信息。
const uint8_t *pData:这是一个指向要发送数据的缓冲区的指针。数据以字节为单位,使用uint8_t类型表示,因此每个字节应该在0到255之间。
uint16_t Size:这是要发送的数据的字节数。您可以通过设置这个参数来指定要发送的数据的大小。
这段代码的意思就是通过串口1发送test这个数组**
顺带提一嘴就是test这个数组的长度其实是12个字节,最后有一个结束标识符,实际有用的是11个,所以我这里就只发送了11个字节,也就是只发送了test这个数据的11个字节,也可以只发送2个那就是He,大家可以自己去尝试
串口接收函数-轮询模式
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
功能: 用于从UART接收数据
过程: 该函数的作用是从UART外设接收数据。当调用该函数后,它会等待接收数据,直到满足以下任一条件:
Size
指定的字节数)。Timeout
指定的毫秒数)。一旦满足上述条件之一,函数将返回,并将接收到的数据存储在提供的缓冲区中。
使用实例和讲解:
**uint8_t temp[3];
if ( HAL_UART_Receive(&huart1,temp,2,100) == HAL_OK )
{
HAL_UART_Transmit(&huart1,temp,2,100);
}**
**这个方式还是不是很好,会有不反应的情况,个人觉得能开中断就用中断
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
UART_HandleTypeDef *huart:这是一个指向UART_HandleTypeDef结构体的指针,包含有关UART外设的配置和状态信息。
uint8_t *pData:这是一个指向接收数据的缓冲区的指针。接收到的数据将被存储在这个缓冲区中。
uint16_t Size:这是要接收的数据的字节数。您可以设置这个参数来指定要接收的数据的大小。
uint32_t Timeout:这是接收超时时间,以毫秒为单位。如果在超时时间内没有接收到数据,函数将返回。
函数的返回类型是HAL_StatusTypeDef,它是一个枚举类型,表示函数执行的状态。可能的返回值包括:
HAL_OK:函数执行成功。
HAL_ERROR:函数执行过程中发生了错误。
HAL_BUSY:UART外设正在接收其他数据。
HAL_TIMEOUT:接收数据超时。**
串口接收函数-中断模式
**HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);**
功能: 是用于使用中断方式从UART接收数据的函数
过程: 调用该函数后,UART外设将开始接收数据,并在每接收到一个字节时产生一个接收完成中断(接收缓冲寄存器非空中断)将触发串口中断服务函数的执行。当HAL_UART_Receive_IT
函数需要接收的数据字节数达到时,程序将触发接收完成中断,并执行串口接收完成中断回调函数
使用实例和讲解:
**uint8_t temp[3];
HAL_UART_Receive_IT(&huart1,temp,3);//接收3个字节
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//串口接收完成中断回调函数
{
printf("66\r\n");//发送66和换行回车
HAL_UART_Transmit_IT(&huart1,temp,3);//发送接收到的数据
HAL_UART_Receive_IT(&huart1,temp,3);//再次打开接收中断,用于下一次的接收
}
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
UART_HandleTypeDef *huart:这是一个指向UART_HandleTypeDef结构体的指针,包含有关UART外设的配置和状态信息。
uint8_t *pData:这是一个指向接收数据的缓冲区的指针。接收到的数据将被存储在这个缓冲区中。
uint16_t Size:这是要接收的数据的字节数。您可以设置这个参数来指定要接收的数据的大小。
函数的返回类型是HAL_StatusTypeDef,它是一个枚举类型,表示函数执行的状态。可能的返回值包括:
HAL_OK:函数执行成功。
HAL_ERROR:函数执行过程中发生了错误。
HAL_BUSY:UART外设正在接收其他数据。**
串口中断服务函数
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart);
功能: 是用于处理UART外设的中断的函数
过程: 该函数的作用是在发生UART相关的中断时,调用相应的中断处理函数。它是由中断向量表中的UART中断向量所调用的。
当UART外设发生中断时,例如接收完成中断或发送完成中断,系统会进入中断服务例程(ISR)并调用HAL_UART_IRQHandler
函数。
在HAL_UART_IRQHandler
函数内部,它会根据中断源的不同,调用相应的中断处理函数。例如,如果是接收完成中断,它将调用HAL_UART_RxCpltCallback
函数;如果是发送完成中断,它将调用HAL_UART_TxCpltCallback
函数。
这些中断处理函数是由用户在应用程序中定义的,用于处理具体的中断事件。您可以在这些中断处理函数中编写自定义的代码来执行特定的操作,比如处理接收到的数据或发送下一组数据。
使用实例和讲解:
**/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
这里是把stm32f1xx_it.c源文件里面截取的一部分
这部分是CubeMx帮我们配置好的
意思就是所有的串口中断都会进这个void USART1_IRQHandler(void)函数
然后执行 HAL_UART_IRQHandler(&huart1);**
串口接收完成中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
功能: 是一个回调函数,用于处理UART接收完成中断的事件
过程: 该函数是由HAL_UART_IRQHandler
内部在接收完成中断发生时调用的。当UART外设成功接收到指定数量的数据时,会触发接收完成中断。
在应用程序中,您可以实现自己的HAL_UART_RxCpltCallback
函数,并在其中编写自定义的代码来处理接收完成中断事件。
使用实例和讲解:
**/* 接收完成中断回调函数,
定义:当串口中断接收到的数据长度达到HAL_UART_Receive_IT
规定的字节数据长度时,中断服务函数运行完之后就会来调用这个函数
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
printf("66\r\n");
HAL_UART_Transmit_IT(&huart1,temp,3);
HAL_UART_Receive_IT(&huart1,temp,3);
}**
首先就是初始化-就是这个部分的配置好之后生成的代码**初始化**
然后就是在主程序中利用发送或者接收函数进行数据接收和发送
轮询方式放在什么地方都可以
中断方式建议写一个源文件用于进行串口接收完成回调函数的自定义编写
1.直接在usart.c文件中写下下面的代码就行
/* USER CODE BEGIN 0 */
#include "stdio.h"
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
/* 函数
定义:串口发送重定向,这样就可以在程序中直接使用printf来发送数据
*/
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,100);
return ch;
}
/* USER CODE END 1 */
2.打开keil的Use MicroLIB (很重要哦,不然串口助手没有东西显示)
初始化-发送-时间达到-发送结束-轮询模式发送
初始化-串口发送函数(中断模式)-一个字节一个字节的发送数据-发送数据字节长度达到函数设定-跳转到串口发送完成中断回调函数-回到主程序-中断模式发送
当串口接收到任意一个三个字节的数据,发送66和接收到的这个数据,使用串口中断的方式
在线串口调试网站推荐:波特律动 串口助手 (keysking.com)
main.c
**uint8_t test[] = "Hello,World";
uint8_t temp[3];
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1,temp,3);串口接收中断函数
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
// HAL_UART_Transmit(&huart1,test,12,100);
// HAL_Delay(100);
// HAL_UART_Receive(&huart1,temp,2,50);
// if ( HAL_UART_Receive(&huart1,temp,2,100) == HAL_OK )
// {
// HAL_UART_Transmit(&huart1,temp,2,100);
// }//这个方式还是不是很好,会有不反应的情况,个人觉得能开中断就用中断
// HAL_UART_Transmit_IT(&huart1,test,12);
// HAL_Delay(500);
// printf("66");
// HAL_Delay(500);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}**
main.h
...
extern uint8_t test[];//全局声明变量,以便于其他文件中只需要调用main.h就可以使用这些变量
extern uint8_t temp[];//同上
...
uart_it.c(自己编写的一以串口中断源文件模块,用于存放回调函数)
**#include "uart.it.h"
#include "main.h"
#include "usart.h"
#include "stdio.h"
/* 接收中断回调函数,
定义:当串口中断接收到的数据长度达到HAL_UART_Receive_IT
规定的字节数据长度时,中断服务函数运行完之后就会来调用这个函数
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
printf("66\r\n");
HAL_UART_Transmit_IT(&huart1,temp,3);
HAL_UART_Receive_IT(&huart1,temp,3);
}**
usart.c
**/* USER CODE BEGIN 0 */
#include "stdio.h"
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
/* 函数
定义:串口发送重定向,这样就可以在程序中直接使用printf来发送数据
*/
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,100);
return ch;
}
/* USER CODE END 1 */**