Плавное включение и отключение кнопкой светодиода

Добрый день!
Помогите доработать программу по плавному включению и отключению светодиода кнопкой. Нажал/отпустил - плавно загорелся, нажал/отпустил - плавно погас.
В приложенном скетче реализовал только плавное загорание. Нажал на кнопку - плавно загорелся и если кнопку держать нажатой, то горит. Если отпустить, то плавно гаснет. Что то упускаю, не могу понять. Занимаюсь не долго, просьба камнями не закидывать. Помогите новичку. Заранее спасибо.

int actLed = 0;
int pinLed = 10;
int pinKey = 2;
int y;

void setup() {
pinMode(pinLed, OUTPUT);
pinMode(pinKey, INPUT);
}
void loop() {
while (1) {
y = digitalRead(pinKey);
if ((y == HIGH) && (actLed < 255)) {
for (actLed = 0; actLed <= 254; actLed += 5) {
analogWrite(pinLed, actLed);
delay(30);
}
}
if ((y == LOW) && (actLed > 0)) {
for (actLed <= 254; actLed >= 0; actLed -= 5) {
analogWrite(pinLed, actLed);
delay(30);
}
}
}
}

читать до посинения

Добрый день!
Помогите доработать программу по плавному включению и отключению светодиода кнопкой. Нажал/отпустил - плавно загорелся, нажал/отпустил - плавно погас.
В приложенном скетче реализовал только плавное загорание. Нажал на кнопку - плавно загорелся и если кнопку держать нажатой, то горит. Если отпустить, то плавно гаснет. Что то упускаю, не могу понять. Занимаюсь не долго, просьба камнями не закидывать. Помогите новичку. Заранее спасибо.

int pinLed = 10;
int pinKey = 2;
int y;

void setup() {
pinMode(pinLed, OUTPUT);
pinMode(pinKey, INPUT);
}
void loop() {
while (1) {
y = digitalRead(pinKey);
if ((y == HIGH) && (actLed < 255)) {
for (actLed = 0; actLed <= 254; actLed += 5) {
analogWrite(pinLed, actLed);
delay(30);
}
}
if ((y == LOW) && (actLed > 0)) {
for (actLed <= 254; actLed >= 0; actLed -= 5) {
analogWrite(pinLed, actLed);
delay(30);
}
}
}
}```

Как раз тема-пример сегодняшнего разговора…
Конечные автоматы - для "школьников". Есть такое? - #100 от пользователя lilik
…надо избавляться от delay() и for(){}

Если кнопка активна высоким уровнем, то надо делать соответствующую схему подключения с подтяжкой к GND.
Или делать INPUT_PULLUP - когда активна низким уровнем
Где ваша схема?

Зачем в одном цикле ещё один? Это лишнее

Так же подправьте скетч, потерялась переменная

Не пойму, какая именно переменная? Я уже запутался.

int actLed при копировании потеряли

Про подключение кнопки смотрим здесь
https://forum.arduino.ru/t/podklyuchenie-knopki-i-schityvanie-nazhatiya-knopki/9413

Спасибо большое. Буду разбираться.

Имхо, пока не тот уровень, уже следующим шагом))

Ну и исходную задачу надо уточнить : кратко нажал- нарастает яркость от текущего значения до 255 или нового текущего, ещё раз кратко нажал - убывает от текущего до 0 (нового текущего). Жать можно ведь не дожидаясь конца разжигания или гашения.

Яркость нарастает от 0. Функционал обычного выключателя. Только включение и отключение диода плавноею а не мгновенное.

Тут очень много чего нужно уточнять: по какому событию (нажатие или отпускание) следует инициализировать процесс, что делать, если кнопку нажали в процессе “включения” или “отключения”, цикл включения/отключения однократный или многократный и т.п. И это даже не говоря о том, что не приведена схема.

а так попробуй


```cpp
int pinLed = 10;
int pinKey = 2;
int y;
bool up_dwn=0;
bool do_=0;
bool dbnc=0;
uint8_t actled=0;

void setup() {
pinMode(pinLed, OUTPUT);
pinMode(pinKey, INPUT_PULLUP);
}
void loop() {

if(!digitalRead(pinKey) && !dbnc){
  dbnc=1;
  do_=1;
  actled<5?up_dwn=1:up_dwn=0;
}

while (do_) {
actled=up_dwn?actled+=5:actled-=5;
analogWrite(pinLed, actled);
if ((actled<=5)||(actled>=250))
{
do_=0;
dbnc=0;
}
delay(30);
}
}

после 19 строки добавить else up_dwn=0;

Да можно безо всяких дребезгов сделать, если цикл включения/выключения будет блокирующим.
Первый же сигнал с кнопки и погнали в цикле.

Спасибо большое!!! Буду пробовать.

Так у него код рабочий, кнопка неправильно подключена

Памогаю, в честь Рождества, ахреневай

Спойлер
// аффтар DtS 07.01.2024

#include <Arduino.h>

using byte		= uint8_t;
using dword		= uint32_t;

