ESP8266 jak zliczać impulsy zewnętrzne timerem program w arduino
attachInterrupt()
),Kluczowe punkty
• attachInterrupt()
= łatwe, dowolny pin, ale ograniczona prędkość.
• TIMER0 = brak obciążenia CPU, wysoka częstotliwość, tylko GPIO0 i konfiguracja rejestrów.
• Piny specjalne (GPIO0/2/15) muszą mieć poprawny stan podczas resetu.
• Debouncing i separacja galwaniczna – zależnie od źródła impulsów.
const uint8_t PULSE_PIN = D2; // dowolny pin wspierający IRQ
volatile uint32_t pulseCnt = 0;
IRAM_ATTR void onPulse() { pulseCnt++; }
void setup() {
Serial.begin(115200);
pinMode(PULSE_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(PULSE_PIN), onPulse, RISING); // lub FALLING/CHANGE
}
void loop() {
static uint32_t last = 0;
noInterrupts(); uint32_t v = pulseCnt; interrupts();
if (millis() - last >= 1000) {
Serial.printf("Impulsy/s: %u\n", v);
noInterrupts(); pulseCnt = 0; interrupts();
last = millis();
}
}
• Czas ISR < 3 µs → do ok. 30 kHz.
• W ISR unikaj Serial
, delay()
, dynamicznej alokacji.
• Gdy źródłem jest przycisk – wstaw filtr RC lub programowy debouncing (np. minimalny odstęp > x ms
).
TIMER0 potrafi liczyć impulsy bez udziału CPU. Arduino-core go nie używa, dlatego można go skonfigurować bez konfliktów. Wejście licznika przydzielone jest na GPIO0, który podczas bootu musi być w stanie HIGH.
Minimalny, praktyczny kod:
#include <Arduino.h>
#define REG_T0_LOAD (*(volatile uint32_t*)0x60000600)
#define REG_T0_COUNT (*(volatile uint32_t*)0x60000604)
#define REG_T0_CTRL (*(volatile uint32_t*)0x60000608)
#define T0_CTRL_EN (1U << 31)
#define T0_CTRL_AUTOREL (1U << 30)
#define T0_CTRL_DIV1 (0U << 16) // dzielnik 1 => każdy impuls
void setup() {
Serial.begin(115200);
// 1. GPIO0 jako T0CKI
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, 1); // funkcja 1 = CLK_OUT1/T0CKI
pinMode(0, INPUT_PULLUP); // pull-up dla poprawnego bootu
// 2. konfiguracja timera
REG_T0_LOAD = 0; // licz od zera w górę
REG_T0_CTRL = T0_CTRL_EN | T0_CTRL_AUTOREL | T0_CTRL_DIV1;
}
void loop() {
static uint32_t prev = 0, tPrev = 0;
uint32_t now = REG_T0_COUNT;
if (millis() - tPrev >= 1000) { // co sekundę
Serial.printf("Impulsy/s: %u\n", now - prev);
prev = now;
tPrev = millis();
}
}
• Zdolność zliczania: > 2 MHz (ograniczenie elektryczne wejścia).
• Brak ISR ⇒ rdzeń Wi-Fi / TCP nie jest zakłócany.
• W razie potrzeby restart licznika: wyłącz timer, zapisz REG_T0_LOAD = 0
, ponownie włącz.
Jeśli używasz przerwań GPIO, możesz dodać soft-timer (Ticker
, ESP8266TimerInterrupt
) który raz na N ms odczyta i wyzeruje pulseCnt
– otrzymasz próbkowanie częstotliwości bez blokowania pętli.
Sygnały z czujników mechanicznych:
• RC 1 kΩ + 100 nF,
• Schmitt-trigger (74HC14),
• opto-izolacja w środowisku wysokoszumowym.
volatile
– kompilator nie buforuje zmiennej modyfikowanej w ISR. IRAM_ATTR
(nowe core) = ICACHE_RAM_ATTR
(stare core) – przenosi kod ISR do RAM (czas dostępu). Serial.print()
w ISR. Zliczanie impulsów w ESP8266:
Wybierz metodę adekwatną do częstotliwości, liczby dostępnych pinów oraz wymagań niezawodności programu.