c - 为什么我在串行终端仿真器上收到额外的字符?& 避免他们?
问题描述
我目前正在尝试在 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');
}
}
解决方案
您的中断处理程序不正确。它将一直被调用,因为如果你不放任何东西,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,因为您无需修改相同的变量。
推荐阅读
- ruby-on-rails - Ruby on Rails - 参数丢失或值为空
- azure - 我们应该将什么服务连接添加到 Azure 管道中的“调用 REST API:POST”
- r - 用于删除组内值的 R 代码
- c# - Asp.Net Core 3.1 MVC 使用代码优先迁移创建 NLog 表模式
- python - 寻找解释 Python 语法选项的资源
- authentication - Azure DevOps 私有 Linux 代理 - YAML 管道签出失败 - 可以使用“git config --global --unset http.extraHeader”修复,但还不够早
- jquery - 如何在角度选择中获取选项的值?
- php - 表单提交后PHP标头重定向(不起作用)
- django - Django 在基于类的视图中提示用户登录
- php - 如果 1 或 2 个元素,foreach 循环不会遍历所有内容