Клон Digispark. Тот же ATtiny85, только с USB

Опубликовал | 10.12.2015

То, о чем говорили большевики… хотя стоп. Это не совсем то, о чем говорили большевики. Это новый подход к прототипированию устройств на ATtiny85 в среде Arduino. А ATtiny85 — это как раз то, что отлично подходит для многих вещей, где полноценные Arduino-совместимые платы вроде Pro Mini, Uno и, тем более, Mega избыточны. Причем конкретно эта штука хороша тем, что на ней можно быстро, без паутины проводов и программаторов обкатать код, который потом будет трудиться в чем-то готовом.

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

Небольшая политинформация. ATtiny85 — небольшой микроконтроллер с приличными возможностями и приятными особенностями, включая:

— 8 КБ памяти для программного кода, 512Б памяти для исполняемого кода
— 6 цифровых пинов
— 4 входа ADC
— 2 выхода PWM
— аппаратное прерывание
— частота от 1 МГц до 20 МГц
— питание от 1,8В до 5,5В (в зависимости от модификации)
— потребляемый ток — от 0,1 мкА при 1,8В в режиме максимальной экономии энергии
— выпускается (помимо прочих) в миниатюрном SOIC8 и более удобном для начинающих DIP-корпусах

Даташит на случай, если я что-то переврал.

Вообще это семейство также включает ATtiny25 и ATtiny45 — c 2КБ (128Б) и 4КБ (256Б) памяти для программного кода (исполняемого кода) соответственно. Легко видеть, почему я отдаю предпочтение ATtiny85: максимум памяти.

Казалось бы — этот контроллер идеальный кандидат в заместители Arduino, когда нужно миниатюрное, автономное и долгоживущее (от одного комплекта батарей) устройство. Например, так любимый нами всеми метеодатчик.

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

С программатором, предположим, да — завершаются (при условии, что есть нужная колодка). Но если его нет, а есть Arduino, то для каждой прошивки к ATtiny85 нужно подключать 6 (!) проводов. Конечно, со временем я научился делать это не за шесть операций, а всего лишь за четыре.

Но все равно очень утомительно.

И на этом фоне разработка парней из Digistump, которые придумали, как сделать так, чтобы ATtiny85 можно было без проблем программировать через USB, выглядит фантастически привлекательно. Решение, насколько я могу судить, комбинированное — немного согласующей обвязки для USB, плагин для среды Arduino и хитроумный бутлоадер (micronucleus tiny85) в микроконтроллере.

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

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

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

По крайней мере только этим можно объяснить феноменальное количество всевозможных клонов Digispark в китайских магазинах. Клоны эти во многом идентичны, и различаются разве что конструктивом USB-разъема для подключения к компьютеру. Где-то он интегрирован на плату — как у плоских флешек. Где-то — реализован популярным microUSB.

Второй вариант (о котором речь) мне кажется более рациональным. Во-первых, не надо беспокоиться о наличии свободного места для подключения платы. Во-вторых, при активной отладке не нужно постоянно теребить далеко не вечный разъем у компьютера или хаба. В третьих, постоянно подключенный к компьютеру кабель USB-microUSB можно использовать и в других целях.

Итак, безымянная плата ATTINY85 Microcontroller Development Board на основе дизайна Digispark. Здесь мы видим самый обычный ATtiny85 20SU, то есть чип с рабочим диапазоном напряжений 2,7В — 5,5В и максимальной частотой 20 МГц в корпусе SOIC8.

Пинов отрезали ровно девять штук — под число контактов. Не больше, не меньше:

Размеры платы примерно 18х22 мм.

На плате, помимо прочего, размещается стабилизатор напряжения LM78L05. По этой причине питать контроллер можно двумя путями: напряжением до 5В при подключении к пину 5V и до 10В при подключении к пину Vin (через стабилизатор). В теории, если верить даташиту стабилизатора, он может выдержать и до 35В, но, вероятно, недолго.

