Рандомное включение светодиодов

Buzoff
Offline
Зарегистрирован: 03.04.2018

Здравствуйте.
Помогите решить задачку.
Нужно рандомно по очереди по одному включать 10 светодиодов каждые 5 секунд. И при необходимости, также рандомно по одному выключать.
функция "рандом" не подойдет, так как она может повторять значения из диапазона (от 1 до 10).

Хотя бы подскажите куда копать.

rkit
Offline
Зарегистрирован: 23.11.2016

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

Buzoff
Offline
Зарегистрирован: 03.04.2018

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

Buzoff
Offline
Зарегистрирован: 03.04.2018

Хотя если подумать то наверное можно.
Но что-то в две строчки пока не помещаюсь, точнее далеко не в две)

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Так а в чём именно проблема? Как узнать, включен ли светодиод по номеру, который вернул random? Заводите массив на 10 светодиодов. Заводите переменную - счётчик, которая хранит номер текущей ячейки для записи в массив. Как надо включить - начинаете бесконечный цикл, внутри которого: получаете рандомное число, проверяете, есть ли оно в ячейках до счётчика. Если есть - получаете новый random. Если нет - зажигаете светодиод, пишете номер, полученный random, в ячейку, на которую указывает счётчик, увеличиваете счётчик на 1, вываливаетесь из цикла. Проверяете - если счётчик равен 10 - зажгли все светодиоды.

Тушить - примерно в том же разрезе.

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

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

Похоже как люди садятся писать программу, то здравый смысл их оставляет.А может его и не было изначально. ведь живут же люди без здравого смысла и это не смертельно. Вот мне представляется можно выбрать один из вариантов. 1 тогда их можно выключить. 2 передернуть рандом еще раз.

Buzoff
Offline
Зарегистрирован: 03.04.2018

DIYMan пишет:

Заводите массив на 10 светодиодов. Заводите переменную - счётчик,

Тушить - примерно в том же разрезе.

Спасибо, буду пробовать.
С массивом должно получиться компактнее.

Гриша
Offline
Зарегистрирован: 27.04.2014

Хорошая задача, интересная, в плане обучения и получения навыков разработки простейших алгоритмов. Удачи Вам :)

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

DIYMan пишет:

Так а в чём именно проблема? Как узнать, включен ли светодиод по номеру, который вернул random? Заводите массив на 10 светодиодов. Заводите переменную - счётчик, которая хранит номер текущей ячейки для записи в массив. Как надо включить - начинаете бесконечный цикл, внутри которого: получаете рандомное число, проверяете, есть ли оно в ячейках до счётчика. Если есть - получаете новый random. Если нет - зажигаете светодиод, пишете номер, полученный random, в ячейку, на которую указывает счётчик, увеличиваете счётчик на 1, вываливаетесь из цикла. Проверяете - если счётчик равен 10 - зажгли все светодиоды.

Тушить - примерно в том же разрезе.

Это - неправильный алгоритм.

Правильный - такой:

1. Заводим массив на 10 элементов.

2. Заносим в массив числа от 1 до 10.

3. Используя random (*) перемешиваем массив.

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

(*) Примечание: где взять случайное число в микроконтроллере - вопрос отдельный.

 

PS. Если нам нужна перемешанная колода карт, как мы будем поступать?

1. Соберем 100500 колод вместе, высыпаем в большую емкость, будем из емкости выбирать по одной карте, проверяя, не встретилась ли повторная.

2. Берем единственную колоду и тасуем ее.

Green
Offline
Зарегистрирован: 01.10.2015

А так сойдёт? Тренировка после 23-го.)
 

// random leds

#define LED1              2             //на землю
#define LED2              3
#define LED3              4
#define LED4              5
#define LED5              6
#define LED6              7
#define LED7              8
#define LED8              9
#define LED9              10
#define LED10             11

#define LEDS              LED1,LED2,LED3,LED4,LED5,LED6,LED7,LED8,LED9,LED10
#define STEP_TIME         500


uint8_t leds[] = { LEDS };


void setup() {
  for (uint8_t i = 0; i <  sizeof(leds); i++)
    pinMode(leds[i], OUTPUT);
}


