#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
const uint8_t PIN_BTN_UP = PA0;
const uint8_t PIN_BTN_DOWN = PA1;
const uint8_t PIN_LED = PA5;
volatile int counter = 0;
struct ButtonState {
bool stableLevel;
bool lastReading;
uint32_t lastChangeMs;
bool pressedEvent;
};
ButtonState btnUp, btnDown;
const uint32_t DEBOUNCE_MS = 30;
uint32_t lastLedToggleMs = 0;
bool ledState = false;
uint32_t lastLcdUpdateMs = 0;
const uint32_t LCD_UPDATE_MS = 150;
static void initButton(ButtonState &b, bool initialLevel) {
b.stableLevel = initialLevel;
b.lastReading = initialLevel;
b.lastChangeMs = millis();
b.pressedEvent = false;
}
static bool updateButton(ButtonState &b, bool reading, uint32_t nowMs) {
b.pressedEvent = false;
if (reading != b.lastReading) {
b.lastReading = reading;
b.lastChangeMs = nowMs;
}
if ((nowMs - b.lastChangeMs) >= DEBOUNCE_MS) {
if (b.stableLevel != reading) {
bool prev = b.stableLevel;
b.stableLevel = reading;
if (prev == HIGH && b.stableLevel == LOW) {
b.pressedEvent = true;
}
}
}
return b.pressedEvent;
}
static float calcFrequencyHz(int cnt) {
float f = 0.5f + 0.2f * (float)abs(cnt);
if (f > 10.0f) f = 10.0f;
return f;
}
static uint32_t calcHalfPeriodMs(float freqHz) {
float periodMs = 1000.0f / freqHz;
float halfMs = periodMs / 2.0f;
if (halfMs < 20.0f) halfMs = 20.0f;
return (uint32_t)(halfMs + 0.5f);
}
void setup() {
pinMode(PIN_BTN_UP, INPUT_PULLUP);
pinMode(PIN_BTN_DOWN, INPUT_PULLUP);
pinMode(PIN_LED, OUTPUT);
digitalWrite(PIN_LED, LOW);
Wire.begin();
lcd.init();
lcd.backlight();
initButton(btnUp, digitalRead(PIN_BTN_UP));
initButton(btnDown, digitalRead(PIN_BTN_DOWN));
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Counter + Buttons");
lcd.setCursor(0, 1);
lcd.print("Nucleo C031C6");
delay(600);
lcd.clear();
}
void loop() {
uint32_t now = millis();
bool upPressed = updateButton(btnUp, digitalRead(PIN_BTN_UP), now);
bool downPressed = updateButton(btnDown, digitalRead(PIN_BTN_DOWN), now);
if (upPressed) counter++;
if (downPressed) counter--;
float freq = calcFrequencyHz(counter);
uint32_t halfPeriodMs = calcHalfPeriodMs(freq);
if (now - lastLedToggleMs >= halfPeriodMs) {
lastLedToggleMs = now;
ledState = !ledState;
digitalWrite(PIN_LED, ledState ? HIGH : LOW);
}
if (now - lastLcdUpdateMs >= LCD_UPDATE_MS) {
lastLcdUpdateMs = now;
lcd.setCursor(0, 0);
lcd.print("Counter: ");
lcd.setCursor(9, 0);
lcd.print(" ");
lcd.setCursor(9, 0);
lcd.print(counter);
lcd.setCursor(0, 1);
lcd.print("BTN1(UP): ");
lcd.setCursor(10, 1);
lcd.print(btnUp.stableLevel == LOW ? "PRESSED " : "RELEASED");
lcd.setCursor(0, 2);
lcd.print("BTN2(DN): ");
lcd.setCursor(10, 2);
lcd.print(btnDown.stableLevel == LOW ? "PRESSED " : "RELEASED");
lcd.setCursor(0, 3);
lcd.print("LED freq: ");
lcd.setCursor(10, 3);
lcd.print(" ");
lcd.setCursor(10, 3);
lcd.print(freq, 2);
lcd.print(" Hz");
}
}