Регистр UDR всегда читает 0xFF - PullRequest
0 голосов
/ 04 августа 2020

У меня есть ATTiny, который должен получать команды через UART. У меня есть простой дисплей из восьми светодиодов, который должен показывать содержимое самого последнего полученного байта. Я использую прерывание для чтения данных по мере их получения. Независимо от того, какие данные я отправляю, UDR всегда читает 0xFF в прерывании. Я знаю, что прерывание запускается, так как дисплей меняется с 0x00 на 0xFF, но он никогда не отображает значение, которое я отправил по последовательной шине.

Вот как я включаю UART.

UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;

#if USE_2X
UCSRA |= (1U << U2X);
#else
UCSRA &= ~(1U << U2X);
#endif

// Enable receiver and interrupt
UCSRB = (1U << RXEN) | (1U << RXCIE);

// No parity, 8 Data Bits, 1 Stop Bit
UCSRC = (1U << UCSZ1) | (1U << UCSZ0);

Это код в прерывании. Я протестировал display(), и он работает правильно сам по себе, что означает, что message всегда 0xFF.

ISR(USART_RXC_vect) {
    uint8_t message = UDR;
    display(message);
}

Я уверен, что мой компьютер отправляет правильную информацию, но я только проверил это с псевдотерминалом для распечатки отправленных байтов. Я собираюсь sn oop аппаратное соединение с осциллографом, но не думаю, что это проблема. Есть ли что-то, из-за чего UDR всегда читается как 0xFF?

Изменить: я отслеживал соединение с помощью осциллографа и проверял, что компьютер отправляет правильные данные с правильной скоростью. Однако ATTiny не работает с правильной скоростью передачи данных. При скорости 2400 бод импульсы должны быть длиной около 400 микросекунд, однако микроконтроллер выдает импульсы длительностью более 3 миллисекунд. Это объясняет, почему он всегда будет читать 0xFF, компьютер будет отправлять почти весь байт, когда контроллер думает, что он получает стартовый бит, когда контроллер пытается прочитать оставшиеся данные, строки будут отключены, в результате чего он прочитает все. Я до сих пор не знаю, почему это так, поскольку считаю, что правильно устанавливаю скорость передачи данных на контроллере.

Изменить: проблема решена. По умолчанию предварительный делитель тактовой частоты установлен на 8, поэтому устройство работало только на 1 МГц, а не на 8 МГц. Установка предделителя часов на 1 решила проблему.

1 Ответ

1 голос
/ 04 августа 2020

Может быть несколько проблем со связью по uart. Сначала проверьте некоторые вещи:

  1. Контроллер настроен на правильные часы?
    • Внутренний / Внешний
    • Определен ли F_CPU для ?
    • Определяется ли BAUD для ?
    • Используете ли вы контроллер, такой как ATmega16, со специальным доступом к регистрам?
    • Если вы используете внешние часы (которые не должны быть разделены), отключен ли CKDIV8 в FUSES или в специальных регистрах в некоторые контроллеры?
  2. Is:
    • Скорость передачи,
    • Paritybit,
    • Коррекция установки стопового бита на передатчике и приемнике

Отладка:

  • Если вы используете P C для связи, создайте петлю на адаптере UART и проверьте с помощью терминала (TeraTerm, Putty , ...), если сообщения, которые вы отправляете, получены правильно.
  • Вы также можете включить контроллер TX и проверить, работает ли loopback на вашем u C.
  • Если это возможно попробуйте записать полученные данные на несколько светодиодов, чтобы проверить, получена ли какая-то дата
  • Подключено ли заземление между приемником и передатчиком?
  • Одинаковы ли уровни напряжения между передатчиком и приемником?
  • У передатчика и записи у кого есть собственный источник? (Тогда не подключайте V CC!)
  • Проверьте правильность часов на контроллере (включите светодиод с функцией _delay_ms() каждую секунду)

Пример программы

#define F_CPU 12000000UL
#define BAUD 9600UL

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

ISR(USART_RXC_vect)
{
    volatile unsigned char message = UDR;
    
    // If it is possible try to write the received data to
    // LEDs (if there are some at your board)
    
    display(message);
}

int main()
{
    // To allow changes to clock prescaler it is necessary to set the
    // CCP register (Datasheet page 23)!
    CCP = 0xD8;

    // RESET the clock prescaler from /8 to /1 !!!!
    // Or it is necessary to divide F_CPU through the CLK_PRESCALER 
    CLKPSR = 0x00;

    UBRRH = UBRRH_VALUE;
    UBRRL = UBRRL_VALUE;

    #if USE_2X
        UCSRA |= (1<<U2X);
    #else
        UCSRA &= ~(1<<U2X);
    #endif

    // Enable receiver and interrupt
    UCSRB = (1U << RXEN) | (1U << RXCIE);

    // No parity, 8 Data Bits, 1 Stop Bit
    
    // Not necessary! Mostly ATmega controller
    // have 8 bit mode initialized at startup
    //UCSRC = (1U << UCSZ1) | (1U << UCSZ0);
    
    // If you are using ATmega8/16 it is necessary to do some
    // special things to write to the UBRRH and UCSRC register!
    // See ATmega16 datasheet at page 162
    
    // Do not forget to enable interrupts globally!
    sei();
    
    while(1);
}

Пожалуйста, объясните, что делает функция display() ...

...