1.定义初始化句柄
UART_HandleTypeDef USART1_InitStruct; //USART1初始化句柄
DMA_HandleTypeDef hdma_usart1_rx; //USART1_Rx DMA初始化句柄
2.定义串口1相关变量
uint8_t USART1_Rxbuffer[152] = {0}; //接收数据缓存区
uint8_t USART1_Rxflag = 0; //接收数据标志位
uint16_t USART1_RxLength = 0; //接收到数据的长度
3.串口1初始化
void USART1_Init(uint32_t Baud)
{
/* USART Ports Clock Enable */
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10; //TX AND RX
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; //复用输出
GPIO_InitStruct.Pull = GPIO_NOPULL; //不设置上下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; //设置速度
GPIO_InitStruct.Alternate = GPIO_AF7_USART1; //GPIO复用到USART1
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1 Init */
USART1_InitStruct.Instance =USART1; //配置串口1
USART1_InitStruct.Init.BaudRate=Baud; //波特率
USART1_InitStruct.Init.Mode = USART_MODE_TX_RX; //收发
USART1_InitStruct.Init.WordLength = USART_WORDLENGTH_8B; //数据长度
USART1_InitStruct.Init.Parity=USART_PARITY_NONE; //NO校验位
USART1_InitStruct.Init.StopBits= USART_STOPBITS_1; //1停止位
USART1_InitStruct.Init.HwFlowCtl= UART_HWCONTROL_NONE; //不使用硬件流控
USART1_InitStruct.Init.OverSampling = UART_OVERSAMPLING_16; //设置过采样率
USART1_InitStruct.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
HAL_UART_Init(&USART1_InitStruct);
HAL_NVIC_SetPriority(USART1_IRQn,1, 1); //初始化中断[抢占][响应]
HAL_NVIC_EnableIRQ(USART1_IRQn); //启用串口中断
__HAL_UART_ENABLE_IT(&USART1_InitStruct, UART_IT_IDLE); // 使能 IDLE中断,用于接收不定长数据
__HAL_UART_CLEAR_IDLEFLAG(&USART1_InitStruct); //清除IDLE标志位用于下一次接收
/*DMA初始化*/
__HAL_RCC_DMA1_CLK_ENABLE();
hdma_usart1_rx.Instance = DMA1_Channel5; //对应DMA通道5
hdma_usart1_rx.Init.Request = DMA_REQUEST_2; //串口1接收信号为2
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; //外设to内存
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //字节
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; //字节
hdma_usart1_rx.Init.Mode = DMA_NORMAL;
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_usart1_rx);
__HAL_LINKDMA(&USART1_InitStruct, hdmarx, hdma_usart1_rx);
HAL_UART_Receive_DMA(&USART1_InitStruct, USART1_Rxbuffer, sizeof(USART1_Rxbuffer)); //使能DMA接收,数据存放在USART1_Rxbuffer
}
4.IDLE空闲中断服务函数
/* 串口空闲回调函数 [接收完一帧数据]*/
void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1) //串口1接收完一帧数据
{
USART1_RxLength = sizeof(USART1_Rxbuffer) - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); //计算数据长度
if(USART1_RxLength > 1)
{
USART1_Rxflag = 1; //置标志位
__NOP()//自己编写
__HAL_UART_CLEAR_IDLEFLAG(&USART1_InitStruct); //清除Usart1IDLE标志位
__HAL_UART_ENABLE_IT(&USART1_InitStruct, UART_IT_IDLE); //使能 IDLE中断
USART1_RxLength = 0; //数据长度清0
HAL_DMA_Abort(&hdma_usart1_rx); //停止DMA
__HAL_DMA_DISABLE(&hdma_usart1_rx); //先禁用DMA传输
hdma_usart1_rx.Instance->CNDTR = sizeof(USART1_Rxbuffer); //重新设置传输数据的数量
__HAL_DMA_ENABLE(&hdma_usart1_rx); //使能DMA
HAL_UART_Receive_DMA(&USART1_InitStruct, USART1_Rxbuffer, sizeof(USART1_Rxbuffer)); //重新启动DMA数据接收
USART1_Rxflag = 0; //数据处理完清标志位
}
}
5./*串口错误回调函数*/
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(HAL_UART_GetError(huart) & HAL_UART_ERROR_PE){ /*!< Parity error */
//奇偶校验错误
__HAL_UART_CLEAR_PEFLAG(huart);
}else if(HAL_UART_GetError(huart) & HAL_UART_ERROR_NE){ /*!< Noise error */
//噪声错误
__HAL_UART_CLEAR_NEFLAG(huart);
}else if(HAL_UART_GetError(huart) & HAL_UART_ERROR_FE){ /*!< Frame error */
//帧格式错误
__HAL_UART_CLEAR_FEFLAG(huart);
}else if(HAL_UART_GetError(huart) & HAL_UART_ERROR_ORE){ /*!< Overrun error */
//数据太多串口来不及接收错误
__HAL_UART_CLEAR_OREFLAG(huart);
}
//当这个串口发生了错误,一定要在重新使能接收中断
if(huart ->Instance == USART1) {
HAL_UART_Receive_IT(&USART1_InitStruct, USART1_Txbuffer, 1);
}
//其他串口......
}
6.完整源码usart.c
#include "stm32l4xx_hal.h"
UART_HandleTypeDef USART1_InitStruct; //USART1初始化句柄
DMA_HandleTypeDef hdma_usart1_rx; //USART1_Rx DMA初始化句柄
/****************** 串口1变量定义 *********************/
uint8_t USART1_Txbuffer[1]; //发送数据缓存区
uint8_t USART1_Rxbuffer[128] = {0}; //接收数据缓存区
uint8_t USART1_Rxflag = 0; //接收数据标志位
uint16_t USART1_RxLength = 0; //接收到数据的长度
/**
* 函 数:串口1初始化函数
* 参 数:无
* 参 数:无
* 返 回 值:无
* 注 意:无
*/
void USART1_Init(uint32_t Baud)
{
/* USART Ports Clock Enable */
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10; //TX AND RX
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; //复用输出
GPIO_InitStruct.Pull = GPIO_NOPULL; //不设置上下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; //设置速度
GPIO_InitStruct.Alternate = GPIO_AF7_USART1; //GPIO复用到USART1
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1 Init */
USART1_InitStruct.Instance =USART1; //配置串口1
USART1_InitStruct.Init.BaudRate=Baud; //波特率
USART1_InitStruct.Init.Mode = USART_MODE_TX_RX; //收发
USART1_InitStruct.Init.WordLength = USART_WORDLENGTH_8B; //数据长度
USART1_InitStruct.Init.Parity=USART_PARITY_NONE; //NO校验位
USART1_InitStruct.Init.StopBits= USART_STOPBITS_1; //1停止位
USART1_InitStruct.Init.HwFlowCtl= UART_HWCONTROL_NONE; //不使用硬件流控
USART1_InitStruct.Init.OverSampling = UART_OVERSAMPLING_16; //设置过采样率
USART1_InitStruct.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
HAL_UART_Init(&USART1_InitStruct);
HAL_NVIC_SetPriority(USART1_IRQn,1, 1); //初始化中断[抢占][响应]
HAL_NVIC_EnableIRQ(USART1_IRQn); //启用串口中断
__HAL_UART_ENABLE_IT(&USART1_InitStruct, UART_IT_IDLE); // 使能 IDLE中断,用于接收不定长数据
__HAL_UART_CLEAR_IDLEFLAG(&USART1_InitStruct); //清除IDLE标志位用于下一次接收
/*DMA初始化*/
__HAL_RCC_DMA1_CLK_ENABLE();
hdma_usart1_rx.Instance = DMA1_Channel5; //对应DMA通道5
hdma_usart1_rx.Init.Request = DMA_REQUEST_2; //串口1接收信号为2
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; //外设to内存
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //字节
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; //字节
hdma_usart1_rx.Init.Mode = DMA_NORMAL;
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_usart1_rx);
__HAL_LINKDMA(&USART1_InitStruct, hdmarx, hdma_usart1_rx);
HAL_UART_Receive_DMA(&USART1_InitStruct, USART1_Rxbuffer, sizeof(USART1_Rxbuffer)); //使能DMA接收,数据存放在USART1_Rxbuffer
}
/**
* 函 数:串口1发送数据
* 参 数:
@Data:要发送的数据
* 返 回 值:无
* 注 意:无
*/
void USART1_SendData(uint8_t *Data,uint8_t length)
{
HAL_UART_Transmit(&USART1_InitStruct,Data,length,1000);
}
/**
* 函 数:串口1中断服务函数
* 参 数:
* 返 回 值:无
* 注 意:无
*/
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&USART1_InitStruct); //串口中断公共接口函数
}
/* 串口数据接收完成回调函数 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1&& USART1_Rxflag==0)
{
USART1_Rxbuffer[USART1_RxLength] = USART1->RDR; //将数据存到串口1接收缓存区
HAL_UART_Receive_IT(&USART1_InitStruct,USART1_Txbuffer,1);
USART1_RxLength++;
}
}
/*串口1空闲中断标清除*/
void Usart1_Clear_IdleFlag(void)
{
__HAL_UART_CLEAR_IDLEFLAG(&USART1_InitStruct); //清除Usart1IDLE标志位
__HAL_UART_ENABLE_IT(&USART1_InitStruct, UART_IT_IDLE); //使能 IDLE中断
HAL_DMA_Abort(&hdma_usart1_rx); //停止DMA
__HAL_DMA_DISABLE(&hdma_usart1_rx); //先禁用DMA传输
hdma_usart1_rx.Instance->CNDTR = sizeof(USART1_Rxbuffer); //重新设置传输数据的数量
__HAL_DMA_ENABLE(&hdma_usart1_rx); //使能DMA
HAL_UART_Receive_DMA(&USART1_InitStruct, USART1_Rxbuffer, sizeof(USART1_Rxbuffer)); //重新启动DMA数据接收
}
/* 串口空闲回调函数 [接收完一帧数据]*/
void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
{
USART1_RxLength = sizeof(USART1_Rxbuffer) - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); //计算数据长度
if(huart->Instance == USART1) //串口1接收完一帧数据
{
if(USART1_RxLength > 1)
{
USART1_Rxflag = 1; //置串口1接收数据包标志位
}
}
}
/*串口错误回调函数*/
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(HAL_UART_GetError(huart) & HAL_UART_ERROR_PE){ /*!< Parity error */
//奇偶校验错误
__HAL_UART_CLEAR_PEFLAG(huart);
}else if(HAL_UART_GetError(huart) & HAL_UART_ERROR_NE){ /*!< Noise error */
//噪声错误
__HAL_UART_CLEAR_NEFLAG(huart);
}else if(HAL_UART_GetError(huart) & HAL_UART_ERROR_FE){ /*!< Frame error */
//帧格式错误
__HAL_UART_CLEAR_FEFLAG(huart);
}else if(HAL_UART_GetError(huart) & HAL_UART_ERROR_ORE){ /*!< Overrun error */
//数据太多串口来不及接收错误
__HAL_UART_CLEAR_OREFLAG(huart);
}
//当这个串口发生了错误,一定要在重新使能接收中断
if(huart ->Instance == USART1 || huart ->Instance == USART2){
HAL_UART_Receive_IT(&USART1_InitStruct, USART1_Txbuffer, 1);
}
//其他串口......
}
usart.h
#ifndef __USART_H
#define __USART_H
#include "string.h"
extern uint8_t USART1_Rxbuffer[]; //数据缓存区
extern uint8_t USART1_Rxflag;
extern uint16_t USART1_RxLength; // 接收到数据的长度
void USART1_Init(uint32_t Baud) ;
void USART1_SendData(uint8_t *Data,uint8_t length);
void Usart1_Clear_IdleFlag(void);
#endif
main.c
#include "stm32l4xx_hal.h"
#include "SysClk.h"
#include "LED.h"
#include "USART.h"
int main(void)
{
HAL_Init();
My_SystemClock_Config(); //配置系统时钟80M
My_GPIO_Init(); //LED的GPIO初始化
USART1_Init(115200); //初始化串口1波特率为115200负责与上位机通信
while (1)
{
if(USART1_Rxflag==1) //串口1接收1到1帧数据
{
USART1_SendData(USART1_Rxbuffer,USART1_RxLength);//这里只做转发
memset(USART1_Rxbuffer,0x00,128); //处理完数据,清空接收缓存区,准备下一次接收
USART1_RxLength = 0; //长度清为0
USART1_Rxflag = 0; //标志位清0
Usart1_Clear_IdleFlag(); //清除标志位
}
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
}
}
6.看看效果
由于HAL库没有标配空闲中断
配置IDLE空闲中断参考我另一篇博客STM32HAL库空闲中断配置