Почему последовательная связь не работает на 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
Почему самая первая программа в этом вопросе не работает как надо и что нужно в ней изменить, чтобы добиться желаемого поведения?
@Igor Liferenko, 👍0
Обсуждение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
- Почему atmega168/328p начинает перезагружаться?
- Отправка последовательных данных в прерывании
- Последовательная связь ESP8266 с ATMega328P
- Ардуино как ISP с serial monitor для ATmega328
- ATmega328P-PU: программатор не отвечает
- Использование платы Arduino для программирования AVR
- AVRdude неправильно считывает значения байтов предохранителя
- Почему SoftwareSerial не работает как надо на Arduino Pro Mini 3v3?
Как светодиод подключен к 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