На микроконтроллере ATtiny2313 можно собрать простые часы, в качестве индикатора часов будет использоваться модуль TM1637, который представляет собой 4-х разрядный семисегментный дисплей на базе драйвера TM1637 с двоеточием для индикации такта секунд.
Схема часов очень простая, а использование модуля TM1637 упрощает сборку часов. Для коррекции времени служат две кнопки (для минут и часов).
Перед загрузкой скетча рекомендую ознакомится со статьей — ATtiny2313 + Arduino IDE
// tm1637 PB0 === CLK // tm1637 PB1 === DIO int i,i1,hh,mm,bb; void setup() { DDRB = 0b00000000; PORTB |= (1 << 2) | (1 << 3); cli(); TCCR1A = 0; TCCR1B = 0; OCR1A = 18750; // 0.1 s TCCR1B |= (1 << WGM12); TCCR1B |= (1 << CS11) | (1 << CS10); // 64 TIMSK |= (1 << OCIE1A); sei(); } void loop() { print_time(hh * 100 + mm, bb, 7);// int число выводимое на индикатор, двоеточие, яркость от 0 до 7 if(i1 <= 5){bb = 1;}else{bb = 0;} if(((PINB >> 2) & 1) == 0){mm++; if(mm>59){mm = 0;} delay(200);} if(((PINB >> 3) & 1) == 0){hh++; if(hh>23){hh = 0;} delay(200);} } void tm_dec(byte dig){ for(int i = 0; i < 8; i++) { DDRB |= (1 << 0);del(); if (dig & 0x01) DDRB &= ~(1 << 1); else DDRB |= (1 << 1);del(); DDRB &= ~(1 << 0);del(); dig = dig >> 1; } DDRB |= (1 << 0); DDRB &= ~(1 << 1);del(); DDRB &= ~(1 << 0);del(); if (((PINB >> 1) & 1) == 0) DDRB |= (1 << 1);del(); DDRB |= (1 << 0);del(); } void tm_stop(){ DDRB |= (1 << 1);del(); DDRB &= ~(1 << 0);del(); DDRB &= ~(1 << 1);del(); } void tm_start(){ DDRB |= (1 << 1);del(); } void print_time(int t, bool pd_t, int br){ tm_start();tm_dec(0b10001000 + br);//tm_stop();tm_start(); tm_dec(0x40);tm_stop();tm_start(); int data0 = t / 1000; int data1 = t / 100 % 10; int data2 = t / 10 % 10; int data3 = t % 10; for(byte n = 0; n < 4; n++){ int data; switch(n){ case 0: data = data0;break; case 1: data = data1;break; case 2: data = data2;break; case 3: data = data3;break; } switch(data){ // XGFEDCBA case 0: data = 0b00111111;break; // 0 case 1: data = 0b00000110;break; // 1 case 2: data = 0b01011011;break; // 2 case 3: data = 0b01001111;break; // 3 case 4: data = 0b01100110;break; // 4 case 5: data = 0b01101101;break; // 5 case 6: data = 0b01111101;break; // 6 case 7: data = 0b00000111;break; // 7 case 8: data = 0b01111111;break; // 8 case 9: data = 0b01101111;break; // 9 } if(n == 0){data0 = data;} if(n == 1){data1 = data;} if(n == 2){data2 = data;} if(n == 3){data3 = data;} } if(pd_t == 1){data1+= 0b10000000;} tm_dec(0xC0);tm_dec(data0);tm_dec(data1);tm_dec(data2);tm_dec(data3);tm_stop(); } void del(){delayMicroseconds(100);} ISR(TIMER1_COMPA_vect){ i++;i1++; if(i1 > 9){i1 = 0;} if(i > 599){mm++;i = 0;} if(mm > 59){hh++;mm = 0;} if(hh > 23){hh = 0;} }
Скетч использует 1330 байт (64%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 19 байт (14%) динамической памяти, оставляя 109 байт для локальных переменных. Максимум: 128 байт.
Так как в ATtiny2313 еще остается немного памяти и я решил дополнить часы будильником.
Управление часами осуществляется при помощи 4-х кнопок, кнопки НН и ММ для корректировки часов и минут, кнопка SET ALARM служит для установки времени срабатывания будильника, при нажатии на кнопку SET ALARM мигание двоеточия прекращается, что свидетельствует о активации режима корректировки времени будильника, кнопками НН и ММ устанавливается время будильника. При повторном нажатии кнопки SET ALARM происходит переход в режим часов. Кнопка ALARM ON/OFF предназначена для активации режима будильника, при нажатии на кнопку загорается светодиод и при совпадении времени часов и времени будильника будет слышен прерывисты звуковой сигнал, который будет звучать в течении 1 минуты, прервать сигнал можно нажав на кнопку ALARM ON/OFF.
Время будильника сохраняется в энергонезависимой памяти.
// tm1637 PB0 === CLK // tm1637 PB1 === DIO // zummer PD5 // MM+ PB2 // HH+ PB3 // ALARM/TIME PB4 // ALARM ON/OFF PD4 // led ALARM PD3 int i,i1,hh,mm,bb,b_hh,b_mm,bud,blok; void setup() { DDRB = 0b00000000; DDRD = 0b00101000; PORTB |= (1 << 2) | (1 << 3) | (1 << 4); PORTD |= (1 << 4); cli(); TCCR1A = 0; TCCR1B = 0; OCR1A = 18750; // 0.1 s TCCR1B |= (1 << WGM12); TCCR1B |= (1 << CS11) | (1 << CS10); // 64 TIMSK |= (1 << OCIE1A); sei(); b_hh = EEPROM_read(1); b_mm = EEPROM_read(0); } void loop() { if(bud == 0){print_time(hh * 100 + mm, bb, 7);}// int число выводимое на индикатор, двоеточие, яркость от 0 до 7 if(bud == 1){print_time(b_hh * 100 + b_mm, bb, 7);}// int число выводимое на индикатор, двоеточие, яркость от 0 до 7 if(i1 <= 5){bb = 1;}else{bb = 0;} if(bud == 1){bb = 1;} // button set time if(((PINB >> 2) & 1) == 0 && bud == 0){mm++; if(mm>59){mm = 0;} delay(200);} if(((PINB >> 3) & 1) == 0 && bud == 0){hh++; if(hh>23){hh = 0;} delay(200);} // button set alarm if(((PINB >> 4) & 1) == 0 && bud == 0){bud = 1; delay(200);} if(((PINB >> 4) & 1) == 0 && bud == 1){bud = 0; delay(200);} // button set time alarm if(((PINB >> 2) & 1) == 0 && bud == 1){b_mm++; if(b_mm>59){b_mm = 0;}EEPROM_write(0,b_mm); delay(200);} if(((PINB >> 3) & 1) == 0 && bud == 1){b_hh++; if(b_hh>23){b_hh = 0;}EEPROM_write(1,b_hh); delay(200);} // led alarm | button on/off if(((PIND >> 4) & 1) == 0 && blok == 1){blok = 0; delay(200);} if(((PIND >> 4) & 1) == 0 && blok == 0){blok = 1; delay(200);} if(blok == 1){PORTD &= ~(1 << 3);}else{PORTD |= (1 << 3);} // zummer if((hh * 100 + mm) == (b_hh * 100 + b_mm) && blok == 0){if(i1 <= 5){DDRD |= (1 << 5);pic();} else {DDRD &= ~(1 << 5);}} } // loop void pic(){ for(int g=0;g<1000;g++){ PORTD |= (1 << 5); delayMicroseconds(150); PORTD &= ~(1 << 5); delayMicroseconds(100);} } void tm_dec(byte dig){ for(int i = 0; i < 8; i++) { DDRB |= (1 << 0);del(); if (dig & 0x01) DDRB &= ~(1 << 1); else DDRB |= (1 << 1);del(); DDRB &= ~(1 << 0);del(); dig = dig >> 1; } DDRB |= (1 << 0); DDRB &= ~(1 << 1);del(); DDRB &= ~(1 << 0);del(); if (((PINB >> 1) & 1) == 0) DDRB |= (1 << 1);del(); DDRB |= (1 << 0);del(); } void tm_stop(){ DDRB |= (1 << 1);del(); DDRB &= ~(1 << 0);del(); DDRB &= ~(1 << 1);del(); } void tm_start(){ DDRB |= (1 << 1);del(); } void print_time(int t, bool pd_t, int br){ tm_start();tm_dec(0b10001000 + br);//tm_stop();tm_start(); tm_dec(0x40);tm_stop();tm_start(); int data0 = t / 1000; int data1 = t / 100 % 10; int data2 = t / 10 % 10; int data3 = t % 10; for(byte n = 0; n < 4; n++){ int data; switch(n){ case 0: data = data0;break; case 1: data = data1;break; case 2: data = data2;break; case 3: data = data3;break; } switch(data){ // XGFEDCBA case 0: data = 0b00111111;break; // 0 case 1: data = 0b00000110;break; // 1 case 2: data = 0b01011011;break; // 2 case 3: data = 0b01001111;break; // 3 case 4: data = 0b01100110;break; // 4 case 5: data = 0b01101101;break; // 5 case 6: data = 0b01111101;break; // 6 case 7: data = 0b00000111;break; // 7 case 8: data = 0b01111111;break; // 8 case 9: data = 0b01101111;break; // 9 } if(n == 0){data0 = data;} if(n == 1){data1 = data;} if(n == 2){data2 = data;} if(n == 3){data3 = data;} } if(pd_t == 1){data1+= 0b10000000;} tm_dec(0xC0);tm_dec(data0);tm_dec(data1);tm_dec(data2);tm_dec(data3);tm_stop(); } void del(){delayMicroseconds(100);} ISR(TIMER1_COMPA_vect){ i++;i1++; if(i1 > 9){i1 = 0;} if(i > 599){mm++;i = 0;} if(mm > 59){hh++;mm = 0;} if(hh > 23){hh = 0;} } unsigned char EEPROM_read(unsigned int uiAddress){ while(EECR & (1<<EEPE)); EEAR = uiAddress; EECR |= (1<<EERE); return EEDR; } void EEPROM_write(unsigned int uiAddress, unsigned char ucData){ while(EECR & (1<<EEPE)); EEAR = uiAddress; EEDR = ucData; EECR |= (1<<EEMPE); EECR |= (1<<EEPE); }
Следующая версия часов аналогична первым часам, но в них в качестве индикатора используется LCD1602.
// ATTINY2313 V1.25 // D4 = PB0 // D5 = PB1 // D6 = PB2 // D7 = PB3 // E = PB4 // RS = PD6 // button HH = PD3 // button MM = PD4 int i,hh,mm,ss; int a[8]; void setup() { DDRB = 0b00011111; DDRD = 0b01000000; PORTD |= (1 << 4) | (1 << 3); cli(); TCCR1A = 0; TCCR1B = 0; OCR1A = 18750; // 0.1 s TCCR1B |= (1 << WGM12); TCCR1B |= (1 << CS11) | (1 << CS10); // 64 TIMSK |= (1 << OCIE1A); sei(); delay(100); lcd(0x03);delayMicroseconds(4500); lcd(0x03);delayMicroseconds(4500); lcd(0x03);delayMicroseconds(200); lcd(0b00000010);del(); lcd(0b00001100);del(); lcd(0b00000001); } void loop() { if(((PIND >> 4) & 1) == 0){mm++; if(mm>59){mm = 0;}} if(((PIND >> 3) & 1) == 0){hh++; if(hh>23){hh = 0;}} a[0] = hh/10+48; a[1] = hh%10+48; a[2] = mm/10+48; a[3] = mm%10+48; a[4] = ss/10+48; a[5] = ss%10+48; lcd(0b10000000+6); // 0 lcdString("TIME"); lcd(0b11000000+4); // 1 lcdChar(a[0]);lcdChar(a[1]);lcdString(":");lcdChar(a[2]);lcdChar(a[3]);lcdString(":");lcdChar(a[4]);lcdChar(a[5]); delay(100); } void lcdSend(bool isCommand, uint8_t data) { if(isCommand==0){PORTD |= (1 << 6);}//RS if(isCommand==1){PORTD &= ~(1 << 6);}//RS del(); if(((data >> 7) & 1) ==1){PORTB |= (1 << 3);}else{PORTB &= ~(1 << 3);} if(((data >> 6) & 1) ==1){PORTB |= (1 << 2);}else{PORTB &= ~(1 << 2);} if(((data >> 5) & 1) ==1){PORTB |= (1 << 1);}else{PORTB &= ~(1 << 1);} if(((data >> 4) & 1) ==1){PORTB |= (1 << 0);}else{PORTB &= ~(1 << 0);} rs(); if(((data >> 3) & 1) ==1){PORTB |= (1 << 3);}else{PORTB &= ~(1 << 3);} if(((data >> 2) & 1) ==1){PORTB |= (1 << 2);}else{PORTB &= ~(1 << 2);} if(((data >> 1) & 1) ==1){PORTB |= (1 << 1);}else{PORTB &= ~(1 << 1);} if(((data >> 0) & 1) ==1){PORTB |= (1 << 0);}else{PORTB &= ~(1 << 0);} rs(); } void lcd(uint8_t cmd) {lcdSend(true, cmd);} void lcdChar(const char chr) {lcdSend(false, (uint8_t)chr);} void lcdString(const char* str) {while(*str != '\0') {lcdChar(*str);str++;}} void del(){delay(5);} void rs(){PORTB |= (1 << 4);del();PORTB &= ~(1 << 4);} ISR(TIMER1_COMPA_vect){ i++; if(i > 9){ss++;i=0;} if(ss > 59){mm++;ss = 0;} if(mm > 59){hh++;mm = 0;} if(hh > 23){hh = 0;} }
Скетч использует 1316 байт (64%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 41 байт (32%) динамической памяти, оставляя 87 байт для локальных переменных. Максимум: 128 байт.
Форум — http://forum.rcl-radio.ru/viewtopic.php?pid=3185#p3185
Прошивка проводилась при помощи программатора USBasp в среде Arduino IDE 1.8.9, версия платы 1.25
Загрузил на первый взгляд работает.
Я разобрался с проблемой со фьюзами, надо было выбрать нужную частоту и нажать — Записать загрузчик. При запуске микроконтроллера я нажимал — Записать загрузчик, но не придал этому значения.