4 Bits Digital Tube LED Display Module Four Serial for Arduino 595 Driver-Y103 (4-хразрядный 7-сегментный индикатор на сдвиговом регистре 74hc595)

  • Цена: $1.38 (Брал у другого продавца, но там кончились)

Каша из топора.


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


Достались мне такие экранчики по недоразумению. Искал семисегментный индикатор для поделки, в поиске были только такие и на ТМ1637. Но 1637 – были «часовые», с двоеточием между часами-минутами, а мне нужен был с десятичными точками. Вот и взял их.





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

Немного физических параметров

















Схему вызванивать не стал, нашел первое подходящее в инете:



Попробовав их подключать – разочаровался. Уж очень мало нашлось инструкций по работе с ними. Никаких библиотек, только редкие скетчи, которые не всегда толком повторить получалось. Повозился, пока кто-то не объяснил: динамическая индикация… Что это значит? Одновременно у индикатора можно зажечь только одну цифру. А значит – для отображения всех 4-х цифр нужно быстро-быстро зажигать цифры одну-за-другой. Это самое быстро-быстро – и есть недостаток этих индикаторов. Потому что это, во-первых, трата процессорного времени. Во-вторых – необходимость следить, чтобы другие процессы не занимали процессор на долгое время – иначе индикатор начнет «мигать».

Лежали у меня эти экранчики с нового года. Решил – надо их как-то утилизировать. Как всегда – самое сложное в ардуиностроении – придумать, что же такого сделать в этот раз? Частично ответ на этот вопрос может дать гугл

Но мне повезло. Родной ЖКХ, обрадовавшись моим платежам за капремонт, решил планово отключить горячее водоснабжение. Что повлекло необходимость включить водогрейку. Водогрейка старенькая, с одной крутилкой (ТЭНы пора бы проревизировать), и вот призадумался – а до какой температуры она греет? Ну вот – и задача: сделать термометр с показаниями температуры на этот индикатор.

Задействовать под это дело ардуину было жалко – это даже не «из пушки по воробьям»… Поэтому, в хозяйстве нашел такие штучки (другой продавец, у которого брал я — кончились):



Это микроконтроллер, ну прямо почти совсем микро. У него всего 8 ног. Учитывая. Что 2 – это питание и одна — ресет, остается совсем не густо. Ресет правда можно забрать, но вот если проект будет уличный – то придется отдать пару ног под внешний кварц… В общем – с ресурсами ног для большого проекта тут туго. Но нам для индикатора нужно всего 3 ноги. И еще 1 ногу под термодатчик. Да и по условиям ТЗ никакого уличного исполнения не требуется – так что вполне хватит (еще и остается).

Надо сказать – тинька в дип-корпусе, возможно, не лучший выбор. Для ее программирования потребуется программатор. Да, такой программатор делается из любимой ардуины просто подключением проводов. Но если у вас нет свободной ардуины – можно обратить внимание на такую штучку, как дигиспарк. Такие или такие. Это та же тинька, только на плате с гребенкой контактов, стабилизатором питания и, главное, интерфейсом УСБ для прошивки. На вид – очень удобная штука. Но я пока не пробовал, подробностей не расскажу.

Итак, процессор есть, индикатор есть, остался – датчик. За датчик возьмем любимый даллас, знакомый нам со времен метеостанции:



Ну и чтобы собрать все – кусочек макетной платы (посчитал что ЛУТ для этого напрягать не стоит…).

Ну еще понадобятся провода и один резистор на 4,7К



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



Макетку закрепил прямо на выводы индикатора (пришлось их выпаять и удлинить чтобы иметь возможность шить тиньку при необходимости)

Это что касается железа. Но есть же и вторая сторона – софт. Надо сказать, что в среде разработки ардуино есть возможность «подключить» разные типы процессоров и компилировать прошивки под них. Само программирование при этом остается в довольно удобной среде – с возможностью компиляции и отладки. А еще – написанную программу можно скомпилировать под другой процессор просто переключив тип процессор в настройках. Таким образом – работа с термодатчиком сводилась к выбору наиболее удобного куска кода из примеров оболочки (или из тысяч готовых примеров в интернете). А вот индикатор заставил помучатся. В гугле нашлось несколько вариантов работы с индикатором. Но из-за динамической индикации (см выше) это все было несколько неудобно… Поковырявшись пару вечеров – сделал для себя пару подпрограмм, которые позволяли писать основной код относительно комфортно.

На что обратить внимание? Первое: подпрограмма «рисования» на индикаторе должна уметь нарисовать нужные нам символы. 7-сегментный индикатор позволяет кодировать символы одним байтом – 8 бит — это как раз 7 сегментов + десятичная точка. Берем «маску» для цифр из найденных примеров, дорисовываем нужные нам символы (при желании – можно реализовать бОльшую часть латинского алфавита). Готово.

Второе. Нам нужно вызывать эту подпрограмму постоянно. Но, в коде опроса датчика температуры, например, есть место с паузой – нужно ждать минимум 750миллисекунд. Можно попробовать вместо паузы засечь время и пропускать последующий код, пока не пройдет нужное время. А можно написать еще одну процедуру, в которую передавать время паузы. И пусть она сама дергает рефреш индикатора… Такой подход позволит использовать паузу в разных местах, не перегружая код (эта подпрограмма во второй части обзора).

Третье – работать с масками символов не очень удобно. Температуру то нам датчик вернет в виде десятичного значения, а не в виде маски… Значит – делаем еще одну процедуру (зачеркнуто) функцию, которая по значению цифры вернет ее код
Таким образом – работать с индикатором стало вполне удобно. Пишем небольшой код, отлаживаем, запускаем. Добавляем какие-ни-будь фишки, пьем пиво. За несколько вечеров проект запустился и отлично работал. Мигания индикатора (динамическая индикация) не было заметно (для такой маленькой задачи это не удивительно). Начал собирать все на макетку и думать, как встроить полученную конструкцию в водогрейку (блок питания нашелся в виде зарядки от старого мобильника).





Пока отлаживался на тиньку, пришлось научиться пользоваться логическим анализатором. Шикарная штука! У меня не получалось тинькой считать температуру. Анализатор, оказывается, «знает» протоколы, в том числе – 1wire.
Дополнительная информация

При считывании работы тиньки сразу показал, что не выдержаны временные интервалы…. Решилось прошивкой в тиньку загрузчика (все есть в ардуино ide) – видимо пришли от китайцев с загрузчиком на 1мгц, а я шил ее как 8…

В общем – все заработало!



Код получился такой:
// Экран 595 и термодатчик на Attyny85
// © Naevus 2016

#define SCLK 2  // пины Attyny85
#define RCLK 1     
#define DIO 0    
byte digitBuffer[4];

#include <OneWire.h>
OneWire oneWire(4); // пин термодатчика
float Temp;
OneWire ds(4);

long TMillis = 0;
long TPause = 5000; // интервал опроса датчика
long PMillis = 0;
long PPause = 800; // пауза на датчике для протокола (минимум 750)
int s = 0; //скринсейвер
long SMillis = 0;
long SPause = 20000; // интервал скринсейвера