Кроме удобного питания на плате удобно выведены и подробно подписаны пины контроллера. С лица — цифровые, со спины — по протоколу и аналоговым функциям. В общем, не заблудишься.

Для чего все это может пригодиться? Как и говорил — для прототипирования. То есть, для отладки железа и кода перед финальной сборкой. Например, с моими кривыми руками отладка может включать несколько десятков «заливок» кода в контроллер, что при упомянутых выше четырех операциях с проводами (что также подразумевает постоянный контроль правильности подключения) становится мягко говоря утомительным.

Здесь же — подключил один провод, залил код, отключил — проверяешь. Не понравилось — для изменений нужен тот же один провод. Красота.

Но для начала нужно подготовиться, что несложно. В первую очередь напаиваем гребенку для макетирования:

Теперь устанавливаем своеобразный плагин для среды Arduino (поддерживается начиная с версии 1.6.5). Процесс подробно описан в Wiki Digispark.

Открываем настройки:

Вставляем в поле Additional Boards Manager URLs строку

http://digistump.com/package_digistump_index.json

:

Переходим в меню Инструменты — Boards Manager:

В выпадающем списке Type выбираем Contributed, а затем щелкаем по Digistump AVR Boards, при этом появится кнопочка Install, которую и нажимаем:

Начнется скачивание и установка софта и драйверов. Говорим, что согласны на все:

Наконец все готово:

Выбираем рекомендованную для начинающих плату Digispark (Default — 16,5mhz):

Можно вбить классическую «мигалку» из примеров самих Digistump:

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

Таймаут на загрузку — 60 секунд:

Связано это с особым режимом работы загрузчика: при старте контроллера он ждет загрузки кода через USB в течение 5 секунд, а потом переключается в режим исполнения имеющегося в памяти контроллера кода.

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

Загрузка пошла:

Готово:

При прототипировании также следует иметь в виду и другие важные отличия данной платы от Arduino.

Пины 3 и 4 используются для USB, поэтому если они также необходимы в финальном проекте, то подключенную к ним для отладки периферию лучше отключать на время загрузки новой версии прошивки. Также надо иметь в виду, что к пину 3 подключен подтягивающий резистор 1,5К, необходимый для того же самого USB. Т.е. на этом пине по умолчанию будет далеко не ноль.

А помимо ограничений ATtiny85 (поддерживаются не все библиотеки и не все команды языка) есть и ограничение по памяти для программного кода, которой в версии Digispark 6КБ (а не 8КБ, как у «голого» ATtiny85).

Для тех, кто задумывается об использовании данных плат в готовых устройствах сообщаю, что на примере «Пищаля» потребление в активном режиме при напряжении 5В — около 30 мА. В режиме предположительно максимально глубокого сна, на который я способен уговорить контроллер по советам умных людей — 13,38 мА.

На примере «мигалки» получилось 30 мА при погашенном мигающем светодиоде и 35,5 мА — при горящем.

Куда контроллер тратит такую уйму энергии — пока не понимаю. Но подозреваю, что это связано с довольно высокой тактовой частотой (что, впрочем, не объясняет аппетит во время сна).

Где бы мне могла помочь эта плата? Да уже на самом деле в уйме, уйме мест, где работают крохи ATtiny85. Давайте считать.

Сигнализатор открытого дверного замка «Пищаль» (он же — «Трындец»)

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

Пищалка, батарейка, контроллер, микрик — ничего лишнего:

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

И до умопомрачения простым кодом. Который просто включает пищалку примерно через пять минут после включения контроллера. А контроллер, как несложно понять, включается микропереключателем. На микропереключатель, в свою очередь, давит ригель замка.

