我将STM32F407VE连接到外部CAN设备(TCAN4550)。 MCU 接收来自 PC 的命令,并将接收到的 CAN 数据通过 USART 传输至 PC。当循环 CAN 消息处于活动状态时,MCU 会时不时地丢失一个字节。 客服告诉我,USART的发送和接收共享同一个DR,通常使用“询问和应答”模式。我想当发送和接收都发生在一个中断中时,我的问题就会发生。 这是我在 Keil5 中的部分代码:
#define sizeUSART1TX 4096
#define sizeUSART1RX 256
static unsigned char USART1TxBuf[sizeUSART1TX];
static char USART1RxBuf[sizeUSART1RX];
static unsigned short USART1TxIdx0=0, USART1TxIdx1=0, USART1RxIdx=0;
static void USART1SendChar(char *buf, unsigned short cnt)
{
if(USART1Act==0) return;
for (unsigned short idx1 = 0; idx1 < cnt; ++idx1)
{
USART1TxBuf[USART1TxIdx0++] = buf[idx1];
if (USART1TxIdx0 == sizeUSART1TX)
USART1TxIdx0 = 0;
}
if ((USART1->CR1 & 1 << 7) == 0) //TXEIE
USART1->CR1 |= 1 << 7;
}
void USART1_IRQHandler(void)
{
if (USART1->SR & (1 << 5)) //RXNE, reset by reading DR
{
USART1RxBuf[USART1RxIdx++] = USART1->DR;
if (USART1RxBuf[USART1RxIdx-1] == 10) //command end
{
...... //actions
USART1SendChar(USART1RxBuf, USART1RxIdx); //confirm the command
memset(USART1RxBuf, 0, sizeUSART1RX);
USART1RxIdx = 0;
}
}
if ((USART1->SR & 1<<7) && (USART1->CR1 & 1<<7)) //TXE and TXEIE
{
USART1->DR = USART1TxBuf[USART1TxIdx1++]; //writing DR reset interrupts
if (USART1TxIdx1 == sizeUSART1TX)
USART1TxIdx1 = 0;
if (USART1TxIdx1 == USART1TxIdx0)
USART1->CR1 &= ~(1<<7); //turning off TXEIE
}
}
int main()
{
//USART
USART_InitTypeDef USART_InitStructure;
RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2Periph_SYSCFG;
//PA9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//PA10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_DeInit(USART1);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
USART1->SR = ~(0x00F0); //clear interrupts
while(1){}
}
USART有可能实现真正的全双工吗?
当循环 CAN 消息处于活动状态时,MCU 会到处丢失一个字节。
如果 CAN 使用较长的中断(长于 Rx 字符持续时间加上字符之间的任何间距),并且这些中断的优先级与 UART ISR 相同或更高,则某些 Rx 字符可能会由于之前未从 UART_DR 中选取而丢失下一个角色到来。
在 ISR 中检查 UART Rx Overrun。
JW