const byte chr[4] = { // маска для разряда
      0b00001000,  
      0b00000100,  
      0b00000010,  
      0b00000001  
  };

int T = 0; // сотни
int D = 2; // десятки
int U = 0; // единицы


void setup(void)
{
  pinMode(RCLK, OUTPUT);
  pinMode(SCLK, OUTPUT);
  pinMode(DIO, OUTPUT);  
  pinMode(3, OUTPUT);  
}

void loop(void)
{ 

  // скринсейвер
  if (millis() > SMillis){
    if (s == 1) {s = 0;} else {s = 1;};
    if (T != 0 && T != 10 ) {s=1;};
    SMillis = millis()+SPause;
  }

  
  // Если пауза больше, то читаем датчик
  if(millis() > TMillis) {

digitalWrite(3,LOW);

    byte i;
    byte present = 0;
    byte data[12];
    byte addr[8];
    ds.reset();
    ds.skip();
    // Start conversion
    ds.write(0x44, 1);

    // Тут по протоколу долна быть пауза 750 минимум
    PMillis = millis()+PPause;
    while (millis() < PMillis){
      // Пока пауза - рефрешим дисплей
      showDisplay(); // delay(1);
    };

    present = ds.reset();
    ds.skip();
    // Issue Read scratchpad command
    ds.write(0xBE);
    // Receive 9 bytes
    for ( i = 0; i < 9; i++) { data[i] = ds.read(); }
    // Calculate temperature value
    Temp = ( (data[1] << 8) + data[0] )*0.0625;
   

    // Сотни
    T = Temp/100; 
    // Десятки
    D = (Temp - (T*100)) / 10;
    // Единицы
    U = Temp - (T*100) - (D*10);
  
  
    if (T == 0) {T = 10;} // пусто
    if (s==0) { digitBuffer[3]= 10; }
    else { digitBuffer[0]= T; };
    digitBuffer[0+s]= D; 
    digitBuffer[1+s]= U; 
    digitBuffer[2+s]= 11;   

digitalWrite(3,HIGH);
 
    TMillis = millis()+TPause; 
  }

//595
  showDisplay();   
}

void showDisplay(){
  
  const byte digit[18] = {  // маска для 7 сигментного индикатора  
      0b11000000, // 0
      0b11111001, // 1
      0b10100100, // 2
      0b10110000, // 3
      0b10011001, // 4
      0b10010010, // 5
      0b10000010, // 6
      0b11111000, // 7
      0b10000000, // 8
      0b10010000, // 9 
      0b11111111, // 10 Пусто
      0b10011100, // 11 Градус
      0b10001000, // 12 A
      0b11000110, // 13 C
      0b10100001, // 14 d
      0b10000110, // 15 E
      0b10101111, // 16 r
      0b10001011, // 17 h
      
  };

  // отправляем в цикле по два байта в сдвиговые регистры
  for(byte i = 0; i <= 3; i++){ 
    digitalWrite(RCLK, LOW); // открываем защелку
      shiftOut(DIO, SCLK, MSBFIRST, digit[digitBuffer[i]]);  // отправляем байт с "числом"
      shiftOut(DIO, SCLK, MSBFIRST, chr[i]);   // включаем разряд
    digitalWrite(RCLK, HIGH); // защелкиваем регистры
  }  
}


Похвастался конструкцией товарищу. Он тут же дал мне ссылку на сообщество ардуинщиков на драйве (сам он заядлый участник драйва). Зашел ради интереса. И в первых же строках увидел топик «Безнадега…» с фотографией обозреваемого индикатора. Человек просил помощи в подключении этого чуда. Я не мог оставить просьбу о помощи без внимания. Отписал… Завязалась переписка… В общем – на пару недель я занялся его проблемой. От него было четкое ТЗ (см начало обзора про проблемы с придумыванием), что служило стимулом к работе. Неудобно было делать все дистанционно, но я уже имел опыт «редактирования autoexec.bat по телефону с бухгалтером», так что боле мене мы справились. Из неудач – нашел удобную библиотеку под RTC, но она не заработала у «заказчика». Пришлось переделывать на библиотеку, которая у него запускалась. Код поэтому страшный – преобразование типов (как и их выбор) наверняка можно сделать проще. Но главное – работает.
С этой задачей я забросил свой водонагревательный проект на самом завершающем этапе. А потом уже и воду горячую дали…

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


Итак, задача была простая: выводить на индикатор время от rtc и периодически менять его на показания температуры. В процессе реализации проект немного оброс фичами. Постарался сделать их отключаемыми (доделываю потихоньку). Что получилось:
  • Часы. Возможность корректировки показаний двумя кнопками. «Ход» часов обеспечивает модуль RTC с отдельным питанием.
  • Термометр. Сменяет показания часов по кнопке или по времени (настраивается перед прошивкой)
  • Вольтметр. Меняет показания по кнопке. Может контролировать выход напряжения за заданный предел и мигать индикатором
  • Управление реле по напряжению – пределы включения и выключения задаются отдельно.

Что для этого понадобилось? Ну кроме индикатора и термодатчика из первой половины обзора:
  • Ардуина. Да, Тиньки тут уже мало – по количеству ног не вписывается. Зато на ардуине можно в дальнейшем наращивать фичи. Уже есть парочка в планах.
    Подойдет любая ардуина. Я использую нано,
    Дополнительная информация


    она подходящих размеров и имеет порт УСБ, что позволяет шить ее непосредственно компьютером. (ардуино мини, например, меньше размером, но без порта – шить ее можно другой ардуиной или программатором)
  • Модуль часов RTC. У меня под рукой был такой (другой продавец).
    Дополнительная информация





    А у «заказчика» – такой (другой продавец, вернее, я вообще такие не заказывал еще). Это добавило головняков с несовместимостью библиотек и отладкой.
  • Пара резисторов. Неплохо бы подобрать резисторы с минимальным температурным коэффициентом. Ну или хотя-бы максимально одинаковых. Предлагаю взять 4 одинаковых резистора (5-10килоом) и соединить три из них последовательно. Получится делитель 4:1, что позволит измерять напряжение до 20вольт. Если у вас в хламе не найдется 4 резисторов – в ближайшем магазине они стоят копейки.
  • Кнопки. Я для тестирования использовал первые попавшиеся. У «заказчика» кнопки были в подготовленном корпусе для устройства.
  • Реле. На один канал (другой продавец)
    Дополнительная информация



    или на два (для будущих фич) (другой продавец)
    Дополнительная информация

  • Питание. До реализации в авто я не дошел (да и не собирался пока), поэтому вопрос питания оставил на усмотрение «заказчика». Простое решение – старый автомобильный зарядник для телефона.

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

Код
// Термометр, часы 1307 и вольтметр на 7-сегментном дисплее на 595 (динамическая индикация)
// © Naevus 2016

