单片机学习小组
直播中

李泽明

7年用户 1201经验值
私信 关注

测试h750板子的485串口收发功能遇到的问题记录

如何对h750板子上的485串口进行收发功能测试呢?
怎样行使用hal库的接口进行字节的收发和接收中断处理呢?

回帖(1)

杨文英

2022-2-18 09:16:10
    最近在对h750板子上的485串口进行收发功能测试的时候,遇到的一个问题,特地记录一下。
    由于对板子上的485引脚做了特殊处理,在通过Tx引脚发送报文的时候,Rx也会收到Tx发送出去的报文,触发接收中断,所以我的报文发送逻辑是:发送N个字节时,只主动发送第一个字节,然后在接收中断中判断接收到的字节和我发送的字节是否一致,如果一致则继续发送下一个字节,不一致则发送失败,退出发送。
     一开始使用的是野火的485例程,使用hal库的接口进行字节的收发和接收中断处理
中断使能

  /* 配置抢占优先级的分组 */
    HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
    /*中断设置,抢占优先级0,子优先级为0*/
    HAL_NVIC_SetPriority(USART6_IRQn, 0,0);
    HAL_NVIC_EnableIRQ(USART6_IRQn);
    /*配置串口接收中断 */
    __HAL_UART_ENABLE_IT(&Uart6_Handle,UART_IT_RXNE);
    __HAL_UART_ENABLE_IT(&Uart6_Handle,USART_IT_ERR);
    __HAL_UART_ENABLE_IT(&Uart6_Handle,UART_IT_PE);
