UART 只能以一种方式正常工作 (ATmega328p)
UART only working correctly one way (ATmega328p)
我得到了一个由 ATmega328P 驱动的 Arduino Uno。而且我想离开它的图书馆,并在 较低的 水平上做所有事情以用于学习目的。但是我无法让 uart 正常工作,它现在只有在发送到设备时才能工作。收到 returns 终端无法打印的奇怪垃圾。
#define BAUDRATE (((F_CPU / (BAUD * 16UL))) - 1)
void init_uart()
{
UBRR0H = BAUDRATE >> 8; // set high baud
UBRR0L = BAUDRATE; //set low baud
UCSR0B = _BV(TXEN0) | _BV(RXEN0); //enable duplex
UCSR0C = _BV(UCSZ00) | _BV(UCSZ01) | _BV(USBS0); //8-N-1
}
void putchar_uart(char c, FILE* stream)
{
loop_until_bit_is_set(UCSR0A, UDRE0); //wait till prev char is read
UDR0 = c;
}
char getchar_uart(FILE* stream)
{
loop_until_bit_is_set(UCSR0A, RXC0); //wait if there is data
return UDR0;
}
//^ actually is in a seperate file which gets linked
int main()
{
DDRD |= PIN_LED;
PORTD |= PIN_LED;
stdout = &mystdout;
stdin = &mystdin;
char buf[0xFF];
init_uart();
while (1)
{
char c = getchar_uart(NULL);
if (c == 'a')
{
PIND = PIN_LED;
printf("%s\n", "Hallo");
}
}
}
我是 运行 Ubuntu 14.04 LTS 并使用 minicom 进行通信。设置为:115200 8N1(当然使用正确的串行设备。)
编译为:
avr-gcc -Wall -Os -mmcu=atmega328p -DF_CPU=16000000UL -DBAUD=115200 -std=c99 -L/home/joel/avr-libs/lib -I/home/joel/avr-libs/inc -o firmware.o main.c -luart
那么我怎么知道一种方法有效呢?因为 LED 仅在输入 'a' 时才会切换。但响应是无效字符。十六进制:
c8 e1 ec ec ef 8a
当 Chris 建议打印出 Arduino 使用的配置寄存器时,我解决了这个问题,我注意到它使用双模式。我无法使用 minicom 配置它,或者我错过了它。也许默认使用这种模式。不管怎样,现在可以了。
我还了解到 avr-libc 提供了一个名为 util/setbaud.h 的 header,它会自动计算正确的波特率。在 UBRRL_VALUE 和 UBRRH_VALUE 字段中。
通过设置 USBS 位,您正在命令第二个停止位。
这似乎会导致您的计算机错误地认为设置了 MSB(这是最后一个数据位),但它不会导致您接收到的数据与 0x80 进行“或”运算。
虽然这会导致帧错误,但它可能不是错误 MSB 的原因。您自己关于切换到 2x 模式(并因此更准确地近似波特率)的答案对解决方案更为关键,但您也应该更正此问题。
我得到了一个由 ATmega328P 驱动的 Arduino Uno。而且我想离开它的图书馆,并在 较低的 水平上做所有事情以用于学习目的。但是我无法让 uart 正常工作,它现在只有在发送到设备时才能工作。收到 returns 终端无法打印的奇怪垃圾。
#define BAUDRATE (((F_CPU / (BAUD * 16UL))) - 1)
void init_uart()
{
UBRR0H = BAUDRATE >> 8; // set high baud
UBRR0L = BAUDRATE; //set low baud
UCSR0B = _BV(TXEN0) | _BV(RXEN0); //enable duplex
UCSR0C = _BV(UCSZ00) | _BV(UCSZ01) | _BV(USBS0); //8-N-1
}
void putchar_uart(char c, FILE* stream)
{
loop_until_bit_is_set(UCSR0A, UDRE0); //wait till prev char is read
UDR0 = c;
}
char getchar_uart(FILE* stream)
{
loop_until_bit_is_set(UCSR0A, RXC0); //wait if there is data
return UDR0;
}
//^ actually is in a seperate file which gets linked
int main()
{
DDRD |= PIN_LED;
PORTD |= PIN_LED;
stdout = &mystdout;
stdin = &mystdin;
char buf[0xFF];
init_uart();
while (1)
{
char c = getchar_uart(NULL);
if (c == 'a')
{
PIND = PIN_LED;
printf("%s\n", "Hallo");
}
}
}
我是 运行 Ubuntu 14.04 LTS 并使用 minicom 进行通信。设置为:115200 8N1(当然使用正确的串行设备。)
编译为:
avr-gcc -Wall -Os -mmcu=atmega328p -DF_CPU=16000000UL -DBAUD=115200 -std=c99 -L/home/joel/avr-libs/lib -I/home/joel/avr-libs/inc -o firmware.o main.c -luart
那么我怎么知道一种方法有效呢?因为 LED 仅在输入 'a' 时才会切换。但响应是无效字符。十六进制:
c8 e1 ec ec ef 8a
当 Chris 建议打印出 Arduino 使用的配置寄存器时,我解决了这个问题,我注意到它使用双模式。我无法使用 minicom 配置它,或者我错过了它。也许默认使用这种模式。不管怎样,现在可以了。
我还了解到 avr-libc 提供了一个名为 util/setbaud.h 的 header,它会自动计算正确的波特率。在 UBRRL_VALUE 和 UBRRH_VALUE 字段中。
通过设置 USBS 位,您正在命令第二个停止位。
这似乎会导致您的计算机错误地认为设置了 MSB(这是最后一个数据位),但它不会导致您接收到的数据与 0x80 进行“或”运算。
虽然这会导致帧错误,但它可能不是错误 MSB 的原因。您自己关于切换到 2x 模式(并因此更准确地近似波特率)的答案对解决方案更为关键,但您也应该更正此问题。