/// Настройки. Все насройки, которые слдует просмотреть/изменить под себя помечены тремя косыми чертами ///


/// Блоки условного компилирования. Если какое то оборудование не используется - отключите его и прошивка 
/// скомпилируется без этого функционала (и можно не настраивать соответствующий блок в настройках
#define D7SEG  1 /// Если подключен 7 сегментный дисплей, то 1 иначе 0.
#define VOLT   1 /// Если подключен вольтметр... (мигать экраном при выходе напряжения за пределы)
#define DS1820 1 /// Если подключен термодатчик...
#define RTCDS  1 /// Если подключен модуль RTC...
#define BUTTN  1 /// Если подключены кнопки...


#if D7SEG == 1
  /// Экран на 595 сдвиговом регистре
  #define SCLK 12 /// пины для подключения экрана
  #define RCLK 11 ///
  #define DIO  10 ///
  byte digit[4]; // Буфер значений знакомест. В буфер помещается маска выводимых символов для отправки на дисплей
#endif


#if VOLT == 1
  /// Вольтметр
  // 
  //  Измеряемое
  //  напряжение  ─┐
  //              ┌┴┐
  //              │  │R2
  //              └┬┘
  //                ├───── Аналоговый вход Arduino
  //              ┌┴┐
  //              │  │R1
  //              └┬┘
  //              ═╧═
  //
  // Rmax должно быть минимум в 3 раза больше Rmin. (позволяет измерять напряжение до 20в).
  // Например 30 и 10 КОм соответственно. Лучше взять 4 одинаковых резистора, один R1 и три последовательно на R2
  #define R1  7.3     /// Резистор в нижнем плече делителя. У меня 7,3К 
  #define R2  29.5    /// Резистор в верхнем плече делителя. У меня 29,5К. 
  #define VIN A0      /// аналоговый вход для вольтметра
  #define VCORR 0.912 /// коэффициент корректировки
                      /// Для расчета коэффициента:
                      /// 1. выставляем коэффициент = 1
                      /// 2. Выставляем vmin = 100
                      /// 3. Компилируем, запускаем.
                      /// 4. Подключаем источник напряжения (АКБ 12В)
                      /// 5. Записываем показания индикатора (например 13,5)
                      /// 6. Замеряем это же напряжение образцовым вольтметром. Записываем (например 12,3)
                      /// 7. Делим замеренное на показаное. Т.е. 12,3/13,5=0,911
                      /// 8. Это и есть коэффициент для вашего экземпляра ардуины. Прописываем его в vcorr
                      /// 9. Не забываем вернуть обратно vmin
  /// Если не подключен или не используется - задайте VMIN = 0 а VMAX = 1000. 
  #define VMIN  0     /// минимальное напряжение для аларма (если ниже - будет мигать)
  #define VMAX 15.1   /// максимальное напряжение для аларма (если выше - будет мигать)
  #define VRPIN 13    /// Пин для подключения реле 
  #define VRMIN 11.0  /// Реле выключается если напряжение меньше VRMIN
  #define VRMAX 12.5  /// Реле включается если напряжение больше VRMAX
  float vvalue; // Напряжение
#endif

#if DS1820 == 1
  /// Термодатчик
  #define TPIN 9 /// Пин термодатчика. Тип термодатчика DS18x20 определяется автоматически
  #include <OneWire.h> // Библиотека термодатчика
  OneWire ds(TPIN);
  byte type_s = 0;     // Тип датчика (после автоматического определения)
#endif


/// Часы
#define POINTTIME 500 /// Полупериод мигания точкой - полсекунды. Этот же период берется за основу для мигания прочих элементов.
#define SETPAUSE 500  /// Пауза для быстрой смены показаний при настройке часов при удержании кнопки set
#include <Time.h>
#include <DS1307RTC.h>
#include <Wire.h>
long pointmillis; // Время для мигания точкой
int point = HIGH; // состояние точки в данный момент
int H;            // часы
int M;            // минуты
long setmillis=0; //Время для паузы корректировки показаний длинного нажатия


#if BUTTN == 1
  /// Кнопки. Кнопки без резисторов, замыкание на землю.
  // "Режим" - длинное нажатие переводит в режим установки часов. Выход из режима так же или через 5сек
  // Короткое нажатие - меняет режим установки часов на минут и обратно. 
  // В режиме часов короткое нажатие показывает напряжение
  // "Установка" - в режиме часов показывает термометр.
  // В режиме корректировки меняет значение часов или минут.
  #define MPIN 8      /// пин кнопки "Режим"
  #define SPIN 7      /// пин кнопки "Установка"
  #define BPAUSE 2000 /// пауза для длинного нажатия 2 сек
  #define AD 5        /// пауза для антидребезга. подбирать для конкретных кнопок экспериментально
  #define TOPAUSE 5000/// пауза для автоматического выхода из режима уствновки часов-минут
  int mstate = 0; // состояние кнопки mode
  int sstate = 0; // состояние кнопки set
                  // 0 - не нажата
                  // 1 - нажата, не отпущена (короткое нажатие)
                  // 2 - нажата, отпущена (короткое нажатие)
                  // 3 - нажата не отпущено (длинное нажатие)
                  // 4 - нажата, отпущена (длинное нажатие)
  long mmillis;   // время для запоминания нажатия кнопки mode
  long smillis;   // время для запоминания нажатия кнопки set
  #include "Bounce2.h"; // Библиотека с антидребезгом
  Bounce mbutton = Bounce(); // Антидребезговые кнопки
  Bounce sbutton = Bounce();
#endif


/// Общие переменные и константы
#define CPAUSE 20000 /// Время отображения часов - 20 сек
#define TPAUSE  3500 /// Время отображения градусника (или напряжения) - 3.5 сек
long ctmillis = 0; // Время для счетчика переключателя часы-температура
int state; // Режим работы:
           // 0 - Часы. Отображает часы, мигает точкой раз в секунду. Каждые (задано) сек переключается в режим температуты
           // 1 - Термометр. Запрашивает температуру, отображает заданое время, по окончании - возврат в часы.
           // 2 - Установка часов. Вход а режим - длительное нажатие кнопки mode. Выход так же или через (задано) сек неактивности. 
           // 3 - Установка минут. Вход а режим - короткое нажатие кнопки mode из режима установки часов. Выход так же или через (задано) сек неактивности. 
           // 4 - Аларм по напряжению. Мигает напряжением если оно вышло за пределы
           // 5 - Напряжение. время отображения - как у термометра
           // Из 2 в 3 и обратно - короткое нажатие mode. В 2 и 3 нажатие set меняет показания часов/минут.
           // Если состояние требует различать вход и повторный вход, то для повторного к состоянию добавляем 10.
           // Т.е. 0 - часы первый запуск, 10 - часы последующие запуски
char dbuffer [6]; // буффер для строки с запятой