发送


    if(BSP_RS485_TxState != RS485_TX_ING)
    {
        BSP_RS485_BusFreeCount = 0;
        Enter_485Tx();

        p = RS485_Tx_Buf;
        for(i=0; i             *p++ = *myData++;

        pTx = RS485_Tx_Buf;
        TxLen = DatLen;

        Tx_Last = *pTx++;
                HAL_UART_Transmit(&Uart6_Handle, (uint8_t *)&Tx_Last, 1, 10);
        return TRUE;
    }
接收中断


    if(__HAL_UART_GET_IT(&Uart6_Handle,USART_IT_ORE)!=RESET) {
        __HAL_UART_CLEAR_OREFLAG(&Uart6_Handle);
    }

    if((__HAL_UART_GET_FLAG(&Uart6_Handle,UART_FLAG_RXNE)!=RESET))
    {
        HAL_UART_Receive(&Uart6_Handle, (uint8_t *)(&temp),1, 1000);
        BSP_RS485_BusFreeCount = 0;

        USART_RX_vect(temp);
    }
        else if(__HAL_UART_GET_FLAG(&Uart6_Handle,USART_IT_TC)!=RESET)
        {
                __HAL_UART_CLEAR_IT( &Uart6_Handle, USART_IT_TC );
        }
        else
        {
                 HAL_UART_Receive(&Uart6_Handle, (uint8_t *)(&temp),1, 1000);
               
        }
         __HAL_UART_CLEAR_OREFLAG(&Uart6_Handle);
    if(__HAL_UART_GET_FLAG(&Uart6_Handle, USART_FLAG_NE) != RESET)
    {
        __HAL_UART_CLEAR_NEFLAG(&Uart6_Handle);
    }




    if(__HAL_UART_GET_FLAG(&Uart6_Handle, USART_FLAG_FE) != RESET)
    {
        __HAL_UART_CLEAR_FEFLAG(&Uart6_Handle);
    }


    if(__HAL_UART_GET_FLAG(&Uart6_Handle, USART_FLAG_PE) != RESET)
    {
        __HAL_UART_CLEAR_PEFLAG(&Uart6_Handle);
    }


接收中断中发送处理


        if(c != Tx_Last)
        {   //发送的同接收的不一致,退出发送
            _485_RX_EN();
            BSP_RS485_TxState = RS485_TX_FAIL;
        } else
        {   //发送下一个
            if(--TxLen>0)
            {
                Tx_Last = *pTx;
                ch=*pTx++;
                                RS485_UART->TDR=ch;
            } else
            {
                Enter_485Rx();
                BSP_RS485_TxState = RS485_TX_SUCCESS;
            }
        }
在实际使用过程中,发现虽然也能正常的进行收发,但是时不时会在接收中断的发送处理函数出现问题,经常出现发送的字节和接收中断收到的字节不一致的问题,导致报文发送失败,并且一旦出现这种情况,接收中断就会失效,再也无法触发。后来想的办法是在发生错误时重新初始化串口,这样又能继续收发了,但是这种方式治标不治本,还是无法解决报文频繁发送失败的问题。


        if(c != Tx_Last)
        {   //发送的同接收的不一致,退出发送
                        BSP_RS485_Init(19200);
            BSP_RS485_TxState = RS485_TX_FAIL;
        }
最后,参考了安富莱的485例程,不调用hal库接口,而是直接对寄存器进行操作。


中断使能


SET_BIT(RS485_UART->ICR, USART_ICR_TCCF);        /* 清除TC发送完成标志 */
SET_BIT(RS485_UART->RQR, USART_RQR_RXFRQ);  /* 清除RXNE接收标志 */
SET_BIT(RS485_UART->CR1, USART_CR1_RXNEIE);        /* 使能PE. RX接受中断 */
发送接收


RS485_UART->TDR=Tx_Last;//发送
temp = READ_REG(RS485_UART->RDR);//接收
接收中断


volatile UNS8 temp;
        uint32_t isrflags   = READ_REG(RS485_UART->ISR);
        uint32_t cr1its     = READ_REG(RS485_UART->CR1);
        uint32_t cr3its     = READ_REG(RS485_UART->CR3);
       
                /* 处理接收中断  */
        if ((isrflags & USART_ISR_RXNE_RXFNE) != RESET)
        {
                temp = READ_REG(RS485_UART->RDR);
                BSP_RS485_BusFreeCount = 0;
                USART_RX_vect(temp);
        }
        if ( ((isrflags & USART_ISR_TXE_TXFNF) != RESET) && (cr1its & USART_CR1_TXEIE) != RESET)
        {
                CLEAR_BIT(RS485_UART->CR1, USART_CR1_TXEIE);
        }
        if (((isrflags & USART_ISR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
        {
                CLEAR_BIT(RS485_UART->CR1, USART_CR1_TCIE);
        }
       
                /* 清除中断标志 */
        SET_BIT(RS485_UART->ICR, UART_CLEAR_PEF);
        SET_BIT(RS485_UART->ICR, UART_CLEAR_FEF);
        SET_BIT(RS485_UART->ICR, UART_CLEAR_NEF);
        SET_BIT(RS485_UART->ICR, UART_CLEAR_OREF);
        SET_BIT(RS485_UART->ICR, UART_CLEAR_IDLEF);
        SET_BIT(RS485_UART->ICR, UART_CLEAR_TCF);
        SET_BIT(RS485_UART->ICR, UART_CLEAR_LBDF);
        SET_BIT(RS485_UART->ICR, UART_CLEAR_CTSF);
        SET_BIT(RS485_UART->ICR, UART_CLEAR_CMF);
        SET_BIT(RS485_UART->ICR, UART_CLEAR_WUF);
        SET_BIT(RS485_UART->ICR, UART_CLEAR_TXFECF);
改成寄存器版后,错误基本不再出现,两个版本的差异在于接收中断中对于中断信号的处理,野火基本只处理了接收中断,其他中断都没怎么处理,一开始直接hal库的HAL_UART_IRQHandler(&Uart6_Handle);接口让其自行处理,发现没啥用后我才按照网上其他人的说法多加了几个中断处理。不过仍然无法彻底解决问题。另外就是收发接口的不同,HAL_UART_Receive和HAL_UART_Transmit接口会进行不少操作,不知道会不会出现问题。而安富莱的例程是直接操作寄存器,且对中断信号做了不少处理。
    至于到底是和原因导致的错误,时间有限,没空去进行验证了,反正先用第二种方法进行485的收发完成项目再说。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分