Рандом и лампочки

sirius1
Offline
Зарегистрирован: 17.03.2016

Добрый день. Возник следующий вопрос.

Есть две лампочки, LedR и LedL. Есть кнопка, при нажатии на которую срабатывает "рандом". В 10 процентах должна включаться LedL на 2 секунды, в остальных LedR так же на 2 секунды. Код ниже:

int ledL = 7;
int ledR = 8;
int button = 4;
long randNumber;
void setup() {

  pinMode(ledL, OUTPUT);
  pinMode(ledR, OUTPUT);
  pinMode(button, INPUT);
  randomSeed(analogRead(0));
}
void loop() {
  if(digitalRead(button) == HIGH)
{
  randNumber = random(100);
  if( randNumber <=9)
   {
    digitalWrite(ledL, HIGH);
    digitalWrite(ledR, LOW);
    delay(2000);
    }
    else
    {
    digitalWrite(ledL, LOW);
    digitalWrite(ledR, HIGH);
    delay(2000);
      }
  }
  else
  {
    digitalWrite(ledL, LOW);
    digitalWrite(ledR, LOW);
    }
}

Собственно вопрос. Как сделать то же самое, но на 3 кнопки и 6 лампочек. Кнопки должны работать независимо: пока горит лампочка из первой группы, и нажата кнопка второй группы, лампочка группы 2 должна загореться не потушив при этом лампу группы 1. Одна кнопка - 2 лампы. Надеюсь понятно объяснил))

Натолкните на мысль.

Заранее благодарен.

P.S. Есть возможность контролировать время нажатия кнопок. Может так будет проще и отталкиваться от этого?

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Ну, на худой конец также и делай, просто кода будет больше. Хотя, правильнее создать классы для ламп и кнопок, тогда можно хоть на 10 делать без дублирования одного и того же

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Ворота пишет:
Ну, на худой конец также и делай, просто кода будет больше. Хотя, правильнее создать классы для ламп и кнопок, тогда можно хоть на 10 делать без дублирования одного и того же

Так же делать бессмысленно. Ему нужно конечный автомат реализовывать.

sirius1
Offline
Зарегистрирован: 17.03.2016

На сколько я понимаю, delay() подразумевает остановку всего на заданный  интервал, т.е. если нажатие второй кнопки попадет в delay() первой, то ничего не произайдет. Значит от этого нужно уходить. mills()? как вариант, но смущает необходимость переодического перезапуска для сброса счетчика. Может есть еще варианты?

P.S. Напишу опять в конце. Появилась мысли привязаться к времени нажатия кнопки, которое есть вариант контролировать, но! если подключить не 2, а 4 лампочки, две из которых горят, а две - мигать...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sirius1 пишет:

смущает необходимость переодического перезапуска для сброса счетчика. 

Зачем его сбрасывать? Я что-то не понял, о чём это Вы, можно поподробнее с этого места?

sirius1
Offline
Зарегистрирован: 17.03.2016

"сбрасывает в ноль". Все. Понял. Небольшой баг раз в 50 дней, не факт которые раметишь. Пошел пробовать.

Yarik.Yar
Offline
Зарегистрирован: 07.09.2014

Ну как сказать баг...баг с постоянной периодичностью есмь фича, так что переполнение переменной millis скорее фича.

sirius1
Offline
Зарегистрирован: 17.03.2016

Тогда так. На сколько данный код корректен? И будет ли он работать?

int ledRed1 = 13;
int ledGreen1 = 12;
int button1 = 3;
long randNumber;
unsigned long time1;

void setup() {
pinMode (ledRed1, OUTPUT);
pinMode (ledGreen1, OUTPUT);
pinMode (button1, INPUT);
randomSeed(analogRead(0));
}

void loop() {
if(button1 == HIGH){
  randNumber = random(100);
  time1 = millis();
    if(randNumber < 10){
      if(millis() - time1 < 2000){
      ledRed1 = HIGH;
      }
    }
    else{
      if(millis() - time1 < 2000){
      ledGreen1 = HIGH;
      }
    } 
}
else{
ledRed1 = LOW;
ledGreen1 = LOW;
  }
}

 

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

sirius1 пишет:

"сбрасывает в ноль". Все. Понял. Небольшой баг раз в 50 дней, не факт которые раметишь. Пошел пробовать.

ничего не нужно сбрасывать #14

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sirius1 пишет:

"сбрасывает в ноль". Все. Понял. Небольшой баг раз в 50 дней, не факт которые раметишь. Пошел пробовать.

Никто ничего не сбрасывает, если правильно писать. Даже не парьтесь. Если правильно напишете работы с millis никаких проблем от переполнения не будет.

sirius1
Offline
Зарегистрирован: 17.03.2016

А можете прокомментировать код, который выше с millis()? Будет ли он работать? Может быть какие-нибудь недочеты, ошибки?

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

