Почему последовательная связь не работает на atmega168/328p?

Я ожидаю, что следующая программа serial.c зажжет светодиод, если я отправлю ключ 1 с терминала, и зажжет светодиод, когда я отправлю ключ 0 с терминала:

#define F_CPU 16000000UL
#define BAUD 9600
#include <avr/io.h>
char data;
void main(void) {
  #include <util/setbaud.h> 
  UBRR0H = UBRRH_VALUE;
  UBRR0L = UBRRL_VALUE;
  UCSR0B |= (1<<RXEN0);
  UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);
  DDRB |= (1<<PB1);
  while(1) {
    while(!(UCSR0A&(1<<RXC0)));
    data = UDR0;
    if (data=='0') PORTB &= ~(1<<PB1);
    if (data=='1') PORTB |= (1<<PB1);
  }
}

Для компиляции и записи всех программ я использую следующие команды:

avr-gcc -Os -mmcu=atmega328p -c -o serial.o serial.c
avr-ld -o serial.elf serial.o
avr-objcopy -O ihex serial.elf serial.hex
avrdude -c usbasp -p atmega328p -U flash:w:serial.hex

Вывод avrdude следующий:

$ avrdude -c usbasp -p atmega328p -U flash:w:serial.hex

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e950f
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "serial.hex"
avrdude: input file serial.hex auto detected as Intel Hex
avrdude: writing flash (12 bytes):

Writing | ################################################## | 100% 0.03s

avrdude: 12 bytes of flash written
avrdude: verifying flash memory against serial.hex:
avrdude: load data flash data from input file serial.hex:
avrdude: input file serial.hex auto detected as Intel Hex
avrdude: input file serial.hex contains 12 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.02s

avrdude: verifying ...
avrdude: 12 bytes of flash verified

avrdude: safemode: Fuses OK (E:07, H:DE, L:FF)

avrdude done.  Thank you.

Для последовательного подключения я пробовал переходники usb-com PL2302 и FT232RL - эффект всегда один и тот же.

Настройки терминала на компьютере правильные (9600,8N1).

avr-gcc версии 4.8.1 версия 6.1

Почему самая первая программа в этом вопросе не работает как надо и что нужно в ней изменить, чтобы добиться желаемого поведения?

, 👍0

Обсуждение

Как светодиод подключен к ATMega?, @Majenko

@Majenko: один светодиод встроен от платы arduino duemilanove (PB5), другой - обычный светодиод, напрямую подключенный к GND и PB1., @Igor Liferenko

Значит, на светодиоде PB1 нет резистора?, @Majenko

@Majenko: без резистора. Я попробую с 270 Ом между GND и светодиодом (правильно?) и сообщу через минуту ...., @Igor Liferenko

Да, вы делаете это. 270 Ом должно быть в порядке., @Majenko

Кроме того, у вас установлен загрузчик Arduino на этом чипе?, @Majenko

@Majenko: Нет, так как в настройках предохранителей у меня включен BOOTRST., @Igor Liferenko

@Majenko: С резистором странное мигание исчезло., @Igor Liferenko

Итак, проблема решена: один светодиод, скорее всего, вызывал срабатывание детектора отключения и сброс микросхемы. Теперь мы можем решить проблему с вашим кодом. Я предлагаю вам обновить свой вопрос, теперь мигание больше не является проблемой, поэтому ответы могут быть сосредоточены на проблеме с программным обеспечением., @Majenko

@Majenko: Я обновлю вопрос через мгновение ... Непонятно насчет детектора Браунаута - он у меня полностью отключен в предохранителях. И откуда вообще могла появиться эта проблема с напряжением? 5V обеспечивает ПК., @Igor Liferenko

Но светодиод имеет фиксированное прямое напряжение, скажем, 2 В. При отсутствии сопротивления ток, потребляемый светодиодом, теоретически бесконечен. Это может вызвать всевозможные проблемы, в том числе падение напряжения питания и общие сбои и сбросы даже при отключенном отключении питания. При его включении он просто перезагружается чисто. Когда он отключен, он просто беспорядочно падает. Хорошей новостью является то, что я могу воспроизвести симптомы вашего первого фрагмента кода на моем Uno, поэтому я могу диагностировать проблему сейчас., @Majenko


1 ответ


Лучший ответ:

1

Ваша проблема заключается в том, что ваша скорость передачи данных установлена неправильно.

У вас есть только часть необходимых вам настроек. В файле setbaud.h есть третий макрос, который необходимо учитывать: USE_U2X.

Это определяет, нужно ли вам устанавливать или очищать бит U2X0 UCSRA0. Если это установлено неправильно, ваша скорость передачи данных будет либо вдвое, либо в два раза меньше, чем вы хотите, в этом случае она выходит вдвое.

Измените свой код, чтобы назначить скорость передачи следующим образом:

