Термометр на 7-сегментном дисплее

justMike
Offline
Зарегистрирован: 05.11.2014

Здравствуйте всем! Вот и меня поразила ардуиноболезнь, начал тренироваться, как полагается, «на кошках» :)

Это мой первый пост про arduino.

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

Возникла необходимость сделать термометр с дисплеем. Есть требование: постоянное отображение информации и необходимость сделать оповещение в случае достижения температуры выше 90 градусов.

 В качестве исходного материала послужили:

 arduino nano (китай)

7-сегментный 4-цифровой индикатор

датчик температуры  ds18b20

сдвиговый регистр 74HC595

 пьезоэлемент

резисторы: 8*100 Ом, 1*4.7 кОм.

Разберемся со светодиодным индикатором. Насколько я смог его понять, он с общим анодом. Вот его вид:

 

 

Распишем теперь его пины:

 

Пин индикатора

Примечание

1

Сегмент a

2

Сегмент b

3

Сегмент c

4

Сегмент d

5

Сегмент e

6

Общий анод сегмента № 1

7

Сегмент f

8

Общий анод сегмента № 2

9

Общий анод сегмента № 3

10

3Сегмент g

11

Сегмент h

12

Общий анод сегмента № 4

 

Итак, теперь что мы с этим будем делать. Надо представить привычные нам цифры в двоичном формате, как мы будем зажигать наши сегменты. Отмечу: поскольку у нас сегменты-аноды, то в нашем случае будут зажигаться «ноли». Так, например, будет выглядеть цифра 7:

 

0  1  0  1  0  1  1  1

h  g   f  e  d   c   b  a

 

Зажгутся соответственно секции d, f иh.

Для удобства записи будем использовать их десятичные значения. Распишу таблицу приведения:

 

Знак

Общий анод

Двоичная система

Десятичная система

«0»

00010100

20

«1»

11010111

215

«2»

01001100

76

«3»

01000101

69

«4»

10000111

135

«5»

00100101

37

«6»

00100100

36

«7»

01010111

87

«8»

00000100

4

«9»

00000101

5

 

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

Общие аноды я подключил непосредственно к выходам 6,7,8 и 9 самого arduino.

 

 

 Приложу скетч.

 

 #include <OneWire.h>

//Пин подключен к ST_CP входу 74HC595
int latchPin = 4;
//Пин подключен к SH_CP входу 74HC595
int clockPin = 5;
//Пин подключен к DS входу 74HC595
int dataPin = 3;

//Пины на общие катоды дисплея
int seg1 = 6;
int seg2 = 7;
int seg3 = 8;
int seg4 = 9;

int a1;
int a2;
int a3;
int a4;
int type_s;

int ltr[] = {20,215,76,69,135,37, 36, 87,4,5, 0, 0,0,0,0,0,0,0}; 
byte addr[8]={0x28,0x1F,0xB9,0x6A,0x6,0x0,0x0,0x87};
OneWire  ds(2); 

void setup() {
  //устанавливаем режим OUTPUT
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(seg1, OUTPUT);
  pinMode(seg2, OUTPUT);
  pinMode(seg3, OUTPUT);
  pinMode(seg4, OUTPUT);
  noTone(13);

  Serial.begin(9600);
       }
 
void loop() {
   
    //
  int temper;
  int tmp;
  byte i;
  byte type_s;
  byte data[12];
  float celsius, fahrenheit;
  type_s = 0;
  int j;
  ds.reset();
  numbShow (1);
  ds.write(0xCC);

numbShow (1);
ds.write(0x44);
numbShow (20);
    
  ds.reset();
  numbShow (1);
  ds.write(0xCC);
numbShow (1);
ds.write(0xBE);
numbShow (1);

    for ( i = 0; i < 9; i++) {           // we need 9 bytes for temperature
    data[i] = ds.read();
    numbShow (1);
    
    }
  // Convert the data to actual temperature
  // because the result is a 16 bit signed integer, it should
  // be stored to an "int16_t" type, which is always 16 bits
  // even when compiled on a 32 bit processor.
  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
  }
  celsius = (float)raw / 16.0;
  
  celsius*=100;
  temper=(int)celsius;
  tmp=temper;
  //Serial.println(temper);
  //Serial.println();
      
 a1=tmp%10;// здесь мы получаем последнюю цифру
