Почему моя плата arduino не мигает должным образом?
У меня есть два файла
blink1.cpp
typedef unsigned char int8_t;
typedef volatile int8_t * volatile port_type;
port_type portB = (port_type) 0x25;
port_type ddrB = (port_type) 0x24;
void delay_500ms()
{
asm (
// 8000000 циклов
"ldi r19, 150 \n\t"
"ldi r20, 128 \n\t"
"ldi r23, 41 \n\t"
"L1: \n\t"
"dec r20 \n\t"
"brne L1 \n\t"
"dec r19 \n\t"
"brne L1 \n\t"
"dec r23 \n\t"
"brne L1 \n\t"
);
}
int main()
{
ddrB = (port_type) 0x20;
while(true)
{
*portB = (int8_t) 0x20;
delay_500ms();
*portB = (int8_t) 0x00;
delay_500ms();
}
}

blink2.cpp
typedef unsigned char int8_t;
typedef volatile int8_t * volatile port_type;
port_type portB = (port_type) 0x25;
port_type ddrB = (port_type) 0x24;
port_type portC = (port_type) 0x28;
port_type ddrC = (port_type) 0x27;
port_type portD = (port_type) 0x2B;
port_type ddrD = (port_type) 0x2A;
void delay_500ms()
{
asm (
// 8000000 циклов
"ldi r19, 150 \n\t"
"ldi r20, 128 \n\t"
"ldi r23, 41 \n\t"
"L1: \n\t"
"dec r20 \n\t"
"brne L1 \n\t"
"dec r19 \n\t"
"brne L1 \n\t"
"dec r23 \n\t"
"brne L1 \n\t"
);
}
int main()
{
ddrB = (port_type) 0x20;
while(true)
{
*portB = (int8_t) 0x20;
delay_500ms();
*portB = (int8_t) 0x00;
delay_500ms();
}
}

Разница между этими двумя файлами заключается в определении только нескольких неиспользуемых портов в blink2.
Я компилирую и загружаю их на плату
avr-g++ blink1.cpp -o blink1
avr-objcopy -O ihex -R .eeprom blink1 blink1.hex
avrdude -F -V -c arduino -p ATMEGA328P -P /dev/ttyUSB0 -b 115200 -U flash:w:blink1.hex
avr-g++ blink2.cpp -o blink2
avr-objcopy -O ihex -R .eeprom blink2 blink2.hex
avrdude -F -V -c arduino -p ATMEGA328P -P /dev/ttyUSB0 -b 115200 -U flash:w:blink2.hex
Первый не моргает должным образом, но второй делает это. В чем проблема первого кода?
@ar2015, 👍1
Обсуждение1 ответ
Лучший ответ:
Здесь есть несколько проблем.
Один из них уже был поднят в комментарии:
int main()
{
- ddrB = (port_type) 0x20;
+ *ddrB = (int8_t) 0x20;
while(true)
{
Более серьезная проблема связана с командной строкой, которую вы использовали для компиляции
программы. При компиляции для Uno вы должны добавить следующую опцию
-mmcu=atmega328p. Таким образом, компилятор знает, какую версию
среды выполнения C он должен добавить в вашу программу. В противном случае компилятор
вообще не будет включать время выполнения.
Среда выполнения C выполняет некоторые важные инициализации. Например, он
очищает регистр r1, который требуется ABI, и принимает
чтобы быть таковым со стороны компилятора. Например, когда вы пишете *portB = (int8_t) 0x00;, компилятор копирует r1 в порт, предварительно
не очищая его. Еще одна важная роль среды выполнения C заключается в вызове
main(). Без него программа начнет выполнять любую
функцию, которая окажется в начале флэш. Если вы не программируете в
сборке, вы не можете контролировать это. Если первой функцией
является main(), программа может работать так, как ожидалось. Если это другая
функция, то эта функция может затем вернуться в загрузчик. Любое, казалось
бы, безобидное изменение в программе может затем изменить поведение.
Затем несколько незначительных проблем, которые не должны мешать работе программы :
int8_tдолжен быть подписанным типом. Если вам нужна unsigned версия, используйтевместо нее uint8_t. Конечно, это ваши собственные определения типов, но создание типа, который конфликтует со стандартным типом , может только создать путаницу. Лучший вариант-отбросить определение и включитьвместо него <stdint.h><stdint.h>.В то
времякак port_type, безусловно, должен быть “указателем на изменчивые” данные, нет никакого смысла делать сам указатель изменчивым. Это может только помешать правильной оптимизации.portBиddrBдолжны бытьconst, и это может позволить компилятору лучше оптимизировать их. Но почему бы не использоватьPORTBиDDRBиз<avr/io.h>?
Я подтверждаю, что использование "avr-g++ -mmcu=atmega328p` вместо" avr-g++ " устранило проблему. Огромное спасибо., @ar2015
- Почему использование serial.readBytes увеличивает размер программы на 10 КБ?
- Как использовать SPI на Arduino?
- Библиотека DHT.h не импортируется
- Светодиоды: разница между общим анодом и общим катодом
- Как повторить кусок кода
- Как работают прерывания на Arduino Uno и аналогичных платах?
- Ошибка компиляции кода для Arduino/Genuino Uno
- Миграция проекта Arduino Uno R3 в Wemos D1 R2 — проблемы с распиновкой
Ведут ли себя оба файла одинаково при использовании
avr-g++ -Os blink1/2.cpp -o мигнуть 1/2для компиляции?, @Maximilian Gerhardt@MaximilianGerhardt, используя "- Os", оба действуют как и раньше., @ar2015
Я думаю, что "ddrB = (тип порта) 0x20;
должно быть" *ddrB = (int8_t) 0x20;нет?, @Maximilian Gerhardt@MaximilianGerhardt, Вы правы. Однако это исправление ничего не меняет. Поведение платы сильно зависит от переменной, которую вы определяете после ddrB, и ее значения., @ar2015
@MaximilianGerhardt, интересно, что когда я использую
*ddrB = (int8_t) 0x20;с-Os " индикатор включается, но не мигает. Если я не использую " - Os, он будет нормально мигать., @ar2015Возможно, вы уничтожаете содержимое используемых регистров. Проверьте разборку, чтобы увидеть, перемещаются ли регистры, которые вы используете в сборке, в стек перед использованием и отключаются после - если это не так, то вам следует сделать это вручную., @Majenko
https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Clobbers-and-Scratch-Registers, @Mat
Возможно, вы захотите обменять код сборки на код C для теста и посмотреть, в чем проблема, например, с кодом https://pastebin.com/Z5m2fvWt, @Maximilian Gerhardt
@MaximilianGerhardt: Ваша "задержка_500ms ()" более чем на порядок медленнее, чем оригинал., @Edgar Bonet