问题描述:
- 接收中断每次接收1个字节,在一次性收到多个字节的数据时,会出现进入不了接收中断的问题。
- 接收与发送同时触发时,导致接收的字节出现错误。
问题解决:
对比与stm32的空闲中断,判断从机报文发送结束芯片进入中断。这样就可以保证不需要每次有数据过来都进入一次中断,只需要数据接收完毕处理一次即可。
先配置串口驱动,我这里使用lpuart,对于传输类型使用中断还是DMA,我认为都可以,但是DMA需要确定数组大小。我使用的是中断
初始化串口,并安装中断回调函数。接收中断RS485_URT_RX_ISR 中,如果接收字节超过256,会触发接收满事件,这时候截断后面的数据重新接收。其中mb_rtu1.mb_adu_buff为接收的数组。
//缓存大小
#define MB_ADU_BUFF_SIZE 256
uint8_t mb_adu_buff[MB_ADU_BUFF_SIZE];
void RS485_URT_RX_ISR (void *driverState, uart_event_t event, void *userData)
{
(void) driverState;
(void) userData;
//串口接收缓存满事件
if(event == UART_EVENT_RX_FULL)
{
LPUART_DRV_AbortReceivingData(INST_RS485_LPUART);
//等待发送完成
if (LPUART_DRV_GetTransmitStatus(INST_RS485_LPUART, &rs485_bytesRemaining) != STATUS_BUSY)
{
LPUART_DRV_ReceiveData(INST_RS485_LPUART, mb_adu_buff, MB_ADU_BUFF_SIZE);
}
else
{
//清除中断标志位并重新开始接收串口数据
LPUART_DRV_ReceiveData(INST_RS485_LPUART, mb_adu_buff, MB_ADU_BUFF_SIZE);
}
}
else if(event == UART_EVENT_ERROR)//接收模式进的错误
{
LPUART_DRV_ReceiveData(INST_RS485_LPUART, mb_adu_buff, MB_ADU_BUFF_SIZE);
}
else
{
}
}
//uart485发送完成产生中断
void RS485_URT_TX_ISR (void *driverState, uart_event_t event, void *userData)
{
(void) driverState;
(void) userData;
//发送完成
if(event==UART_EVENT_END_TRANSFER)
{
LPUART_DRV_ReceiveData(INST_RS485_LPUART, mb_adu_buff, MB_ADU_BUFF_SIZE);
}
}
void uart_Init(void)
{
LPUART_DRV_Init(INST_RS485_LPUART, &rs485_lpuart_State, &rs485_lpuart_InitConfig0); //初始化串口
LPUART_DRV_InstallTxCallback(INST_RS485_LPUART,RS485_URT_TX_ISR, NULL);//安装发送中断回调函数
LPUART_DRV_InstallRxCallback(INST_RS485_LPUART,RS485_URT_RX_ISR, NULL);//安装接收中断回调函数
LPUART_DRV_ReceiveData(INST_RS485_LPUART, mb_adu_buff, MB_ADU_BUFF_SIZE); //开启串口接收,每次接收一个字节,并安装中断
INT_SYS_SetPriority(LPUART2_RxTx_IRQn,configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
}
接收和发送中断写好,如何判断从机数据发送结束是一个问题。通过读UART寄存器的空闲标志位可以判断从机是否发送结束。空闲函数判断LPUART的STAT寄存器中空闲标志位来确定。并且通过LPUART_DRV_GetReceiveStatus函数可以确定本次数据还剩多少字节,定义的总字节数减去获取到的该值可得出数据一共接收了多少字节。最后重启接收就可以了。
void MB_IT_IDLE_IQR(MB_RCB_T * const p_mb_rtu)
{
uint32_t empty_size = 0;
uint8_t adu_buff_pos = 0;
//读寄存器空闲标志位触发
if((LPUART2->STAT >> 20 & 0x01))
{
LPUART2->STAT |= 0<<20;
LPUART_DRV_GetReceiveStatus(INST_RS485_LPUART,&empty_size);
adu_buff_pos = MB_ADU_BUFF_SIZE - empty_size;
//增加信号量
if(xSemaphore != NULL)
{
xSemaphoreGive(xSemaphore);
}
LPUART_DRV_SetRxBuffer(INST_RS485_LPUART,mb_adu_buff, MB_ADU_BUFF_SIZE);
LPUART_DRV_ReceiveData(INST_RS485_LPUART, mb_adu_buff, MB_ADU_BUFF_SIZE);
}
}
空闲函数放到一个任务或者定时器中,轮询空闲标志位是否触发。我使用信号量同步其他任务来处理报文。