void loop() {
  static bool back;  
  for (uint8_t j = 0; j < sizeof(leds); j++) {
    uint8_t i;
    do
      i = random(0, sizeof(leds));
    while (digitalRead(leds[i]) != back);
    digitalWrite(leds[i],!back);
    
    delay(STEP_TIME);
  }
  back = !back;
}

 

Buzoff
Offline
Зарегистрирован: 03.04.2018

В бесконечных циклах меня смущает одно, их бесконечность в случае постоянного (или очень долгого) выпадания одних и тех же, выпадавших ранее, номеров. Пока не знаю, может на практике такого и не будет. По крайней мере, я представляю как это (вариант 1) реализовать.

Алгоритм с перемешиванием массива (вариант 2), мне изначально показался проще, пока не задумался, а как перемешать массив, не используя тот же бесконечный цикл? Пока ничего не придумал.

gene
Offline
Зарегистрирован: 07.02.2020

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

В общем и целом, надо сначала подумать. И в нынешние времена это очень сложно, я знаю.

Green
Offline
Зарегистрирован: 01.10.2015

"Да что там думать - трясти надо!"

Buzoff
Offline
Зарегистрирован: 03.04.2018

Green пишет:

"Да что там думать - трясти надо!"

покажите где палка лежит.

Green
Offline
Зарегистрирован: 01.10.2015

#9

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

andriano пишет:

DIYMan пишет:

Так а в чём именно проблема?

Это - неправильный алгоритм.

Правильный - такой:

 

И тот, и другой алгоритм - правильный, потому что - рабочий. И тот, и другой алгоритм - не более, чем тренировка навыков. Лично я - подключил бы stl и поюзал бы random_shuffle, но говорить об этом новичку - только запутывать.

Buzoff
Offline
Зарегистрирован: 03.04.2018

Green пишет:

#9

разбираюсь.

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

но пока не могу понять, этот алгоритм рандомно включает выключенные светодиоды и выключает включенные?

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

может пока не разобрался с "back"

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Я где-то в теме про наливатор выкладывал пример случайного перебора тостов, без повторения. Можно его и на числа переделать. Ссылку с планшета не дам, где-то на 8-10 странице. Паматри

Green
Offline
Зарегистрирован: 01.10.2015

Всё строго по ТЗ ТС.) "Полная" случайность - ещё пару строк.

Green
Offline
Зарегистрирован: 01.10.2015

Прибедняться не надо.)
Если нужен "случайный рандом":

EEMEM uint8_t ee_cnt;
  randomSeed(eeprom_read_byte(&ee_cnt));
  eeprom_write_byte(&ee_cnt, eeprom_read_byte(&ee_cnt) + 1);

 

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

А randomSeed() в размерности байта действительно имеет смысл?

Green
Offline
Зарегистрирован: 01.10.2015

Конечно. Только 256 псевдослучайностей думаю достаточно для индейца "нетренированный глаз"?

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

Я когда-то разбирался с этим randomSeed() - там и результат analogRead() оказался не пришитым к кобыле хвостом. 

Green
Offline
Зарегистрирован: 01.10.2015

Да. Думаю из за того что аналог менялся незначительно. Вот если бы руку на этот вход положить...)

negavoid
Offline
Зарегистрирован: 09.07.2016

Зачем руку, можно зенер с резистором.

Green
Offline
Зарегистрирован: 01.10.2015

Привычка.) Рука по молодости помогала находить обрывы в CMOS цепях.)

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

А, я нашёл ту тему. analogRead() не хватало, чтобы "настоящую" энтропию засеять. Первое число всегда получалось кратным 7.  

Гриша
Offline
Зарегистрирован: 27.04.2014

а если помножить время на analogRead(), ну и соответственно брать младшие разряды :)))))))))))  

Green
Offline
Зарегистрирован: 01.10.2015

Ну если один из множителей имеет малую девиацию, то хоть на что его не множь - всё равно получится член.)

SLKH
Offline
Зарегистрирован: 17.08.2015

Что-то вчерашний день навеял: https://www.anekdot.ru/id/-1080619021/

Green
Offline
Зарегистрирован: 01.10.2015

+1. Я имел ввиду что второй множитель (время) без изменений. А ведь так оно и получается.)