Код
  // Код сна: http://donalmorrissey.blogspot.ru/2010/04/sleeping-arduino-part-5-wake-up-via.html  #include <avr/sleep.h>  #include <avr/power.h>  #include <avr/wdt.h>    volatile int f_wdt=1;  #define alPin 1 // пин пищалки  #define alTime 38 // таймаут для сигнала в 8-секундных интервалах = alTime*8  boolean alarm = false; // флаг включения сигнала  byte alTimeOut = 0; // счетчик таймаута    // www.technoblogy.com/show?KX0  #define adc_disable() (ADCSRA &= ~(1<<ADEN)) // disable ADC (before power-off)   #define adc_enable() (ADCSRA |= (1<<ADEN)) // re-enable ADC    ISR(WDT_vect)  {    if(f_wdt == 0)    {      f_wdt=1;    }  }    void enterSleep(void)  {  pinMode(alPin, INPUT);    set_sleep_mode(SLEEP_MODE_PWR_DOWN);     sleep_enable();    sleep_mode();    sleep_disable();     power_all_enable();    pinMode(alPin, OUTPUT);  digitalWrite(alPin, LOW);    }    void setup() {    adc_disable();    /*wdt_enable(WDTO_8S);  WDTCR |= _BV(WDIE);  */     /*** Setup the WDT ***/      /* Clear the reset flag. */    MCUSR &= ~(1<<WDRF);      /* In order to change WDE or the prescaler, we need to     * set WDCE (This will allow updates for 4 clock cycles).     */    WDTCR |= (1<<WDCE) | (1<<WDE);      /* set new watchdog timeout prescaler value */    WDTCR = 1<<WDP0 | 1<<WDP3; /* 8.0 seconds */      /* Enable the WD interrupt (note no reset). */    WDTCR |= _BV(WDIE);    pinMode(alPin, OUTPUT);  tone(alPin, 300, 500);  delay(500);    }    void loop() {    if(f_wdt == 1) {    if (alarm == false) {      if (alTime > alTimeOut) { // если время таймаута не прошло            alTimeOut++; // увеличиваем счетчик            f_wdt = 0; // переключаем флаг признака просыпания          } else {            alarm = true; // иначе разрешаем сигнал          }      }  }      if (alarm == true) {        makeSound();      }     if (f_wdt == 0) {      enterSleep();    }  }    void makeSound() {    tone(alPin, 450, 250);    delay(350);    tone(alPin, 750, 250);    delay(3000);  }    

То есть, пока ригель давит — контроллер выключен. Перестал давить — контроллер включился. Ну а таймаут в 5 минут сделан, чтобы пищалка не мешала при так сказать обычном использовании двери.

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

Ну и еще нюанс: при включении (считай открытии двери) контроллер издает однократный писк. Это чтобы знать, что конструкция работает, как и батарейка.

Все идеально поместилось внутри дверной коробки. И уже неоднократно доказало свою пользу.

Автомат света «Артефакт»

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

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

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

Стало очевидно, что дороги назад нет: надо менять сам принцип. Под это дело купил в Fix price несколько различных светильников (на корпуса), разломал дачный фонарик на солнечной батарейке под датчик света, в хозяйственном подвале приобрел батарейные отсеки под элементы ААА, в запасах откопал резервный передатчик на 433 МГц и популярный датчик движения HC-SR501.

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