tmp/=10;// n=n/10 тем самым отбрасываем последнюю цифру
 a2=tmp%10;
 tmp/=10;// n=n/10 тем самым отбрасываем последнюю цифру
 a3=tmp%10;
 tmp/=10;// n=n/10 тем самым отбрасываем последнюю цифру
 a4=tmp%10;
      
   numbShow (10);
      if (temper>9000)
        { 
        tone (13,2000);
        // Serial.println(temper);
         }
 else noTone (13);  
 }
      
   void segment(int x, int y,int del)
   {
   digitalWrite(latchPin, LOW);
    // передаем последовательно на dataPin
    shiftOut(dataPin, clockPin, MSBFIRST, x); 
     //"защелкиваем" регистр, тем самым устанавливая значения на выходах
     digitalWrite(latchPin, HIGH);
    switch (y)
   {
     case 1:
   digitalWrite(seg1,  HIGH);
   digitalWrite(seg2,  LOW);
   digitalWrite(seg3, LOW);
   digitalWrite(seg4, LOW);
   break;
    case 2:
   digitalWrite(seg1,  LOW);
   digitalWrite(seg2,  HIGH);
   digitalWrite(seg3, LOW);
   digitalWrite(seg4, LOW);
   break;
   case 3:
   digitalWrite(seg1,  LOW);
   digitalWrite(seg2,  LOW);
   digitalWrite(seg3, HIGH);
   digitalWrite(seg4, LOW);
   break;
   case 4:
   digitalWrite(seg1,  LOW);
   digitalWrite(seg2,  LOW);
   digitalWrite(seg3, LOW);
   digitalWrite(seg4, HIGH);
   break;
   
   default:
   digitalWrite(seg1,  LOW);
   digitalWrite(seg2,  LOW);
   digitalWrite(seg3, LOW);
   digitalWrite(seg4, LOW);
      }
        
    if (del==1) delay(4);
  }
  
  void numbShow (int cycle)
  {
  for (int i=0;i<cycle;i++)
   { 
     segment (ltr[a4],4,1);
     segment (ltr[a3]-4,3,1);
     segment (ltr[a2],2,1);
    segment (ltr[a1],1,1);
    
   }
  }

По данной схеме была сделана печатная плата и собрано устройство:

 

 

 

Все собрано и работает. Ура!

Однако есть неприятный глюк. Если подключать питание с компьютера через miniUSB, то устройство успешно работает минуту-две, затем оно начинает зависать… Причины данного поведения мне непонятны. Если кто-нибудь поможет разобраться или поможет со схемой, я буду очень рад! А также отвечу на возникаемые вопросы. Спасибо за внимание.

axill
Offline
Зарегистрирован: 05.09.2011

Поздравляю с первым опытом!

сдвиговый регистр в вашем случае лишний, но если ради обучения, то хорошо

зависать может из за превышения токов потребления. Так как вы общие аноды подключили напрямую к ардуине нужно обеспечить, чтобы через один сегмент протекало не более 40/8 мА и соответственно 40мА на все 8 сегментов. Иначе у вас перегруз портов по току

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

 

justMike
Offline
Зарегистрирован: 05.11.2014

Спасибо! Со сдвиговым регистром просто хотелось поработать, поэтому я его сюда и включил. Что касается токов потребления: Вы предлагаете ограничить ток на общих анодах? Можно ли сделать это, установив резисторы на анодах? Я не знаю, какие токи потребляет мой индикатор.

Про обработчик прерываний слышал, но до практических действий не доходило. Если будет время, я поищу информацию на этот счет. Еще раз спасибо за ответ!

axill
Offline
Зарегистрирован: 05.09.2011

Ток ограничивают на катодах. Чтобы на аноде было не больше 40 на каждом катоде должно быть не больше 5

для красных при питании 5в сопротивления должны  быть 600 и более ом

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

управление по анодам - или транзисторные ключи, или ещё один сдвиговый регистр 74HC595 - разгрузится МК по выходным токам

axill
Offline
Зарегистрирован: 05.09.2011

Можно конечно выходы усилить, но сдвиговый резистор лишнее при свободных портах. Лучше pnp транзисторы или логика обычная. А еще круче драйвер типа max7219

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

