Термометр на 7-сегментном дисплее
- Войдите на сайт для отправки комментариев
Здравствуйте всем! Вот и меня поразила ардуиноболезнь, начал тренироваться, как полагается, «на кошках» :)
Это мой первый пост про 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, то устройство успешно работает минуту-две, затем оно начинает зависать… Причины данного поведения мне непонятны. Если кто-нибудь поможет разобраться или поможет со схемой, я буду очень рад! А также отвечу на возникаемые вопросы. Спасибо за внимание.
Поздравляю с первым опытом!
сдвиговый регистр в вашем случае лишний, но если ради обучения, то хорошо
зависать может из за превышения токов потребления. Так как вы общие аноды подключили напрямую к ардуине нужно обеспечить, чтобы через один сегмент протекало не более 40/8 мА и соответственно 40мА на все 8 сегментов. Иначе у вас перегруз портов по току
динамическая индикация куда лучше работает если отображение делать не в loop(), а в обработчике прерываний
Спасибо! Со сдвиговым регистром просто хотелось поработать, поэтому я его сюда и включил. Что касается токов потребления: Вы предлагаете ограничить ток на общих анодах? Можно ли сделать это, установив резисторы на анодах? Я не знаю, какие токи потребляет мой индикатор.
Про обработчик прерываний слышал, но до практических действий не доходило. Если будет время, я поищу информацию на этот счет. Еще раз спасибо за ответ!
Ток ограничивают на катодах. Чтобы на аноде было не больше 40 на каждом катоде должно быть не больше 5
для красных при питании 5в сопротивления должны быть 600 и более ом
управление по анодам - или транзисторные ключи, или ещё один сдвиговый регистр 74HC595 - разгрузится МК по выходным токам
Можно конечно выходы усилить, но сдвиговый резистор лишнее при свободных портах. Лучше pnp транзисторы или логика обычная. А еще круче драйвер типа max7219
Но если нужна максимальная простота, можно не усложнять. Для красных светодиодов как правило 5ма на сегмент достаточно при отсутствии яркого солнечного света в помещении
axill, SU-27-16, спасибо большое за ответы!
У меня есть и второй 74HC595, и первые модели на Breadboard'е я собирал именно на нем, используя аналог arduino mega. Поэтому можно сделать решение на этих элементах. Но пока буду переделывать ту, что имею.
С другой стороны, много читал про MAX7219, но... С точки зрения обучения хочется сделать все управление сегментами самому :) Попробую поставить вместо резисторов на 100 Ом резисторы на 1 кОм. Посмотрим, что изменится.
Если переделывать схему на транзисторных ключах, можете подсказать, куда их необходимо ставить? На общие аноды или на катоды? И какие транзисторы для данных целей подойдут?
Еще раз спасибо, без вас как без рук!
вам нужно четыре верхних ключа между МК и индикатором
если поставить ещё восемь нижних ключей, то регистр не нужен
а 8 нижних ключей заменяет одна UNL2003 :)
Попробовал "убавить яркость" поставив килоомные резисторы... Смотрится тускло, откровенно говоря. По поводу 74HC595 - пока оставлю, как есть :) А насчет ключей - обязательно поставлю, как будет возможность их приобрести.
Спасибо!
ставьте резисторы 220 - а яркостью можно управлять ШИМом подав её на вход - /OE output enable (active LOW) регистра 74HC595
вам нужно четыре верхних ключа между МК и индикатором
нужна верхняя схема, R2 на схеме лишний. подойдут практически любые PNP транзисторы
Надо было писать раньше, перед разводкой и монтажом :) С другой стороны, это все опыт! Сейчас заменил резисторы на 240 Ом (судя по маркировке), все показывает нормально. Пин ОЕ, к сожалению, "намертво" разведен на минус. Есть полностью идентичный второй комплект на таком же железе, вот там как раз и поэкспериментирую с ШИМ на ОЕ. Спасибо!
а 8 нижних ключей заменяет одна UNL2003 :)
вы собрались по 500мА на сегмента подать? на катодах вообще никто не нужен, порт выдает 40мА, 200мА на весь МК, этого хватит для этих индикаторов выше крыши
ставьте резисторы 220 - а яркостью можно управлять ШИМом подав её на вход - /OE output enable (active LOW) регистра 74HC595
назло бабушке можно и уши отморозить. ШИМ никак не спасет порты от перегрузок. ставить нужно 600ом и выше, либо усиливать аноды ключами на транзисторах или микросхемах. 1к это почти в два раза больше чем 600оМ. Так что в просто те конструкции еще не все потерно. Можно поставить 510-560 ом, с учетом падения на выходных транзисторах примерно 5мА и выйдет
а 8 нижних ключей заменяет одна UNL2003 :)
вы собрались по 500мА на сегмента подать? на катодах вообще никто не нужен, порт выдает 40мА, 200мА на весь МК, этого хватит для этих индикаторов выше крыши
чтобы с запасом.... и ТС на дальше будет знать :)
Еще один вопрос: как запитать эту плату от аккумулятора? Можно ли в плату воткнуть USB разъем, а на его конец - на красный и черный провод - подключить аккумулятор на 12 вольт? Или все-таки необходимо подключать 12 вольт на землю и 30 пин (нерегулируемый источник питания)?
ШИМ - для яркости, а не от перегрузок, опять же ТСу - будет знать что за нога /OE :)
5 V - на юсб - нана выдаст ещё и 3,3 V
5 V - на 5 V - нана не выдаст 3,3 V
7....12 V - как вы и спросили
вот мой пример устройства и схемы. у меня усилены и катоды и аноды, но там индикаторы покрупнее. для ваших катоды усиливать точно нет необходимости
http://radiokot.ru/circuit/digital/home/176/
Всем очень благодарен за ответы! Во многом вы помогли разобраться, как и задать вектор для дальнейших изысканий. Мир вашему дому :)
ШИМ - для яркости, а не от перегрузок, опять же ТСу - будет знать что за нога /OE :)
с этим не спорю, спорю с советом ставить 220ом, это двухкратный перегруз портов при 8 горяших сегментах
220 - для варианта 4 ключа анодных, регистр.... классные "Умные часы" !
ОК ) спасибо за часы)
корпус для часов - какой материал ?
Извиняюсь, еще один глупый вопрос. Как лучше организовать питание? Я себе представляю 3 варианта:
1. Подключить аккумулятор 12 В на землю и вход 30(нерегулируемый источник питания).
2. Пустить ток с аккумулятора через стабилизатор (нашел в Интернетах К1156ЕН1П, например?) на вход27 (регулируемый источник питания).
3. Пустить ток с аккумулятора через стабилизатор (нашел в Интернетах К1156ЕН1П, например?) через USB-разъем.
Что-то из этого похоже на вменяемое решение? Или необходимо что-то другое? Спасибо за ответы
почему именно от аккумулятора? питайте через USB от любой телефонной зарядки
корпус для часов - какой материал ?
PLA https://www.thingiverse.com/thing:160569
Не хочется питать от сети, дабы не оставлять в розетке устройство, пока никого нет дома
Не хочется питать от сети, дабы не оставлять в розетке устройство, пока никого нет дома
ну в розетке у вас будет покупная зарядка, а вся ваша конструкция будет питаться низковольтным напряжением и даже если что то там закоротит ничего страшного не случится
аккумулятора на долго не хватит. Несли от аккумулятора питать то лучше тогда применить преобразоватеть DC-DC. Они как готовые модули продаются. Он сэкономить энергию аккумулятора
Посоветуйте, пожалуйста, готовый. Я вижу в основном стабилизатор на LM2596. Как я понял его принцип работы, "лишнее" напряжение он рассеивает в виде тепла. Спасибо
Я не знаю, какие токи потребляет мой индикатор.
Сейчас заменил резисторы на 240 Ом (судя по маркировке)
Я конечно дико извиняюсь за оффтоп, но... Вы занимаетесь электроникой и у Вас нет мультиметра? Вот хотябы замерить потребляемый ток и сопротивление. Их же сейчас что грязи, и недорогие есть - тот же M830 (только не китайская пародия на мультиметр DT830, а какой-нибудь Uni-T М830 или Mastech M830).
Мультиметр остался на работе, а там, откуда я пишу -дома в сельской местности - его нет. Однако оказалась горстка сопротивлений и паяльник, а также интернет, чтобы увидеть маркировку резисторов. Этого мне хватило вполне, чтобы справиться с задачей. Вот так как-то. Впредь буду внимательней к рассчетной части.
Посоветуйте, пожалуйста, готовый. Я вижу в основном стабилизатор на LM2596. Как я понял его принцип работы, "лишнее" напряжение он рассеивает в виде тепла. Спасибо
лучше более современные, например на базе микросхемы mp1584, они в разы компактнее и эффективнее, стоят примерно столько же. Их принцип действия в импульсном преобразовании, тепла там выделается не много. Много тепла выделяется в линейных стабилизаторах типа 7805 или LM317
Я конечно дико извиняюсь за оффтоп, но... Вы занимаетесь электроникой и у Вас нет мультиметра? Вот хотябы замерить потребляемый ток и сопротивление. Их же сейчас что грязи, и недорогие есть - тот же M830 (только не китайская пародия на мультиметр DT830, а какой-нибудь Uni-T М830 или Mastech M830).
Мультиметр безусловно штука полезная, но в данном конкретном случае резисторы можно расчитать без него. Forward voltage красных светодиодов 2в плюс минус 0.2в
Добрый день всем!
Вот уже энное количество дней мой термометр работает без сбоев, за что горячо благодарю axill и SU-27-16. После установки резисторов номиналом 240 Ом и запитав схему с 27 пина, использовав в качестве питания блок питания от телефона, система вошла в стабильное состояние. Ура!
#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 разрядный индикатор с ОА можно и выводить целые числа ?