void setup(void)
{
  // Инициализация пинов экрана
  pinMode(RCLK, OUTPUT);
  pinMode(SCLK, OUTPUT);
  pinMode(DIO, OUTPUT);  


  #if BUTTN == 1
    // Инициализация пинов кнопок. 
    pinMode(MPIN, INPUT_PULLUP);
    pinMode(SPIN, INPUT_PULLUP);
    // инициализация антидребезга
    mbutton.attach(MPIN);
    sbutton.attach(SPIN);
    mbutton.interval(AD);
    sbutton.interval(AD);
  #endif
  

  #if VOLT == 1
    // Инициализация пина вольтметра
    pinMode(VIN, INPUT);
    pinMode (VRPIN, OUTPUT);
  #endif

#if DS1820 == 1
  //Поиск и распознавание термодатчика 
  byte addr[8];
  if ( !ds.search(addr)) {ds.reset_search(); type_s = 99;} // датчик не найден
  else {switch (addr[0]) { // Первый байт - тип датчика
          case 0x10: type_s = 1; break; //DS18S20 или старый DS1820
          case 0x28: type_s = 0; break; //DS18B20
          case 0x22: type_s = 0; break; //DS1822
          default: type_s = 99; //ошибка определения типа датчика      
       }
  } 
#endif  


  // Инициализация часов
  setSyncProvider(RTC.get);   // получаем время с RTC
  ///установим вручную - один раз установили и хватит
  ///TimeElements te;
  ///te.Second = 0; //секунды
  ///te.Minute = 53; //минуты
  ///te.Hour = 12; //часы
  ///te.Day = 16; //день
  ///te.Month = 2; // месяц
  ///te.Year = 2016 - 1970; //год в библиотеке отсчитывается с 1970
  ///time_t timeVal = makeTime(te);
  ///RTC.set(timeVal);
  ///setTime(timeVal);

  state = 0; // По умолчанию - часы
}



void loop(void)
{  
  switch(state){      
    case  0 : rclock();  break; // отрабатываем часы (первый раз)
    case 10 : rclock();  break; // отрабатываем часы
    #if DS1820 == 1
      case  1 : rtemp() ;  break; // отрабатываем термометр (первый раз)
      case 11 : rtemp() ;  break; // отрабатываем термометр
    #endif
    #if BUTTN == 1
      case  2 : rhour ();  break; // установка часов
      case 12 : rhour ();  break; // установка часов
      case  3 : rmin  ();  break; // установка минут
      case 13 : rmin  ();  break; // установка минут
    #endif
    #if VOLT == 1
      case  4 : rvalarm(); break; // отрабатываем аларим по напряжению (первый раз)
      case 14 : rvalarm(); break; // отрабатываем аларим по напряжению
      case  5 : rvolt() ;  break; // отрабатываем напряжение (первый раз)
      case 15 : rvolt() ;  break; // отрабатываем напряжение
    #endif
    default   : rclock();
  }


  #if VOLT == 1
    // Вольтметр   
    float vread = analogRead(VIN);                   // Читаем АЦП
    vvalue = vread * ((5*VCORR*(R1+R2)/R1)/1024);    // Преобразуем к напряжению
    if (vvalue < VRMIN){digitalWrite(VRPIN,LOW);}    // Выкл реле если напряжение меньше
    if (vvalue > VRMAX){digitalWrite(VRPIN,HIGH);}   // Вкл реле если напряжение больше
    if (vvalue > VMAX || vvalue < VMIN) {state = 4;};// аларм вольтметра
  #endif
  

  #if BUTTN == 1
    rbutton(); // опрашиваем кнопки
  #endif

  
  showDisplay(); // Рефрешим дисплей
}


#if BUTTN == 1
  void rbutton (void) { // Кнопки
    mbutton.update(); // Mode
    switch (mstate){
      case 0: if (!mbutton.read()){mstate = 1; mmillis = millis() + BPAUSE;}// нажали кнопку
              break;    
      case 1: if ( mbutton.read()){mstate = 2;} // отжали кнопку
              else {if (millis()>mmillis){mstate = 3;}} // длинное нажатие
              break;
      case 2: mstate = 0; break; 
      case 3: if ( mbutton.read()){mstate = 4;} // отжали длинное нажатие
              break;
      case 4: mstate = 0; break;
      default: mstate = 0;
    }  
    sbutton.update(); // Set
    switch (sstate){
      case 0: if (!sbutton.read()){sstate = 1; smillis = millis() + BPAUSE;}// нажали кнопку
              break;    
      case 1: if ( sbutton.read()){sstate = 2;} // отжали кнопку
              else {if (millis()>smillis){sstate = 3;}} // длинное нажатие
              break;
      case 2: sstate = 0; break; 
      case 3: if ( sbutton.read()){sstate = 4;} // отжали длинное нажатие
              break;
      case 4: sstate = 0; break;
      default: sstate = 0;
    }
  }
#endif



#if VOLT == 1
  void rvolt(void){ // Отображение напряжения
    if (state == 15) { // Повторный вход. просто проверяем время и выходим
      if (millis() > ctmillis){state = 0;} // Если время отображения термометра кончилось, переключаемся на часы  
      return;
    } else {
      dtostrf(vvalue, 4, 1, dbuffer); // Преобразуем напряжение в набор символов
      // пытаемся вставить знак U в нужное место (проверяем, есть ли в наборе символов точка или запятая)
      if (dbuffer[1]==44 || dbuffer[1]==46 ||
          dbuffer[2]==44 || dbuffer[2]==46){dbuffer[4] = 'U';}
      else {dbuffer[3] = 'U';}

      led7print(dbuffer); // Функция для записи символов в буфер индикатора  

      ctmillis = millis()+TPAUSE; // время для переключения обратно на часы
      state = 15; // меняем состояние на повторное
    }  
  }
#endif


#if VOLT == 1
  void rvalarm(void){ // Аларм напряжения (мигает)
    if (vvalue>VMIN && vvalue<VMAX) {state = 0; return;} //Если напряжение нормальное - выходим в часы

    if (millis()>=pointmillis) {
      point = !point; //раз в pointtime мигаем напряжением
      pointmillis = pointmillis + POINTTIME; 
      if (point) {
        dtostrf(vvalue, 4, 1, dbuffer); // Преобразуем напряжение в набор символов
        // пытаемся вставить знак U в нужное место (проверяем, есть ли в наборе символов точка или запятая)
        if (dbuffer[1]==44 || dbuffer[1]==46 ||
            dbuffer[2]==44 || dbuffer[2]==46){dbuffer[4] = 'U';}
        else {dbuffer[3] = 'U';}
      }
      else {
        dbuffer[0] = ' ';
        dbuffer[1] = ' ';
        dbuffer[2] = ' ';
        dbuffer[3] = ' ';
       } //  мигаем напряжением

      led7print(dbuffer); // Функция для записи символов в буфер индикатора  
    }
  }
#endif



