AVR - 高速中断驱动的 UART 代码不工作

Posted

技术标签:

【中文标题】AVR - 高速中断驱动的 UART 代码不工作【英文标题】:AVR - High speed interrupt driven UART code not working 【发布时间】:2018-10-25 08:15:54 【问题描述】:

我想制作一个中断驱动的 uart 程序,以绝对最小的 cpu 开销高速发送大量数据。我结合现有代码和数据表的阅读来制作此代码。它在 atmega328p (Atmega328p Xplained Mini) 上的 Atmel Studio 7 中编译时没有错误或警告。

我遇到的问题是数据不稳定,有时它会发送“你好!”有时一时无事。 'H' 经常被跳过,我不明白这一点,因为 ISR 不应该在从 UDR0 复制到发送之前执行。

任何帮助将不胜感激!

您好,

伯特。

#define F_CPU 16000000

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <string.h>

volatile uint8_t transmit_index = 0;
volatile char str[] = "Hello!\n";
volatile uint8_t len = 6;

int main(void)
    UCSR0A = 0b00000010;
    UCSR0B = 0b00111000;
    UCSR0C = 0b00000110;

//9600 baud
    UBRR0L = 207; 
    UBRR0H = 0;

    DDRD |= 0x02;

    sei();

    //Flash led
    DDRB |= 0b00100000;
    PORTB |= 0b00100000;
    _delay_ms(1000);
    PORTB &= ~0b00100000;
    _delay_ms(1000);

    while (1)  
        transmit_index = 1;

        //Enable udre interrupt
        UCSR0B |= 0b00100000; //enable interrupt

        //Send first byte in main()
        while (!(UCSR0A & 0b00100000))  //Wait for register empty
        UDR0 = str[0]; //send first byte

        _delay_ms(1000);
    


ISR(USART_UDRE_vect) 
    //Buffer empty, ready for new data
    if (transmit_index < (len + 1)) 
        UDR0 = str[transmit_index];
        transmit_index++;
     else 
        UCSR0B &= ~0b00100000; //disable interrupt
    

【问题讨论】:

如果在发送第一个字节之后 启用中断会发生什么?或者根本不在循环中发送它,而只是启用中断?并且不要重置transmit_index 在循环中做的第一件事? 您在主循环和 ISR 之间进行了一些交互(您每次都在重置 transmit_index,但 ISR 会增加它并且可能会在启用中断后立即触发,从而导致问题)。我认为您希望等待 ISR 被禁用,等待寄存器为空,加载数据,启用 ISR 并重复。 @Someprogrammerdude 移动中断的启用工作!我不知道为什么,但非常感谢^^ 【参考方案1】:

根据数据表:

"当UCSRnB中的数据寄存器空中断使能(UDRIE)位 写入“1”,USART 数据寄存器空中断将被 只要设置了UDRE就执行”

一旦启用中断,就会触发 ISR,从而跳过“H”。你有几个选择。 1) 在发送 H. 2)只需使用 ISR 发送整个消息,包括 H(例如,不要在主程序中发送任何内容。 3) 使用 Tramsmit Complete ((TXC) 中断。如果使用这个,请在​​主程序中发送 H,一旦传输,ISR 将触发,您的 ISR 将发送其余消息。

最后,将“transmit_index

【讨论】:

只是评论建议的优化以消除+ 1。这不应该是必要的,编译器通常可以很好地计算出生成最佳代码,所以我说写什么更直观。此 ISR 代码的有效优化可能是确保仅在至少有 1 个字符要发送时启用它,然后在 ISR 中,在递增后进行适当的比较,是否应禁用中断。这将删除不必要的中断条目(对于清空的缓冲区),并且消除 else 路径也有帮助。 好点,编译器应该足够聪明才能弄清楚。我通常会在尝试优化自己时出错。【参考方案2】:

在你的主循环中,改变这一行:

transmit_index = 1;

对于这一行:

transmit_index = 0;

str[0] = 'H' 但你从索引 [1] 开始...

【讨论】:

以上是关于AVR - 高速中断驱动的 UART 代码不工作的主要内容,如果未能解决你的问题,请参考以下文章

AVR单片机教程——定时器中断

AVR的UART接受中断问题,中断老是不能正常触发

带有 STM32 HAL 驱动程序的 FreeRTOS 中的 UART 中断

六 linux UART串口驱动代分析

在 AVR 中处理多个 PCINT 的最佳方法

arduino Usart1 中断