enum class TBrightDir : bool { Less  = false, More    = true }; // Направление изменения яркости уменьшать/увеличивать
enum class TKeyState  : bool { KeyUp = false, KeyDown = true }; // Кнопка нажата/отпущена

constexpr byte	PIN_LED_ALIVE		= LED_BUILTIN;	// встроенный светлодиод
constexpr byte	PIN_PWM_LED			= 10;			// PWM выход на светлодиодик
constexpr byte	PIN_KEY				= 2;			// кнопка подключена с этова пина на GND

constexpr byte	PWM_MIN_VALUE		= 0x00;
constexpr byte	PWM_MAX_VALUE		= 0xFF;
constexpr byte	PWM_STEP_VALUE		= 0x05;
constexpr byte	PWM_STEP_TIME		= 50;

constexpr byte	KEY_READ_ATTEMPTS	= 10;
constexpr dword	KEY_READ_INTERVAL	= 100;	// читать кнопку не чаще, миллисекунд

constexpr dword LED_FLASH_TIME		= 500;

constexpr byte ACTIVE_KEY_LEVEL		= LOW;	// кнопка замыкается в на GND


// Globals

TBrightDir	BrightDir		= TBrightDir::More;
byte		CurrentBright	= PWM_MIN_VALUE;
bool		KeyPressed		= false;


// #implementation

static void SetBrightness(const byte APWMPin, const byte APWMValue) {
	analogWrite(APWMPin, APWMValue);

}

static void onKeyPressed() {
	KeyPressed = false;

	if (BrightDir == TBrightDir::More)
		BrightDir = TBrightDir::Less;
	else
		BrightDir = TBrightDir::More;
}

static TKeyState ReadKeyState(const byte AKeyPin) {
	for (byte i = 0; i < KEY_READ_ATTEMPTS; ++i) {
		if (digitalRead(AKeyPin) != ACTIVE_KEY_LEVEL) return TKeyState::KeyUp;
		delay(1);
	}
	return TKeyState::KeyDown;
}

static void ReadKey(const byte AKeyPin) {
	static dword  LastReadTime = 0;
	static TKeyState LastKeyState = TKeyState::KeyUp;  // ненажата

	dword now = millis();
	if (now - LastReadTime < KEY_READ_INTERVAL) return; 

	LastReadTime = now;

	TKeyState state = ReadKeyState(AKeyPin);

	if (LastKeyState == state) return;

	LastKeyState = state;

	KeyPressed = (state == TKeyState::KeyUp);

	if (KeyPressed) onKeyPressed();
}

static byte BrightDown(const byte AValue) {
	if (AValue > PWM_STEP_VALUE)
		return AValue - PWM_STEP_VALUE;
	else
		return PWM_MIN_VALUE;
}

static byte BrightUp(const byte AValue) {
	if (AValue < (PWM_MAX_VALUE - PWM_STEP_VALUE))
		return AValue + PWM_STEP_VALUE;
	else
		return PWM_MAX_VALUE;
}

static void Animate(void) {
	static dword lastAnimatedTime = 0;

	dword now = millis();
	if (now - lastAnimatedTime < PWM_STEP_TIME) return;
	lastAnimatedTime = now;

	if (BrightDir == TBrightDir::Less)
		CurrentBright = BrightDown(CurrentBright);
	else
		CurrentBright = BrightUp(CurrentBright);

	SetBrightness(PIN_PWM_LED, CurrentBright);

}

void setup() {
	pinMode(PIN_LED_ALIVE, OUTPUT);
	pinMode(PIN_PWM_LED, OUTPUT);
	SetBrightness(PIN_PWM_LED, CurrentBright);

	pinMode(PIN_KEY, INPUT_PULLUP);
}

void loop() {
	static dword lastLedFlash = 0;

	ReadKey(PIN_KEY);
	Animate();

	dword now = millis();
	if (now - lastLedFlash < LED_FLASH_TIME) return;  // ну и помигаем 13м светлодиодиком, заадно
	lastLedFlash = now;
	digitalWrite(PIN_LED_ALIVE, !digitalRead(PIN_LED_ALIVE));
}

2 лайка

Простейший вариант, как по мне самый раз для новичков. Без delay(). Serial можно раскомментировать, посмотреть для проверки

Спойлер
int actLed = 0;
int pinLed = 10;
int pinKey = 2;
int y;
unsigned long last_millis = 0;

void setup() {
 // Serial.begin(9600);
  pinMode(pinLed, OUTPUT);
  pinMode(pinKey, INPUT);
}


void loop() {
  if (millis() - last_millis > 5) {
    last_millis = millis();
    y = digitalRead(pinKey);

    if ((y == HIGH) && (actLed < 255)) {  
        actLed += 5;
        analogWrite(pinLed, actLed);
      //  Serial.println(actLed);
    }
    if ((y == LOW) && (actLed >= 5 )) { 
        actLed -= 5;
        analogWrite(pinLed, actLed);
      //  Serial.println(actLed);
    }
  }
}

Проверил в Wokwi, схема подключения кнопки как у ТС

Спойлер

А я - в железе. :upside_down_face:

3 лайка