最近在对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的收发完成项目再说。
最近在对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的收发完成项目再说。
举报