HAL_UART_Receive_IT和HAL_UART_IRQHandler相互配合使用
1.(HAL_UART_Receive_IT打开接收中断,保存接收数据地址)-->2.(串口接收到数据产生中断调用USART1_IRQHandler)--> 3.(UART_Receive_IT读取DR保存到pRxBuffPtr指向的变量,RxXferCount !=0重复流程2-3) --> 4.(关接收中断,调用回调函数HAL_UART_RxCpltCallback)-->5.在HAL_UART_RxCpltCallback里面打开接收中断HAL_UART_Receive_IT。
*pTxBuffPtr(指向 uint8_t 类型的指针) 指向需要发送的数据缓冲区的指针
TxXferSize(uint16_t 类型) 记录需要发送的数据总量
TxXferCount(volatile uint16_t 类型) 需要发送的剩余数据量
*pRxBuffPtr(指向 uint8_t 类型的指针) 指向用于保存接收数据缓冲区的指针
RxXferSize(uint16_t 类型) 记录需要接收的数据总量
RxXferCount(volatile uint16_t 类型) 剩余的需要接收的数据量
1)不定长接收方法
- 初始化函数:
__HAL_UART_ENABLE_IT(&g_rs458_handler, UART_IT_IDLE); /* 开启空闲中断 */
HAL_UART_Receive_IT(&g_rs458_handler,(uint8_t*)&g_RS485_rx_buf,RS485_REC_LEN);
HAL_NVIC_EnableIRQ(RS485_UX_IRQn); /* 使能USART2中断 */
HAL_NVIC_SetPriority(RS485_UX_IRQn, 3, 3); /* 抢占优先级3,子优先级3 */
- 中断服务函数:
void RS485_UX_IRQHandler(void)
{
HAL_UART_IRQHandler(&g_rs458_handler);
if( __HAL_UART_GET_FLAG(&g_rs458_handler, UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(&g_rs458_handler);
g_RS485_rx_cnt = RS485_REC_LEN - g_rs458_handler.RxXferCount;
HAL_UART_AbortReceive_IT(&g_rs458_handler);
}
}
- 接收完成空闲中断回调函数
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART2){
memcpy(g_RS485_tx_buf,g_RS485_rx_buf,g_RS485_rx_cnt);
memset(g_RS485_rx_buf,0x00,g_RS485_rx_cnt);
rxstate = 1;
HAL_UART_Receive_IT(&g_rs458_handler,(uint8_t*)&g_RS485_rx_buf,RS485_REC_LEN);
}
}
- main函数
int main(void)
{
while (1)
{
if(rxstate==1)
{ rxstate=0;
rs485_send_data(g_RS485_tx_buf, g_RS485_rx_cnt);
}
}
}
2.标志位接收方法
- 初始化函数:
HAL_UART_Receive_IT(&g_rs458_handler,(uint8_t*)&aBuffer,1);
HAL_NVIC_EnableIRQ(RS485_UX_IRQn); /* 使能USART2中断 */
HAL_NVIC_SetPriority(RS485_UX_IRQn, 3, 3); /* 抢占优先级3,子优先级3 */
- 中断服务函数:
void RS485_UX_IRQHandler(void)
{
HAL_UART_IRQHandler(&g_rs458_handler);
}
- 接收中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
g_RS485_rx_buf[g_RS485_rx_cnt++]= aBuffer;
if(g_RS485_rx_cnt>2&&g_RS485_rx_buf[g_RS485_rx_cnt-1]==0xFF&&g_RS485_rx_buf[g_RS485_rx_cnt-2]==0xFF)
{
memcpy(g_RS485_tx_buf,g_RS485_rx_buf,g_RS485_rx_cnt);
memset(g_RS485_rx_buf,0x00,g_RS485_rx_cnt);
rxstate = 1;
}
HAL_UART_Receive_IT(&g_rs458_handler,(uint8_t*)&aBuffer,1);
}
}
2.__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE)。手动使能接收中断后,因为pRxBuffPtr为NULL,需要在中断函数USART1_IRQHandler中直接读取DR寄存器的值。读取DR值后SR的RXNE位会被清零,所以在这之后再调用HAL_UART_IRQHandler的话,由于RXNE被清零条件判断不会操作pRxBuffPtr读取DR寄存器,中断不会被关闭,回调函数HAL_UART_RxCpltCallback也不会被执行。
1)不定长接收方法
- 初始化函数:
__HAL_UART_ENABLE_IT(&g_rs458_handler, UART_IT_RXNE); /* 开启接收中断 */
HAL_NVIC_EnableIRQ(RS485_UX_IRQn); /* 使能USART2中断 */
HAL_NVIC_SetPriority(RS485_UX_IRQn, 3, 3); /* 抢占优先级3,子优先级3 */
- 接收中断服务函数
void RS485_UX_IRQHandler(void)
{
uint8_t res =0;//接收数据
if( __HAL_UART_GET_FLAG(&g_rs458_handler, UART_FLAG_RXNE))
{
if(g_RS485_rx_cnt == 0){
__HAL_UART_ENABLE_IT(&g_rs458_handler,UART_IT_IDLE); //使能空闲中断
}
g_RS485_rx_buf[g_RS485_rx_cnt++]= (uint8_t)(g_rs458_handler.Instance->DR & (uint8_t)0x00FF);
}
空闲中断
else if( __HAL_UART_GET_FLAG(&g_rs458_handler, UART_FLAG_IDLE)){
res=(uint8_t)(g_rs458_handler.Instance->DR &(uint8_t)0x00FF); //清楚idle空闲标志
memcpy(g_RS485_tx_buf,g_RS485_rx_buf,g_RS485_rx_cnt);
memset(g_RS485_rx_buf,0x00,g_RS485_rx_cnt);
rxstate = 1;
__HAL_UART_DISABLE_IT(&g_rs458_handler,UART_IT_IDLE);
}
}
2)标志位接收方法
- 初始化函数:
__HAL_UART_ENABLE_IT(&g_rs458_handler, UART_IT_RXNE); /* 开启接收中断 */
HAL_NVIC_EnableIRQ(RS485_UX_IRQn); /* 使能USART2中断 */
HAL_NVIC_SetPriority(RS485_UX_IRQn, 3, 3); /* 抢占优先级3,子优先级3 */
- 接收中断服务函数
void RS485_UX_IRQHandler(void)
{
if( __HAL_UART_GET_FLAG(&g_rs458_handler, UART_FLAG_RXNE))
{
g_RS485_rx_buf[g_RS485_rx_cnt++]= (uint8_t)(g_rs458_handler.Instance->DR & (uint8_t)0x00FF);
if(g_RS485_rx_cnt>2&&g_RS485_rx_buf[g_RS485_rx_cnt-1]==0xFF&&g_RS485_rx_buf[g_RS485_rx_cnt-2]==0xFF)
{
memcpy(g_RS485_tx_buf,g_RS485_rx_buf,g_RS485_rx_cnt);
memset(g_RS485_rx_buf,0x00,g_RS485_rx_cnt);
rxstate = 1;
}
}
}
3)DMA
- 初始化函数:
__HAL_UART_ENABLE_IT(&g_rs458_handler, UART_IT_IDLE); /* 开启空闲中断 */
HAL_UART_Receive_DMA(&g_rs458_handler,(uint8_t*)&g_RS485_rx_buf,RS485_REC_LEN);
HAL_NVIC_EnableIRQ(RS485_UX_IRQn); /* 使能USART2中断 */
HAL_NVIC_SetPriority(RS485_UX_IRQn, 3, 3); /*
- HAL_UART_MspInit
if(huart->Instance == USART2) /* 如果是串口1,进行串口1 MSP初始化 */
{
/* IO 及 时钟配置 */
RS485_RE_GPIO_CLK_ENABLE(); /* 使能 RS485_RE 脚时钟 */
RS485_TX_GPIO_CLK_ENABLE(); /* 使能 串口TX脚 时钟 */
RS485_RX_GPIO_CLK_ENABLE(); /* 使能 串口RX脚 时钟 */
RS485_UX_CLK_ENABLE(); /* 使能 串口 时钟 */
__HAL_RCC_DMA1_CLK_ENABLE(); /* 使能 串口 时钟 */
GPIO_InitTypeDef gpio_initure;
gpio_initure.Pin = RS485_TX_GPIO_PIN;
gpio_initure.Mode = GPIO_MODE_AF_PP;
gpio_initure.Pull = GPIO_PULLUP;
gpio_initure.Speed = GPIO_SPEED_FREQ_HIGH;
gpio_initure.Alternate = GPIO_AF7_USART2; /* 复用为串口2 */
HAL_GPIO_Init(RS485_TX_GPIO_PORT, &gpio_initure); /* 串口TX 脚 模式设置 */
gpio_initure.Pin = RS485_RX_GPIO_PIN;
HAL_GPIO_Init(RS485_RX_GPIO_PORT, &gpio_initure); /* 串口RX 脚 必须设置成输入模式 */
gpio_initure.Pin = RS485_RE_GPIO_PIN;
gpio_initure.Mode = GPIO_MODE_OUTPUT_PP;
gpio_initure.Pull = GPIO_PULLUP;
gpio_initure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(RS485_RE_GPIO_PORT, &gpio_initure); /* RS485_RE 脚 模式设置 */
dmatx.Instance =DMA1_Stream6;
dmatx.Init.Channel=DMA_CHANNEL_4;
dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
dmatx.Init.MemInc = DMA_MINC_ENABLE;
dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
dmatx.Init.Mode = DMA_NORMAL;
dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&g_rs458_handler, hdmatx, dmatx);
HAL_DMA_Init(&dmatx);
HAL_NVIC_SetPriority(DMA1_Stream6_IRQn ,3,0);
HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn );
dmarx.Instance = DMA1_Stream5;
dmarx.Init.Channel=DMA_CHANNEL_4;
dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
dmarx.Init.MemInc = DMA_MINC_ENABLE;
dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
dmarx.Init.Mode = DMA_NORMAL;
dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&g_rs458_handler, hdmarx, dmarx);
HAL_DMA_Init(&dmarx);
HAL_NVIC_SetPriority(DMA1_Stream5_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
RS485_RE(0); /* 默认为接收模式 */
}
- 中断服务函数
void RS485_UX_IRQHandler(void)
{
HAL_UART_IRQHandler(&g_rs458_handler);
if( __HAL_UART_GET_FLAG(&g_rs458_handler, UART_FLAG_IDLE))
{
HAL_UART_DMAStop(&g_rs458_handler);
__HAL_UART_CLEAR_IDLEFLAG(&g_rs458_handler);
g_RS485_rx_cnt = RS485_REC_LEN - g_rs458_handler.hdmarx->Instance->NDTR;
HAL_UART_AbortReceive_IT(&g_rs458_handler);
}
}
- 接收完成回调函数
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART2){
memcpy(g_RS485_tx_buf,g_RS485_rx_buf,g_RS485_rx_cnt);
memset(g_RS485_rx_buf,0x00,g_RS485_rx_cnt);
rxstate = 1;
HAL_UART_Receive_DMA(&g_rs458_handler,(uint8_t*)&g_RS485_rx_buf,RS485_REC_LEN);
}
}