Маленькая проблемка

Xtro
Xtro аватар
Offline
Зарегистрирован: 26.09.2017

Здравствуйте, уважаемые завсегдатаи данного форума.

Имеется достаточно простой код в котором при нажатии кнопки светодиод плавно загорается, а при отпускании так же плавно гаснет...

[code]


#define button1 3
#define led1 0

uint8_t light1;
uint32_t time;

int buttonState;   // переменная для хранения состояния кнопки

void setup() {
  pinMode(button1, INPUT);  //настариваем пин кнопки на вход
  pinMode(led1, OUTPUT);   //настариваем пин светодиода на выход

}

void loop() {
  buttonState = digitalRead(button1);// считываем значения с входа кнопки

  if (millis() - time >= 30) {
    if (buttonState == LOW )time = millis();

    if (buttonState == LOW  && light1 < 155) light1++;
    if (buttonState == HIGH  && light1 > 0) light1--;

    time = millis();

  }
  analogWrite(led1, light1);
}

[/code]

Пытаюсь реализовать следующее: при нажатии кнопки светодиод плавно загорается, при отпускании плавно гаснет, но если кнопка находится в нажатом состоянии более 60 сек, светодиод должен также плавно погаснуть...а вот с этим проблема...

По сути...если таймер истек а светодиод горит - гасим светодиод

if ((millis() - time > время_ожидания) && светодиод_горит) гасим_светодиод ;

Но что-то не так...

Проконсультируйте пожалуйста...

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Дед Пи Xtro, а вы в курсе что слона надо есть по кусочку, а не кидать его целиком в костер, потому что так "просто готовить". 

ПС: Не гонялся бы ты поп за простотой кода? 

VasiliyV
Offline
Зарегистрирован: 09.07.2018

А Вы всегда предоставляете полномочия компилятору самому устанавливать значения переменным? Я про переменные time, light1...

Ещё. При нажатии кнопки на пине 3 что? Единичка или нолик? Шарада....

Что делать программе если 

 
24

    if (buttonState == LOW  && light1 >= 155) ?????; 

 

Xtro
Xtro аватар
Offline
Зарегистрирован: 26.09.2017

Приветствую, уважаемуй gwone!

Да и я вот тоже подумал...не столь простой код тут должен быть...

К стати...очень понравился Ваш шаблон с millis...

 

Xtro
Xtro аватар
Offline
Зарегистрирован: 26.09.2017

Вообще light >= 155 не рассматривается...

Можно написать light < 255

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Так шаблон с millis() это так один из краеугольных камней. У вас в задаче два объекта светодиод с 4-мя состояниями (не горит,горит,плавно разгарается и плавно гаснет) и обработчик кнопки с в вызовом 3 обработчиков (только что нажато, только что отжато и нажато 60 секунд). Все. Через классы и цифровой автомат решается в два тычка простым кодом, но уровнем повыше Ардуино простого стиля.

Xtro
Xtro аватар
Offline
Зарегистрирован: 26.09.2017

qwone пишет:

... Через классы и цифровой автомат решается в два тычка простым кодом, но уровнем повыше Ардуино простого стиля.

Я давно заметил Вашу приверженность к классам...

Буду подробно изучать...

Спасибо...

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Это как переходит от простой математики к уравнением с иксами. Сначало немного перестроить мышление, а потом при решение идет автоматом.

ПС: Разумеется потом надо изучать глубже математику. Но тогда и проще решать более сложные задачи.

Xtro
Xtro аватар
Offline
Зарегистрирован: 26.09.2017

Еще раз спасибо...за направление.

Araris
Offline
Зарегистрирован: 09.11.2012

"На большинстве плат Arduino (на базе микроконтроллеров ATmega168 или ATmega328) функция analogWrite() работает с выводами 3, 5, 6, 9, 10 и 11. На Arduino Mega функция работает с выводами со 2 по 13. На более старых версиях Arduino (на базе микроконтроллера ATmega8) функция analogWrite() работает только с выводами 9, 10 и 11.

Arduino Due поддерживает функцию analogWrite() для выводов со 2 по 13, а также для выводов DAC0 и DAC1. В отличие от ШИМ-выводов, DAC0 и DAC1 являются выводам цифро-аналоговых преобразователей, поэтому при вызове analogWrite() ведут себя как обычные аналоговые выходы.