Код
  // Код сна: http://donalmorrissey.blogspot.ru/2010/04/sleeping-arduino-part-5-wake-up-via.html  // Библиотека Livolo: http://forum.arduino.cc/index.php?topic=153525.0    #include <avr/sleep.h>  #include <avr/power.h>  #include <livolo.h>    #define adc_disable() (ADCSRA &= ~(1<<ADEN)) // disable ADC (before power-off)   #define adc_enable() (ADCSRA |= (1<<ADEN)) // re-enable ADC    #define txPin 1 // пин передатчика  #define txPowerPin 0 // питание передатчика  #define intPin 2 // пин прерывания  #define lightPin A2 // пин датчика света (цифровой пин 4, физический пин 3)  #define sparePin 3 // пустой пин (аналоговый пин 3, физический пин 2)  #define lightTimeOut 60000 // таймаут выключения света  #define lightTreshold 55 // порог уровня света для включения (датчик свет/тьма)   unsigned long lightTime; // счетчик таймаута до выключения света    // УПРАВЛЕНИЕ Livolo  Livolo livolo(txPin);    void intHandler() {      while(analogRead(lightPin) < lightTreshold) {            lightsOn(); // выключение света, если он включен            }      lightTime = millis();     }    void enterSleep()  {       pinMode(txPin, INPUT);   pinMode(txPowerPin, INPUT);      GIMSK |= _BV(PCIE); // Enable Pin Change Interrupts    PCMSK |= _BV(PCINT2); // Use PB2 as interrupt pin      adc_disable();        set_sleep_mode(SLEEP_MODE_PWR_DOWN);        sleep_enable();        sleep_mode();        /* The program will continue from here. */        /* First thing to do is disable sleep. */    sleep_disable();       power_all_enable();   adc_enable();       pinMode(txPin, OUTPUT);    digitalWrite(txPin, LOW);    pinMode(txPowerPin, OUTPUT);    digitalWrite(txPowerPin, LOW);  }    void setup()  {    /* Setup the pin direction. */    pinMode(intPin, INPUT);    pinMode(lightPin, INPUT);    pinMode(txPin, OUTPUT);    pinMode(sparePin, INPUT);    digitalWrite(txPin, LOW);    pinMode(txPowerPin, OUTPUT);    digitalWrite(txPowerPin, LOW);    attachInterrupt(0, intHandler, CHANGE);    lightTime = millis();    }    void loop()  {    if ((millis() - lightTime) > lightTimeOut) {      while(analogRead(lightPin) > lightTreshold) {            lightsOn(); // выключение света, если он включен        delay(1500);    }        enterSleep();      }   }    void lightsOn() {   digitalWrite(txPowerPin, HIGH);   noInterrupts();   livolo.sendButton(6400, 80);   interrupts();   digitalWrite(txPowerPin, LOW);      }    

Зато результат — симпатичная пирамидка, которая стоит на одной из полок и кажется, что ничего не делает. А на самом деле происходит следующее: контроллер спит до обнаружения движения, а когда его увидит, то оценивает уровень освещенности. Если света мало — включает, если много — ничего не трогает, что очень. Свет включается по радио, через выключатели Livolo.

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

Потребление в спящем режиме — около 60 мкА (с учетом датчика движения), в активном — около 8-9 мА.

Плюс конструкции по сравнению с «глупым» датчиком двери и в том, что если вдруг забудешь, что внутри автомат света и включишь свет вручную, то при открытии двери свет не выключится — такова логика «Артефакта».

Из той же логики растет недостаток: если свет включить вручную и не заходить, то «Око» свет не выключит, пока кто-то не зайдет.

Датчик протечек «Капель»

Это, если честно, не совсем удачная идея. То есть, железка удалась, но ее применение — нет. Дело в том, что в сантехническом шкафу однажды обнаружилась очень неприятная штука: ползучая протечка. Иными словами, соединение подтекало так, что это было особо незаметно, однако в итоге воды набралось столько, что стали возмущаться соседи снизу.

После этого я стал регулярно заглядывать в сантехшкаф, внимательно осматривая соединения и его «дно», и параллельно думал о том, как бы автоматизировать процесс. Теоретически меня могла бы спасти «нечеткая логика», то есть не совсем традиционное использование обычного метеодатчика.

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

Придумано — сделано. Благодаря популярному датчику температуры и влажности ATtiny85 превратился в «Капель». Аппарат на макетной плате простоял в сантехническом шкафу две недели. Этого мне хватило для сбора статистики по влажности, которая, как оказалось, гуляет там в довольно широких пределах.

Но проблема оказалась не в пределах. Собственно, я для того и собирал статистику, чтобы понять порог срабатывания сигнализации. Проблема оказалась в том, что при натурном тесте (мокрая тряпка в сантехническом шкафу) влажность особенно не изменилась.

В общем, от «Капели» я отказался, но метеодатчик, который может передавать данные на Народный Монитор через домашний контроллер — остался. Точнее, остался код, а вот сам прибор я разобрал, поскольку стал заниматься «Артефактом».

