Почему моя плата 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
- Как использовать SPI на Arduino?
- Библиотека DHT.h не импортируется
- Светодиоды: разница между общим анодом и общим катодом
- Как повторить кусок кода
- Ошибка компиляции кода для Arduino/Genuino Uno
- Миграция проекта Arduino Uno R3 в Wemos D1 R2 — проблемы с распиновкой
- Почему эта программа на C++ не может прочитать Serial.write() моего arduino?
- Будет ли .ino-скетч ардуино компилироваться непосредственно на GCC-AVR?
Ведут ли себя оба файла одинаково при использовании
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