При работе с analogWrite() предварительный вызов функции pinMode() для переключения выводов в режим «выход» не требуется."

       А Вы пытаетесь управлять яркостью светодиода на нулевом пине:   #define led1 0

Xtro
Xtro аватар
Offline
Зарегистрирован: 26.09.2017

Уважаемый Araris...
Это не ардуино...это просто МК...

b707
Offline
Зарегистрирован: 26.05.2017

Xtro пишет:
Уважаемый Araris... Это не ардуино...это просто МК...

какой?

Xtro
Xtro аватар
Offline
Зарегистрирован: 26.09.2017

Да Тинька маааленькая...13-я...

Araris
Offline
Зарегистрирован: 09.11.2012

Xtro пишет:
Уважаемый Araris... Это не ардуино...это просто МК...

Извините, не знал.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Xtro, ну для начала просто бы подчистить код: что light1 и time неплохо бы проинициализировать (хотя бы нулем), Вам уже написали. Нет, работать будет и так, но небрежный стиль программирования приводит к массе глупых ошибок, поэтому лучше инициализацией переменных не пренебрегать даже в том случае, когда она вроде бы и не нужна. Далее: buttonState присваивается первой же строкой loop, поэтому делать ее глобальной нет абсолютно никакого смысла. При наличии строки 27 строка 22 не нужна абсолютно.

Теперь, собственно, о Вашей хотелке. Пока Ваш код опирается исключительно на текущее состояние устройств ввода, а Вы хотите/, чтобы он обладал некоторой памятью, например, отслеживал интервалы времени. Это - классический случай задачи, которая решается конечным автоматом. Т.е. считаем, что система может находиться в одном из нескольких состояний. Например, таких:

0 - начальное состояние (кнопка отпущена, светодиод не горит),

1 - кнопка нажата, светодиод увеличивает яркость,

2 - кнопка отпущена, светодиод уменьшает яркость,

3 - кнопка нажата, светодиод горит с максмиальной яркостью, но время свечения еще не истекло,

4 - кнопка нажата, но светодиод уменьшает яркость по таймауту,

5 - кнопка нажата, но светодиод не горит,

...

Для описания состояния, естественно нужна переменная. Ну а еще пара переменных для отслеживания времени и яркости светодиода у Вакс уже есть.

Теперь нужно сообразить, из каких состояний возможны переходы в какие другие состояния (например, из состояния 1 может быть переход в состояния 2 или 3, но не может быть - в 0, 4 или 5), и какие действия нужно выполнить при этих переходах, а также в самих состояниях (реально действия нужны только в состояниях 1, 2 и 4 - где меняется яркость светодиода). И описать все эти переходы в своей программе.

Но, тут возникнет еще одна проблема: коль скоро Вы перейдете от реакции на текущее состояние устройств ввода на реакцию по изменению состояния, перед вами, вероятно, встанет проблема дребезга контактов, - к этому тоже надо быть готовым.

Xtro
Xtro аватар
Offline
Зарегистрирован: 26.09.2017

Да, уважаемый andriano, код не причесаный...просто для того, чтобы показать саму идею...
Есть несколько вариантов...а Ваши рекомендации учту...
Спасибо за оказанное внимание.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вот что такое кнопка в обычной среде Ардуино с точки зрения построения с помощью объектов.  digitalRead(pin). Два состояния нажато, и не нажато. И то подавления дребезга и когда эта кнопка была нажата/отжата.  То есть изначально для вашей задачи не пригодно. А код вокруг это костыли что бы это убрать.  А вот если был к примеру объект кнопка  у которого было 3 состояния - отжато/нажато/нажато долго . И считывалось простейшей функцией ReadBtnState(). То было замечательно.

  Опять же что такое "аналоговый светодиод". Светодиод с 256 состояниями и все. Никакого затухания и зажигания нет там. Что опять костыли городить. А так LedUp(),LedDown(). И все. 

  Вот что бы все это реализовать нужны классы и библиотеки заточеные под эту задачу. И все это надо уметь писать. Но народ видно не очень хочет.  Костыли это наше все.

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

пожалуй стоит лучше описать что должно происходить:

1. нажатие кнопки (с антидребезгом или без не суть, это блокируется в дальнейшем коде)

