На микроконтроллере 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
Скетч первых часов реален ? Повторил проект ,нет только конденсаторов на кварце. Часы не работают , только нули. Точки мигают с интервалом 5 секунд.
Если есть нули и точки мигают, значит часы работают. Нужен кварц на 12 МГц или на другую частоту с небольшой коррекцией кода. При включении на часах всегда будут нули, нужно кнопками установить время.
Кварц стоит как по схеме 12 мгц. Но при включении часов разделитель мигает с интервалом около 5 секунд а должно 1 сек. При попытке выставить минуты надо долго ждать переключения с 1 до 2 итд. Какие полные установки в ардуино ide ?
1 Чип 2313
2 Внешний кварц 16
3
4
Если рабочий скетч ,чудес не должно быть.
Поставьте конденсаторы на кварц
в настройках платы ни чего не менял, только частоту кварца
Привет. Сегодня для надежности проверил работу кварца, работает. Впечатление такое что чип прошивается не полностью , при включении запускается дисплей и очень медленно мигают разделительные точки. Чипы брал у китайцев они оказались промаркированные . Есть возможность считать с чипа часов фьюзы ?
Да для справки мигание не пропадает при удалении кварца.
Вы прошиваете как рекомендовано здесь — http://rcl-radio.ru/?p=94074
плата в Arduino IDE версии 1.2.5 — 1.3.0
hex — http://rcl-radio.ru/wp-content/uploads/2021/03/16_MHZ.zip
Привет. Купил сегодня новый чип и прошил ,результата нет. Библиотека 1.2.5 ,версия ide 1.8.13
Частота внешнего кварца при прошивке 12 мгц , емкости поставил. Прошиваю через программатор
usbasp плюс платка переходник но без кварца.
Программой avrdude 3.3 чип определяется.
Вопрос решился перепрограммированием , включением фьюза ckdiv8 в программе avrdude_prog 3.3
Скетч залил через arduino ide , коррекцию фьюзов делал avrdude_prog 3.3.
Я прошивал немного по другому, собрал всю схему с кварцем и конденсаторами, в Arduino IDE выбрал контроллер attiny2313 и установил нужную частоту кварца (12MHz external), подключил USBasp, выбрал USBasp в качестве программатора и нажал «Прошить через программатор».
Без кварца даже если выбрать 8MHz internal (внутренний генератор) прошивка не удавалась.
Привет. Выяснил что часы пошли но сильно начинают отставать.
Точность часов зависит только от точности кварца.
Таймер генерирует прерывания с частотой 10 Гц, для создания интервала 0,1 сек
Предделитель равен 64, регистр сравнения OCR1A = 18750
12000000 / 64 / 18750 = 10 Гц
Если Вы подсчитаете погрешность, то можно изменить значение регистра OCR1A, тогда точность часов будет очень высокой.
Например, за час часы отстали на 2 секунды
то есть за час таймер совершил 35980 прерываний (10 прерываний за 1 сек)
18750 / 36000 * 35980 = 18739
OCR1A = 18739
Я могу и если да,на какой ноге посмотреть прерывания ?
При установке времени (минут) при достижении (10минут-пример) ход идет с 00 или 59 секунд.
Пожелание. После 23 часов минимальная яркость, в 6-7 нормальная.
Типа кнопки старта ,я выставил 13-40 (пример) жду по интернет часам достижения этого времени
и отпускаю или что то аналогичное Как ?
Я могу и если да,на какой ноге посмотреть прерывания ?
— просто замерьте на сколько секунд отстают часы в течении 1 часа, прерывания программные.
При установке времени (минут) при достижении (10минут-пример) ход идет с 00 или 59 секунд.
— секунды не корректируются, на ход секунд корректировка минут или часов не отражается. Можно доделать, но тогда надо еще одну кнопку добавить (обнуление секунд)
Типа кнопки старта ,я выставил 13-40 (пример) жду по интернет часам достижения этого времени
и отпускаю или что то аналогичное Как ?
— не совсем понял вопрос
Сейчас время 13-21 я ставлю 13-23 и жду ,при достижении стартую (по сигналу точного времени )
Да, все верно,в 14-23 сделаете замер времени
http://forum.rcl-radio.ru/viewtopic.php?pid=3205#p3205