STM32G474单片机串口中断接收与发送详解
在使用STM32G474单片机串口时,若将UART_HandleTypeDef定义的变量,用作全局变量时,确实很浪费内存,若不定义为全局变量,就无法使用HAL库自带的串口函数。若采用自定义的宏来实现标准库的部分功能,就可将UART_HandleTypeDef型变量定义为局部变量。
1、自己定义的“串口宏定义”
#define _HAL_UART_SendByte(Instance, __DATA__) Instance->TDR = ( (__DATA__) & (uint16_t)0x01FF );
//将(__DATA__)写入串口发送缓冲区
#define _HAL_UART_ReceiveByte( Instance ) ( (uint16_t)( Instance->RDR & (uint16_t)0x01FF) )
//读串口接收缓冲区
/** @brief Enable the specified UART interrupt.
* @param Instance specifies the UARTx.
* @param __INTERRUPT__ specifies the UART interrupt source to enable.
* This parameter can be one of the following values:
* @arg @ref UART_IT_RXFF RXFIFO Full interrupt
* @arg @ref UART_IT_TXFE TXFIFO Empty interrupt
* @arg @ref UART_IT_RXFT RXFIFO threshold interrupt
* @arg @ref UART_IT_TXFT TXFIFO threshold interrupt
* @arg @ref UART_IT_WUF Wakeup from stop mode interrupt
* @arg @ref UART_IT_CM Character match interrupt
* @arg @ref UART_IT_CTS CTS change interrupt
* @arg @ref UART_IT_LBD LIN Break detection interrupt
* @arg @ref UART_IT_TXE Transmit Data Register empty interrupt
* @arg @ref UART_IT_TXFNF TX FIFO not full interrupt
* @arg @ref UART_IT_TC Transmission complete interrupt
* @arg @ref UART_IT_RXNE Receive Data register not empty interrupt
* @arg @ref UART_IT_RXFNE RXFIFO not empty interrupt
* @arg @ref UART_IT_IDLE Idle line detection interrupt
* @arg @ref UART_IT_PE Parity Error interrupt
* @arg @ref UART_IT_ERR Error interrupt (frame error, noise error, overrun error)
* @retval None
*/
#define _HAL_UART_ENABLE_IT(Instance, __INTERRUPT__) (((((uint8_t)(__INTERRUPT__)) >> 5U) == 1U)? (Instance->CR1 |= (1U << ((__INTERRUPT__) & UART_IT_MASK))): \
((((uint8_t)(__INTERRUPT__)) >> 5U) == 2U)? (Instance->CR2 |= (1U << ((__INTERRUPT__) & UART_IT_MASK))): \
(Instance->CR3 |= (1U << ((__INTERRUPT__) & UART_IT_MASK))))
/** @brief Disable the specified UART interrupt.
* @param Instance specifies the UARTx.
* @param __INTERRUPT__ specifies the UART interrupt source to disable.
* This parameter can be one of the following values:
* @arg @ref UART_IT_RXFF RXFIFO Full interrupt
* @arg @ref UART_IT_TXFE TXFIFO Empty interrupt
* @arg @ref UART_IT_RXFT RXFIFO threshold interrupt
* @arg @ref UART_IT_TXFT TXFIFO threshold interrupt
* @arg @ref UART_IT_WUF Wakeup from stop mode interrupt
* @arg @ref UART_IT_CM Character match interrupt
* @arg @ref UART_IT_CTS CTS change interrupt
* @arg @ref UART_IT_LBD LIN Break detection interrupt
* @arg @ref UART_IT_TXE Transmit Data Register empty interrupt
* @arg @ref UART_IT_TXFNF TX FIFO not full interrupt
* @arg @ref UART_IT_TC Transmission complete interrupt
* @arg @ref UART_IT_RXNE Receive Data register not empty interrupt
* @arg @ref UART_IT_RXFNE RXFIFO not empty interrupt
* @arg @ref UART_IT_IDLE Idle line detection interrupt
* @arg @ref UART_IT_PE Parity Error interrupt
* @arg @ref UART_IT_ERR Error interrupt (Frame error, noise error, overrun error)
* @retval None
*/
#define _HAL_UART_DISABLE_IT(Instance, __INTERRUPT__) (((((uint8_t)(__INTERRUPT__)) >> 5U) == 1U)? (Instance->CR1 &= ~ (1U << ((__INTERRUPT__) & UART_IT_MASK))): \
((((uint8_t)(__INTERRUPT__)) >> 5U) == 2U)? (Instance->CR2 &= ~ (1U << ((__INTERRUPT__) & UART_IT_MASK))): \
(Instance->CR3 &= ~ (1U << ((__INTERRUPT__) & UART_IT_MASK))))
/** @brief Check whether the specified UART flag is set or not.
* @param Instance specifies the UART Handle.
* @param __FLAG__ specifies the flag to check.
* This parameter can be one of the following values:
* @arg @ref UART_FLAG_TXFT TXFIFO threshold flag
* @arg @ref UART_FLAG_RXFT RXFIFO threshold flag
* @arg @ref UART_FLAG_RXFF RXFIFO Full flag
* @arg @ref UART_FLAG_TXFE TXFIFO Empty flag
* @arg @ref UART_FLAG_REACK Receive enable acknowledge flag
* @arg @ref UART_FLAG_TEACK Transmit enable acknowledge flag
* @arg @ref UART_FLAG_WUF Wake up from stop mode flag
* @arg @ref UART_FLAG_RWU Receiver wake up flag (if the UART in mute mode)
* @arg @ref UART_FLAG_SBKF Send Break flag
* @arg @ref UART_FLAG_CMF Character match flag
* @arg @ref UART_FLAG_BUSY Busy flag
* @arg @ref UART_FLAG_ABRF Auto Baud rate detection flag
* @arg @ref UART_FLAG_ABRE Auto Baud rate detection error flag
* @arg @ref UART_FLAG_CTS CTS Change flag
* @arg @ref UART_FLAG_LBDF LIN Break detection flag
* @arg @ref UART_FLAG_TXE Transmit data register empty flag
* @arg @ref UART_FLAG_TXFNF UART TXFIFO not full flag
* @arg @ref UART_FLAG_TC Transmission Complete flag
* @arg @ref UART_FLAG_RXNE Receive data register not empty flag
* @arg @ref UART_FLAG_RXFNE UART RXFIFO not empty flag
* @arg @ref UART_FLAG_IDLE Idle Line detection flag
* @arg @ref UART_FLAG_ORE Overrun Error flag
* @arg @ref UART_FLAG_NE Noise Error flag
* @arg @ref UART_FLAG_FE Framing Error flag
* @arg @ref UART_FLAG_PE Parity Error flag
* @retval The new state of __FLAG__ (TRUE or FALSE).
*/
#define _HAL_UART_GET_FLAG(Instance, __FLAG__) ((Instance->ISR & (__FLAG__)) == (__FLAG__))
/** @brief Clear the specified UART pending flag.
* @param Instance specifies the UART Handle.
* @param __FLAG__ specifies the flag to check.
* This parameter can be any combination of the following values:
* @arg @ref UART_CLEAR_PEF Parity Error Clear Flag
* @arg @ref UART_CLEAR_FEF Framing Error Clear Flag
* @arg @ref UART_CLEAR_NEF Noise detected Clear Flag
* @arg @ref UART_CLEAR_OREF Overrun Error Clear Flag
* @arg @ref UART_CLEAR_IDLEF IDLE line detected Clear Flag
* @arg @ref UART_CLEAR_TXFECF TXFIFO empty clear Flag
* @arg @ref UART_CLEAR_TCF Transmission Complete Clear Flag
* @arg @ref UART_CLEAR_LBDF LIN Break Detection Clear Flag
* @arg @ref UART_CLEAR_CTSF CTS Interrupt Clear Flag
* @arg @ref UART_CLEAR_CMF Character Match Clear Flag
* @arg @ref UART_CLEAR_WUF Wake Up from stop mode Clear Flag
* @retval None
*/
#define _HAL_UART_CLEAR_FLAG(Instance, __FLAG__) (Instance->ICR = (__FLAG__))
2、串口初始化
//将PA9复用为USART1_TX
//将PA10复用为USART1_RX
//本程序适合在中断程序中处理接收和在中断程序中处理发送
uint8_t USART1_RX_Buffer[USART1_RX_Buffer_Size]; //USART1接收缓冲区数组
uint8_t USART1_RX_Buffer_Load_Index; //USART1_RX_Buffer[]的装载索引值
uint8_t USART1_TX_Buffer[USART1_TX_Buffer_Size]; //USART1发送缓冲区数组
uint8_t USART1_TX_Buffer_Load_Index; //USART1_TX_Buffer[]的装载索引值
uint8_t USART1_TX_Buffer_Send_Index; //发送下标值
void USART1_Init(uint32_t baudrate);
void USART1_Load_Send_Data(void);
void Start_USART1_Send_Data(void);
void USART1_Init(uint32_t baudrate)
{
UART_HandleTypeDef HardwareUSART1;
HardwareUSART1.Instance = USART1;
HAL_UART_DeInit(&HardwareUSART1);
//目的是令HardwareUSART1.gState = HAL_UART_STATE_RESET;
//允许HAL_UART_Init()执行时,会先调用HAL_UART_MspInit()
HardwareUSART1.Init.BaudRate = baudrate; //波特率
HardwareUSART1.Init.WordLength = UART_WORDLENGTH_8B; //字长为8位数据格式
HardwareUSART1.Init.StopBits = UART_STOPBITS_1; //一个停止位
HardwareUSART1.Init.Parity = UART_PARITY_NONE; //无奇偶校验位
HardwareUSART1.Init.Mode = UART_MODE_TX_RX; //收发模式
HardwareUSART1.Init.HwFlowCtl = UART_HWCONTROL_NONE; //无硬件流控
HardwareUSART1.Init.OverSampling = UART_OVERSAMPLING_16; //过采样率
HardwareUSART1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
HardwareUSART1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
HardwareUSART1.AdvancedInit.AutoBaudRateEnable = UART_ADVFEATURE_AUTOBAUDRATE_DISABLE;
HardwareUSART1.AdvancedInit.AutoBaudRateMode = UART_ADVFEATURE_AUTOBAUDRATE_ONSTARTBIT;
HardwareUSART1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
HardwareUSART1.FifoMode=UART_FIFOMODE_DISABLE;
if (HAL_UART_Init(&HardwareUSART1) != HAL_OK)
{
Error_Handler();
}
使用“中断发送和接收”配置开始/
__HAL_UART_CLEAR_FLAG(&HardwareUSART1, UART_CLEAR_TCF);
//Transmission Complete Clear Flag
__HAL_UART_ENABLE_IT(&HardwareUSART1, UART_IT_RXNE);
开启串口接收中断
//串口接收数据时,使能"接收数据寄存器不为空"则产生中断(位RXNE=1)
//Enable the UART Data Register not empty Interrupt
__HAL_UART_DISABLE_IT(&HardwareUSART1, UART_IT_TXE);
//串口发送数据时,不使能"串口发送数据寄存器为空"产生中断(位TXE=0)
//Disable the UART Transmit Complete Interrupt
__HAL_UART_DISABLE_IT(&HardwareUSART1,UART_IT_TC);
//串口发送数据时,不使能"串口发送完成"产生中断(位TC=1)
HAL_NVIC_EnableIRQ(USART1_IRQn);
HAL_NVIC_SetPriority(USART1_IRQn,8,0);
//设置NVIC中断分组4:4位抢占优先级,0位响应优先级
//选择中断优先级组4,即抢占优先级为4位,取值为0~15,响应优先级组为0位,取值为0
使用“中断发送和接收”配置结束/
USART1_RX_Buffer_Load_Index = 0;
memset(USART1_RX_Buffer,0,USART1_RX_Buffer_Size);
}
//HAL_UART_Init()执行时,会先调用HAL_UART_MspInit()
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
if(uartHandle->Instance==USART1)
{
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{ //HAL_RCCEx_PeriphCLKConfig()初始化USART1外设时钟
//Initializes the peripherals clocks
Error_Handler();
}
__HAL_RCC_USART1_CLK_ENABLE(); //使能USART1外设时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA外设时钟
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;//选择引脚编号9和10
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; //复用功能推挽模式
GPIO_InitStruct.Pull = GPIO_NOPULL; //不用上拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; //引脚速度为低速
GPIO_InitStruct.Alternate = GPIO_AF7_USART1; //将引脚复用为USART1
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}
//HAL_UART_DeInit()执行时,会先调用HAL_UART_MspDeInit()
//其实这个程序没什么用
void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{
if(uartHandle->Instance==USART1)
{
__HAL_RCC_USART1_CLK_DISABLE();//不使能USART1外设时钟
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
}
}
3、启动发送
void Start_USART1_Send_Data(void)
{
char i;
for(i=0;i<USART1_RX_Buffer_Size;i++)//串口接送测试
{
if(USART1_RX_Buffer[i-1]=='\r'&&USART1_RX_Buffer[i]=='\n')//收到结束符号
{
USART1_RX_Buffer_Load_Index = 0;
memset(USART1_TX_Buffer,0,USART1_TX_Buffer_Size);
strcpy((char*)USART1_TX_Buffer,(char*)USART1_RX_Buffer);
memset(USART1_RX_Buffer,0,USART1_RX_Buffer_Size);
USART1_Load_Send_Data();
}
}
}
//函数功能:启动串口1发送
void USART1_Load_Send_Data(void)
{
uint16_t k;
k=strlen((char*)USART1_TX_Buffer);
USART1_TX_Buffer_Load_Index = k;
启动发送/
_HAL_UART_SendByte(USART1,USART1_TX_Buffer[0]);
//发送一个字节
//启动发送
USART1_TX_Buffer_Send_Index=1;
_HAL_UART_ENABLE_IT(USART1,UART_IT_TXE);//启动发送///
//将"串口控制寄存器1(USART_CR1)中的TXEIE位"设置为1
//串口发送数据时,使能"串口发送数据寄存器为空"产生中断(位TXEIE=1)
//Enable the UART Transmit Complete Interrupt
}
4、串口中断程序
void USART1_IRQHandler(void)
{
uint8_t RX_temp;
(void)RX_temp;//防止RX_temp不使用而产生警告
if( _HAL_UART_GET_FLAG(USART1,UART_FLAG_RXNE) )
{//在串口状态寄存器中,发现RXNE=1
RX_temp =_HAL_UART_ReceiveByte(USART1);//读串口数据
USART1_RX_Buffer[USART1_RX_Buffer_Load_Index] = RX_temp;//保存接收到的新数据
USART1_RX_Buffer_Load_Index++;
if(USART1_RX_Buffer_Load_Index>=USART1_RX_Buffer_Size-2)
{
USART1_RX_Buffer[USART1_RX_Buffer_Size-2]='\0';
USART1_RX_Buffer_Load_Index = 0;//防止USART1_RX_Buffer[]溢出
}
if(USART1_RX_Buffer[USART1_RX_Buffer_Load_Index-2]=='\r'&&USART1_RX_Buffer[USART1_RX_Buffer_Load_Index-1]=='\n')
{//收到"\r\n"结束符号
USART1_RX_Buffer[USART1_RX_Buffer_Load_Index]='\0';
USART1_RX_Buffer_Load_Index++;
}
//软件先读"串口状态寄存器(USART_ISR)",然后再读"串口数据寄存器USART_RDR",就可以将ORE位(Overrun错误标志)清零;
//软件先读"串口状态寄存器(USART_ISR)",然后再读"串口数据寄存器USART_RDR",就可以将NE位(噪声错误标志)清零;
//软件先读"串口状态寄存器(USART_ISR)",然后再读"串口数据寄存器USART_RDR",就可以将FE位(帧错误标志)清零;
//软件先读"串口状态寄存器(USART_ISR)",然后再读"串口数据寄存器USART_RDR",就可以将PE位(奇偶校验值错误)清零;
//软件读"串口数据寄存器USART_RDR",就可以将RXNE位清零
}
if( _HAL_UART_GET_FLAG(USART1,USART_ISR_TXE) )
{
_HAL_UART_CLEAR_FLAG(USART1,UART_CLEAR_TCF);//清除TXE标志位
if(USART1_TX_Buffer_Send_Index < USART1_TX_Buffer_Load_Index) //未发送完全部数据
{
_HAL_UART_SendByte(USART1,USART1_TX_Buffer[USART1_TX_Buffer_Send_Index]);
//将USART1_TX_Buffer[USART1_TX_Buffer_Send_Index]的值写入串口发送"串口发送数据寄存器"
USART1_TX_Buffer_Send_Index++;
}
else
{
_HAL_UART_DISABLE_IT(USART1,UART_IT_TXE);
//串口发送数据时,不使能"串口发送数据寄存器为空"产生中断(位TXE=0)
//Disabless Transmit Data Register empty interrupt
_HAL_UART_ENABLE_IT(USART1,UART_IT_TC);
//将"串口控制寄存器1(USART_CR1)中的TCIE位"设置为1
//串口发送数据时,使能"串口发送完成"产生中断(位TCIE=1)
//Enables Transmission complete interrupt
}
}
if( _HAL_UART_GET_FLAG(USART1,USART_ISR_TC) )
{
_HAL_UART_CLEAR_FLAG(USART1,UART_CLEAR_TCF);
_HAL_UART_DISABLE_IT(USART1,UART_IT_TC);
//将"串口控制寄存器1(USART_CR1)中的TCIE位"设置为0
//串口发送数据时,不使能"串口发送完成"产生中断(位TCIE=0)
//Disable the UART Transmit Complete Interrupt
USART1_TX_Buffer_Send_Index = 0;//清除USART1_TX_Buffer[]的发送索引值
USART1_TX_Buffer_Load_Index = 0;//清除USART1_TX_Buffer[]的装载索引值
}
}
作者:LaoZhangGong123