2. флаг1 нажатия кнопки, флаг2 окончания изменения светодиода, флаг3 предыдущего состояния светодиода (включался или выключался) контроль времени если прошло 50мс например и флаг 2 не изменился то обнулить флаг1

3. условие: если была нажата кнопка флаг1 =1 и флаг2=0 (будем считать что 0 это яркостьв текущий момент не меняется)

условие внутри если флаг3 равен 1 то увеличиваем шим , иначе уменьшаем, разумеется с граничными условиями.

соответственно пока не отработает регулировка яркости (если это подходит тебе) кнопка будет игнорироваться 

далее можно избавится от флага 3, использовать вместо него значения шим, они же хранятся. далее можно избавится от контроля времени из 2 пункта, не изменять флаг1 если не флаг2 не установлен. и т.д. 

подумай

sadman41
Offline
Зарегистрирован: 19.10.2016

Вот ходили бы все строем по улице и проблемы со сталкиванием лбами не было... а если бы еще глазом обозначали намерение повернуть... Но народ, почему-то, не очень хочет. Уличная пешеходная анархия - это наше все.

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

а может вы просто зажрались? вам уже интереснее потроллить чем помочь. люди смотрю тут сильно изменились с тех пор как пришли сюда с такими же вопросами

Xtro
Xtro аватар
Offline
Зарегистрирован: 26.09.2017

Еще раз огромная благодарность всем, кто откликнулся!

Не просил код по одной простой причине...простое копирование кода, на мой взгляд, не приводит к положительным результатам...поэтому просил подсказать направление, хотя и сам понимаю, что без классов, кейсов и флагов не построить чего-нибудь действительно стоящего...

СПАСИБО!!!

Logik
Offline
Зарегистрирован: 05.08.2014

//а может вы просто зажрались? 

Просто с такой элементарщиной приходят... Ну смотрим работающий код, от него пляшем. Хотелка ТС легко выполнимама с минимумом телодвижений если в строке после 21 через требуемые 60 и более сек устанавливать buttonState в состояние отпущеной кнопки. Существующая логика кода все решит. Остается вопрос узнать что прошл 60 и более сек удержания кнопки. Тоже элементарно, благодаря вобщем удачному подходу - формированию 30мсек интервалов. Если в условии стр21 прошли 60/0,03=2000 раз при нажатой кнопке - значить удерживается 60сек. А это счетчик который инкрементим при нажатой до 2000 и сбрасываем в 0 при отпущенной. Вот по достижению 2000 значить и надо установить buttonState в отпущенно. Все элементарно и как для автора  приведеного кода легко реализуемо. Зачем с таким на форум лезть. 

ПС. С чего стр.19 и 30 при каждом проходе лопа делается - загадка. Раз в 30 мсек - самое оно.

5N62V
Offline
Зарегистрирован: 25.02.2016

jeka_tm пишет:

а может вы просто зажрались? вам уже интереснее потроллить чем помочь. люди смотрю тут сильно изменились с тех пор как пришли сюда с такими же вопросами

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

На тематическом форуме трудно получить блага незаслуженно, кмк, т.к. благо тут одно: пощекотить свое самолюбие. Это у отвечающих. А у вопрошающих  - получить ответ, мнение, совет, информацию. Часто незаслуженно, ибо иногда лень элементарное погуглить. Тэк что кто тут зажрался - это еще вопрос.

 

Я , кстати, тоже заметил, что качество ответов изменилось не в лучшую сторону. Но надо помнить, что тут никто и никого не обязывает делиться информацией, и если кто-то и делает это добровольно, то за это надо быть благодарным.

 

Пардон за офф. 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Цитата:
Пытаюсь реализовать следующее: при нажатии кнопки светодиод плавно загорается, при отпускании плавно гаснет, но если кнопка находится в нажатом состоянии более 60 сек, светодиод должен также плавно погаснуть...а вот с этим проблема...

По сути...если таймер истек а светодиод горит - гасим светодиод

#define button1 3
#define led1 0

uint8_t light1;
uint32_t time;

const uint32_t pressPeriod = 60*1000; // max time for button is pressed
uint32_t       timePressed = 0;       // current time when pressed

int buttonState=1;   // переменная для хранения состояния кнопки (not pressed!)