justMike
Offline
Зарегистрирован: 05.11.2014

axill, SU-27-16, спасибо большое за ответы!

У меня есть и второй 74HC595, и первые модели на Breadboard'е я собирал именно на нем, используя аналог arduino mega. Поэтому можно сделать решение на этих элементах. Но пока буду переделывать ту, что имею.

С другой стороны, много читал про MAX7219, но...  С точки зрения обучения хочется сделать все управление сегментами самому :) Попробую поставить вместо резисторов на 100 Ом резисторы на 1 кОм. Посмотрим, что изменится.

Если переделывать схему на транзисторных ключах, можете подсказать, куда их необходимо ставить? На общие аноды или на катоды? И какие транзисторы для данных целей подойдут?

Еще раз спасибо, без вас как без рук!

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

вам нужно четыре верхних ключа между МК и индикатором

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

если поставить ещё восемь нижних ключей, то регистр не нужен

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

а 8 нижних ключей заменяет одна  UNL2003 :)

justMike
Offline
Зарегистрирован: 05.11.2014

Попробовал "убавить яркость" поставив килоомные резисторы... Смотрится тускло, откровенно говоря. По поводу 74HC595 - пока оставлю, как есть :) А насчет ключей - обязательно поставлю, как будет возможность их приобрести.

Спасибо! 

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

ставьте резисторы 220 - а яркостью можно управлять ШИМом подав её на вход  - /OE output enable (active LOW) регистра 74HC595

axill
Offline
Зарегистрирован: 05.09.2011

SU-27-16 пишет:

вам нужно четыре верхних ключа между МК и индикатором

нужна верхняя схема, R2 на схеме лишний. подойдут практически любые PNP транзисторы

justMike
Offline
Зарегистрирован: 05.11.2014

Надо было писать раньше, перед разводкой и монтажом :) С другой стороны, это все опыт! Сейчас заменил резисторы на 240 Ом (судя по маркировке), все показывает нормально. Пин ОЕ, к сожалению, "намертво" разведен на минус. Есть полностью идентичный второй комплект на таком же железе, вот там как раз и поэкспериментирую с ШИМ на ОЕ. Спасибо!

axill
Offline
Зарегистрирован: 05.09.2011

SU-27-16 пишет:

а 8 нижних ключей заменяет одна  UNL2003 :)

вы собрались по 500мА на сегмента подать? на катодах вообще никто не нужен, порт выдает 40мА, 200мА на весь МК, этого хватит для этих индикаторов выше крыши

axill
Offline
Зарегистрирован: 05.09.2011

SU-27-16 пишет:

ставьте резисторы 220 - а яркостью можно управлять ШИМом подав её на вход  - /OE output enable (active LOW) регистра 74HC595

назло бабушке можно и уши отморозить. ШИМ никак не спасет порты от перегрузок. ставить нужно 600ом и выше, либо усиливать аноды ключами на транзисторах или микросхемах. 1к это почти в два раза больше чем 600оМ. Так что в просто те конструкции еще не все потерно. Можно поставить 510-560 ом, с учетом падения на выходных транзисторах примерно 5мА и выйдет

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

axill пишет:

SU-27-16 пишет:

а 8 нижних ключей заменяет одна  UNL2003 :)

вы собрались по 500мА на сегмента подать? на катодах вообще никто не нужен, порт выдает 40мА, 200мА на весь МК, этого хватит для этих индикаторов выше крыши

чтобы с запасом.... и ТС на дальше будет знать :) 

justMike
Offline
Зарегистрирован: 05.11.2014

Еще один вопрос: как запитать эту плату от аккумулятора? Можно ли в плату воткнуть USB разъем, а на его конец - на красный и черный провод - подключить аккумулятор на 12 вольт? Или все-таки необходимо подключать 12 вольт на землю и 30 пин (нерегулируемый источник питания)?

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

ШИМ - для яркости, а не от перегрузок, опять же ТСу - будет знать что за нога /OE :)

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

5 V - на юсб - нана выдаст ещё и 3,3 V

5 V - на 5 V - нана не выдаст 3,3 V

7....12 V - как вы и спросили

axill
Offline
Зарегистрирован: 05.09.2011

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

