Прямые манипуляции с портом по какой-то причине выполняются за 300 наносекунд.
У меня есть этот код
#include <Arduino.h>
void setup() {
DDRD = B00001000;
}
void delayNanoSeconds(int time){
int ans = (float)time / 62.5;
for(int i = 0; i < ans; i++){
_NOP();
}
}
#define delay250 _NOP(); _NOP();_NOP(); _NOP();
#define delay1000 delay250 delay250 delay250 delay250
void loop() {
while(1){
PORTD ^= B00001000;
delay1000; delay1000;
}
}
но я получаю задержку 2300 us вот картинка логического анализатора и когда я изменяю задержку на 250 или 1000, я все еще получаю эти дополнительные 300 нс, так почему же
@Abdrlrahman, 👍3
1 ответ
▲ 6
Помните: все, что делает ЦП, требует времени. Вот
разборка вашего loop()
:
ldi r25, 0b00001000 ; r25 = B00001000
1: in r24, PORTD ; r24 = PORTD
eor r24, r25 ; r24 ^= r25
out PORTD, r24 ; PORTD = r24
nop
nop
...
nop
rjmp 1b ; goto previous label 1
Как видите, кроме набора nop
, в
цикл:
in
,eor
иout
занимают по одному циклу каждыйrjmp
занимает два цикла.
Общие накладные расходы составляют 5 циклов ЦП или 312,5 нс при работает на частоте 16 МГц. Довольно близко к тому, что вы видите.
Если вам нужны точные тайминги, вам придется дизассемблировать код и подсчитайте накладные циклы, как я сделал здесь. Тогда я предлагаю это проще подход:
#define OVERHEAD_CYCLES 5
void loop() {
for (;;) {
PORTD ^= _BV(PD3);
_delay_us(2 - OVERHEAD_CYCLES / (F_CPU / 1e6));
}
}
,
@Edgar Bonet
Смотрите также:
- Как использовать SPI на Arduino?
- Как решить проблему «avrdude: stk500_recv(): programmer is not responding»?
- Как создать несколько запущенных потоков?
- Как подключиться к Arduino с помощью WiFi?
- avrdude ser_open() can't set com-state
- Как узнать частоту дискретизации?
- Что такое Serial.begin(9600)?
- Я закирпичил свой Arduino Uno? Проблемы с загрузкой скетчей на плату
Ок спасибо за помощь, @Abdrlrahman
Кстати как вы увидели ассемблерный код, @Abdrlrahman
@Abdrlrahman: «Как вы увидели код сборки»:
avr-objdump -SCz sketch.elf > sketch.lss
. Вы должны увидеть расположение файла ELF, если вы включите подробную компиляцию. Инструмент avr-objdump находится где-то в вашей установке Arduino, но точное местоположение может зависеть от вашей ОС и установленной версии Arduino. Возможно, вам придется поискать его., @Edgar BonetКстати не должно быть
`
_delay_us(2 - OVERHEAD_CYCLES * (F_CPU / 1e6));`
вместо /, @Abdrlrahman@Abdrlrahman: Нет, это действительно разделение. В итоге получается 2 − 5/16,0 = 1,6875 мкс., @Edgar Bonet
2 - OVERHEAD_CYCLES/(F_CPU/1e6)
, конечно, должен оцениваться во время компиляции. Таким образом, 2 нельзя добавить во время выполнения. Интересно, что _delay_us имеет параметр с плавающей точкой, по сравнению сdelayMicroseconds(unsigned int)
в Arduino., @DataFiddler