void rclock(void) { // Отображение часов
  char cbuff[6]; //Буфер для часов

  
  if (state == 10) { // Повторный вход. просто проверяем время 
    if (millis() > ctmillis){state = 1; return;} // Если время отображения часов кончилось, переключаемся на термометр

    #if BUTTN == 1
      // Проверяем кнопки
      #if VOLT == 1
        if (mstate == 2) {state = 5; return;} // если нажата Mode то переходим к вольтметру
      #endif
      #if DS1820 == 1
        if (sstate == 2) {state = 1; return;} // если нажата Set то переходим к термометру
      #endif
      if (mstate == 3) {state = 2; return;} // если долго нажата Mode то переходим к корректировке часов
    #endif
  }
  else{
    #if BUTTN == 1
      if (mstate != 4) { //если длинная кнопка отпущена
         state = 10; ctmillis = millis()+CPAUSE;} // если первый вход - запоминаем время
    #else
      state = 10; ctmillis = millis()+CPAUSE;
    #endif
  }
   
    
  // мигание точки в часах
  if (millis()>=pointmillis) {
    point = !point; //раз в pointtime меняем точку на не точку
    pointmillis = pointmillis + POINTTIME; 

    H=hour(); 
    M=minute();

    if (point) {
      cbuff[0]=H/10;
      cbuff[1]=H-(cbuff[0]*10);
      cbuff[0]=cbuff[0]+48; // +48, чтобы из значения получить ascii код цифры
      cbuff[1]=cbuff[1]+48;
      cbuff[2]=',';
      cbuff[3]=M/10;
      cbuff[4]=M-(cbuff[3]*10);
      cbuff[3]=cbuff[3]+48;
      cbuff[4]=cbuff[4]+48;
    } 
    else {
      cbuff[0]=H/10;
      cbuff[1]=H-(cbuff[0]*10);
      cbuff[2]=M/10;
      cbuff[3]=M-(cbuff[2]*10);
      cbuff[0]=cbuff[0]+48;
      cbuff[1]=cbuff[1]+48;
      cbuff[2]=cbuff[2]+48;
      cbuff[3]=cbuff[3]+48;
    } 

    led7print(cbuff); // выводим время и мигаем точкой
  }
}


#if BUTTN == 1
  void rhour(void) { // Установка часов
    char cbuff[6]; //Буфер для часов
    M=minute();

    if (state == 2) { // Первый вход. Ждем когда отпустят кнопку mode
      if (mstate != 3){ //Если кнопку отпустили
        state = 12; ctmillis = millis()+TOPAUSE;  // Запоминаем время
        H=hour();}
    }   

    if (state == 12){
      if (millis()>ctmillis){state = 0;}  

      // Проверяем кнопки
      if (mstate == 2) {state = 3; return;} // если была нажата Mode то переходим к установке минут
      if (mstate == 3) {state = 0; return;} // если долго нажата Mode то переходим к часам

      if (sstate == 2){ // если  нажата Set
        H = H+1; if(H > 23) {H = 0;}
        ctmillis = millis()+TOPAUSE; // и обнуляем таймаут для выхода
      }    
      if (sstate == 3) { // если долго нажата Set
        if (millis() > setmillis) {
          H++; if(H > 23) {H = 0;}
          setmillis = millis() + SETPAUSE; // пауза чтобы показания менялись не слишком быстро
        }
        ctmillis = millis()+TOPAUSE; // и обнуляем таймаут для выхода
      }
      if (sstate == 2 || sstate == 4) { //кнопку отпустили - толкаем все в rtc
        setTime(H, M, 0, day(), month(), year()); 
        RTC.set(now());      
      }
    }

    cbuff[0]=H/10;
    cbuff[1]=H-(cbuff[0]*10);
    cbuff[0]=cbuff[0]+48; // +48, чтобы из значения получить ascii код цифры
    cbuff[1]=cbuff[1]+48;
    cbuff[2]=',';
    cbuff[3]=M/10;
    cbuff[4]=M-(cbuff[3]*10);
    cbuff[3]=cbuff[3]+48;
    cbuff[4]=cbuff[4]+48;

    // мигание часов
    if (millis()>=pointmillis) {
      point = !point; //раз в pointtime меняем точку на не точку
      pointmillis = pointmillis + POINTTIME;
      if (point && sstate != 3) { //мигаем если не нажата set
        cbuff[0]=' ';
        cbuff[1]=' ';
      }
     
    led7print(cbuff); // выводим время и мигаем

    }
  }
#endif


#if BUTTN == 1
  void rmin(void) { // Установка минут
    char cbuff[6]; //Буфер для часов
    H=hour();

    if (state == 3) { // Первый вход.
        state = 13; ctmillis = millis()+TOPAUSE;  // Запоминаем время
        M=minute();
    }   

    if (state == 13){
      if (millis()>ctmillis){state = 0;}  

      // Проверяем кнопки
      if (mstate == 2) {state = 2; return;} // если была нажата Mode то переходим к установке часов
      if (mstate == 3) {state = 0; return;} // если долго нажата Mode то переходим к часам

      if (sstate == 2) { // если нажата Set то прибавляем часы
        M = M+1; if(M > 59) {M = 0;}
        ctmillis = millis()+TOPAUSE; // и обнуляем таймаут для выхода
      }
      if (sstate == 3) { // если нажата Set то прибавляем часы
        if (millis() > setmillis) {
          M = M+1; if(M > 59) {M = 0;}
          setmillis = millis() + SETPAUSE; // пауза чтобы показания менялись не слишком быстро
        }       
        ctmillis = millis()+TOPAUSE; // и обнуляем таймаут для выхода
      }

      if (sstate == 2 || sstate == 4) {     
        /// тут как то надо затолкать часы в RTC
        setTime(H, M, 0, day(), month(), year()); 
        RTC.set(now());      
      }
    }
    
    cbuff[0]=H/10;
    cbuff[1]=H-(cbuff[0]*10);
    cbuff[0]=cbuff[0]+48; // +48, чтобы из значения получить ascii код цифры
    cbuff[1]=cbuff[1]+48;
    cbuff[2]=',';
    cbuff[3]=M/10;
    cbuff[4]=M-(cbuff[3]*10);
    cbuff[3]=cbuff[3]+48;
    cbuff[4]=cbuff[4]+48;

    // мигание часов
    if (millis()>=pointmillis) {
      point = !point; //раз в pointtime меняем точку на не точку
      pointmillis = pointmillis + POINTTIME;
      if (point && sstate != 3) { //мигаем если не нажата set
        cbuff[3]=' ';
        cbuff[4]=' ';
      }
     
    led7print(cbuff); // выводим время и мигаем

    }
  }
#endif