Код
  // Код сна: http://donalmorrissey.blogspot.ru/2010/04/sleeping-arduino-part-5-wake-up-via.html  // Основа для радиопротокола: http://thomasolson.com/PROJECTS/SC2262/  // Библиотека DHT: http://learn.adafruit.com/dht/downloads    /*   * Sketch for testing sleep mode with wake up on WDT.   * Donal Morrissey - 2011.   *   */  #include <avr/sleep.h>  #include <avr/power.h>  #include <avr/wdt.h>    #include "DHT.h"    #define adc_disable() (ADCSRA &= ~(1<<ADEN)) // disable ADC (before power-off)  #define adc_enable()  (ADCSRA |=  (1<<ADEN)) // re-enable ADC    volatile int f_wdt=1;  byte timeOut = 0;    #define txPin 1 // пин передатчика  #define sensorPower 4 // питание датчика  #define sensorPin 3  // пин датчика  #define DHTTYPE DHT22  #define txPower 0 // питание передатчика  #define alPin 2 // пин пищалки  #define interval 25 // число 8-секундных интервалов между отправками, около 200 секунд    #define PULSESHORT 450  // confirmed  #define PULSELONG  1350  #define PULSESYNC  13950 // Aproximately 10.67 times PULSELONG    byte param = 0; // тип данных (температура/влажность)  unsigned long myData; // данные к отправке  byte i = 0;  boolean leak = false;    DHT dht(sensorPin, DHTTYPE);      /***************************************************   *  Name:        ISR(WDT_vect)   *   *  Returns:     Nothing.   *   *  Parameters:  None.   *   *  Description: Watchdog Interrupt Service. This   *               is executed when watchdog timed out.   *   ***************************************************/  ISR(WDT_vect)  {    if(f_wdt == 0)    {      f_wdt=1;    }  }      /***************************************************   *  Name:        enterSleep   *   *  Returns:     Nothing.   *   *  Parameters:  None.   *   *  Description: Enters the arduino into sleep mode.   *   ***************************************************/  void enterSleep(void)  {       digitalWrite(txPin, LOW);   digitalWrite(sensorPower, LOW); // выключаем датчик   digitalWrite(txPower, LOW); // выключаем передатчик   pinMode(sensorPower, INPUT);   pinMode(txPower, INPUT);   pinMode(txPin, INPUT);   pinMode(alPin, INPUT);   pinMode(sensorPin, INPUT);    adc_disable();        set_sleep_mode(SLEEP_MODE_PWR_DOWN);   /* EDIT: could also use SLEEP_MODE_PWR_DOWN for lowest power consumption. */    sleep_enable();        /* Now enter sleep mode. */    sleep_mode();        /* The program will continue from here after the WDT timeout*/    sleep_disable(); /* First thing to do is disable sleep. */        /* Re-enable the peripherals. */    power_all_enable();       pinMode(sensorPower, OUTPUT);   pinMode(txPower, OUTPUT);   pinMode(txPin, OUTPUT);   digitalWrite(txPin, LOW);   digitalWrite(sensorPower, HIGH); // включаем датчик   digitalWrite(txPower, HIGH); // включаем передатчик   digitalWrite(sensorPin, INPUT_PULLUP); // включаем датчик  }        /***************************************************   *  Name:        setup   *   *  Returns:     Nothing.   *   *  Parameters:  None.   *   *  Description: Setup for the serial comms and the   *                Watch dog timeout.    *   ***************************************************/  void setup()  {        /*** Setup the WDT ***/        /* Clear the reset flag. */    MCUSR &= ~(1<<WDRF);        /* In order to change WDE or the prescaler, we need to     * set WDCE (This will allow updates for 4 clock cycles).     */    WDTCR |= (1<<WDCE) | (1<<WDE);      /* set new watchdog timeout prescaler value */    WDTCR = 1<<WDP0 | 1<<WDP3; /* 8.0 seconds */        /* Enable the WD interrupt (note no reset). */    WDTCR |= _BV(WDIE);    pinMode(sensorPower, OUTPUT);  pinMode(txPower, OUTPUT);  pinMode(txPin, OUTPUT);  digitalWrite(txPin, LOW);  digitalWrite(sensorPower, HIGH); // включаем датчик  digitalWrite(txPower, HIGH); // включаем передатчик    dht.begin();    getWeather();  }        /***************************************************   *  Name:        enterSleep   *   *  Returns:     Nothing.   *   *  Parameters:  None.   *   *  Description: Main application loop.   *   ***************************************************/  void loop()  {   if (leak == false) {    if (f_wdt == 1)    {     if (timeOut > interval) {      getWeather();      timeOut = 0;      } else {         timeOut++;         }            // Don't forget to clear the flag.       f_wdt = 0;            // Re-enter sleep mode.             enterSleep();    }    else    {      // Do nothing.     }   } else {    digitalWrite(alPin, HIGH);    delay(750);    digitalWrite(alPin, LOW);    }  }    // ПОЛУЧЕНИЕ И ОТПРАВКА ПОГОДЫ  void getWeather()    {        delay(3000);        int h = dht.readHumidity()*10;    // Read temperature as Celsius (the default)    int t = dht.readTemperature()*10;      // Check if any reads failed and exit early (to try again).    if (isnan(h) || isnan(t)) {      rcSend(133331);      return;    }                if (t < 0) {          myData = 15101000 + abs(t);} // температура = код датчика + признак температуры + знак температуры + температура  //        myData = abs(myData);} // температура = код датчика + признак температуры + знак температуры + температура                  else {              myData = 15100000 + t;} // температура = код датчика + признак температуры + знак температуры + температура   //            myData = DHT.temperature*10;} // температура = код датчика + признак температуры + знак температуры + температура                        rcSend(myData);                      delay(1000);    // теперь отправляем влажность        myData = 15110000 + h; // влажность = код датчика + признак влажности + влажность  //       myData = DHT.humidity*10; // влажность = код датчика + признак влажности + влажность                rcSend(myData); // отправляем влажность              if (h > 700) { // если влажность больше 70% - поднимаем тревогу      rcSend(3502421);       leak = true;     }  }      static void rcSend(long remoteCode) {        for(int repeat=0; repeat<4; repeat++){       for (byte i = 24; i>0; i--) { // transmit remoteID      byte txPulse=bitRead(remoteCode, i-1); // read bits from remote ID       // Serial.print(txPulse);        switch (txPulse) {                case 0:  // 00            ookPulse(PULSESHORT,PULSELONG);            //ookPulse(PULSESHORT,PULSELONG);            break;                  case 1:  // 11            ookPulse(PULSELONG,PULSESHORT);            //ookPulse(PULSELONG,PULSESHORT);            break;        } // switch      } // for loop      ookPulse(PULSESHORT,PULSESYNC); // S(ync)    //  Serial.println();    } // repeat  }    static void ookPulse(int on, int off) {    digitalWrite(txPin, HIGH);    delayMicroseconds(on);    digitalWrite(txPin, LOW);    delayMicroseconds(off);  }    

Корректор не только осанки «Позиционер»

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

Разумеется, что внутри у него все тот же самый ATtiny85.

На будущее

В планах, которые неизвестно когда сбудутся, переключатель освещения «Ротор». Очень хочется, знаете, такой портативный арт-объект с круглой, наподобие регулятора громкости в аудиотехнике, ручкой, вращение которой переключает свет во всей квартире.

То есть, крутишь в одну сторону — сначала включается фоновый свет, потом половина верхнего, потом — вторая половина верхнего. Крутишь в другую — все гаснет в обратной последовательности.

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

Однако до финала еще далеко.

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

Товар предоставлен для написания обзора магазином. Обзор опубликован в соответствии с п.18 Правил сайта.

(c) 2015 Источник материала.

Рекламные ссылки