На светодиодной матрице MAX7219 8х8 можно собрать простые часы. В часах используется матрица состоящая их четырех модулей MAX7219. Помимо матрицы в часах используется плата Arduino Nano, часы реального времени DS1307 (DS3231 — с небольшим изменением скетча *), датчик температуры и влажности DHT11.
Более подробно про LED матрицу на MAX7219 можно узнать — http://rcl-radio.ru/?p=98863
!!! Обратите внимание, что при полной яркости LED матрица может потреблять более 1,5 А, поэтому для питания матрицы используйте отдельный источник питания 5 В с максимальным выходным током не менее 2 А!!!
На LED матрице MAX7219 поочередно выводится время (часы:минуты), дата (дата,месяц), температура и влажность.
Для корректировки параметров часов используются кнопки SET, UP, DW, которые позволяют изменять часы, минуты, дату, месяц и яркость свечения светодиодов матрицы (0…16).
Для первоначальной установки времени часов реального времени необходимо в скетче найти и раскомментировать строку:
set_time(21,2,5,3,0,4,0);// год 00-99, ДН 1-7 (1=ВС), месяц 1-12, дата 1-31, час 0-23, минуты 0-59, секунды 0-59
Загрузите скетч в микроконтроллер и закомментируйте строку:
// set_time(21,2,5,3,0,4,0);// год 00-99, ДН 1-7 (1=ВС), месяц 1-12, дата 1-31, час 0-23, минуты 0-59, секунды 0-59
Далее снова загрузите скетч.
Скетч полностью совместим с микроконтроллерами ATmega168, ATmrga328, ATmega8.
////////// |PORT |pin | Arduino // MAX7219 #define CLK PD2 // | 4 | D2 #define CS PD3 // | 5 | D3 #define DIN PD4 // | 6 | D4 // DS1307 #define SDA PB3 // | 17 | D11 #define SCL PB2 // | 16 | D10 #define SQW PB4 // | 18 | D12 // DHT11 #define OUT PB0 // | 14 | D8 // BUTTON #define SET PC0 // | 23 | A0 #define UP PC1 // | 24 | A1 #define DW PC2 // | 25 | A2 int beg,obr,br; byte data_dht[5]; byte d0,d1,d2,d3,i1,bb,i3,f1,sett; byte hh,mm; byte dat[18][8] = {{B00111100,B01100110,B01101110,B01111110,B01110110,B01100110,B00111100,B00000000},//0 {B00011000,B00111000,B00011000,B00011000,B00011000,B00011000,B00011000,B00000000},//1 {B00111100,B01100110,B00000110,B00011100,B00110000,B01100000,B01111110,B00000000},//2 {B00111100,B01100110,B00000110,B00011100,B00000110,B01100110,B00111100,B00000000},//3 {B00001110,B00011110,B00110110,B01100110,B01111110,B00000110,B00000110,B00000000},//4 {B01111110,B01100000,B01111100,B00000110,B00000110,B01100110,B00111100,B00000000},//5 {B00011100,B00110000,B01100000,B01111100,B01100110,B01100110,B00111100,B00000000},//6 {B01111110,B00000110,B00000110,B00001100,B00011000,B00011000,B00011000,B00000000},//7 {B00111100,B01100110,B01100110,B00111100,B01100110,B01100110,B00111100,B00000000},//8 {B00111100,B01100110,B01100110,B00111110,B00000110,B00001100,B00111000,B00000000},//9 {B00110000,B00110000,B01111100,B00110000,B00110000,B00110100,B00011000,B00000000},//t = 10 {B01100110,B01100110,B01100110,B01111110,B01100110,B01100110,B01100110,B00000000},//H = 11 {B00000000,B00111000,B01101100,B01101100,B00111000,B00000000,B00000000,B00000000},// градус = 12 {B00000000,B11000110,B11001100,B00011000,B00110000,B01100110,B11000110,B00000000},// % = 13 {B11000110,B11101110,B11111110,B11111110,B11010110,B11000110,B11000110,B00000000},// M = 14 {B01111000,B01101100,B01100110,B01100110,B01100110,B01101100,B01111000,B00000000},// D = 15 {B01111100,B01100110,B01100110,B01111100,B01100110,B01100110,B01111100,B00000000},// B = 16 {B00000000,B00000000,B01011100,B01110110,B01100000,B01100000,B01100000,B00000000} // r = 17 }; void setup() { // Serial.begin(9600); DDRB &= ~(1 << SQW);PORTB |= (1 << SQW); // set_time(21,2,5,3,0,4,0);// год 00-99, ДН 1-7 (1=ВС), месяц 1-12, дата 1-31, час 0-23, минуты 0-59, секунды 0-59 ds_write(0x07, 0b00010000); // выход SQW, частота 1 Гц delay(2); br = EEPROM_read(0); if(br==255){br=0;EEPROM_write(0,br);} DDRD |= (1 << DIN) | (1 << CS) | (1 << CLK); PORTC |= (1 << SET) | (1 << UP) | (1 << DW); max7219_L(0x0F, 0);// тест выкл. max7219_L(0x0C, 0x01010101);// вкл. индик. max7219_L(0x0A, 0x01010101*br);// яркость max7219_L(0x09, 0);// дешифраторы выкл. max7219_L(0x0B, 0x07070707);// кол-во разрядов } void loop() { int sec = (ds_read(0) & 0x0F) + (((ds_read(0) & 0x70) >> 4) * 10); int min = (ds_read(1) & 0x0F) + (((ds_read(1) & 0x70) >> 4) * 10); int hour = ((ds_read(2) & 0x0F) + ((ds_read(2) & 0x70) >> 4) * 10); int datat = ((ds_read(4) & 0x0F) + ((ds_read(4) & 0x70) >> 4) * 10); int mont = ((ds_read(5) & 0x0F) + ((ds_read(5) & 0x70) >> 4) * 10); if(((PINC >> SET) & 1) == 0){sett++;if(sett>5){sett=0;}delay(300);} if(((PINC >> UP) & 1) == 0 && sett == 1){hour++;if(hour>23){hour=0;}set_time(255,255,255,255,hour,255,255);delay(300);} if(((PINC >> DW) & 1) == 0 && sett == 1){hour--;if(hour<0){hour=0;}set_time(255,255,255,255,hour,255,255);delay(300);} if(((PINC >> UP) & 1) == 0 && sett == 2){min++;if(min>59){min=0;}set_time(255,255,255,255,255,min,255);delay(300);} if(((PINC >> DW) & 1) == 0 && sett == 2){min--;if(min<0){min=0;}set_time(255,255,255,255,255,min,255);delay(300);} if(((PINC >> UP) & 1) == 0 && sett == 3){datat++;if(datat>31){datat=1;}set_time(255,255,255,datat,255,255,255);delay(300);} if(((PINC >> DW) & 1) == 0 && sett == 3){datat--;if(datat<1){datat=1;}set_time(255,255,255,datat,255,255,255);delay(300);} if(((PINC >> UP) & 1) == 0 && sett == 4){mont++;if(mont>12){mont=1;}set_time(255,255,mont,255,255,255,255);delay(300);} if(((PINC >> DW) & 1) == 0 && sett == 4){mont--;if(mont<1){mont=1;}set_time(255,255,mont,255,255,255,255);delay(300);} if(((PINC >> UP) & 1) == 0 && sett == 5){br++;if(br>15){br=15;}EEPROM_write(0,br);max7219_L(0x0A, 0x01010101*br);delay(300);} if(((PINC >> DW) & 1) == 0 && sett == 5){br--;if(br<0){br=0;}EEPROM_write(0,br);max7219_L(0x0A, 0x01010101*br);delay(300);} if(sett==0){ if(((PINB >> SQW) & 1)==1){bb = 0;}else{bb = 3;} if(obr==2 &&f1==0){f1=1; dht_read();delay(1000);} if(obr!=2){f1=0;} switch(obr){ case 0: d0=hour/10;d1=hour%10;d2=min/10;d3=min%10;break; case 1: d0=hour/10;d1=hour%10;d2=min/10;d3=min%10;break; case 2: d0=datat/10;d1=datat%10;d2=mont/10;d3=mont%10;break; case 3: d0=datat/10;d1=datat%10;d2=mont/10;d3=mont%10;break; case 4: d0=11;d1=data_dht[0]/10;d2=data_dht[0]%10;d3=13;break; case 5: d0=11;d1=data_dht[0]/10;d2=data_dht[0]%10;d3=13;break; case 6: d0=10;d1=data_dht[2]/10;d2=data_dht[2]%10;d3=12;break; case 7: d0=10;d1=data_dht[2]/10;d2=data_dht[2]%10;d3=12;break; } beg++; ///// time ///////////////////// if(obr==0){ for(int z=0;z<8;z++){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<17 | (unsigned int)dat[d2][z]<<7 | dat[d3][z]) << beg); if(z==1||z==2||z==4||z==5){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<17 | (unsigned int)dat[d2][z]<<7 | dat[d3][z] | (int long)bb << 15) << beg);}} if(beg>32){beg=0;obr=7;}} if(obr==1){ for(int z=0;z<8;z++){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<17 | (unsigned int)dat[d2][z]<<7 | dat[d3][z]) >> 32 - beg); if(z==1||z==2||z==4||z==5){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<17 | (unsigned int)dat[d2][z]<<7 | dat[d3][z] | (int long)bb << 15) >> 32 - beg);}} if(beg>32){beg=-120;obr=0;}} /////// data ///////////////////////////////////////////////// if(obr==2){ for(int z=0;z<8;z++){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<17 | (unsigned int)dat[d2][z]<<7 | dat[d3][z]) << beg); if(z==6||z==7){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<17 | (unsigned int)dat[d2][z]<<7 | dat[d3][z] | (int long)3 << 15) << beg);}} if(beg>32){beg=0;obr=1;}} if(obr==3){ for(int z=0;z<8;z++){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<17 | (unsigned int)dat[d2][z]<<7 | dat[d3][z]) >> 32 - beg); if(z==6||z==7){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<17 | (unsigned int)dat[d2][z]<<7 | dat[d3][z] | (int long)3 << 15) >> 32 - beg);}} if(beg>32){beg=-50;obr=2;}} ////// hhhh //////////////////////////////////////////////////////////////////////// if(obr==4){ for(int z=0;z<8;z++){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<15 | (unsigned int)dat[d2][z]<<8 | dat[d3][z]) << beg);} if(beg>32){beg=0;obr=3;}} if(obr==5){ for(int z=0;z<8;z++){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<15 | (unsigned int)dat[d2][z]<<8 | dat[d3][z]) >> 32 - beg);} if(beg>32){beg=-50;obr=4;}} ////// temp //////////////////////////////////////////////////////////////////////// if(obr==6){ for(int z=0;z<8;z++){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<15 | (unsigned int)dat[d2][z]<<8 | dat[d3][z]) << beg);} if(beg>32){beg=0;obr=5;}} if(obr==7){ for(int z=0;z<8;z++){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<15 | (unsigned int)dat[d2][z]<<8 | dat[d3][z]) >> 32 - beg);} if(beg>32){beg=-50;obr=6;}} } if(sett==1){ d0=11;d1=11;d2=hour/10;d3=hour%10; for(int z=0;z<8;z++){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<16 | (unsigned int)dat[d2][z]<<8 | dat[d3][z]));}} if(sett==2){ d0=14;d1=14;d2=min/10;d3=min%10; for(int z=0;z<8;z++){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<16 | (unsigned int)dat[d2][z]<<8 | dat[d3][z]));}} if(sett==3){ d0=15;d1=15;d2=datat/10;d3=datat%10; for(int z=0;z<8;z++){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<16 | (unsigned int)dat[d2][z]<<8 | dat[d3][z]));}} if(sett==4){ d0=1;d1=14;d2=mont/10;d3=mont%10; for(int z=0;z<8;z++){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<16 | (unsigned int)dat[d2][z]<<8 | dat[d3][z]));}} if(sett==5){ d0=16;d1=17;d2=br/10;d3=br%10; for(int z=0;z<8;z++){ max7219_L(z+1, ((unsigned long)dat[d0][z]<<24 | (unsigned long)dat[d1][z]<<16 | (unsigned int)dat[d2][z]<<8 | dat[d3][z]));}} //Serial.println(beg); delay(30); }//loop void max7219_L(byte reg_n, unsigned long h){ byte h1 = h >> 24; byte h2 = h >> 16; byte h3 = h >> 8; byte h4 = h; PORTD &=~(1 << CS);WriteBit16(reg_n,h1);WriteBit16(reg_n,h2);WriteBit16(reg_n,h3);WriteBit16(reg_n,h4);PORTD |=(1 << CS); } void WriteBit16(byte reg, byte data){ for(char i = 7; i >= 0; i--){ PORTD &= ~(1 << CLK); if(((reg >> i) & 1) == 1){PORTD |= (1 << DIN);}else{PORTD &= ~(1 << DIN);} PORTD |=(1 << CLK);} for(char i = 7; i >= 0; i--){ PORTD &= ~(1 << CLK); if(((data >> i) & 1) == 1){PORTD |= (1 << DIN);}else{PORTD &= ~(1 << DIN);} PORTD |=(1 << CLK);} PORTD &= ~(1 << CLK);PORTD |= (1 << DIN); } bool i2c_read_bit() { bool i2c_bit = 1; DDRB &= ~(1 << SDA); delayMicroseconds(10); DDRB &= ~(1 << SCL); if((PINB >> SDA) & 1) i2c_bit=0; delayMicroseconds(10); DDRB |= (1 << SCL); return i2c_bit; } byte i2c_write_byte(byte data){ for (byte i=0; i<8; i++){i2c_write_bit((data&0x80)==0);data<<=1;} return i2c_read_bit(); } byte i2c_read_byte(byte a){ byte i, data=0; for(i=0; i<8; i++){if (!i2c_read_bit()) data++;if(i!=7) data<<=1;} i2c_write_bit(a);return data; } void i2c_write_bit(byte b){ delayMicroseconds(5); if(b){DDRB |= (1 << SDA);}else{DDRB &= ~(1 << SDA);} delayMicroseconds(5); DDRB &= ~(1 << SCL); delayMicroseconds(10); DDRB |= (1 << SCL); } void i2c_start(){ delayMicroseconds(10); DDRB &= ~(1 << SDA); DDRB &= ~(1 << SCL); delayMicroseconds(10); DDRB |= (1 << SDA); PORTB &= ~(1 << SDA); delayMicroseconds(10); DDRB |= (1 << SCL); PORTB &= ~(1 << SCL); delayMicroseconds(10); } void i2c_stop() { DDRB |= (1 << SDA); delayMicroseconds(10); DDRB &= ~(1 << SCL); delayMicroseconds(10); DDRB &= ~(1 << SDA); } byte ds_read(byte reg){ byte data = 0; i2c_start(); i2c_write_byte(0b11010000); i2c_write_byte(reg); i2c_start(); i2c_write_byte(0b11010001); data = i2c_read_byte(0); i2c_stop(); return data; } void ds_write(byte reg, byte data){ i2c_start(); i2c_write_byte(0b11010000); i2c_write_byte(reg); i2c_write_byte(data); i2c_stop(); } void set_time(byte years, byte days, byte monts, byte datas, byte hours ,byte minute, byte second){ if(second<255){ds_write(0x00,(second/10<<4)+second%10);} if(minute<255){ds_write(0x01,(minute/10<<4)+minute%10);} if(hours<255){ds_write(0x02,(hours/10<<4)+hours%10);} if(days<255){ds_write(0x03,days);} if(datas<255){ds_write(0x04,(datas/10<<4)+datas%10);} if(monts<255){ds_write(0x05,(monts/10<<4)+monts%10);} if(years<255){ds_write(0x06,(years/10<<4)+years%10);} } int dht_read(){ byte id = 0,id1 = 0; for(id = 0;id < 5;id++){data_dht[id] = 0;} DDRB |=(1 << OUT); PORTB &= ~(1 << OUT); delay(18); PORTB |= (1 << OUT); delayMicroseconds(40); DDRB &= ~(1 << OUT); delayMicroseconds(80); while(PINB & (1 << OUT)); for (id = 0; id < 5; id++){ data_dht[id]=0; for (id1=0; id1<8; id1++){ while(!(PINB & (1 << OUT))); delayMicroseconds(30); if (PINB & (1 << OUT)){data_dht[id] |= 1 << (7-id1);} while(PINB & (1 << OUT)); }}return 1;} unsigned char EEPROM_read(unsigned int uiAddress){ while(EECR & (1<<EEPE)); // проверка готовности EEPROM EEAR = uiAddress; // регистр адреса EECR |= (1<<EERE);// чтение EEPROM return EEDR; // вывод значения } void EEPROM_write(unsigned int uiAddress, unsigned char ucData){ while(EECR & (1<<EEPE)); // проверка готовности EEPROM EEAR = uiAddress; // регистр адреса EEDR = ucData; // регистр данных EECR |= (1<<EEMPE);// Разрешение записи в EEPROM EECR |= (1<<EEPE); // Запись в EEPROM }
!!! Обратите внимание, что при полной яркости LED матрица может потреблять более 1,5 А, поэтому для питания матрицы используйте отдельный источник питания!!!
Форум — http://forum.rcl-radio.ru/viewtopic.php?id=300
Доработка — изменен порядок вывода параметров на матрицу:
- время
- дата/месяц
- время
- температура
- время
- влажность
Скетч — http://forum.rcl-radio.ru/viewtopic.php?pid=3446#p3446
Доработка — датчик освещенности, матрица меняет яркость в зависимости от освещенности.
В темноте яркость 0, при освещении максимальная яркость та, которая выставлена в параметре BR (в меню настройки времени).
Скетч — http://forum.rcl-radio.ru/viewtopic.php?pid=3465#p3465
* ds_write(0x07, 0b00010000) заменить на ds_write(0x0E, 0b00010000)
С модулем DS1307 между цифрами мигают светодиоды , а с модулем DS3231 их нет.