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

时间:2018-05-15 13:12:32

标签: c avr uart usart

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

我遇到的问题是数据不稳定,有时会发送“ello!'有时候暂时没什么。 ' H'经常被忽略,我不明白这一点,因为ISR不应该在' H'之前执行。已从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
    }
}

2 个答案:

答案 0 :(得分:4)

根据数据表:

  

“当UCSRnB中的数据寄存器空中断使能(UDRIE)位时   写入'1',USART数据寄存器为空中断   只要UDRE设置为“

,就会执行

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

最后,将“transmit_index&lt;(len + 1)”更改为transmit_index&lt; = len。没有必要在ISR中浪费指令

答案 1 :(得分:0)

在主循环中,更改此行:

transmit_index = 1;

这一行:

transmit_index = 0;

str [0] =&#39; H&#39;但你从索引[1] ...

开始