#if DS1820 == 1
  void rtemp (void) { // Отображение температуры
    float temp;      // Температура
    byte present = 0;// Наличие датчика
    byte data[12];   // Сюда читаем данные с датчика

    if (type_s == 99 ) {state = 0; return;} // если датчик не найден, то сразу возвращаемся в часы

    if (state == 11) { // Повторный вход. просто проверяем время и выходим
      if (millis() > ctmillis){state = 0;} // Если время отображения термометра кончилось, переключаемся на часы  
      return;
    }
      
    else { // Иначе - запрашиваем температуру
      byte i;
      ds.reset();
      ds.skip();
      ds.write(0x44, 1);
      delays(800); //по протоколу пауза перед считыванием температуры. Минимум 750мс
      present = ds.reset();
      ds.skip();
      ds.write(0xBE);
      for ( i = 0; i < 9; i++) { data[i] = ds.read(); }
      int16_t raw = (data[1] << 8) | data[0];
      if (type_s) {
        raw = raw << 3; // 9 bit resolution default
        if (data[7] == 0x10) {
          // "count remain" gives full 12 bit resolution
          raw = (raw & 0xFFF0) + 12 - data[6];
        }
      } else {
        byte cfg = (data[4] & 0x60);
        // at lower res, the low bits are undefined, so let's zero them
        if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
        else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
        else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
        // default is 12 bit resolution, 750 ms conversion time
      }
      
      temp = (float)raw / 16.0; // Получаем температуру

      dtostrf(temp, 4, 1, dbuffer); // Преобразуем температуру в набор символов

      // пытаемся вставить знак градуса в нужное место (проверяем, есть ли в наборе символов точка или запятая)
      if (dbuffer[1]==44 || dbuffer[1]==46 ||
          dbuffer[2]==44 || dbuffer[2]==46){
        dbuffer[4] = '"';}
      else {dbuffer[3] = '"';}

      led7print(dbuffer); // Функция для записи символов в буфер индикатора

      ctmillis = millis()+TPAUSE; // время для переключения обратно на часы
      state = 11; // меняем состояние на повторное
    }
  }
#endif



void delays (long pause){ // Замена штатной функции delay на собственную - с рефрешем индикатора
  long pmillis = millis()+pause; // запоминаем время паузы
  while (millis() < pmillis){showDisplay();}; // Ждем наступления времени паузы, попутно рефрешим дисплей
}



void led7print (char dstr[6]){ // Процедура разбора строки и заполнение буфера для индикатора
  byte c = 0;  //счетчик для входного буфера
  byte d = 0;  //счетчик для ВЫходного буфера

  // Разбираем буфер на символы (ищем запятую)
  while (d < 4) {    
    switch (dstr[c]) {
      case 44: c++;bitClear(digit[d-1],7);break; // запятая
      case 46: c++;bitClear(digit[d-1],7);break; // точка
      case 0 : for (byte i=d; i<4; i++) {digit[i]=22;}; d=4; break; //конец строки, заполняем все остальное пробелами
      default: digit[d]=ascii2mask(dstr[c]); c++; d++; // по умолчанию просто переносим символ
    }
  }
}



void showDisplay(void){ // процедура отображения экрана
  const byte chr[4] = {0b00001000,0b00000100,0b00000010,0b00000001}; // маска для разряда знакоместа

  for(byte i = 0; i <= 3; i++){ // отправляем в цикле по два байта в сдвиговые регистры
    digitalWrite(RCLK, LOW); // открываем защелку
    shiftOut(DIO, SCLK, MSBFIRST, digit[i]);  // отправляем байт с "числом"
    shiftOut(DIO, SCLK, MSBFIRST, chr[i]);   // включаем разряд
    digitalWrite(RCLK, HIGH); // защелкиваем регистры
    //delay(1); // ждем немного перед отправкой следующего "числа"... если не ждать то мигания меньше.
  }  
} 


 
byte ascii2mask (int ascii){ // Функция перевода кода символа в его маску
  // Маски символов
  const byte mask[27] = {
      0b11000000, // 0
      0b11111001, // 1
      0b10100100, // 2
      0b10110000, // 3
      0b10011001, // 4
      0b10010010, // 5
      0b10000010, // 6
      0b11111000, // 7
      0b10000000, // 8
      0b10010000, // 9 
      
      0b10001000, // 10 A
      0b10000011, // 11 b
      0b10100111, // 12 c
      0b10100001, // 13 d
      0b10000110, // 14 E
      0b11111111, // 15 F
      
      0b10001011, // 16 h
      0b11000111, // 17 L
      0b10100011, // 18 o
      0b10001100, // 19 P
      0b10101111, // 20 r
      0b10000111, // 21 t
      0b11100011, // 22 u
      
      0b11111111, // 23 Пусто
      0b10011100, // 24 Градус (")
      0b10111111, // 25 -
      0b11110111, // 26 _
  };

  if (ascii > 47 && ascii < 58) {return mask[ascii-48];} // цифры
  if (ascii > 64 && ascii < 71) {return mask[ascii-55];} // A-F
  if (ascii > 96 && ascii < 103){return mask[ascii-87];} // a-f
  switch(ascii){      
    case 32 :return mask[23]; // пробел
    case 34:return mask[24]; // градус
    case 45 :return mask[25]; // -
    case 95 :return mask[26]; // _
    case 72 :return mask[16]; // H
    case 104:return mask[16]; // h
    case 76 :return mask[17]; // L
    case 108:return mask[17]; // l
    case 79 :return mask[18]; // O
    case 111:return mask[18]; // o
    case 80 :return mask[19]; // P
    case 112:return mask[19]; // p
    case 82 :return mask[20]; // R
    case 114:return mask[20]; // r
    case 83 :return mask[5];  // S
    case 115:return mask[5];  // s
    case 84 :return mask[21]; // T
    case 116:return mask[21]; // t
    case 85 :return mask[22]; // U
    case 117:return mask[22]; // u
  }
  return mask[26]; // если символ не из списка, то отображаем подчеркивание
}


Ну и результат:

Время


Температура


Напряжение (для отладки замеряю напряжение стабилизатора 3,3 ардуины)


Фотовспышка засвечивает индикатор до невидимости, вот фото без вспышки (но с шевеленкой, сорри)