sirius1 пишет:
А можете прокомментировать код, который выше с millis()? Будет ли он работать? Может быть какие-нибудь недочеты, ошибки?
Работать не будет, ошибки в строках 15,20,25,30,31.

sirius1
Offline
Зарегистрирован: 17.03.2016

Согласен. А так?

int ledRed1 = 13;
 int ledGreen1 = 12;
long randNumber;
unsigned long time1;

void setup() {
pinMode (ledRed1, OUTPUT); pinMode (ledGreen1, OUTPUT);
pinMode (button1, INPUT);
randomSeed(analogRead(0));
}

void loop() {
if(digitalRead(button1) == HIGH){
  randNumber = random(100);
  time1 = millis();
    if(randNumber < 10){
      if(millis() - time1 < 2000){
      digitalWrite(ledRed1, HIGH);
      }
    }
    else{
      if(millis() - time1 < 2000){
      digitalWrite(ledGreen1; HIGH);
      }
    } 
}
else{
  digitalWrite(ledRed1, LOW); 
  digitalWrite(ledGreen1, LOW);
  }
}

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Работать будет, но не так как ты хочешь. Ошибка в реализации алгоритма. Судя по всему обе лампочки будут сразу включаться по нажатию на кнопку и выключаться по отпусканию.

sirius1
Offline
Зарегистрирован: 17.03.2016

Попробуем по другому. Что скажите по этому поводу?

int ledRed1 = 13; int ledGreen1 = 12;
int button1 = 3
long randNumber;
unsigned long time1;

void setup() {
pinMode (ledRed1, OUTPUT); pinMode (ledGreen1, OUTPUT);
pinMode (button1, INPUT);
randomSeed(analogRead(0));
time1 = 0;
}

void loop() {
  if(digitalRead(button1) == HIGH && time1 == 0){
  randNumber = random(100);
  time1 = millis();
  }
  else if(millis() - time1 < 2000){
    if(randNumber < 10){
    digitalWrite(ledRed1, HIGH);
    }
    else{
    digitalWrite(ledGreen1, HIGH);
    }
  }
  else{
  time1 = 0;
  }
}

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Как бы, давай пропустим твои итерации и перейдем сразу к реализации идеи.

//Объяви свои выводы BUTTON1-3, LED1-6
#define BUTTON1 10
#define BUTTON2 11
#define BUTTON3 12
#define LED1    13
#define LED2    14
#define LED3    15
#define LED4    16
#define LED5    17
#define LED6    18

#define OFF  0
#define WAIT 1
struct myStruct
{
  byte bt, ledL, ledR, st;
  unsigned long tmr;
};

myStruct a={BUTTON1, LED1, LED2, 0, 0};
myStruct b={BUTTON2, LED3, LED4, 0, 0};
myStruct c={BUTTON3, LED5, LED6, 0, 0};

void group(myStruct p)
{
  switch (p.st)
  {
  case OFF: 
    if (digitalRead(p.bt))//проверяю кнопку
    {
      delay(10);//10 мС на антидребезг
      if (digitalRead(p.bt))//кнопка по прежнему нажата
      {
        if (random(100)<10) digitalWrite(p.ledL, HIGH);
        else digitalWrite(p.ledR, HIGH);
        p.tmr = millis();//запоминаю время
        p.st = WAIT;
      }
    }
    break;
  case WAIT: 
    if (millis()-p.tmr > 2000)//если прошло более 2 сек
    {
      digitalWrite(p.ledL, LOW); 
      digitalWrite(p.ledR, LOW); //выключаю обе лампы
      p.st = OFF;
    }
    break;
  }
}

void setup() 
{
  // здесь твоя инициализация
}

void loop() 
{
  group(a);
  group(b);
  group(c);
}

 

sirius1
Offline
Зарегистрирован: 17.03.2016

Спасибо большое. Можно еще 1 глупый вопрос?