rkit
Offline
Зарегистрирован: 23.11.2016
uint8_t pins[] = {2,3,4,5,6,7,8};
uint8_t pins_left = sizeof(pins);


void setup() {
  for(auto p: pins) pinMode(p, OUTPUT);
  randomSeed(analogRead(A0));
}

void loop() {
  while(pins_left) {
    uint8_t r = random(pins_left--);
    for(auto p: pins) digitalWrite(p, digitalRead(p) || r-- == 0);
    delay(1000);
  }
}

 

Green
Offline
Зарегистрирован: 01.10.2015

Ну, rkit! Тут вроде как раздел для новичков... И если новички простой пример не могут одолеть, то вы их запугаете окончательно.

Гриша
Offline
Зарегистрирован: 27.04.2014

Green пишет:

+1. Я имел ввиду что второй множитель (время) без изменений. А ведь так оно и получается.)

эх, согласен... но все одно для разных случаев может оказаться пригодным, при определенном допилинге. Рандом  на МК штука неоднозначная, сложная и путей решения условно несколько...

leks
Offline
Зарегистрирован: 22.10.2017

А нельзя случайность запрограммировать? Например, рандомить в диапазоне 0-2, собирать из этих попыток длинные числа 0-255 потом делить на 25 (26) и получить истинно случайное от 1 до 10 скажем?

negavoid
Offline
Зарегистрирован: 09.07.2016

Нет, потому что числа будут повторяться при каждом запуске. Она (функция random()) потому и называется псевдо-рандомный генератор. Числа даже и с randomSeed(analogRead(0)) будут часто повторяться, потому что инициальное энтропийное число будет тем же самым, что и при предыдущих включениях. Их можно немножко разнообразить, подавая на аналоговый вход полупроводниковый шум, и для большинства любительских применений этого будет достаточно. Тема очень обширная и сложная.

Есть даже специальные модули для генерации рандома. https://www.aliexpress.com/item/32848297519.html

Для местного применения с ардуино - за глаза. Для шифрования банковских транзакций не подойдёт.

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

Ахренеть.

leks
Offline
Зарегистрирован: 22.10.2017

Какой кошмар! Столько усилий и соображалок чтоб сделать так, а не иначе, исключить любую случайность при программировании и вот итог - запрограммировать её нельзя!

 А если серьёзно неужели нет скетчей если не про чистую случайность, то про иллюзию её?

leks
Offline
Зарегистрирован: 22.10.2017

Берём К155ЛА3 (для надёжности), делаем генератор на оч. большую частоту, с кривым кондёром и резистором и читаем выход на Ардуину. Не?

Гриша
Offline
Зарегистрирован: 27.04.2014

leks пишет:

Берём К155ЛА3 (для надёжности), делаем генератор на оч. большую частоту, с кривым кондёром и резистором и читаем выход на Ардуину. Не?

не, "генератор белого шума" обычно на стабилитроне делают, погуглите... как выше написано - тема огромная.  

negavoid
Offline
Зарегистрирован: 09.07.2016

leks пишет:
А если серьёзно неужели нет скетчей если не про чистую случайность, то про иллюзию её?

Для домашнего применения - есть. https://github.com/sirleech/TrueRandom

Отключает ацп, включает, берёт последний бит, набирает из этих битов число. Но энтропия всё равно маленькая.

С генератором на 155ла3 не выйдет. Простейшее решение - использовать avalanche noise диода Зенера (#24), по-русски - стабилитрона. Можно и купить, вот фирменный чип для рандома http://www.fdk.com/cyber-e/pi_ic_rpg100.html

А вот более продвинутые хардварные решения для рандома https://www.idquantique.com/shop/online-shop/

Для задачи ТС это всё абсолютно не нужно :) #9 или #31 - отлично справится.

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

Buzoff пишет:

Алгоритм с перемешиванием массива (вариант 2), мне изначально показался проще, пока не задумался, а как перемешать массив, не используя тот же бесконечный цикл? Пока ничего не придумал.

Если сэр не отличает цикла длиной 10 от бесконечного цикла, вероятно, сэр не умеет считать до 10.

Buzoff
Offline
Зарегистрирован: 03.04.2018

всем большое спасибо за помощь.

информации получил предостаточно, буду разбираться и тестировать.

спасибо