HAL库-Usart

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);
        }
}

  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值