HAL_RS485发送接收_DMA:编码器

发布时间 2023-11-23 16:56:56作者: 易安yan

RS485编码器

使用RS485读取多个编码器

接收数据:空闲中断+DMA

发送数据:DMA

配置串口:

基本与串口通信一致,增加接收和发送DMA,正常模式,另外增加485使能IO

 

 

 

 

  接收数据:

使能空闲中断

         __HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE) ;

         __HAL_UART_CLEAR_IDLEFLAG(&huart3);

增加空闲中断回调函数,自定义的回调函数在void USART3_IRQHandler(void)函数中调用

//串口空闲中断

void UART3_IDLECallBack(UART_HandleTypeDef *huart)

{

         if(huart == &huart3){

                   if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))  {

                            __HAL_UART_CLEAR_IDLEFLAG(&huart3);//清除标志位

                            HAL_UART_DMAStop(&huart3);//停止DMA

//HAL_UART_Transmit(&huart1,uart3RxBuffer2,12,0x1000);               

Uart3.RxLen=(&huart3)->RxXferSize-(&huart3)->hdmarx->Instance->CNDTR;//len==21             

                            RS485_RX_END  = 1;

                   }

         }

}

在主函数中判断RS485_RX_END处理数据

发送数据:

由于需要与多个编码器通信,如果连续发送数据,读不到编码器的数据,猜想是连续的数据会被识别成1条数据,等待huart->gState = HAL_UART_STATE_READY标志位也失败了,所以使用定时器定时50ms发送数据

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

         static uint8_t CmdCNT = 0;

         uint8_t *SendBuf = NULL;

         uint8_t *ReceiveBuf = NULL;

        

         HAL_TIM_Base_Stop_IT(&htim1);

         HAL_UART_DMAStop(&huart3);//停止DMA

         //切换输出的命令

         if(!(ResetRoatFlag & (0x1<<Enc_ID))){

//               printf("Read_RS485:%d", Enc_ID);

                   SendBuf = Read_RS485[Enc_ID];

         }

         else{

                   if(!(CmdCNT&(0x1<<Enc_ID))){

//                         printf("Start_RS485:%d", Enc_ID);

                            SendBuf = Start_RS485[Enc_ID];

                            CmdCNT |= (0x1 << Enc_ID);

                   }else{

//                         printf("Set_RS485:%d", Enc_ID);

                            SendBuf = Set_RS485[Enc_ID];

                            CmdCNT &= ~(0x1 << Enc_ID);

                            ResetRoatFlag &= ~(0x1 << Enc_ID);

                   }

         }       

         // 启用DMA接收

         switch (Enc_ID){

                   case RS485_ENC1:ReceiveBuf = uart3RxBuffer1;break;

                   case RS485_ENC2:ReceiveBuf = uart3RxBuffer2;break;

                   case RS485_ENC3:ReceiveBuf = uart3RxBuffer3;break;

                   default:ReceiveBuf = NULL;

         }

         if(ReceiveBuf != NULL){

                   HAL_UART_Receive_DMA(&huart3,ReceiveBuf,sizeof(uart3RxBuffer) - 1) ;

                   SwRS485Mode(RS485_TX_EN);

                   HAL_UART_Transmit_DMA(&huart3,SendBuf,8);

                   (Enc_ID+1) > 2 ? Enc_ID=0 : Enc_ID++;

         }

         HAL_TIM_Base_Start_IT(&htim1);

}

主要功能就是切换发送的命令,开启DMA接收,发送数据(多缓存接收)

开启DMA接收HAL_UART_Receive_DMA(&huart3,ReceiveBuf,sizeof(uart3RxBuffer) - 1) ;

切换485使能为发送;

HAL_UART_Transmit_DMA(&huart3,SendBuf,8);发送数据

在发送中断回调函数中切换485使能为接收

 

流程:定时器中断→开启DMA接收→切换485为发送,DMA发送→发送中断回调函数切换485为接收→空闲中断接收数据,停止DMA→主函数处理数据→定时器中断

 

但是定时器定时时间不能小于50ms,否则也会接收不到数据,