Понимание UART под ATMEGA168A

Я пытаюсь создать программу C, которая получает символ через UART, «печатает» соответствующий двоичный файл, включая 8 светодиодов на моем макете, и отправляет символ обратно в передатчик.

Вот код, который я использую:

//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 для сравнения. Однако я получаю странные ответы от своего чипа:

введите здесь описание изображения

Мои вопросы относительно UART под ATMEGA168a следующие:

  • При установке F_CPU я должен оставаться с частотой 1 МГц, используемой ATMEGA168a, или мне нужно использовать частоту моего передатчика (Intel i7)? Может ли это быть проблемой?
  • Когда UDR0 «обновляется»? Всякий раз, когда я нажимаю клавишу ввода, чтобы отправить символ на чип через терминал?
  • Что может быть причиной этой проблемы?

person Bob    schedule 20.12.2015    source источник


Ответы (1)


В функции uart_init() вы устанавливаете биты с 7:6 по 10, что является зарезервированным состоянием согласно руководству ATMega 168A. Чтобы получить желаемую функциональность асинхронного UART, установите для них значение 00:

UCSR0C = 0b00000110;

Другой причиной, по которой ваш пример не работал, были настройки скорости передачи, как объясняется в моем комментарии ниже.

Вы уже включили заголовочный файл <util/setbaud.h>, который содержит макросы, облегчающие настройку UART. См. документацию здесь. Эти макросы принимают ввод, предоставленный вами в F_CPU и BAUDRATE, и вычисляют настройки для регистров конфигурации UART (UBRRH_VALUE и UBRRL_VALUE).

Вы использовали его почти правильно, однако, чтобы воспользоваться функцией удвоения скорости передачи данных UART ATmega, добавьте следующий код после установки значения UBRR0H/L:

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

Это устанавливает или очищает бит U2X0 в зависимости от вычислений макросов setbaud.

Кроме того, я считаю, что вы можете удалить строку

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

потому что это именно то, что делает setbaud.h.

person Joe Zocker    schedule 20.12.2015
comment
Только что заметил еще одну вещь: вы используете тактовую частоту процессора 1 МГц и скорость передачи 9600 бод. Согласно таблице 20-4 на странице 187 руководство дает погрешность синхронизации -7,0%. Это может быть проблемой, так что, может быть, попробовать другую скорость передачи данных? - person Joe Zocker; 20.12.2015
comment
Спасибо, Джо. Если я ставлю скорость 1200, все работает отлично. Можно ли работать с более высокими значениями скорости? - person Bob; 21.12.2015
comment
Лучше всего было бы использовать кварцевый генератор с частотой выше 1 МГц, если это возможно. Другой способ — установить бит U2X0 в 1, что удваивает скорость передачи UART. Я обновлю свой ответ соответственно. - person Joe Zocker; 21.12.2015
comment
Вы можете достичь 9600 бод с кварцем 1 МГц, используя бит U2X0. - person Joe Zocker; 21.12.2015