STM32中485采用串口DMA发送,切换收发状态问题

参考网上分享:https://www.amobbs.com/thread-5535672-2-1.html

RS485使用DMA发送,切换收发状态,有以下几种实现方式:

  • 开启DMA的“发送完成中断”,在DMA的发送完成中断中,切换收发的状态。但是,这会导致最后的2个字节发送不出去,这是因为:DMA的“发送完成中断”出现在刚发送倒数第二个字节的起始位置,这个时候切换485的收发,若接收端不是奇校验的话 将会误收到0xFF 最后第一肯定也出不去。
    网上提供的解决办法是:①在DMA的TC中断里面 加大于两个字节的延时 这是OK的。 ②在DMA的TC中断里面 开启USART的“发送完成中断” 去USART的中断里面去处理 这是OK的。
  • 看数据手册,可以利用串口的“发送完成中断TC”实现。开启USART的DMA,开启DMA传输通道,开启USART的“发送完成中断TC”

具体实现:

配置USART和DMA ,DMA中断不用开。
准备发送的时候,

  • 切换为485发送 RS485EN_TX();-
  • 配置好DMA。传输的数据,与长度。
  • 开启USART的传输完成TC中断
  • 使能DMA =======等串口TC中断就行。
  • 中断服务函数中,失能TC 切换485接收。

开始传输:

//-----尝试不开启DMA TC中断  直接直观传输  
void USART2_SendMsg(INT8U *msg,INT8U len)
{
        SET_RS485_SEND;                //高发送
         DMA_ClearFlag(DMA1_FLAG_TC7);      //清DMA发送完成标志
         USART_ClearITPendingBit(USART2,USART_IT_TC);
         DMA_Cmd(DMA1_Channel7, DISABLE);   //停止DMA
        DMA1_Channel7->CMAR = (INT32U) msg;                        //源地址
         DMA1_Channel7->CNDTR = len;//重设传输长度
         USART_ITConfig(USART2,USART_IT_TC,ENABLE);
         DMA_Cmd(DMA1_Channel7, ENABLE);    //启动DMA
}

传输完成后:


void USART2_IRQHandler(void)
{
        /*
        ...................
        */
        if(0x00000040 & (USART2->SR))//(USART_GetITStatus(USART2,USART_IT_TC))
        {
                USART2->SR &= ~0x00000040;//USART_ClearITPendingBit(USART2,USART_IT_TC);
                OSSemPost(Sem_Usart2Send);                
                SET_RS485_RECV;                        //发送完毕 改成接收状态
                USART2->CR1 &= ~0x00000040;//USART_ITConfig(USART2,USART_IT_TC,DISABLE);
                //OSIntExit();
                return;
        }
        /*
        ...................
        */
}        

这里说一下,我由于使用的时候,在发送的时候没有“清除发送完成标志”,导致传输第一个字节后,就进入了TC中断,切换了485状态。
代码:

	RS485EN_TX(); //485切换为发送模式
	__HAL_UART_DISABLE_IT(&UART3_Handler,USART_IT_RXNE); /* 禁止接收中断 */
	__HAL_UART_ENABLE_IT(&UART3_Handler,USART_IT_TC);  /* 使能发送完成中断 */

	if(__HAL_DMA_GET_FLAG(&UART3TxDMA_Handler,DMA_FLAG_TCIF3_7))  //等待传输完成
	{
		__HAL_DMA_CLEAR_FLAG(&UART3TxDMA_Handler,DMA_FLAG_TCIF3_7);//清除DMA1_Steam3传输完成标志
		HAL_UART_DMAStop(&UART3_Handler);                          //传输完成以后关闭串口DMA 
	}		

时序:
在这里插入图片描述
修改后,在前面添加清除发送完成标志TC”后,既可以。
代码:

	RS485EN_TX(); //485切换为发送模式

    __HAL_UART_CLEAR_FLAG(&UART3_Handler,UART_FLAG_TC);
    
	if(__HAL_DMA_GET_FLAG(&UART3TxDMA_Handler,DMA_FLAG_TCIF3_7))  //等待传输完成
	{
		__HAL_DMA_CLEAR_FLAG(&UART3TxDMA_Handler,DMA_FLAG_TCIF3_7);//清除DMA1_Steam3传输完成标志
		HAL_UART_DMAStop(&UART3_Handler);                          //传输完成以后关闭串口DMA 
	}	
    
    __HAL_UART_DISABLE_IT(&UART3_Handler,USART_IT_RXNE); /* 禁止接收中断 */
	__HAL_UART_ENABLE_IT(&UART3_Handler,USART_IT_TC);  /* 使能发送完成中断 */
    
	MYDMA_USART_Transmit(&UART3_Handler,(u8*)USART3_TX_BUF,DRIVER_FRAME_LENGTH); //启动传输

传输完成后:

//串口3中断服务程序
void USART3_IRQHandler(void)                	
{ 	
    uint8_t Res=0;
    uint16_t u16CheckCrcTemp = 0;
    if((__HAL_UART_GET_FLAG(&UART3_Handler,UART_FLAG_TC)!=RESET))
	{
		__HAL_UART_CLEAR_FLAG(&UART3_Handler,UART_FLAG_TC);
        
		RS485EN_RX(); 
		__HAL_UART_ENABLE_IT(&UART3_Handler,USART_IT_RXNE);  
		__HAL_UART_DISABLE_IT(&UART3_Handler,USART_IT_TC);
        
    }
    if((__HAL_UART_GET_FLAG(&UART3_Handler,UART_FLAG_RXNE)!=RESET))
	{
		__HAL_UART_CLEAR_FLAG(&UART3_Handler,UART_FLAG_RXNE);
        
        Res = USART3->DR; 
        g_us485AlarmCnt=0;                  //485通信5s报警检测        
        if(USART3_RX_STA & 0x4000)
        {
            ++USART3_RX_STA;
            USART3_RX_BUF[USART3_RX_STA & 0xfff] = Res;
            if((USART3_RX_STA & 0xfff) == DRIVER_FRAME_LENGTH-1)  //接收帧尾
            {
                u16CheckCrcTemp = *(uint16_t*)(USART3_RX_BUF + DRIVER_FRAME_LENGTH - 2);
                if(u16CheckCrcTemp == crc_16((unsigned char *)USART3_RX_BUF,DRIVER_FRAME_LENGTH-2))
                {
                    if(USART3_RX_BUF[2]==0xff || USART3_RX_BUF[2]==g_ulaGdBuf[INDEX_ID]) //是否是正确的ID
                    {						
                        run_driver_cmd();
                    }
                }
                USART3_RX_STA = 0;
            }
        }
        else if(USART3_RX_STA & 0x8000) //接收一帧数据的第二个数据 ---0xef 2017.1.13
        {
            if(Res != 0xfb)
            USART3_RX_STA = 0;
            else
            {
                USART3_RX_BUF[(++USART3_RX_STA)&0xfff] = Res;
                USART3_RX_STA |= 0x4000;
            }
        }
        else if(Res == 0xbf)  //接收一帧数据的第一个数据 ---0xfb 2017.1.13
        {
            USART3_RX_BUF[USART3_RX_STA & 0xfff] = Res;
            USART3_RX_STA |= 0x8000;            
        }	
    }
} 

时序为:
在这里插入图片描述

发布了61 篇原创文章 · 获赞 89 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/qq_33559992/article/details/88243837
今日推荐