http://radiokot.ru/circuit/digital/home/176/

justMike
Offline
Зарегистрирован: 05.11.2014

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

axill
Offline
Зарегистрирован: 05.09.2011

SU-27-16 пишет:

ШИМ - для яркости, а не от перегрузок, опять же ТСу - будет знать что за нога /OE :)

с этим не спорю, спорю с советом ставить 220ом, это двухкратный перегруз портов при 8 горяших сегментах

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

220 - для варианта 4 ключа анодных, регистр.... классные "Умные часы" !

axill
Offline
Зарегистрирован: 05.09.2011

ОК ) спасибо за часы)

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

корпус для часов - какой материал ?

justMike
Offline
Зарегистрирован: 05.11.2014

Извиняюсь, еще один глупый вопрос. Как лучше организовать питание? Я себе представляю 3 варианта:

1. Подключить аккумулятор 12 В на землю и вход 30(нерегулируемый источник питания).

2. Пустить ток с аккумулятора через стабилизатор (нашел в Интернетах К1156ЕН1П, например?) на вход27 (регулируемый источник питания).

3. Пустить ток с аккумулятора через стабилизатор (нашел в Интернетах К1156ЕН1П, например?) через USB-разъем.

Что-то из этого похоже на вменяемое решение? Или необходимо что-то другое? Спасибо за ответы

axill
Offline
Зарегистрирован: 05.09.2011

почему именно от аккумулятора? питайте через USB от любой телефонной зарядки

axill
Offline
Зарегистрирован: 05.09.2011

SU-27-16 пишет:

корпус для часов - какой материал ?

PLA https://www.thingiverse.com/thing:160569

justMike
Offline
Зарегистрирован: 05.11.2014

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

axill
Offline
Зарегистрирован: 05.09.2011

justMike пишет:

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

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

аккумулятора на долго не хватит. Несли от аккумулятора питать то лучше тогда применить преобразоватеть DC-DC. Они как готовые модули продаются. Он сэкономить энергию аккумулятора

justMike
Offline
Зарегистрирован: 05.11.2014

Посоветуйте, пожалуйста, готовый. Я вижу в основном стабилизатор на LM2596. Как я понял его принцип работы, "лишнее" напряжение он рассеивает в виде тепла. Спасибо

 

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

justMike пишет:

 Я не знаю, какие токи потребляет мой индикатор.

justMike пишет:

Сейчас заменил резисторы на 240 Ом (судя по маркировке)

Я конечно дико извиняюсь за оффтоп, но... Вы занимаетесь электроникой и у Вас нет мультиметра? Вот хотябы замерить потребляемый ток и сопротивление. Их же сейчас что грязи, и недорогие есть - тот же M830 (только не китайская пародия на мультиметр DT830, а какой-нибудь Uni-T М830 или Mastech M830). 

 

justMike
Offline
Зарегистрирован: 05.11.2014

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

axill
Offline
Зарегистрирован: 05.09.2011

justMike пишет:

Посоветуйте, пожалуйста, готовый. Я вижу в основном стабилизатор на LM2596. Как я понял его принцип работы, "лишнее" напряжение он рассеивает в виде тепла. Спасибо

лучше более современные, например на базе микросхемы mp1584, они в разы компактнее и эффективнее, стоят примерно столько же. Их принцип действия в импульсном преобразовании, тепла там выделается не много. Много тепла выделяется в линейных стабилизаторах типа 7805 или LM317

axill
Offline
Зарегистрирован: 05.09.2011

Jeka_M пишет:

Я конечно дико извиняюсь за оффтоп, но... Вы занимаетесь электроникой и у Вас нет мультиметра? Вот хотябы замерить потребляемый ток и сопротивление. Их же сейчас что грязи, и недорогие есть - тот же M830 (только не китайская пародия на мультиметр DT830, а какой-нибудь Uni-T М830 или Mastech M830). 

Мультиметр безусловно штука полезная, но в данном конкретном случае резисторы можно расчитать без него. Forward voltage красных светодиодов 2в плюс минус 0.2в

justMike
Offline
Зарегистрирован: 05.11.2014

Добрый день всем!

