为什么在串行终端仿真器上收到额外的字符?和避免它们?

问题描述

我目前正在尝试在具有中断的STM32F103C8T6微控制器上实现串行通信。当我尝试分别发送字符ABCDE时,由我“ semi”编写的代码有效,但是我在台式机(Putty)上的终端应用程序正在显示我的一些遗漏字符。

我在终端模拟器中的结果 为什么几个字符重复?以及如何避免这种情况?

ABBCDEABCDEEABCDEABCCDEABCDEABBCDEABCDEEABCDEABCCDEABCDEAABCDEABCDDEABCDEABCCDEA
BCDEAABCDEABCDDEABCDEABBCDEABCDEEABCDEABCDDEABCDEABBCDEABCDEEABCDEABCCDEABCDEAAB
CDEABCDEEABCDEABCCDEABCDEAABCDEABCDDEABCDEABBCDEABCDEAABCDEABCDDEABCDEABBCDEABCD 

请在下面喜欢我的代码

usart.c

#include "usart.h"

void usart_init(uint32_t Baudrate)
{
    SystemCoreClockUpdate();
    RCC->APB2ENR |=(RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_USART1EN);
    GPIOA->CRH |= (GPIO_CRH_MODE9_0 | GPIO_CRH_MODE9_1);
    GPIOA->CRH &= ~(GPIO_CRH_MODE10_0 | GPIO_CRH_MODE10_1);
    GPIOA->CRH |= GPIO_CRH_CNF9_1;
    GPIOA->CRH &= ~GPIO_CRH_CNF9_0;
    GPIOA->CRH |= GPIO_CRH_CNF10_0;
    GPIOA->CRH &= ~GPIO_CRH_CNF10_1;
    
    USART1->BRR = (SystemCoreClock/Baudrate);
    USART1->CR1 |= (USART_CR1_UE | USART_CR1_RE | USART_CR1_TE);
    //USART1->CR1 |= USART_CR1_TXEIE;
    NVIC_EnableIRQ(USART1_IRQn);
}

void buffer_init(void)
{
    TxBuffer.in = 0;
    TxBuffer.out = 0;
}

void putchar(unsigned char data)
{
    __disable_irq();
    struct Buffer_Struct *p = &TxBuffer;
    p->Buffer[p->in & (BufferSize - 1)] = data;
    p->in++;    
    if(tx_start)
    {
        tx_start = 0;
        USART1->CR1 |=USART_CR1_TXEIE;
    }
    __enable_irq();
}

void USART1_IRQHandler(void)
{
    struct Buffer_Struct *p;
    if(USART1->SR & USART_SR_TXE)
    {
        p = &TxBuffer;
        if(p->in != p->out)
        {
            USART1->DR = (p->Buffer[p->out & (BufferSize - 1)] & 0x1FF);
            p->out++;
            tx_start = 0;
        }
    }
}

usart.h

#ifndef USART_H
#define USART_H
#include "stm32f10x.h"
#include <stdbool.h>

#define BufferSize      64

struct Buffer_Struct {
    unsigned int in;
    unsigned int out;
    unsigned char Buffer[BufferSize];
};

static struct Buffer_Struct TxBuffer = {0,};

static bool tx_start = 1;

void buffer_init(void);
void usart_init(uint32_t Baudrate);
void putchar(unsigned char data);

#endif

main.c

#include "stm32f10x.h"
#include "usart.h"

int main (void)
{
    usart_init(9600);
    while(1)
    {
        putchar('A');
        putchar('B');
        putchar('C');
        putchar('D');
        putchar('E');
    }
}

解决方法

您的中断处理程序不正确。如果您不在其中放置任何内容,TXE始终为空,它将一直被调用。您需要在中断处理程序中禁用该中断。

我还喜欢使用编译器来完成这项工作,并在缓冲区大小为2的幂的情况下尝试使用位域

#define BufferSize         6      

struct Buffer_Struct {
    volatile unsigned int in : BufferSize;
    volatile unsigned int out : BufferSize;
    unsigned char Buffer[2 << BufferSize];
};


void putchar(unsigned char data)
{
    TxBuffer.Buffer[TxBuffer.in] = data;
    TxBuffer.in++;    
    USART1->CR1 |=USART_CR1_TXEIE;
}

void USART1_IRQHandler(void)
{
    if(USART1->SR & USART_SR_TXE)
    {
        if(TxBuffer.in != TxBuffer.out)
        {
            USART1->DR = TxBuffer.Buffer[TxBuffer.out];
            TxBuffer.out++;
            if(TxBuffer.out == TxBuffer.in)
                USART1->CR1 &= ~USART_CR1_TXEIE;
        }
    }
}

您的putchar函数也是错误的,因为它不检查缓冲区是否已满。

顺便说一句,在这种情况下,您不必禁用IRQ,因为您无需修改​​相同的变量。