void group(myStruct p)
25
	{
26
	  switch (p.st)

что значит буква p после myStruct, равно как - почему переменная записана как p.st - т.е. с точкой?

Или подскажите о чем почитать, чтобы понять это.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

p это ссылка на структуру, которую передаем функции в качестве параметра, можно назвать как угодно, например:

void group(myStruct myFuckingLinkToStructure), тогда и обращаться к полям структуры придется myFuckingLinkToStructure.st

Набери в поисковике "оператор точка".

sirius1
Offline
Зарегистрирован: 17.03.2016

Вроде все встало на свои места. Еще раз спасибо.

sirius1
Offline
Зарегистрирован: 17.03.2016

После нажатия на кнопку загораются обе лампочки и не тухнут. Где искать?

Хотя все должно работать...

//Объяви свои выводы BUTTON1-3, LED1-6
#define BUTTON1 2
#define BUTTON2 3
#define BUTTON3 4
#define LED1    5
#define LED2    6
#define LED3    7
#define LED4    8
#define LED5    9
#define LED6    10

#define OFF  0
#define WAIT 1
struct myStruct
{
  byte bt, ledL, ledR, st;
  unsigned long tmr;
};

myStruct a={BUTTON1, LED1, LED2, 0, 0};
myStruct b={BUTTON2, LED3, LED4, 0, 0};
myStruct c={BUTTON3, LED5, LED6, 0, 0};

void group(myStruct p)
{
  switch (p.st)
  {
  case OFF: 
    if (digitalRead(p.bt))//проверяю кнопку
    {
      delay(10);//10 мС на антидребезг
      if (digitalRead(p.bt))//кнопка по прежнему нажата
      {
        if (random(100)<10) digitalWrite(p.ledL, HIGH);
        else digitalWrite(p.ledR, HIGH);
        p.tmr = millis();//запоминаю время
        p.st = WAIT;
      }
    }
    break;
  case WAIT: 
    if (millis()-p.tmr > 2000)//если прошло более 2 сек
    {
      digitalWrite(p.ledL, LOW); 
      digitalWrite(p.ledR, LOW); //выключаю обе лампы
      p.st = OFF;
    }
    break;
  }
}

void setup() 
{
  // здесь твоя инициализация
pinMode(BUTTON1, INPUT);
pinMode(BUTTON2, INPUT);
pinMode(BUTTON3, INPUT);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
pinMode(LED4, OUTPUT);
pinMode(LED5, OUTPUT);
pinMode(LED6, OUTPUT);
randomSeed(analogRead(0));
}

void loop() 
{
  group(a);
  group(b);
  group(c);
}

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Судя по всему надо передавать указатель на структуру void group(myStruct *p).

  group(&a);
  group(&b);
  group(&c);

а доступ к полям структуры через указатель p->st, p->tmr, p->ledR  и т.д.

sirius1
Offline
Зарегистрирован: 17.03.2016

Сейчас "поигрался" с платой. Почему срабатывало две лампы - нашел - кинул сопративление от пина кнопки на землю. Решил потестить через "слушанье порта". Вот что там пишет:

antidrebizg
bolee 10
Zapomnil vremya
antidrebizg
menee 10
Zapomnil vremya
 

соответственно два нажатия. т.е. casse OFF отрабатывает, а вот в case WAIT затем не переходит. Код ниже

//Объяви свои выводы BUTTON1-3, LED1-6
#define BUTTON1 2
#define BUTTON2 3
#define BUTTON3 4
#define LED1    5
#define LED2    6
#define LED3    7
#define LED4    8
#define LED5    9
#define LED6    10

#define OFF  0
#define WAIT 1
struct myStruct
{
  byte bt, ledL, ledR, st;
  unsigned long tmr;
};

myStruct a={BUTTON1, LED1, LED2, 0, 0};
myStruct b={BUTTON2, LED3, LED4, 0, 0};
myStruct c={BUTTON3, LED5, LED6, 0, 0};

void group(myStruct p)
{
  switch (p.st)
  {
  case OFF: 
    if (digitalRead(p.bt) == HIGH)//проверяю кнопку
    {
      delay(10);//10 мС на антидребезг
      Serial.println("antidrebizg");
      if (digitalRead(p.bt) == HIGH)//кнопка по прежнему нажата
      {
        if (random(100)<10) { digitalWrite(p.ledL, HIGH);
        Serial.println("menee 10");
        delay(1000);}
        else  {digitalWrite(p.ledR, HIGH);
        Serial.println("bolee 10");
        delay(1000);}
        p.tmr = millis();//запоминаю время
        p.st = WAIT;
        Serial.println("Zapomnil vremya");
        delay(1000);
      }
    }
    break;
  case WAIT: 
    if (millis()-p.tmr > 2000)//если прошло более 2 сек
    {
      digitalWrite(p.ledL, LOW); 
      digitalWrite(p.ledR, LOW); //выключаю обе лампы
      p.st = OFF;
      Serial.println("VKL vse");
        delay(1000);
    }
    break;
  }
}

void setup() 
{
  // здесь твоя инициализация
pinMode(BUTTON1, INPUT);
pinMode(BUTTON2, INPUT);
pinMode(BUTTON3, INPUT);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
pinMode(LED4, OUTPUT);
pinMode(LED5, OUTPUT);
pinMode(LED6, OUTPUT);
randomSeed(analogRead(0));
Serial.begin(9600);
}

void loop() 
{
  group(a);
  group(b);
  group(c);
}

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Все верно, надо передавать указатель на структуру в качестве параметра функции. Иначе компилятор создает копию структуры в стеке и все изменения происходят в этой копии, а не в самих структурах a,b,c

sirius1
Offline
Зарегистрирован: 17.03.2016

Действительно, так намного лучше)) все работает идеально)