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 代码不工作的主要内容,如果未能解决你的问题,请参考以下文章