c - 了解 ATMEGA168A 下的 UART

标签 c avr uart atmega

我正在尝试创建一个 C 程序,它通过 UART 接收一个字符,通过打开我面包板上的 8 个 LED 来“打印”相应的二进制文件,并将该字符发送回发射器。

这是我使用的代码:

//CPU clock
#define F_CPU 1000000UL
//Baud
#define BAUD 9600
//Baud rate
#define BAUDRATE ((F_CPU)/(BAUD*16UL)-1)

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

//Communication Parameters: 
//8 bits of data
//1 bit stop
//No parity
void uart_init(void){

    //Bit 7 - RXCIEn: RX complete interrupt enable
    //Bit 6 - TXCIEn: TX complete interrupt enable
    //Bit 5 - UDRIE: USART data register empty interrupt enable
    //Bit 4 - RXENn: Receiver enable
    //Bit 3 - TXENn: Transmitter enable
    UCSR0B = 0b10011000;

    //Bit 7 - RXCn: USART receive complete.
    //Bit 6 - TXCn: USART transmit complete
    //Bit 5 - UDREn: USART data register empty
    UCSR0A = 0b00000000;


    //Bit 11:0 – UBRR11:0: USART baud rate register
    //Whereas H are the higher bits and L the lower bits
    //It comes from the setbaud.h
    UBRR0H = UBRRH_VALUE;
    UBRR0L = UBRRL_VALUE;

    //Bit 7:6 - UMSELn1:0: USART mode select
        //00    Asynchronous USART
        //01    Synchronous USART
        //11    Master SPI
    //Bit 5:3 - Reserved bits in MSPI mode
    //Bit 2 - UDORDn: Data order
    //Bit 1 - UCPHAn: Clock phase
    //Bit 0 - UCPOLn: Clock polarity
    UCSR0C = 0b10000110;
}

// function to send data
void uart_transmit (uint8_t data)
{
    while (!( UCSR0A & (1<<UDRE0)));            // wait while register is free
    UDR0 = data;                             // load data in the register
}

int main (void)
{
    //Starts UART
    uart_init();
    //All led GPIOs as output
    DDRB = 0xFF;
    DDRC = 0x01;
    //Enabling interrupts
    sei();

    while(1)
    {
        ;
    }

    return 0;
}

ISR(USART_RX_vect)
{
    //Variable to hold the incoming char
    uint8_t received_bit = UDR0;
    PORTC ^= 0x01;
    PORTB = 0x00;
    PORTB = received_bit;
    uart_transmit(received_bit);
}

当我将它闪存到芯片并开始使用它时,我发现了一个奇怪的行为。 我正在发送一个“U”,它是一个很好的二进制 01010101 用于比较。 然而,我从我的芯片中得到了奇怪的答案:

enter image description here

我对 ATMEGA168a 下的 UART 的问题如下:

  • 在设置 F_CPU 时,我应该继续使用 ATMEGA168a 使用的 1MHZ 还是必须使用我的发射器之一 (Intel i7)?这可能是问题所在吗?
  • UDR0 何时“更新”?每当我按回车键通过终端将字符发送到芯片时?
  • 是什么导致了这个问题?

最佳答案

在函数中 uart_init()你设置位 7:610根据 ATMega 168A 手册,这是保留状态。要获得所需的异步 UART 功能,请将它们设置为 00 :

UCSR0C = 0b00000110;

您的示例无法正常工作的另一个原因是波特率设置,正如我在下面的评论中所解释的那样。

您已经包含了 <util/setbaud.h>头文件,其中包含使 UART 设置更容易的宏。看here对于文档。这些宏采用您在 F_CPU 中提供的输入和 BAUDRATE并计算 UART 配置寄存器的设置(UBRRH_VALUEUBRRL_VALUE)。

您几乎正确地使用了它,但是要利用 ATmega 的 UART 波特率加倍功能,请在设置 UBRR0H/L 值后添加以下代码:

#if USE_2X
UCSR0A |= (1 << U2X0);
#else
UCSR0A &= ~(1 << U2X0);
#endif

这会设置或清除 U2X0位取决于 setbaud 宏的计算。

此外,我相信你可以删除该行

#define BAUDRATE ((F_CPU)/(BAUD*16UL)-1)

因为这正是 setbaud.h 所做的。

关于c - 了解 ATMEGA168A 下的 UART,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34379332/

相关文章:

C 中的 crc32 计算在 ATMEGA 和 Linux 机器上产生不同的结果

uart - 我正在寻找示例代码以通过 DMA 而不是中断为 MSP430 上的 USCI (UART) 提供服务

c - 一定限度后结果不同

c - 没有系统刷新控制台值 ("cls");

c - 如果 char 按标准为 1,为什么要写 `sizeof(char)`?

c - 使用复合文字初始化指向结构的指针

Codevision AVR 使用 TWI 访问外部 eeprom 24c02B

c - 为什么 AVR-GCC 编译器在乘法后附加 "clr r1"行?

c - PIC 18F46K22,微型 : 'Multitasking' simple and time consuming task

java - PeripherialManager.getInstance() 抛出 java.lang.RuntimeException : Stub