首页 > 解决方案 > 为什么我在串行终端仿真器上收到额外的字符?& 避免他们?

问题描述

我目前正在尝试在 STM32F103C8T6 微控制器上实现带中断的串行通信。当我尝试单独发送字符 ABCDE 时,我编写的代码“半”有效,但我在桌面(腻子)上的终端应用程序显示了我丢失的一些字符。

我在终端模拟器中的结果为什么很少有字符重复?&如何避免这种情况?

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,0, };

static bool tx_start = 1;

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

#endif

主程序

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

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

标签: cstm32serial-communicationkeilusart

解决方案


您的中断处理程序不正确。它将一直被调用,因为如果你不放任何东西,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,因为您无需修改​​相同的变量。


推荐阅读