Итог. Неплохой в принципе индикатор при условии наличия избытка вычислительных мощностей. Но если у вас основа поделки – часы, лучше взять индикатор на tm1637 (вроде бы видел такие комбинированные – с десятичными точками и двоеточием одновременно. Но сейчас навскидку не нашел :(, только индикаторы отдельно).

Рабочие моменты







Планирую купить +16 Добавить в избранное +34 +53
+
avatar
+6
Да, нужны достаточно веские причины, чтобы использовать этот индикатор, а не ТМ1637, который значительно дешевле ($0,87-$0,88) и гораздо проще в использовании (куча библиотек и примеров использования)
Но обзор понравился
Спасибо
+
avatar
  • Naevus
  • 17 июля 2016, 18:26
0
Спасибо, старался. Критерии выбора написал в самом начале, но ниже kyrios дал основную причину: действительно когда брал их, вообще ничего не знал ни об ардуинах, ни о индикаторах.
+
avatar
0
с точками есть хороший дисплей на микросхеме MAX7219 и еще и с 8 цифрами
+
avatar
  • Naevus
  • 17 июля 2016, 18:28
0
Матрицы 8*8? Я такие показывал в обзоре метеостанции (ссылка в тексте). Приятные и каскадируютя удобно.
+
avatar
0
нет не матрицы
точки — разрядность, и цена тоже хорошая.
aliexpress.com/item/New-MAX7219-LED-Dot-matrix-8-Digit-Digital-Display-Control-Module-for-Arduino-Wholesale/32605671192.html,searchweb201602_2_10039_10057_10048_10047_10056_10055_10037_10049_10059_10033_10046_10058_10032_10045_10017_405_404_407_10040,searchweb201603_4&btsid=56d70f2d-1af7-433e-9b08-ae87c2634a54
+
avatar
  • Naevus
  • 17 июля 2016, 19:17
0
А, точно. Видел их. Такие в прошивке метеостанции тоже поддерживаются (в платной версии). Разрядность, кстати, не всегда «больше-лучше». Вот для термометра — три разряда — вполне достаточно (мне даже пришлось сделать «скринсейвер» чтобы выжигать разряды равномернее). А вот второй проект — наверное да — удобно было бы — половина под часы, половина под температуру. Главное — чтобы было куда потом эту линейку приспособить.
+
avatar
  • kyrios
  • 17 июля 2016, 19:23
0
Кстати эта бы подошла лучше, т.к. остается свободное пространство по бокам и теперь думаю как покрасивее это сделать.А тут решение само собой.
+
avatar
+2
Творчество у нас в почете! Спасибо за обзор.
+
avatar
  • kyrios
  • 17 июля 2016, 14:55
0
Да, нужны достаточно веские причины, чтобы использовать этот индикатор, а не ТМ1637
Или же просто ничего не знать по этой теме на момент приобретения.
Спасибо тебе,Naevus, за помощь в освоении этого индикатора, уверен это пригодится еще многим.
P.S.Кот прикольный.
+
avatar
  • Naevus
  • 17 июля 2016, 18:29
0
Кот любит помогать когда что то делаешь. А в такую жару (см показания термометра) мучается бедненький.
+
avatar
  • kyrios
  • 17 июля 2016, 18:50
+1
Хотел своего сфотографировать на фоне 34.8 градусов в комнате, он не согласился)))
+
avatar
+1
Супер, однозначно плюс за такой обзор!
+
avatar
  • kopa
  • 17 июля 2016, 15:31
0
а эта библиотека не подойдет? alexgyver.ru/arduino/TM74HC595.zip
+
avatar
  • Naevus
  • 17 июля 2016, 18:34
0
Спасибо! поковыряю. но судя по примеру в библиотеке — работать с ней менее удобно чем с моими подпрограммами. Видимо делалась под какую то конкретную задачу.
ps О, оттуда можно выковырять маски на алфавит.
+
avatar
0
зря вы на индикатор наговариваете тут даже в вики тему отразили. очень удобно использовать каскадирование при применении сегмисегментных индикаторов большого размера которые в китайских модулях редки и ценник на них не гуманный. я на соседней с нашим ЦТО помойке постоянно подбираю дюймовые индикаторы серии АЛС со старых ККМ. и пересадить их на новую плату с 595 пара минут. Учитывая обособленные выводы кажного знакоместа можно с динамической индикацией не заморачиваться, просто по 595 на каждый индикатор повесить и забыть о циклах регенирации данных.
+
avatar
  • Naevus
  • 17 июля 2016, 18:36
0
Так кто-ж спорит, что когда 1 595-я на 1 сегмент — это удобно? Вопрос то был — куда деть уже купленные по недоразумению 4-хсегментники с 2-я 595-ми :(
+
avatar
  • DMA
  • 17 июля 2016, 16:25
0
Обзор отличный. Для индикаторов на tm1638 никто не подскажет готового решения по использованию? Валяется парочка в запасах, всё никак руки до них не дотяну,
+
avatar
  • Naevus
  • 17 июля 2016, 18:47
+1
Вот тут
arduino-kit.ru/catalog/id/modul-klaviaturyi-i-svetodiodnoy-indikatsii-tm1638-led_key
отличное описание и пример и библиотека.
+
avatar
  • DMA
  • 17 июля 2016, 21:26
0
Шикарно! Спасибо.
+
avatar
  • chaloc
  • 17 июля 2016, 18:32
0
DS1307RTC.h универсальная библиотека и одинаково работает что на 1307, что на 3231(если не использовать встроенную память часов). В итоге пишем все под 1307, под который примеров масса, а модуль подключаем 3231 — у него точность значительно выше. Wire.h кстати в ней уже содержится.
С платы 3231 нужно выпаять мелкий красный диод справа от м/с часов. Иначе батарейка быстро выйдет из строя от перезаряда.
+
avatar
  • Naevus
  • 17 июля 2016, 18:42
0
С библиотекой — так и сделано. Все работает и у меня на 3231 и у «заказчика» на 1307. Но изначально я делал на библиотеке iarduino_RTC.h. Сравните кусок мигания точкой в скетче из обзора и на этой библиотеке:
if (point) {led7print(time.gettime("H,i"));} else {led7print(time.gettime("Hi"));}

В общем — мне оно больше нравилось… Про диод — у китайцев в эти модули видимо ставятся аккумуляторы литиевые, и диод — это цепь подзарядки. Не представляю — зачем (если и на батарейке они проживут несколько лет), так что спасибо что напомнили — диод удалять.
+
avatar
0
Обзор замечательный! Спасибо. В закладки однозначно. Кое-что из проекта обязательно использую. Плюс!
Маленький вопрос: а в тиньку 13 первый код поместится?
+
avatar
  • Naevus
  • 17 июля 2016, 19:25
0
А сколько памяти в 13-й? Нашел — 1кбайт :( Маловато. Первый скетч в 85-ю компилируется так:
Скетч использует 3 352 байт (40%) памяти устройства. Всего доступно 8 192 байт.
Глобальные переменные используют 99 байт (19%) динамической памяти, оставляя 413 байт для локальных переменных. Максимум: 512 байт.
Можно убрать ненужные символы, переменные перевести в постоянные, отказаться от «скринсейвера»… но, боюсь что в 3 раза этим код не ужмешь. Более того — думаю, что основной объем дает библиотека 1wire. А как от нее избавиться — я не знаю :(
+
avatar
0
Спасибо. Будем думать.
+
avatar
  • Naevus
  • 17 июля 2016, 19:41
0
У меня почему то в менеджере плат не оказалось 13-й. Только 25-я, поэтому проверить не могу (вдруг там под другое ядро по другому компилируется)
+
avatar
  • vismyk
  • 18 июля 2016, 07:54
0
Полезный обзор. Сам уже пару недель конструирую электронный таймер в духовку на замену заедающему механическому. Тоже пришёл к выводу, что индкатор лучше светодиодный 7-сегментный. Но я заказал лысых индикаторов, т.к. 595 на запасе были, да и первоначальная мечта обойтись ATTiny13A обломилась: ног на всю периферию (индикатор, энкодер с кнопкой, реле и динамик) не хватает, поэтому переориентировался на Ардуино ПроМини на 168 атмеге. Пока заказанные индикаторы едут, выдрал 2,5-разрядный индикатор (старшая цифра может быть только 1) из старого АТ-шного кузова и пока экспериментирую с ним. Опыты с динамической индикацией привели к тому, что плюнул на это извращение и достал из закромов второй 595. ;) Сейчас пытаюсь побороть дребезг контактов энкодера и заставить ардуину петь динамиком пионерско-горнистский сигнал «На приём пищи»… ;)
+
avatar
  • Naevus
  • 18 июля 2016, 08:49
0
С дребезгом — посмотрите на библиотеку во второй половине обзора — по ресурсам должна влезть. А по работе — я изначально этот дребезг ловил в блоке обработке клавиш и в каждой подрограмме где по кнопкам менялось состояние. Учитывая динамическую индикацию — просто ужас. Кнопки тупили и глючили… Поискал аппаратное решение (одной ТМ2 на две кнопки как раз хватило бы наверное), но встретил упоминание об этой библиотеке. Я даже не насраивал ничего, убрал свои «ловушки» и просто прыгал от счастья что все работает просто отлично…
+
avatar
  • vismyk
  • 18 июля 2016, 09:08
0
Я находил какую-то очень нахваливаемую библиотеку, но она оказалась несовместимой со свежей Arduino IDE. :( Попробую старую IDE развернуть…
+
avatar
  • Naevus
  • 18 июля 2016, 09:23
0
Ну я делал все на последней версии ide. И библиотеку тупо установил из менеджера библиотек в самом ide. Но судя по тому, что библиотека называется Bounce2.h, где то раньше была и первая версия, которая, возможно, и оказалась несовместимой.
ide 1,0,6 храню на всякий случай, хотя по слухам в ней тоже есть несовместимости с 1,0,5
+
avatar
  • vismyk
  • 18 июля 2016, 09:33
0
Гут, попробую эту Bounce2. А я говорил про эту библиотеку, она в свежей IDE не пашет, пишет что-то типа «не поддерживается на плате ProMini», хотя замена платы на Уно или Мегу в результате меняет только эту надпись… ;)
+
avatar
  • Naevus
  • 18 июля 2016, 10:12
0
Там у вас либа под энкодер заточенная. Не пробовал еще энкодеры (вот, надо заказать… или из мышек надергать...)
+
avatar
  • vismyk
  • 18 июля 2016, 10:55
0
Так я тоже в первый раз с энкодером столкнулся, хотя купил десяток ещё года два-три назад. Девайс оказался не так прост, как хотелось бы… :/
З.Ы. Сейчас вот идея возникла: может вообще вместо энкодера аналоговый джойстик влепить? И программировать проще, и у кого ещё духовка с джойстиком есть? ;)
+
avatar
  • Naevus
  • 18 июля 2016, 11:34
