Стандартная функция _delay_ms() использует циклы, которые считают такты. Но она блокирует процессор и не позволяет делать ничего другого.
Хак: Используем прерывания таймера для создания неблокирующих задержек.
Код на ассемблере для таймера 0:
#define __SFR_OFFSET 0x00
#include <avr/io.h>
.global timer0_init
.global timer0_reset
timer0_ms_counter: .byte 1
timer0_init:
; Настраиваем таймер 0 на прерывание каждые 1 мс
LDI R16, 249 ; OCR0A = 249 (16 МГц / 64 / 250 = 1000 Гц)
OUT OCR0A, R16
LDI R16, (1 << WGM01) ; Режим CTC
OUT TCCR0A, R16
LDI R16, (1 << CS01) | (1 << CS00) ; Прескалер 64
OUT TCCR0B, R16
LDI R16, (1 << OCIE0A) ; Включаем прерывание по совпадению
OUT TIMSK0, R16
CLR R16
STS timer0_ms_counter, R16
RET
; Обработчик прерывания TIMER0_COMPA_vect
.global __vector_TIMER0_COMPA
__vector_TIMER0_COMPA:
PUSH R16
LDS R16, timer0_ms_counter
INC R16
STS timer0_ms_counter, R16
POP R16
RETI
timer0_reset:
CLR R16
STS timer0_ms_counter, R16
RET
; Функция получения миллисекунд
.global timer0_get_ms
timer0_get_ms:
LDS R16, timer0_ms_counter
RET
Использование в C++:
extern "C" {
void timer0_init();
void timer0_reset();
uint8_t timer0_get_ms();
}
void setup() {
Serial.begin(115200);
timer0_init();
sei();
timer0_reset();
}
void loop() {
if (timer0_get_ms() >= 1000) {
Serial.println("Прошла 1 секунда!");
timer0_reset();
}
// CPU свободен для других задач!
}