一、前言
1、简介
回顾上一篇UART发送当中,已经讲解了如何实现UART的发送操作了,接下来这一篇将会继续讲解如何实现UART的接收操作。
2、UART简介
嵌入式开发中,UART串口通信协议是我们常用的通信协议之一,全称叫做通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)。
3、准备工作
在UART详解中已经有了详细的说明,按照里面的说明即可。
二、CubeMx配置及函数说明
1、CubeMx配置
1)按照UART详解配置UART(若配置过,可以继续使用)
2)使能串口中断
3)设置中断优先级(如果没开启其他中断,那就默认即可,直接跳过)
4)代码生成(点击前最好把原本的工程关掉,不然有可能会有问题)
2、函数说明
1)CubeMx生成的UART初始化(在usart.c中)
1 UART_HandleTypeDef huart1;
2
3 /* USART1 init function */
4
5 void MX_USART1_UART_Init(void)
6 {
7
8 huart1.Instance = USART1;
9 huart1.Init.BaudRate = 115200;
10 huart1.Init.WordLength = UART_WORDLENGTH_8B;
11 huart1.Init.StopBits = UART_STOPBITS_1;
12 huart1.Init.Parity = UART_PARITY_NONE;
13 huart1.Init.Mode = UART_MODE_TX_RX;
14 huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
15 huart1.Init.OverSampling = UART_OVERSAMPLING_16;
16 if (HAL_UART_Init(&huart1) != HAL_OK)
17 {
18 Error_Handler();
19 }
20
21 }
22
23 void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
24 {
25
26 GPIO_InitTypeDef GPIO_InitStruct = {0};
27 if(uartHandle->Instance==USART1)
28 {
29 /* USER CODE BEGIN USART1_MspInit 0 */
30
31 /* USER CODE END USART1_MspInit 0 */
32 /* USART1 clock enable */
33 __HAL_RCC_USART1_CLK_ENABLE();
34
35 __HAL_RCC_GPIOA_CLK_ENABLE();
36 /**USART1 GPIO Configuration
37 PA9 ------> USART1_TX
38 PA10 ------> USART1_RX
39 */
40 GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
41 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
42 GPIO_InitStruct.Pull = GPIO_PULLUP;
43 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
44 GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
45 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
46
47 /* USART1 interrupt Init */
48 HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
49 HAL_NVIC_EnableIRQ(USART1_IRQn);
50 /* USER CODE BEGIN USART1_MspInit 1 */
51
52 /* USER CODE END USART1_MspInit 1 */
53 }
54 }
55
56 void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
57 {
58
59 if(uartHandle->Instance==USART1)
60 {
61 /* USER CODE BEGIN USART1_MspDeInit 0 */
62
63 /* USER CODE END USART1_MspDeInit 0 */
64 /* Peripheral clock disable */
65 __HAL_RCC_USART1_CLK_DISABLE();
66
67 /**USART1 GPIO Configuration
68 PA9 ------> USART1_TX
69 PA10 ------> USART1_RX
70 */
71 HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
72
73 /* USART1 interrupt Deinit */
74 HAL_NVIC_DisableIRQ(USART1_IRQn);
75 /* USER CODE BEGIN USART1_MspDeInit 1 */
76
77 /* USER CODE END USART1_MspDeInit 1 */
78 }
79 }
UART init
2)CubeMx生成的UART中断处理函数(在stm32f4xx_it.c中)
/**
* @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 */
}
3)HAL库函数HAL_UART_Transmit(在stm32f4xx_hal_uart.c中)
1 /**
2 * @brief Sends an amount of data in blocking mode.
3 * @param huart Pointer to a UART_HandleTypeDef structure that contains
4 * the configuration information for the specified UART module.
5 * @param pData Pointer to data buffer
6 * @param Size Amount of data to be sent
7 * @param Timeout Timeout duration
8 * @retval HAL status
9 */
10 HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
11 {
12 uint16_t *tmp;
13 uint32_t tickstart = 0U;
14
15 /* Check that a Tx process is not already ongoing */
16 if (huart->gState == HAL_UART_STATE_READY)
17 {
18 if ((pData == NULL) || (Size == 0U))
19 {
20 return HAL_ERROR;
21 }
22
23 /* Process Locked */
24 __HAL_LOCK(huart);
25
26 huart->ErrorCode = HAL_UART_ERROR_NONE;
27 huart->gState = HAL_UART_STATE_BUSY_TX;
28
29 /* Init tickstart for timeout managment */
30 tickstart = HAL_GetTick();
31
32 huart->TxXferSize = Size;
33 huart->TxXferCount = Size;
34 while (huart->TxXferCount > 0U)
35 {
36 huart->TxXferCount--;
37 if (huart->Init.WordLength == UART_WORDLENGTH_9B)
38 {
39 if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
40 {
41 return HAL_TIMEOUT;
42 }
43 tmp = (uint16_t *) pData;
44 huart->Instance->DR = (*tmp & (uint16_t)0x01FF);
45 if (huart->Init.Parity == UART_PARITY_NONE)
46 {
47 pData += 2U;
48 }
49 else
50 {
51 pData += 1U;
52 }
53 }
54 else
55 {
56 if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
57 {
58 return HAL_TIMEOUT;
59 }
60 huart->Instance->DR = (*pData++ & (uint8_t)0xFF);
61 }
62 }
63
64 if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)
65 {
66 return HAL_TIMEOUT;
67 }
68
69 /* At end of Tx process, restore huart->gState to Ready */
70 huart->gState = HAL_UART_STATE_READY;
71
72 /* Process Unlocked */
73 __HAL_UNLOCK(huart);
74
75 return HAL_OK;
76 }
77 else
78 {
79 return HAL_BUSY;
80 }
81 }
HAL_UART_Transmit
4)HAL库函数HAL_UART_Receive(在stm32f4xx_hal_uart.c中)
1 /**
2 * @brief Receives an amount of data in blocking mode.
3 * @param huart Pointer to a UART_HandleTypeDef structure that contains
4 * the configuration information for the specified UART module.
5 * @param pData Pointer to data buffer
6 * @param Size Amount of data to be received
7 * @param Timeout Timeout duration
8 * @retval HAL status
9 */
10 HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
11 {
12 uint16_t *tmp;
13 uint32_t tickstart = 0U;
14
15 /* Check that a Rx process is not already ongoing */
16 if (huart->RxState == HAL_UART_STATE_READY)
17 {
18 if ((pData == NULL) || (Size == 0U))
19 {
20 return HAL_ERROR;
21 }
22
23 /* Process Locked */
24 __HAL_LOCK(huart);
25
26 huart->ErrorCode = HAL_UART_ERROR_NONE;
27 huart->RxState = HAL_UART_STATE_BUSY_RX;
28
29 /* Init tickstart for timeout managment */
30 tickstart = HAL_GetTick();
31
32 huart->RxXferSize = Size;
33 huart->RxXferCount = Size;
34
35 /* Check the remain data to be received */
36 while (huart->RxXferCount > 0U)
37 {
38 huart->RxXferCount--;
39 if (huart->Init.WordLength == UART_WORDLENGTH_9B)
40 {
41 if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
42 {
43 return HAL_TIMEOUT;
44 }
45 tmp = (uint16_t *) pData;
46 if (huart->Init.Parity == UART_PARITY_NONE)
47 {
48 *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
49 pData += 2U;
50 }
51 else
52 {
53 *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
54 pData += 1U;
55 }
56
57 }
58 else
59 {
60 if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
61 {
62 return HAL_TIMEOUT;
63 }
64 if (huart->Init.Parity == UART_PARITY_NONE)
65 {
66 *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
67 }
68 else
69 {
70 *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
71 }
72
73 }
74 }
75
76 /* At end of Rx process, restore huart->RxState to Ready */
77 huart->RxState = HAL_UART_STATE_READY;
78
79 /* Process Unlocked */
80 __HAL_UNLOCK(huart);
81
82 return HAL_OK;
83 }
84 else
85 {
86 return HAL_BUSY;
87 }
88 }
HAL_UART_Receive
三、代码编写:实现UART接收
1、直接接收(不建议)
1)在main主函数中定义一个变量,负责接收数据
/* USER CODE BEGIN 1 */
unsigned char uRx_Data = ;
/* USER CODE END 1 */
2)在main主函数while循环中调用HAL库UART接收函数
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while ()
{
/* 判断是否接收成功 */
if(HAL_UART_Receive(&huart1, &uRx_Data, , ) == HAL_OK)
{
/* 将接收成功的数据通过串口发出来 */
HAL_UART_Transmit(&huart1, &uRx_Data, , 0xffff);
} /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
整个main函数如下:
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
unsigned char uRx_Data = ;
/* 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 */ /* USER CODE END 2 */ /* Infinite loop */
/* USER CODE BEGIN WHILE */
while ()
{
/* 判断是否接收成功 */
if(HAL_UART_Receive(&huart1, &uRx_Data, , ) == HAL_OK)
{
/* 将接收成功的数据通过串口发出来 */
HAL_UART_Transmit(&huart1, &uRx_Data, , 0xffff);
} /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
3)编译、下载烧写
4)实现效果(接收到数据后,调用UART发送函数将数据发送到电脑)
2、中断接收(接收并发送)(不推荐)
1)在HAL_UART_MspInit(在usart.c中)使能接收中断
/* USER CODE BEGIN USART1_MspInit 1 */
__HAL_UART_ENABLE_IT(uartHandle, UART_IT_RXNE);
/* USER CODE END USART1_MspInit 1 */
整个HAL_UART_MspInit函数如下:
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{ GPIO_InitTypeDef GPIO_InitStruct = {};
if(uartHandle->Instance==USART1)
{
/* USER CODE BEGIN USART1_MspInit 0 */ /* USER CODE END USART1_MspInit 0 */
/* USART1 clock enable */
__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_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, , );
HAL_NVIC_EnableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspInit 1 */
__HAL_UART_ENABLE_IT(uartHandle, UART_IT_RXNE);
/* USER CODE END USART1_MspInit 1 */
}
}
2)在USART1_IRQHandler(在stm32f4xx_it.c中)定义一个变量,负责接收数据
unsigned char uRx_Data = ;
3)在USART1_IRQHandler(在stm32f4xx_it.c中)调用HAL库的UART接收函数以及发送函数
/* -1- 接收 */
HAL_UART_Receive(&huart1, &uRx_Data, , );
/* -2- 将接收成功的数据通过串口发出去 */
HAL_UART_Transmit(&huart1, &uRx_Data, , 0xffff);
整个USART1_IRQHandler(在stm32f4xx_it.c中)函数如下:
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
unsigned char uRx_Data; /* -1- 接收 */
HAL_UART_Receive(&huart1, &uRx_Data, , );
/* -2- 将接收成功的数据通过串口发出去 */
HAL_UART_Transmit(&huart1, &uRx_Data, , 0xffff); /* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */ /* USER CODE END USART1_IRQn 1 */
}
4)编译、下载烧写
5)实现效果(接收到数据后,调用UART发送函数将数据发送到电脑)
3、中断接收(先接收完,后处理)(推荐)
1)在HAL_UART_MspInit(在usart.c中)使能接收中断(与方式2相同)
/* USER CODE BEGIN USART1_MspInit 1 */
__HAL_UART_ENABLE_IT(uartHandle, UART_IT_RXNE);
/* USER CODE END USART1_MspInit 1 */
整个HAL_UART_MspInit(在usart.c中)函数如下:
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{ GPIO_InitTypeDef GPIO_InitStruct = {};
if(uartHandle->Instance==USART1)
{
/* USER CODE BEGIN USART1_MspInit 0 */ /* USER CODE END USART1_MspInit 0 */
/* USART1 clock enable */
__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_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, , );
HAL_NVIC_EnableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspInit 1 */
__HAL_UART_ENABLE_IT(uartHandle, UART_IT_RXNE);
/* USER CODE END USART1_MspInit 1 */
}
}
2)在USART1_IRQHandler(在stm32f4xx_it.c中)定义三个静态变量
static unsigned char uRx_Data[] = {} ; //存储数组
static unsigned char * pRx_Data = uRx_Data; //指向存储数组将要存储数据的位
static unsigned char uLength = ; //接收数据长度
3)在USART1_IRQHandler(在stm32f4xx_it.c中)调用HAL库的UART接收函数以及发送函数
/* -1- 接收数据 */
HAL_UART_Receive(&huart1, pRx_Data, , ); /* -2- 判断数据结尾 */
if(*pRx_Data == '\n')
{
/* -3- 将接收成功的数据通过串口发出去 */
HAL_UART_Transmit(&huart1, uRx_Data, uLength, 0xffff); /* -4- 初始化指针和数据长度 */
pRx_Data = uRx_Data; //重新指向数组起始位置
uLength = ; //长度清零
}
/* -5- 若未结束,指针往下一位移动,长度自增一 */
else
{
pRx_Data++;
uLength++;
}
整个USART1_IRQHandler(在stm32f4xx_it.c中)函数如下:
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
static unsigned char uRx_Data[] = {} ; //存储数组
static unsigned char * pRx_Data = uRx_Data; //指向存储数组将要存储数据的位
static unsigned char uLength = ; //接收数据长度 /* -1- 接收数据 */
HAL_UART_Receive(&huart1, pRx_Data, , ); /* -2- 判断数据结尾 */
if(*pRx_Data == '\n')
{
/* -3- 将接收成功的数据通过串口发出去 */
HAL_UART_Transmit(&huart1, uRx_Data, uLength, 0xffff); /* -4- 初始化指针和数据长度 */
pRx_Data = uRx_Data; //重新指向数组起始位置
uLength = ; //长度清零
}
/* -5- 若未结束,指针往下一位移动,长度自增一 */
else
{
pRx_Data++;
uLength++;
} /* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */ /* USER CODE END USART1_IRQn 1 */
}
4)编译、下载烧写
5)实现效果(接收到数据后,调用UART发送函数将数据发送到电脑)
四、结尾
1、总结
这一篇博客带来的是两种简单的接收方式(方式1:直接接收、方式2:中断接收1),还有一种接收方式(方式3:中断接收2),并实现了接收的操作。
但前面两种方式是不推荐的,因为在接收数据的时候,建议程序只在负责接收程序,直至接收完毕为止,数据接收完毕再进入自己处理数据的函数内。
除了上面的方法,还有DMA接收方法没介绍,这里先不说了。
整体来说,自我感觉还是讲解得比较清楚得,如果还有对于此篇博客不懂之处,可以在下方评论留言提问,我会尽快回复的。
2、回顾
1)UART详解
2)UART发送
3、后续
待补充
~
~
~
~
感谢阅读~
欢迎大家关注我的博客,一起分享嵌入式知识~