STM32 在同时发送和接收 USART 期间随机丢失字节

问题描述 投票:0回答:1

我将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有可能实现真正的全双工吗?

stm32 interrupt keil usart
1个回答
0
投票

当循环 CAN 消息处于活动状态时,MCU 会到处丢失一个字节。

如果 CAN 使用较长的中断(长于 Rx 字符持续时间加上字符之间的任何间距),并且这些中断的优先级与 UART ISR 相同或更高,则某些 Rx 字符可能会由于之前未从 UART_DR 中选取而丢失下一个角色到来。

在 ISR 中检查 UART Rx Overrun。

JW

© www.soinside.com 2019 - 2024. All rights reserved.