Электронный «шар судьбы» на ATtiny13

    image

    Привет. Недавно пересматривал один из моих любимых фильмов, а именно «Трасса 60» с Эми Смарт в главной роли. Там у главного героя была такая вещица, под названием «шар судьбы», который отвечал ему на разные вопросы. Ну и после просмотра у меня появилась мысль, а почему бы не сделать что-то подобное на микроконтроллере, тем более недавно разблокировал 4 штуки ATtiny13 которые, когда-то заблокировал по незнанию, что такое фьюзы и с чем его едят. Ещё один аргумент ATtiny13 — цена, очень дешёвый микроконтроллер.

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



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

    Код для ATtiny13 написан в Arduino IDE, но в силу большого потребления ресурсов этой IDE, которые к стати итак сильно ограничены в ATtiny13(а именно 1024 байта под код), памяти мне не хватило, и тут мне пригодились мои начальные знания регистров микроконтроллера и мизерный опыт работы с ними, вот что в итоге получилось:

    Посмотреть код
    #define F_CPU 1200000UL  // Частота МК в герцах
    
    #include <avr/io.h>
    #include <avr/sleep.h> // здесь описаны режимы сна
    #include <util/delay.h>
    
    #define led_Yes 0 // grn
    #define led_No 1 // red 
    #define rand_gen 3 
    #define wait 5000 // тайм аут перехода в спящий режим
    
    void setup() {
      //pinMode(led_Yes, OUTPUT); 
      DDRB |= (1<<led_Yes);
      //pinMode(led_No, OUTPUT); 
      DDRB |= (1<<led_No);
    }
    
    void loop() {
      randomSeed(analogRead(rand_gen)); // не псевдо радном
      byte randomValue;
      randomValue = random(0,2); // диапазон генератора случайных чисел от 0 до 1
      if(randomValue > 0){   
        //digitalWrite(led_Yes, HIGH);
        PORTB |= (1<<led_Yes);  
      }
      else{
        //digitalWrite(led_No, HIGH); 
        PORTB |= (1<<led_No);  
      }
    
      _delay_ms(wait); 
      system_sleep();
    }
    
    void system_sleep(){ 
      //digitalWrite(led_No, LOW); 
      PORTB &= ~(1<<led_No);
      //digitalWrite(led_Yes, LOW); 
      PORTB &= ~(1<<led_Yes);
    
      ADCSRA &= ~(1 << ADEN); // перед сном отключим АЦП
      ACSR |= (1 << ACD); // и компаратор
      // для уменьшения энергопотребления во сне
      set_sleep_mode(SLEEP_MODE_PWR_DOWN); // если спать - то на полную
      while(1) {
        sleep_enable(); // разрешаем сон
        sleep_cpu(); // спать!
      }
    }
    
    //Размер скетча в двоичном коде: 912 байт (из 1 024 байт максимум)
    


    Как это работает? Дело в том, что мы в строчках randomSeed(analogRead(rand_gen)); задаём некое значение которое поступает в микроконтроллер из вне, так как порт микроконтроллера ни к чему не подключен, то есть «висит в воздухе», то на нём присутствует некий белый шум. Для микроконтроллера он выглядит примерно так:

    image

    Если микроконтроллер будет выводить не очень ожидаемый ответ, то можно переназначить пины, то есть поменять местами, порты которые заданы при помощи директивы #define led_Yes 0 и #define led_No 1 или же ещё простой способ — банально поменять местами светодиоды. В строчке #define wait 5000 задаётся тайм аут перехода в спящий режим в миллисекундах, то есть, сколько времени будет светить светодиод.

    Давай посмотрим потребление микроконтроллера в спящем режиме в даташите:

    image

    Как видишь ток всего 0.2 мкА, при таком токе аккумулятор сам по себе быстрее «сядет», чем микроконтроллер его разрядит хотя бы на 1 процент.

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

    Схема очень простая:

    image

    Всего 6 компонентов не считая литиевой батарейки CR2025. Резисторы R1 и R3 добавил чисто для приличия как говорится, без них схема будет работать не хуже чем с ними, правда резистор R1 немного уменьшает ток светодиодов, но нужен, если напряжение питания схемы превышало бы 3 вольта.

    Интересно, на сколько нажатий хватит батарейки CR2025, емкость которой к стати примерно 150 мА/ч?

    При единичном нажатии на кнопку светодиод горит 5 сек, то есть 60 сек / 5 = 12 нажатий на минуту * 60 минут = 720 непрерывных нажатий в час, за час схема будет потреблять ток 1.5 мА(измерил мультиметром потребление когда горит красный светодиод), при емкости в 150 мА/ч получится 150/1.5 мА/ч что схема проработает 100 часов, так как за час можно совершить максимум 720 нажатий то 720 * 100 = 72 000.

    Из грубого подсчёта выходит, что до полного истощения литиевой батарейки CR2025 нужно совершить 72 тысячи нажатий, и это притом если нажимать ещё кнопку непрерывно, на это уйдёт 100 часов, что есть чуть больше 4-х суток.

    Фьюзы стандартные, а именно те, которые зашиты в микроконтроллере с завода, если ATtiny13 только что из магазина, то ничего там с фьюзами изменять не нужно. Добавляю на всякий случай скрин из калькулятора фьюзов:

    image

    UPD по совету одного человека, я добавил в функцию system_sleep() отключение аналогового компаратора для ещё большей экономии заряда батарейки. Файлы в низу статьи перезалито.

    Ссылки:

    Фильм Трасса 60(википедия);
    Даташит на ATtiny13;
    Прошивка и программирование ATtiny13 при помощи Arduino;
    Arduino IDE;
    Функция randomSeed();
    Белый шум;
    Как экономить место на микроконтроллере?;
    Софт которым сделал скриншонт шума — Serial oscilloscope;
    Все файлы по этому проекту(перезалито);
    Все мои публикации.

    P.S. схема в Proteus работать откажется, будет постоянно гореть один и тот же светодиод, так как данная программа не умеет эмулировать те наводки на порту АЦП, что будут в реальной схеме.

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 44

      +2
      Немного не понял почему
      randomSeed(analogRead(rand_gen)); // не псевдо радном

      Вроде как analogRead читает состояние pin'а rand_gen. Или я что-то путаю?
      В целом была мысль сделать непсевдорандом основанный на акселерометре, магнетометре/компасе и барометре. Но так и не придумал практического применения, потому забил.
        +1
        Дело в том что мы питаемся считать значение на «висящем в воздухе» пине, он работает как антенна в радиоприемнике, включи не настроений радиоприемник и услышишь шум, такой же шум и «слышит» микроконтроллер.

        image

        На скриншонте показано как микроконтроллер видит белый шум.
          0
          Я догадывался, что вы используете pin как антенну, только вот я не очень знаком ATtiny13. На всяких там ARM'ах чтобы нога считалась поднятой, нужно иметь какой-то минимальный уровень, например ~2,8 вольта. Получить такой уровень возмущениями Э/М поля в окружающей среде сложновато, потому GPIO и не дрыгаются когда не попади.
            +3
            Это analogRead — по факту, используется низкоразрядный АЦП. Измеряет напряжение между пином (не все пины одинаково полезны могут быть аналоговыми) и землей и проецирует его значения от 0 до 5 вольт на целочисленное значение от 0 до 1023.

            В реальных генераторах СЧ применяются шумящие диоды или стабилитроны, как источник случайности. В данном случае наводок на пине должно быть достаточно и в их применении вряд ли есть необходимость.
              0
              Спасибо, как раз прочел внимательнее описание.
              +1
              На ATtiny13 порты по умолчанию находятся в высокоимпедансном состоянии, то есть Hi-Z состоянии, это как бы и не логическая 1 и не лог. 0, к тому же порт установлен как вход.
              За счёт этого можно ничего не изменяя состояния на порту как говорил один человек «нарубить случайных чисел».
                0
                Сообразил я не правильно трактовал значение возвращемое analogRead, думал, что оно возращает текущее состояние PIN т.е. 0 или 1. Сейчас прочел внимательнее описание.
                  +2
                  analogRead() использует АЦП, возвращает значение от 0 до 1023.
                  +2
                  хм. Не очень похоже на белый шум. Это слишком узкополосный сигнал чтобы его называть белым шумом.
                  Уж лучше измерять длительность нажатия на кнопку.
                  Кстати, не удивлюсь если один квадратик сетки по горизонтали это 20мс реального времени.
                  Амплитуда данного сигнала составляет 40 единиц, а это значит что у вас будет вызван набор не более чем из 40 заранее известных результатов, так не проще ли их было внести в таблицу? Ведь после установки randomSeed последовательность будет всегда повторяться для одного и того же входного числа. А поскольку чисел АЦП может дать не более 1024 то и результатов будет не больше… стоит ли вообще возится со случайными числами в таких случаях? Проще использовать простейший хеш над измеренным числом… и то для того чтобы предотвратить предсказуемость под управлением человека с отличнейшей реакцией. иначе можно просто взять младший бит АЦП и считать его случайным.

                  ИМХО, вы совершаете того же рода ошибку что люди использующие двойное и тройное шифрование одним и тем же алгоритмом для увеличения стойкости алгоритма к взлому.

                  Возьмите транзистор вроде ГТ109, соедините базу с коллектором и используйте транзистор как диод — напряжение на нем под действием тока будет больше похоже на белый шум нежели свободно болтающийся вывод микроконтроллера.
                  И да, его надо будет усилить либо снизить опорное напряжение АЦП для большей чувствительности.транзистор не обязательно всегда держать под током — включить его можно только на время измерения и просуммировать 16 измерений чтобы добавить еще 4 бита к результату.

                  Да, ваша схема будет более предсказуемой в чистом поле, где будет только медленно меняющаяся электростатическая наводка.
              • UFO just landed and posted this here
                  0
                  Можно добавить ещё два светодиода для простоты.
                  • UFO just landed and posted this here
                      0
                      Ты бы хоть статью на педивикии прочёл.

                      ru.wikipedia.org/wiki/Magic_8_ball

                      Классический шарик имеет 20 ответов в четырёх группах — «положительные», «уклончиво положительные», «нейтральные» и «отрицательные».
                    0
                    Для такого варианта можно oled-экранчик, например, использовать. А для аутентичности «интерфейса» — акселерометр замест кнопки, тогда уж.
                    • UFO just landed and posted this here
                    +2
                    Надо было сделать кнопку на питание, а не на сброс.
                    Тогда бы батарейки хватило на вечно.
                    Нажал кнопку, микроконтроллер включился, сгенерил случайное число, зажег светодиод на пару сек. потушил и ушел в бесконечный цикл (или даже в стендбай режим, если он там есть). до тех пор пока снова кнопкой не перезапустили программу по питанию.

                    А еще это добавило бы тактильных ощущений, кнопку пришлось бы жать до получения ответа.
                      +1
                      Боюсь что так кнопка быстро выгорит.
                      У меня микроконтроллер после свечения переходит в спящий режим, в котором микроконтроллер потребляет по даташиту:

                      image

                      Всего 0.2 мкА. Чтобы микроконтроллер разрядил батарею нужно наверное тысячи лет, скорей батарейка сама по себе разрядится за такое время.
                        0
                        А с чего бы кнопке выгореть?
                        В рабочем режиме ток будет порядка десятков миллиампер. Обычная тактовая кнопка выдержит это без проблем.
                          0
                          Ток в работе 1.5-2 мА, но всё же просто «прижимать» пин ресет на землю — думаю в таком случае ток будет проходить через кнопку значительно меньше.
                            0
                            Ток через светодиод будет около 9мА. Плюс ток рабочего режима контроллера.
                            Через ресет, как у вас, действительно ток меньше, но это неважно.
                            Я не говорю, что у вас плохое решение, просто сжечь кнопку парой десятков миллиампер нереально.
                              0
                              Мультиметр показывает что схема потребляет 0.75 мА когда горит зелёный светодиод и 1.50 мА когда красный. Может батарейка малость подсела.
                      +3
                      Да, с таким током в спящем режиме можно и так.
                        +1
                        Если наводка будет сильной и низкочастотной, то analogRead будет возвращать, в основном, 0 или 1023.
                        Вдалеке от ЛЭП и гаджетов вполне может возвращать одно и то же значение.
                          0
                          А кстати интересно как будет этот девайс вести себя под ЛЭП. Надо будет на днях катнуть на велике по окрестностям…
                            0
                            Думаю, что вполне нормально будет вести. Ведь момент нажатия на кнопку сам по себе случаен и никак не синхронен с частотой сети.
                              0
                              Дело в том что напряженность электрического поля под ЛЭП будет перегружать АЦП и вместо красивой синусоиды там будет что-то вроде меандра. На установку ГСЧ будут преимущественно идти два крайних значения — 0 и 1023 с незначительными вкраплениями других чисел(если момент нажатия попадет на фронты). Не очень хорошее распределение для такого ГСЧ. Может статься так что эти два крайних значения будут давать один и тот же результат…
                          0
                          Забавно. Я как-то давно также сделал подобное устройство, случайные числа получал следующим образом — читал результат преобразования АЦП, вывод которого тоже в воздухе висел, брал младший бит и так пять раз подряд. А число, представленное этими 5-ю битами и было результатом. Только использовал, ЕМНИП, tiny2313, поскольку девайс был с ЖКИ. Правда, девайс подвисал иногда, да и код был кривой до безобразия… Так где-то и валяется.
                            0
                            У ATTiny2313 нет АЦП, только аналоговый компаратор.
                            Досадно, что для работы с HD44780 нужно целых шесть ножек контроллера (выбор регистра RS, строб EN, 4 бита данных). У восьминогих AVR можно конечно же отключить RESET и получить как раз шесть ног, но все они будут завязаны на дисплей, и ГСЧ сделать не удастся.

                            Однако при этом можно использовать любую линию, кроме EN для цифрового обмена с другими устройствами — пока нет сигналов на EN, дисплею безразлично состояние других его выводов.
                              0
                              Значит это была mega8. Точно уже не помню, года два прошло.
                              Кстати, по поводу дисплея — можно использовать дисплеи с i2c или spi интерфейсами.
                                0
                                Если выводить на индикатор по отпусканию кнопки то можно использовать практически любой вывод его… впрочем, существуют сдвиговые регистры и индикатор можно задействовать используя всего 3 вывода контроллера.
                                  0
                                  Тогда уж проще взять более ногастый контроллер, чем ставить второй корпус, да еще к нему конденсатор.
                                  Да и скорость обмена сядет в 8 раз, хоть это и не принципиально.
                                    0
                                    А как же принцип «что есть под рукой»? Конечно, можно еще для этих целей задействовать STM32F4xx, там уж точно выводов хватит.
                              0
                              UPD по совету одного человека, я добавил в функцию system_sleep() отключение аналогового компаратора для ещё большей экономии заряда батарейки. Файлы в низу статьи перезалито.
                                0
                                Таблица 11 на странице 27 даташита утверждает, что в используемом вами режиме Power Down АЦП и так будет остановлен, без дополнительных команд.
                                  0
                                  Странно? Но почему тогда микроконтроллер потреблял около 400 мкА в режиме сна до момента пока руками не прописал отключение?
                                    +1
                                    Атмел такой Атмел — любят они в даташитах путаницу.
                                    Ответ нашелся на странице 28:
                                    If enabled, the ADC will be enabled in all sleep modes. To save power, the ADC should
                                    be disabled before entering any sleep mode. When the ADC is turned off and on again,
                                    the next conversion will be an extended conversion. Refer to “Analog to Digital Con-
                                    verter” on page 77 for details on ADC opera

                                    Если АЦП включен, он будет работать во всех режимах сна

                                    То есть на два абзаца выше они рисуют, что тактирование на АЦП в режиме Power Down не идет, и тут же пишут опровержение!

                                    Такие вот новости, когда на соседних страницах разные утверждения.
                                0
                                Хм… спустя некоторое время батарейка разрядилась, но ведь так не должно было быть, ток потребления в режиме сна замерить обычным мультиметром не возможно… Просто мистика какая-то.
                                  0
                                  Никакой мистики. Вероятно девайс часто просыпался от помех. Например, от излучения мобилки или ошибки в программе.
                                  0
                                  Биг сенкс! Вы сделали вчера мой день: я бился над тем, что самым подходящим контроллером была Тинька, но все контакты были заняты и повесить кнопку на прерывание было невозможно… И тут как гром среди ясного неба — натыкаюсь на эту статью!
                                    0
                                    Правда батарейка через месяц почему-то села… Почему я хз… А так — пожалуйста.
                                      0
                                      Знаешь, грешу на подтяжку! Знакомые говорят, что через подтягивающий резистор ток не течёт и расхода нет, но иначе ЗАЧЕМ-БЫ ОН ВООБЩЕ БЫЛ НУЖЕН?!

                                      В принципе — мне ок и с потреблением «батарейка-в-неделю-и-вообще-поюзал-вынь!»
                                      Просто чтобы при нерабочем состоянии она расходовалась поменьше!
                                        0
                                        О, я заметил что у меня нету подтягивающего резистора для ресет, может и потому плата порой что-то потребляла?
                                          0
                                          На том выводе есть встроенный порядка 100кОм.
                                            0
                                            Наверное этого оказалось мало и плата время от времени перезагружалась…

                                  Only users with full accounts can post comments. Log in, please.