0
Блин — энкодер на установку часов… что-то я по понедельникам туплю конкретно :) Ваще замечательная вешь должна получиться…
С джойстиком прикольно :)
+
avatar
  • johnes
  • 18 июля 2016, 09:31
+2
Кстати (а может уже и знаете эту инфу), с датчиком температуры лучше работать не по времени, т.е. не тупо спать 750мс, не пытаться засекать время начала преобразования, а использовать переывания на ножке контроллера. В доке по дачику сказано, что дачик по окончанию процесса измерения притянет ногу к 0 на определенной время. Т.е. в Вашем случае нужно просто ставить обработчик прерывания на ногу куда прикручен дачик после отправки коммнады на преобразование. В обработчике прерывания взводите флажок что показания готовы, и уже из основной программы читаете данные в том месте где вам удобно. Тем самым вы делаете процесс асинхронным и не зависимым от таймингов преобразования.
+
avatar
  • Naevus
  • 18 июля 2016, 10:13
0
Да, я пока ковырялся с датчиком на тиньке (несколько дней провозился) встречал описание этого способа. Но, во первых — никогда не работал с прерываниями (на ардуине. А на тиньке даже не читал еще про прерывания — это вообще можно сказать первый мой законченный код). А во вторых — оно и так заработало. Но на будущее учту (у меня еще 2 таких индикатора осталось :) ) Спасибо.
+
avatar
  • vismyk
  • 18 июля 2016, 10:50
0
А я попробовал сам по ардуинному справочнику прерывание на спад сигнала на ноге А энкодера присобачить — лажа полная вылазила. И не у меня одного, как оказалось, надо всё же контроллер поглубже изучать, чем в ардуино-справочнике пишут… ;)
+
avatar
  • Naevus
  • 18 июля 2016, 11:36
0
все, пошел заказывать энкодер… странно что я такую штуку удобную (в плане юзабилити) упусил…
:)
+
avatar
  • johnes
  • 18 июля 2016, 14:52
0
За ардуину я не отвечу, я с ней не особо программил, а вот на msp430 делал через прерывания и на stm32 делал, но думаю в ардуине все тоже должно работаь нормально, прерывания по спаду/наростанию фронта это практически базовый функционал для микроконтроллеров (как я понял из моего крошечного опыта общения с ними).
+
avatar
  • Naevus
  • 18 июля 2016, 15:15
0
Вы с vismyk о разных вещах говорите. Чтение датчика температуры через прерывания я встречал на ардуине — тут все точно должно работать. А у vismyk головная боль с энкодером. И, как я успел просмотреть пару тем, даже с прерываниями там хватает геморроя. :(
ps Энкодеры заказал, будет на чем поиграться через месяц
+
avatar
  • vismyk
  • 18 июля 2016, 15:51
0
Так точно, прерывания на ардуине есть, но конкретно с энкодерами есть свои нюансы. :/ Кстати, я в своё время энкодеры покупал, чтобы вот этот девайс повторить, но так и не дошли руки… :(
+
avatar
  • vismyk
  • 18 июля 2016, 15:36
0
Есть нюансы. ;) Я тоже думал всё просто будет: ставлю прерывание на спад А, в обработчике прерывания читаю состояние В и исходя их него определяю, вправо крутят ручку или влево. На практике всё оказалось не так просто. :/ И как показал поиск в И-нете, много таких оптимистов точно так же обломились. ;)
+
avatar
  • Naevus
  • 18 июля 2016, 10:11
0
удалено (не туда ответил)
+
avatar
  • Alcest
  • 24 августа 2020, 20:01
0
Сам не знаю, зачем купил эту ерунду. Решил, что статическая индикация, хотя видел, что всего две HC595 на плате. Думал, еще два регистра прячутся сверху под индикатором. Оказалось индикация динамическая. Даже не представляю, куда я мог бы поставить это шумящее помехами изделие. Выброшу, наверное.
+
avatar
  • Naevus
  • 24 августа 2020, 21:15
0
ну я обе купленные таки оприходовал — сделал термометры на тиньке. Один — собственно в обзоре. а другой — на термопаре для бани.
+
avatar
  • Alcest
  • 24 августа 2020, 21:24
0
Для термометров и термостатов пойдет, наверное. А я хотел в индикатор частоты настройки FM приемника втулить. Думал статика. А динамика будет шуметь и помехи радиоприему создавать.