8-и разрядный 7-сегментный индикатор - нужна помощь
- Войдите на сайт для отправки комментариев
Здравствуйте, уважаемые!
Пришла мне сегодня вот такая железяка: MAX7219 Red Module 8-Digit 7 Segment Digital LED Display Tube For Arduino MCU. Попытался подключить - получается не очень.
Подключаю модуль к ардуинке используя вот эту инструкцию. Из библиотеки LedControl взял пример LCDemo7Segment - всё работает. Точнее, в первом экранчике всё работает - циферки бегают по первым 4 символам не переходя на второй экранчик.
Поковырялся с кодом, понял, как выводить на вторую часть символы. Захотелось мне большего. Для пробы решил подключить ещё и DHT11 (датчик температуры и влажности который), чтобы на одну половину экрана выводить температуру, а на вторую - влажность. И вот тут затык полный. У меня получается выводить только одинарные символы. А как заставить экран выводить число 10, например, правильно - в два экранных символа? Даже так: может кто ткнёт носом в готовый пример, где температура (+/- двузначное число) и влажность (двузначное число) выводятся на 7-сегментный экранчик?
Примеры, которые я нашёл в сети в большинстве своём расписаны для экранов, подключающихся к ардуинке напрямую, что мне вроде как не очень подходит.
У меня получилось только вот так:
//We always have to include the library
#include "LedControl.h"
#include "DHT.h"
#define DHTPIN 2 // what pin we're connected to
#define DHTTYPE DHT11 // DHT 11
/*
Now we need a LedControl to work with.
***** These pin numbers will probably not work with your hardware *****
pin 12 is connected to the DataIn
pin 11 is connected to the CLK
pin 10 is connected to LOAD
We have only a single MAX72XX.
*/
LedControl lc=LedControl(12,11,10,1);
/* we always wait a bit between updates of the display */
unsigned long delaytime=250;
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
Serial.println("DHTxx test!");
dht.begin();
/*
The MAX72XX is in power-saving mode on startup,
we have to do a wakeup call
*/
lc.shutdown(0,false);
/* Set the brightness to a medium values */
lc.setIntensity(0,8);
/* and clear the display */
lc.clearDisplay(0);
}
/*
This method will display the characters for the
word "Arduino" one after the other on digit 0.
*/
void writeArduinoOn7Segment() {
lc.setChar(0,0,'a',false);
delay(delaytime);
lc.setRow(0,0,0x05);
delay(delaytime);
lc.setChar(0,0,'d',false);
delay(delaytime);
lc.setRow(0,0,0x1c);
delay(delaytime);
lc.setRow(0,0,B00010000);
delay(delaytime);
lc.setRow(0,0,0x15);
delay(delaytime);
lc.setRow(0,0,0x1D);
delay(delaytime);
lc.clearDisplay(0);
delay(delaytime);
}
/*
This method will scroll all the hexa-decimal
numbers and letters on the display. You will need at least
four 7-Segment digits. otherwise it won't really look that good.
*/
void scrollDigits() {
for(int i=0;i<13;i++) {
lc.setDigit(0,3,i,false);
lc.setDigit(0,2,i+1,false);
lc.setDigit(0,1,i+2,false);
lc.setDigit(0,0,i+3,false);
delay(delaytime);
}
lc.clearDisplay(0);
delay(delaytime);
}
void loop() {
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(t) || isnan(h)) {
Serial.println("Failed to read from DHT");
} else {
Serial.print("Humidity: ");
Serial.print(h);
Serial.print(" %\t");
Serial.print("Temperature: ");
Serial.print(t);
Serial.println(" *C");
}
double t1 = floor(t/10);
double t2 = (t - t1*10);
if (t < 0) {
lc.setChar(0,6,'-',false);
}
lc.setChar(0,5,t1,false);
lc.setChar(0,4,t2,false);
double h1 = floor(h/10);
double h2 = (h - h1*10);
lc.setChar(0,1,h1,false);
lc.setChar(0,0,h2,false);
// lc.setDigit(0,5,1,false);
// writeArduinoOn7Segment();
// scrollDigits();
}
Но ведь это же изврат, верно?
Ай, простите! Забыл автоматом свернуть код :(
Эксперементировал несколько месяцев назад с индикатором. могу подогнать код собственного написания, хотя он очень ламерский, посмотри, может чего полезного почерпнешь
///376 кадров в секунду //нужны переменные x количество печатаемых байт 0-7 kolichestvo_simvolov_pechati //адрес начального регистра 0-15 nachalnyi_razryad_pechati //номер символа в массиве print_digits[] с которого начнем печать start_byte //первым делом введем в индикатор настройки byte load=8;// пины для подключения byte clk=9; byte din=10; volatile long High=0; volatile long Decimal; unsigned long last = millis(); byte temp[9];// на 7 цифр разложим число static int8_t Tube[] = { 0b01111110, // 0 0b00110000, // 1 0b01101101, // 2 0b01111001, // 3 0b00110011, // 4 0b01011011, // 5 0b01011111, // 6 0b01110000, // 7 0b01111111, // 8 0b01111011, // 9 0b00000001 //minus };//0~9,A,b,C,d,E,F,"-"," " и другие символы static int8_t print_digits[] = {//разложенный массив данных регистров идущих на загрузку в микросхему 0b00000000, // 0, адрес // 00000000 0b00000000, // 1 0b00000000, // 2 0b00000000, // 3 0b00000000, // 4 0b00000000, // 5 0b00000000, // 6 0b00000000, // 7 0b00000000, // 8----------------------------------------------- 0b00000000, // 9, 00000000 Decode Mode 0 ("No decode") или 1 ("BCD code B") 0b00000000, // 10 00001111 яркость 0b11111111, // 11 00000111 ОБСЛУЖИВАЕМ ВСЕ 8 РАЗРЯДОВ 0b00000001, // 12 Включение индикаторов MAX7219 производится записью 1 выключение 0 0b00000000, // 13 nop 0b00000000, // 14 nop 0b00000000, // 15 display test 00000000 }; volatile byte kolichestvo_simvolov_pechati=14;//количество регистров к загрузкеот 0 до 14 (0 грузим всего один регистр) volatile byte nachalnyi_massiv=1;// начинаем с заливки массива элемента масссива volatile byte start_razryad=1;// загружаем сначала регистр 1 void setup() { pinMode(load, OUTPUT); //load(cs) pinMode(clk, OUTPUT);//clk pinMode(din, OUTPUT);//din print_segmetnts(kolichestvo_simvolov_pechati, nachalnyi_massiv, start_razryad); } // задаем данные для начальной загрузки данных void loop() { Decimal=High; // старт разряд=1 количество печатаемых символов-0 ------------------------------------------------------------------------------ //надо скопировать данные из temp[] в print_digits[] и печатать все символы rasklad(Decimal); //12345678 kolichestvo_simvolov_pechati=7;//количество регистров к загрузке от 0 до 7 (8 регистров грузим) nachalnyi_massiv=1;// начинаем с заливки массива print_digits[1] на индикатор start_razryad=1;// загружаем сначала регистр 7,8, 9,10, 11, 12, 15 //byte tmp_nachalnyi_massiv=nachalnyi_massiv; for( byte r=start_razryad; r<=(start_razryad+kolichestvo_simvolov_pechati); r++) { print_digits[r]=Tube[temp[nachalnyi_massiv]];//печатает первый раз 3, а потом 0 nachalnyi_massiv++; } //--------------------------------------------------------------------------------------------------------------------------------------------- print_segmetnts(kolichestvo_simvolov_pechati, nachalnyi_massiv, start_razryad); High++; if (millis() - last > 1000) { while(1);} }//конец основного цикла---------------------- void rasklad(long) { // if((Decimal > 99999999)||(Decimal < -9999999))return; 1000000 if (Decimal < 0) { temp[8] = 10;//minus Decimal = abs(Decimal); temp[7] = Decimal/1000000;//1176/1000 =1. (176) Decimal %= 1000000;//остаток (176) temp[6] = Decimal/100000;//1176/1000 =1. (176) Decimal %= 100000;//остаток (176) temp[5] = Decimal/10000;//1176/1000 =1. (176) Decimal %= 10000;//остаток (176) temp[4] = Decimal/1000;//1176/1000 =1. (176) Decimal %= 1000;//остаток (176) temp[3] = Decimal/100; //176/100 =1. (76) Decimal %= 100; //остаток (76) temp[2] = Decimal / 10;// 76/10=7. (6) temp[1] = Decimal % 10;// остаток 76/10 (6) } else { temp[8] = Decimal/10000000;//1176/1000 =1. (176) Decimal %= 10000000;//остаток (176) temp[7] = Decimal/1000000;//1176/1000 =1. (176) Decimal %= 1000000;//остаток (176) temp[6] = Decimal/100000;//1176/1000 =1. (176) Decimal %= 100000;//остаток (176) temp[5] = Decimal/10000;//1176/1000 =1. (176) Decimal %= 10000;//остаток (176) temp[4] = Decimal/1000;//1176/1000 =1. (176) Decimal %= 1000;//остаток (176) temp[3] = Decimal/100; //176/100 =1. (76) Decimal %= 100; //остаток (76) temp[2] = Decimal / 10;// 76/10=7. (6) temp[1] = Decimal % 10;// остаток 76/10 (6) }// имеем int8_t temp[8]; с разложенной цифрой на разряды. теперь ее необходимо напечатать }//----------------------------------------------------------------------------------------------------------------------------- void print_segmetnts(byte kolichestvo_simvolov_pechati, byte nachalnyi_massiv,byte start_razryad) {// for (byte registeradr=1; registeradr<=15; registeradr++){ for (byte registeradr=start_razryad; registeradr<=(start_razryad+kolichestvo_simvolov_pechati); registeradr++){//за весь цикл грузим все регистры от 0 до 13 микросхемы 7219 digitalWrite(load,LOW);// Установить низкий уровень на линии LOAD if (registeradr==13){registeradr=15; nachalnyi_massiv=15;} // if(registeradr==9 && changesettings==false){ // break; // }//выход из цикла если ненадо грузить байты настройки for (byte i=128; i >= 1; i=i/2){// отправка 7(от 0 до 7) бит адреса регистра содержащегося в registeradr // цикл работает 8 раз и отпревляет 8 бит digitalWrite(clk,LOW);// Установить НИЗКИЙ уровень на линии CLK if ((registeradr & i) > 0 ){ // если результат >0 то отправляем 1 digitalWrite(din,HIGH); //установили высокий уровень din } else{ digitalWrite(din,LOW);//установили низкий уровень din } digitalWrite(clk,HIGH);// Установить ВЫСОКИЙ уровень на линии CLK -ОТПРАВКА БИТА }// i отправили 8 бит адреса registeradr-------------------------------------------- // Serial.print(" data " ); for (byte sendbitdata=128; sendbitdata >= 1; sendbitdata=sendbitdata/2)// отправка 8 бит данных из массива print_digits[registeradr] { digitalWrite(clk,LOW);// Установить НИЗКИЙ уровень на линии CLK if ((print_digits[registeradr] & sendbitdata) > 0 ){ // если результат >0 то отправляем 1 digitalWrite(din,HIGH); //установили высокий уровень din } else{ digitalWrite(din,LOW); //установили низкий уровень din } nachalnyi_massiv++; digitalWrite(clk,HIGH);// ВЫСОКИЙ уровень на линии CLK -ОТПРАВКА БИТА }// sendbitdata отправили 8 бит содержащихся массиве print_digits[] //--------------------------------------------------------------------------------------- // Serial.print(" send 16 bit " ); digitalWrite(load,HIGH);// отправка загруженных 16 бит load=1 }//registeradr // цикл записи всех регистров закончился и теперь необходимо установить changesettings=false; }//возврат из подпрограммы--------------------------------------------------------------------Большое спасибо! Особенно за подробное комментрирование кода. Буду изучать.
вот статьи мне очень помогли, про микросхему max7219
http://radiohlam.ru/raznoe/max7219_7221.htm
http://mcucpu.ru/index.php/pdevices/41-indicators/85-workmax7219
Вот код для max7219 с 8 регистрами. Выводит в первый блок температуру, во второй влажность. С отрицательными температурами работает. Единственное, можно код слегка оптимизировать.
#include "DHT.h" #include "LedControl.h" /* Now we need a LedControl to work with. ***** These pin numbers will probably not work with your hardware ***** pin 12 is connected to the DataIn pin 11 is connected to the CLK pin 10 is connected to LOAD We have only a single MAX72XX. */ LedControl lc=LedControl(12,11,10,1); #define DHTPIN 2 //датчик на 2 pin #define DHTTYPE DHT22 // DHT 22 (AM2302) DHT dht(DHTPIN, DHTTYPE); // для 16 мгц //DHT dht(DHTPIN, DHTTYPE, 3); // для 8 мгц float T; //переменная для хранения температуры int T1; // переменная текущей температуры int ones; // десятичные int tens; // единицы int hundreds; // десятки float H; //переменная для хранения влажности int H1; // переменная текущей влажности int onesH; int tensH; int hundredsH; void setup() { /* The MAX72XX is in power-saving mode on startup, we have to do a wakeup call */ lc.shutdown(0,false); /* Set the brightness to a medium values */ lc.setIntensity(0,8); /* and clear the display */ lc.clearDisplay(0); dht.begin(); } void loop() { T = dht.readTemperature(); if(T < 0 && T > -10) { // ставим минус при отрицательной температуре во 2й разряд lc.setRow(0,1,0b00000001); T = T*-1; } if(T <= -10) { // ставим минус при отрицательной температуре в 1й разряд lc.setRow(0,0,0b00000001); T = T*-1; //избавляемся от минуса } T1 = T*10; hundreds = T1/100; tens=(T1-hundreds*100)/10; ones=T1-(hundreds*100+tens*10); if (hundreds != 0) { lc.setDigit(0,1,hundreds,false); } lc.setDigit(0,2,tens,true); lc.setDigit(0,3,ones,false); H = dht.readHumidity(); H1 = H*10; hundredsH = H1/100; tensH=(H1-hundredsH*100)/10; onesH=H1-(hundredsH*100+tensH*10); lc.setDigit(0,5,hundredsH,false); lc.setDigit(0,6,tensH,true); lc.setDigit(0,7,onesH,false); }Поковырялся с кодом, понял, как выводить на вторую часть символы. Захотелось мне большего. Для пробы решил подключить ещё и DHT11 (датчик температуры и влажности который), чтобы на одну половину экрана выводить температуру, а на вторую - влажность. И вот тут затык полный. У меня получается выводить только одинарные символы. А как заставить экран выводить число 10, например, правильно - в два экранных символа? Даже так: может кто ткнёт носом в готовый пример, где температура (+/- двузначное число) и влажность (двузначное число) выводятся на 7-сегментный экранчик?
посмотри этот пример, там же ссылки на источник (просто скопируй и посмотри чего получается):
по поводу отображения разных цифр в разных сегмента (посмотри по аналогии):
/* датчик температуры на DS22100STZ на ТИП вывод кола АЦП на дисплей */ #include "Wire.h" // enable I2C bus byte saa1064 = 0x70 >> 1; // define the I2C bus address for our SAA1064 (pin 1 to GND) **** int digits[16]={63, 6, 91, 79, 102, 109, 125,7, 127, 111, 119, 124, 57, 94, 121, 113}; // these are the byte representations of pins required to display each digit 0~9 then A~F int sensorValue, VAL, SignBit; byte z, x, c, v; void setup() { Wire.begin(); // start up I2C bus delay(1000); initDisplay(); // Serial.begin(9600); } void initDisplay() // turns on dynamic mode and adjusts segment current to 12mA { Wire.beginTransmission(saa1064); Wire.write(B00000000); // this is the instruction byte. Zero means the next byte is the control byte Wire.write(B01000111); // control byte (dynamic mode on, digits 1+3 on, digits 2+4 on, 12mA segment current Wire.endTransmission(); } void TemperA1 () { sensorValue = analogRead(A1); // код АЦП // VAL = (sensorValue*5 - 1415)*10/23; // Вычисляем температу по формуле но умножаем на 10 чтобы получить десятые градуса // Serial.print("sensorValue1 "); // Serial.println(sensorValue); // SignBit = VAL & 0x8000; // проверяем, знак температуры // if (SignBit) { // получаем модуль температуры // VAL = (VAL ^ 0xffff) + 1; // "переворачиваем" значение если значение минус // } // // if (SignBit) // знак // { z = 64; } // "-" // else // { z = 0; } // "с" v=(sensorValue) /1000%10; // тысячи x=(sensorValue) /100%10; // сотни c=(sensorValue) /10%10; // десятки v=(sensorValue) %10; // един /* Serial.print("sensorValue "); Serial.println(sensorValue); Serial.print("sensorValue, BIN "); Serial.println(sensorValue, BIN ); Serial.print("VAL "); Serial.println(VAL); Serial.print("VAL, BIN "); Serial.println(VAL, BIN); Serial.print("SignBit "); Serial.println(SignBit); // Serial.println(z ); // Serial.println(x ); // Serial.println(c ); // Serial.println(v ); Serial.println("----" ); */ } void loop() { TemperA1 (); delay(2000); Wire.beginTransmission(saa1064); Wire.write(1); // instruction byte - first digit to control is 1 (right hand side) Wire.write(digits[(x)]); //d2 Wire.write(digits[(c)]); //d3 Wire.write(digits[(v)]); //d4 Wire.write(digits[(z)]); //d1 Wire.endTransmission(); delay(500); }суть в том, чтобы получить десятые и сотые - необходимо умножить в вычислениях на 10 или 100 и поставить точку в нужном разряде ( при работе с действительными числами процессор "забывает" про все симвалы после запятой ).
кроме того:
v=(sensorValue) /1000%10; // тысячи
x=(sensorValue) /100%10; // сотни
c=(sensorValue) /10%10; // десятки
v=(sensorValue) %10; // един
попробуйте сами догадаться что здесь написано и куда вам это подставить
valter61, Гриша - спасибо большое. Чуть освобожусь и обязательно попробую всё то, что вы подсказали!
Имеются в наличии два шильда индикатора как по ссылке в первом посте этой темы.
При подключении один работает нормально а другой начинает светиться всеми индикаторами и не тухнет.
В чём может быть причина?
Благодарен за отзыв.
Доброго времени суток. Я правильно понимаю что для передачи на индикатор результат измерения надо разложить на число тысяч, число сотен, число десятков и единиц а потом это последовательно передать? Т.е необходимо двоично-десятичное преобразование.
Никто не заставляет выводить на индикатор именно десятичное число. Можно использовать 16-ричное или текст.
Имеются в наличии два шильда индикатора как по ссылке в первом посте этой темы.
При подключении один работает нормально а другой начинает светиться всеми индикаторами и не тухнет.
В чём может быть причина?
Благодарен за отзыв.
Диод закороти на плате, ей питания не хватает
Только теперь придется следить чтобы не перепутать питание
Доброго времени суток. Я правильно понимаю что для передачи на индикатор результат измерения надо разложить на число тысяч, число сотен, число десятков и единиц а потом это последовательно передать? Т.е необходимо двоично-десятичное преобразование.
Библиотека LedControl, лежит на ГитХабе. С ее помощью можно извращаться как угодно с этим индикатором, вт. ч и выводить какие угодно числа и знаки на него. И с запятой тоже вроде как можно
Хотя нет, заблуждаюсь. Нельзя. Надо делить по разрядам :(
Благодарю. Я не силен в программировании, но пришел к выводу что надо делить по разрядам и передавать. Теперь ясно в каком направлении двигаться.
Вот тут делят на разряды, причем успешно: http://arduino.ru/forum/programmirovanie/razdelenie-chisla-na-otdelnye-tsifry
Сделайте функцию и применяйте когда надо :)
Благодарю!