Вот уже энное количество дней мой термометр работает без сбоев, за что горячо благодарю axill и SU-27-16.  После установки резисторов номиналом 240 Ом и запитав схему с 27 пина, использовав в качестве питания блок питания от телефона, система вошла в стабильное состояние. Ура!  

Darksiders
Offline
Зарегистрирован: 25.02.2016

#include

//Пин подключен к ST_CP входу 74HC595
int latchPin = 4;
//Пин подключен к SH_CP входу 74HC595
int clockPin = 5;
//Пин подключен к DS входу 74HC595
int dataPin = 3;

//Пины на общие катоды дисплея
int seg1 = 6;
int seg2 = 7;
int seg3 = 8;
int seg4 = 9;

int a1;
int a2;
int a3;
int a4;
int type_s;

int ltr[] = {20,215,76,69,135,37, 36, 87,4,5, 0, 0,0,0,0,0,0,0};
byte addr[8]={0x28,0x1F,0xB9,0x6A,0x6,0x0,0x0,0x87};
OneWire ds(2);

void setup() {
//устанавливаем режим OUTPUT
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(seg1, OUTPUT);
pinMode(seg2, OUTPUT);
pinMode(seg3, OUTPUT);
pinMode(seg4, OUTPUT);
noTone(13);

Serial.begin(9600);
}

void loop() {

//
int temper;
int tmp;
byte i;
byte type_s;
byte data[12];
float celsius, fahrenheit;
type_s = 0;
int j;
ds.reset();
numbShow (1);
ds.write(0xCC);

numbShow (1);
ds.write(0x44);
numbShow (20);

ds.reset();
numbShow (1);
ds.write(0xCC);
numbShow (1);
ds.write(0xBE);
numbShow (1);

for ( i = 0; i < 9; i++) { // we need 9 bytes for temperature
data[i] = ds.read();
numbShow (1);

}
// Convert the data to actual temperature
// because the result is a 16 bit signed integer, it should
// be stored to an "int16_t" type, which is always 16 bits
// even when compiled on a 32 bit processor.
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
}
celsius = (float)raw / 16.0;

celsius*=100;
temper=(int)celsius;
tmp=temper;
//Serial.println(temper);
//Serial.println();

a1=tmp%10;// здесь мы получаем последнюю цифру
tmp/=10;// n=n/10 тем самым отбрасываем последнюю цифру
a2=tmp%10;
tmp/=10;// n=n/10 тем самым отбрасываем последнюю цифру
a3=tmp%10;
tmp/=10;// n=n/10 тем самым отбрасываем последнюю цифру
a4=tmp%10;

numbShow (10);
if (temper>9000)
{
tone (13,2000);
// Serial.println(temper);
}
else noTone (13);
}

void segment(int x, int y,int del)
{
digitalWrite(latchPin, LOW);
// передаем последовательно на dataPin
shiftOut(dataPin, clockPin, MSBFIRST, x);
//"защелкиваем" регистр, тем самым устанавливая значения на выходах
digitalWrite(latchPin, HIGH);
switch (y)
{
case 1:
digitalWrite(seg1, HIGH);
digitalWrite(seg2, LOW);
digitalWrite(seg3, LOW);
digitalWrite(seg4, LOW);
break;
case 2:
digitalWrite(seg1, LOW);
digitalWrite(seg2, HIGH);
digitalWrite(seg3, LOW);
digitalWrite(seg4, LOW);
break;
case 3:
digitalWrite(seg1, LOW);
digitalWrite(seg2, LOW);
digitalWrite(seg3, HIGH);
digitalWrite(seg4, LOW);
break;
case 4:
digitalWrite(seg1, LOW);
digitalWrite(seg2, LOW);
digitalWrite(seg3, LOW);
digitalWrite(seg4, HIGH);
break;

default:
digitalWrite(seg1, LOW);
digitalWrite(seg2, LOW);
digitalWrite(seg3, LOW);
digitalWrite(seg4, LOW);
}

if (del==1) delay(4);
}

void numbShow (int cycle)
{
for (int i=0;i {
segment (ltr[a4],4,1);
segment (ltr[a3]-4,3,1);
segment (ltr[a2],2,1);
segment (ltr[a1],1,1);

}
}
Данный скетч адаптировать под 3 разрядный индикатор с ОА можно и выводить целые числа ?