Ранее в статье http://rcl-radio.ru/?p=77848 был описан пример создания часов на цифровом многоразрядном вакуумном люминесцентном индикаторе ИВЛ1-7/5. В этой статье аналогичный проект, но в нем применена упрощенная схема питания и применен недорогой микроконтроллер Atmega8.
Основные данные индикатора ИВЛ1–7/5:
- Цвет свечения: Зеленый
- Номинальная яркость индикатора 500 кд/м2, минимальная – 300 кд/м2.
- Напряжение накала: 5 В
- Ток накала: 120 ± 12 мА
- Напряжение анода–сегмента импульсное: 27 В
- Ток анодов–сегментов импульсный одного разряда: 12 мА
- Напряжение сетки импульсное: 27 В
- Ток сетки импульсный одного разряда: 12 мА
- Скважность: 5 ± 0,5
- Минимальная наработка: 10 000 ч
- Яркость индикатора, изменяющаяся в течение минимальной наработки, не менее: 100 кд/м2
- Срок хранения не менее: 4 лет
Предельно допустимый электрический режим индикатора ИВЛ1–7/5:
- Напряжение накала строго в пределах: 4,5–5,8 В
- Наибольшее напряжение анодов–сегментов: 50 В
- Наибольшее напряжение сетки импульсное: 50 В
Схема часов
Для установки текущего времени используются три кнопки, но рекомендую при первом запуске использовать установку времени по времени компиляции, для этого необходимо раскомментировать строку:
// set_time(22,7,2,26,13,10,0);// год 00-99, ДН 1-7 (1=ВС), мес 1-12, дата 1-31, час 0-23, мин 0-59, сек 0-59
Залить скетч в микроконтроллер, далее закомментировать строку и залить скетч по новой.
// ATMEGA8 12MHz #define G0_D PD6 #define G1_B PB1 #define G2_B PB2 #define G3_B PB5 #define DP_C PC1 //PD SETKA #define E_B PB3 #define G_B PB4 #define B_B PB0 #define F_D PD7 #define A_D PD5 #define D_C PC2 #define C_C PC3 #define SET PD0 #define UP PD1 #define DOWN PD2 #include <avr/io.h> #include <util/delay.h> #define ADDR_DS1307 0b1101000 #define CPU_F 12000000 // Clock Speed #define SCL_F 100000 // // I2C Speed byte a[4],an,segm,i; int msec,sec,min,hour,set; int set_sec,set_min,set_hour; int main() { TWBR = (((CPU_F)/(SCL_F)-16 )/2) ; TWSR = 0; // set_time(22,7,2,26,13,10,0);// год 00-99, ДН 1-7 (1=ВС), месяц 1-12, дата 1-31, час 0-23, минуты 0-59, секунды 0-59 cli(); // (12000000/((18749+1)x64))=10 Hz OCR1A = 18749; TCCR1B |= (1 << WGM12); // Prescaler 64 TCCR1B |= (1 << CS11) | (1 << CS10); TIMSK |= (1 << OCIE1A); // (12000000/((155+1)x256))=300.48076923077 Hz OCR2 = 155; TCCR2 |= (1 << WGM21); // Prescaler 256 TCCR2 |= (1 << CS22) | (1 << CS21); TIMSK |= (1 << OCIE2); sei(); DDRB|=(1<<G1_B)|(1<<G2_B)|(1<<G3_B)|(1<<E_B)|(1<<G_B)|(1<<B_B); DDRC|=(1<<D_C)|(1<<C_C)|(1<<DP_C); DDRD|=(1<<G0_D)|(1<<F_D)|(1<<A_D); PORTD|=(1<<SET)|(1<<UP)|(1<<DOWN); while(1) { sec = (i2c_read_1bit(ADDR_DS1307,0) & 0x0F) + (((i2c_read_1bit(ADDR_DS1307,0) & 0x70) >> 4) * 10); min = (i2c_read_1bit(ADDR_DS1307,1) & 0x0F) + (((i2c_read_1bit(ADDR_DS1307,1) & 0x70) >> 4) * 10); hour = ((i2c_read_1bit(ADDR_DS1307,2) & 0x0F) + ((i2c_read_1bit(ADDR_DS1307,2) & 0x70) >> 4) * 10); if(((PIND >> SET) & 1) == 0){set++;if(set>3){set=0;}_delay_ms(300);} set_sec=sec; set_min=min; set_hour=hour; if(((PIND >> UP) & 1) == 0 && set==1){set_hour++;if(set_hour>23){set_hour=23;}_delay_ms(300);set_time(255,255,255,255,set_hour,255,255);} if(((PIND >> DOWN) & 1) == 0 && set==1){set_hour--;if(set_hour<0){set_hour=0;}_delay_ms(300);set_time(255,255,255,255,set_hour,255,255);} if(((PIND >> UP) & 1) == 0 && set==2){set_min++;if(set_min>59){set_min=59;}_delay_ms(300);set_time(255,255,255,255,255,set_min,255);} if(((PIND >> DOWN) & 1) == 0 && set==2){set_min--;if(set_min<0){set_min=0;}_delay_ms(300);set_time(255,255,255,255,255,set_min,255);} if(((PIND >> UP) & 1) == 0 && set==3){set_sec=0;_delay_ms(300);set_time(255,255,255,255,255,255,set_sec);} if(((PIND >> DOWN) & 1) == 0 && set==3){set_sec=0;_delay_ms(300);set_time(255,255,255,255,255,255,set_sec);} if(set==0){ a[3]=hour/10; a[2]=hour%10; a[1]=min/10; a[0]=min%10; } if(set==1&&(msec==0||msec==5)){a[3]=10;}else{a[3]=hour/10;} if(set==1&&(msec==0||msec==5)){a[2]=10;}else{a[2]=hour%10;} if(set==2&&(msec==0||msec==5)){a[1]=10;}else{a[1]=min/10;} if(set==2&&(msec==0||msec==5)){a[0]=10;}else{a[0]=min%10;} if(set==3){ if(msec==0||msec==5){a[1]=10;a[3]=10;a[2]=10;}else{a[3]=10;a[2]=10;a[1]=sec/10;} if(msec==0||msec==5){a[0]=10;a[3]=10;a[2]=10;}else{a[3]=10;a[2]=10;a[0]=sec%10;} } if(msec<5){PORTC |=(1<<DP_C);} if(msec>=5){PORTC &=~(1<<DP_C);} _delay_ms(100); }} ISR(TIMER2_COMP_vect){ switch(i){ case 0: segm=a[0]; an=0; anod();segment(); break; case 1: segm=a[1]; an=1; anod();segment(); break; case 2: segm=a[2]; an=2; anod();segment(); break; case 3: segm=a[3]; an=3; anod();segment(); break; }i++;if(i>3){i=0;}} void segment(){ switch(segm){ case 0: PORTD &=~(1<<A_D);PORTB &=~(1<<B_B);PORTC &=~(1<<C_C);PORTC &=~(1<<D_C);PORTB &=~(1<<E_B);PORTD &=~(1<<F_D);PORTB |=(1<<G_B);break; case 1: PORTD |=(1<<A_D);PORTB &=~(1<<B_B);PORTC &=~(1<<C_C);PORTC |=(1<<D_C);PORTB |=(1<<E_B);PORTD |=(1<<F_D);PORTB |=(1<<G_B);break; case 2: PORTD &=~(1<<A_D);PORTB &=~(1<<B_B);PORTC |=(1<<C_C);PORTC &=~(1<<D_C);PORTB &=~(1<<E_B);PORTD |=(1<<F_D);PORTB &=~(1<<G_B);break; case 3: PORTD &=~(1<<A_D);PORTB &=~(1<<B_B);PORTC &=~(1<<C_C);PORTC &=~(1<<D_C);PORTB |=(1<<E_B);PORTD |=(1<<F_D);PORTB &=~(1<<G_B);break; case 4: PORTD |=(1<<A_D);PORTB &=~(1<<B_B);PORTC &=~(1<<C_C);PORTC |=(1<<D_C);PORTB |=(1<<E_B);PORTD &=~(1<<F_D);PORTB &=~(1<<G_B);break; case 5: PORTD &=~(1<<A_D);PORTB |=(1<<B_B);PORTC &=~(1<<C_C);PORTC &=~(1<<D_C);PORTB |=(1<<E_B);PORTD &=~(1<<F_D);PORTB &=~(1<<G_B);break; case 6: PORTD &=~(1<<A_D);PORTB |=(1<<B_B);PORTC &=~(1<<C_C);PORTC &=~(1<<D_C);PORTB &=~(1<<E_B);PORTD &=~(1<<F_D);PORTB &=~(1<<G_B);break; case 7: PORTD &=~(1<<A_D);PORTB &=~(1<<B_B);PORTC &=~(1<<C_C);PORTC |=(1<<D_C);PORTB |=(1<<E_B);PORTD |=(1<<F_D);PORTB |=(1<<G_B);break; case 8: PORTD &=~(1<<A_D);PORTB &=~(1<<B_B);PORTC &=~(1<<C_C);PORTC &=~(1<<D_C);PORTB &=~(1<<E_B);PORTD &=~(1<<F_D);PORTB &=~(1<<G_B);break; case 9: PORTD &=~(1<<A_D);PORTB &=~(1<<B_B);PORTC &=~(1<<C_C);PORTC &=~(1<<D_C);PORTB |=(1<<E_B);PORTD &=~(1<<F_D);PORTB &=~(1<<G_B);break; case 10: PORTD |=(1<<A_D);PORTB |=(1<<B_B);PORTC |=(1<<C_C);PORTC |=(1<<D_C);PORTB |=(1<<E_B);PORTD |=(1<<F_D);PORTB |=(1<<G_B);break; }} void anod(){ switch(an){ case 0: PORTB |=(1<<G3_B);PORTD &=~(1<<G0_D);break; case 1: PORTD |=(1<<G0_D);PORTB &=~(1<<G1_B);break; case 2: PORTB |=(1<<G1_B);PORTB &=~(1<<G2_B);break; case 3: PORTB |=(1<<G2_B);PORTB &=~(1<<G3_B);break; }} ISR(TIMER1_COMPA_vect){msec++;if(msec>9){msec=0;}} void set_time(byte years, byte days, byte monts, byte datas, byte hours ,byte minute, byte second){ if(second < 255){i2c_write(ADDR_DS1307,0x00,(second/10<<4)+second%10);} if(minute < 255){i2c_write(ADDR_DS1307,0x01,(minute/10<<4)+minute%10);} if(hours < 255){i2c_write(ADDR_DS1307,0x02,(hours/10<<4)+hours%10);} if(days < 255){i2c_write(ADDR_DS1307,0x03,days);} if(datas < 255){i2c_write(ADDR_DS1307,0x04,(datas/10<<4)+datas%10);} if(monts < 255){i2c_write(ADDR_DS1307,0x05,(monts/10<<4)+monts%10);} if(years < 255){i2c_write(ADDR_DS1307,0x06,(years/10<<4)+years%10);} } void i2c_write(byte i2c_addr, byte i2c_reg, byte i2c_dat){ TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); // START while (!(TWCR & (1<<TWINT))); TWDR = i2c_addr << 1; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWDR = i2c_reg; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWDR = i2c_dat; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); // СТОП } int i2c_read_1bit(byte i2c_addr, byte i2c_reg){ TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); // START while (!(TWCR & (1<<TWINT))); TWDR = i2c_addr << 1; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWDR = i2c_reg; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); // START while (!(TWCR & (1<<TWINT))); TWDR = (i2c_addr << 1) | 1; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA); while(~TWCR&(1<<TWINT)); byte i2c_data = TWDR; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); // СТОП return i2c_data; }
В часах используется модуль часов реального времени DS1307, так же без изменения скетча можно использовать DS3231.
Для использования ATmega8 в Arduino IDE Вам необходимо собрать следующую схему (в данном случае допускается внутрисхемное программирование, то есть прошивать контроллер при полной собранной схеме часов):
Перед прошивкой ATmega8 необходимо установить поддержку контроллера в Arduino IDE, для этого откройте меню Файл >> Настройки и в пункте Дополнительные ссылки для Менеджера плат вставьте ссылку:
https://mcudude.github.io/MiniCore/package_MCUdude_MiniCore_index.json
Далее переходим в меню Инструменты >> Плата >> Менеджер плат
В строке поиска напишите atmega8, списке менеджера плат выберите пакет: MiniCore by MCUdude
После установки поддержки плат в Arduino IDE появится плата Atmega8
- Для прошивки скетча или загрузчика Вам понадобится программатор USBasp
Распиновка USBasp
Перед загрузкой в настройках платы укажите частоту кварцевого резонатора (12 МГц), выбрать программатор USBasp, в пункте Bootloader выберите No bootloader или Yes (UART0) если планируете загружать скетчи через UART ( USB — TTL ).
Во вкладке «Инструменты» нажмите «Записать загрузчик«.(делается только один раз)
После записи загрузчика Вы в Arduino IDE увидите примерно следующее:
Для загрузки скетча выберите вкладку — Скетч >> Загрузить через программатор
После загрузки скетча появится следующее сообщение:
Доброе утро! Есть прошивка в НЕХ? В ардуино выдаёт ошибку.
Попробуйте этот код — http://forum.rcl-radio.ru/viewtopic.php?pid=7843#p7843
То же самое.
http://rcl-radio.ru/wp-content/uploads/2023/05/gps_4_14.ino_.standard.zip