void setup() {
  pinMode(button1, INPUT);  //настариваем пин кнопки на вход
  pinMode(led1, OUTPUT);    //настариваем пин светодиода на выход
}

void loop() {
  uint8_t isPressed; // temporary current state button

  // каждые 30мсек увеличиваем или уменьшаем яркость (так было) and control other conditions
  if (millis() - time >= 30)
  {
    // only control for pressed @TODO to add closing the contact bounce:
    if( digitalRead(button1) == LOW ){ isPressed = 0; }
    else                             { isPressed = 1; }

    // is this a new pressed?
    if( buttonState != isPressed ){
      if( isPressed == 0 ){
        // this is a new pressing: new start timeout pressing
        timePressed = millis();
      }
      buttonState = isPressed;
    }

    if( buttonState == LOW && (millis() - timePressed > pressPeriod) ){
      // if pressed, control time period, light is douwning:
      if( light1>0 ){ light1--; }
    }else{
      // or control and change lighting
      if (buttonState == LOW  && light1 < 155){ light1++; }
      if (buttonState == HIGH  && light1 > 0 ){ light1--; }
      time = millis(); // Упс. Перекрывает действие выше.. удалено
    }
    analogWrite(led1, light1);
  }
}

Ваше направление мысли было верным, но почему-то недодуманным. Действительно, если надо гасить при долгом нажатии, то это также делается через "блинк без делай" .. но нужен СВОЙ таймер - отдельная переменная для контроля своего интервала.

Ну и сразу небольшая оптимизация: минимальный период в 30мсек вполне позволяет проверять кнопку с заданной частотой (а частично будет играть роль подавителя дребезга), соответственно весь код можно загнать внутрь этого "микропериода". Но это не обязательно.

Ну и конечно же правильней переработать само ТЗ в стиль автоматного программирования и оно станет проще, понятней и легче реализуемо. :)

Xtro
Xtro аватар
Offline
Зарегистрирован: 26.09.2017

Приветствую...

Arhat109-2 Спасибо за код...

А стр.43 специально менять не стали? 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Зачем? Она верная, а вот та, что была выше ею перекрывается полностью, стало быть не нужна и редуцирована внутр. оптимизатором. :)

P.S. но попытайтесь перевести это ТЗ в "автоматный стиль":

Это когда есть "объект" с состояниями (переменной состояния) - КА(конченный автомат), который "знает" свои действия по смене состояний и имеет "слушателя новостей" (входной поток событий). При этом в программе таких КА может быть достаточно много и они вполне могут промеж себя "общаться" (изменять состояния друг друга). При этом надо помнить, что "таймаут" - это такое же событие входного потока и "блинк без делай" всего лишь .. его "слушатель". Часть "слушателей" может оказаться процедурами обработки прерываний и работать асинхронно.

В качестве "состояния" может выступать как некое статично повторяемое действие (состояние "включаю": выдаем новое значение ШИМ), так и статичное состояние "между" действиями ("включен" - ожидание иного состояния, например). Кроме этого, действие по переходу или состоянию может быть зависимым от своего же "предыдущего состояния" или "отложенным" до какого-то момента - "КА с памятью", "КА со стеком" или исполняться в зависимости от матрицы вероятностей переходов (самообучаемые КА) и т.д.

Xtro
Xtro аватар
Offline
Зарегистрирован: 26.09.2017

Уважаемый Arhat109-2...

Как раз и получается, что   time = millis() в 43 стр. не дает разгуляться всему этому действу...

Его место после стр.21...

С уважением,я...

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

О, пардон .. его место перед строкой 45. Независимо от того, в каком состоянии находится ваш светодиод, новый период надо устанавливать внутри IF() строки 21. Можно сразу после попадания внутрь строкой 23, но также можно и в самом конце перед/после строки 45. Без разницы.

P.S. Предпочитаю ставить в конце. Тогда время "пропусков" кода перестает зависеть от времени исполнения кода внутри таких "блинк без делай". Но, если надо, чтобы длина паузы включала в себя время исполнения, то да - лучше сразу фиксировать новый отрезок. На выбор. :)

Xtro
Xtro аватар
Offline
Зарегистрирован: 26.09.2017

Но это не освобождает меня от шевеления мозгами...

Еще раз спасибо за пример...