#include <util/setbaud.h> 
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#if USE_U2X
UCSR0A |= (1<<U2X0);
#else
UCSR0A &= ~(1<<U2X0);
#endif
UCSR0B |= (1<<RXEN0);
UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);

Тогда вы сможете получать символы.

В самом рассматриваемом заголовочном файле есть большое количество комментариев и инструкций, в том числе это:

Предполагая, что запрошенный BAUD действителен для данного F_CPU, тогда макрос UBRR_VALUE устанавливается на требуемое значение предделителя. Два дополнительные макросы предусмотрены для младшего и старшего байтов прескалера, соответственно: UBRRL_VALUE устанавливается равным младшему байту UBRR_VALUE и UBRRH_VALUE устанавливаются на старший байт. Ан будет определен дополнительный макрос USE_2X. Его значение равно 1, если желаемая скорость BAUD в пределах заданного допуска может быть только достигается установкой бита U2X в конфигурации UART. Это будет быть определено равным 0, если U2X не требуется.

Моя результирующая конфигурация UART, на которую может повлиять загрузчик, выглядит следующим образом:

UBRR0H: 0x00
UBRR0L: 0x67
UCSR0A: 0x20
UCSR0B: 0x10
UCSR0C: 0x06

Это соответствует пустому регистру данных, RX включен, 8-битному.

На мой взгляд, это эквивалентно значениям, устанавливаемым вручную в коде, так что проблем быть не должно.

,

Нет, это ничего не меняет - все равно программа работает не так, как надо. При F_CPU = 16MHz и BAUD = 9600 настройка U2X0 остается в значении по умолчанию (я уже проверял это раньше)., @Igor Liferenko

Тогда должно быть что-то еще, не связанное с этим, что мешает ему работать. Этот код работает, я тестировал его на Uno., @Majenko

Что бы это могло быть? Я всю неделю с этим боролся..., @Igor Liferenko

Кстати, вы сказали, что у вас не установлен загрузчик, потому что у вас включен BOOTRST? При включенном BOOTRST (hf=0xDE) вы загружаетесь в загрузчик. Когда он выключен (hf=0xDF), вы загружаетесь в свой код., @Majenko

Если он «включен» (=0), вы загружаете загрузчик. Если он отключен (=1), вы загружаете свой код. Убедитесь, что вы установили его правильно, если у вас не установлен загрузчик., @Majenko

О, и на моем Uno, который похож на вашу настройку 16 МГц, мне *пришлось* добавить код U2X, чтобы заставить его работать - бит по умолчанию находился в *неправильном* состоянии для 9600 бод., @Majenko

Конечно, BOOTRST должен быть отключен. Их терминология enable/disabled = 0/1 совершенно сбивает с толку... Я поменяю предохранитель и через минуту доложу..., @Igor Liferenko

Это не их "конвенция" - это нормально. Это все связано с тем фактом, что незапрограммированная ячейка флэш-памяти имеет значение 0xFF, а не 0x00, поэтому они отображают значения по умолчанию как 1, а не по умолчанию — как 0. Таким образом, он может работать прямо с завода без необходимости иметь любые биты предохранителей изменены вручную., @Majenko

Возможно, тот факт, что я использую загрузчик, оставляет какое-то значение в другом состоянии, которое вам нужно изменить. Я просто распечатаю значения регистров... одну секунду..., @Majenko

Мне очень любопытно, в чем проблема... Мне все равно ничего не понятно..., @Igor Liferenko

@IgorLiferenko Вам нужно отключить сторожевой таймер, и единственный способ, который я нашел, чтобы сделать это надежно, — это использовать функции в avr/wdt.h — сторожевой таймер — это правильная боль, и от него может быть трудно избавиться, когда вы этого не сделаете. не хочу - загрузчик обычно отключает его для вас, поэтому раньше я не видел проблемы., @Majenko

Никак не могу его отключить - в фьюзах он отключен и wdt_disable(); не помогает. Я хотел бы использовать загрузчик, чтобы он делал необходимые сбросы. Изменится ли что-нибудь в моем рабочем процессе компиляции-прожига, описанном выше, если я буду использовать загрузчик? (например, записывать мои программы через ICSP, а не через загрузчик). Ответ должен быть отредактирован с этой информацией, поскольку он относится к основной проблеме., @Igor Liferenko

После срабатывания WDT практически невозможно выключить его, за исключением отключения питания. После того, как он выключен, он больше не сработает, поэтому не застрянет в этом состоянии. Единственная разница для использования загрузчика с ICSP заключается в том, чтобы убедиться, что вы не стираете загрузчик при программировании чипа, что означает использование флага -D для отключения стирания чипа., @Majenko

Я нашел решение - см. http://arduinoprosto.ru/q/17585/what-makes-the-watchdog-timer-start-on-atmega168-328p/17614#17614, @Igor Liferenko