Autor: dipcray06
Redakcja: Dondu
Połączenie takich lampowych wyświetlaczy z dzisiejszą elektroniką daje duże możliwości. W prezentowanym zegarze wyświetlanie realizowane jest przez multipleksowanie co znacznie upraszcza sterowanie, a dodatkowo w moim odczuciu zwiększa też żywotność lamp.
Zegar w wersji prototypowej powstał już jakiś czas temu, ale program napisany był w Bascomie, którego do tej pory używałem. Jednak już od jakiegoś czasu chciałem zacząć programować w C i ten projekt jest właśnie moim pierwszym napisanym w tym języku.
Funkcjonalność tego urządzenia to:
- wyświetlanie aktualnej godziny w formacie 24 godzinnym,
- wyświetlanie temperatury z dokładnością do 1/10 stopnia C,
- podtrzymywanie bateryjne godziny po wyłączeniu zasilania,
- czujnik natężenia światła, który decyduje o jasności wyświetlanych cyfr oraz o włączeniu podświetlenia,
- efekt odtruwania katod wyświetlaczy po każdej zmianie minuty,
- wygaszenie pierwszego wyświetlacza dla godzin od 0:00 do 9:59, dzięki czemu zero przed tymi godzinami nie jest wyświetlane,
- wygaszenie ostatniej cyfry wyświetlacza przy wyświetlaniu temperatury.
Zegar powstał z wykorzystaniem darmowego oprogramowania. Schematy ideowe i płytki PCB powstały w programie EAGLE w wersji freeware. Ze względu na ograniczenia darmowej wersji programu co do wielkości płytek, zegar ma konstrukcję modułową. Urządzenie składa się z ośmiu oddzielnych płytek PCB. Płytki zrobione zostały samodzielnie metodą termotransferu. Program powstał w Eclipse Indigo w całości w języku C.
A tak prezentuje się z bliska:
Zegar Nixie 5 |
Schematy elektryczne
Zasilanie tworzy jeden moduł, przedstawiony na poniższym schemacie.Moduł zasilania |
Zegar zasilany jest z 12V zasilacza stabilizowanego DC. Logika urządzenia zasilania jest ze stabilizatora 7805 obniżającego napięcie do 5V. Ponieważ wyświetlacze Nixie do działania wymagają napięcia zasilania 170V, zastosowałem impulsową przetwornicę podwyższającą MC34063.
Najważniejsze jej elementy to dławik L2 330uH, szybka dioda prostownicza D1 BYV29 oraz tranzystor Q1 IRF840. Potencjometrem R5 można regulować napięcie wyjściowe. Przetwornica spisuje się bardzo dobrze. Prąd katody dla zastosowanych wyświetlaczy LC-516 to około 2mA.
Kolejny moduł to logika sterująca całym wyświetlaczem.
Logika |
Wszystkim steruje ATmega8. Początkowo miała być taktowana kwarcem 16MHz, ale program został napisany tak, aby można było wykorzystać wewnętrzny oscylator 8MHz, co okazuje się wystarczające. Procesor wyrabia się ze wszystkimi zadaniami, więc zewnętrznego kwarcu nie trzeba lutować.
Oczywiście sygnał Resetu jest typowo podciągnięty do VCC, ale zegar można zresetować wciskając przycisk S1. Ważna jest również filtracja zasilania. Impulsowe załączanie wyświetlaczy może generować zakłócenia, dlatego obwody zasilania wszystkich układów scalonych na PCB są filtrowane przez kondensatory 100nF, a mikroprocesor dodatkowo przez kondensator elektrolityczny C8 o wartości 10uF.
Ponieważ mikrokontroler miał za mało pinów I/O, użyłem scalonego układu PCF8574, który zwiększył liczbę pinów o 8, co zupełnie wystarcza. Obsługa PCF8574 jest prosta i odbywa się za pomocą dwóch linii SDA i SCL w standardzie I2C.
Na tej samej magistrali pracuje też zegar RTC PCF8563. Linie danych i zegarowa są podciągnięte do VCC przez rezystory R3, R4 o wartości 4,3k. Do zegara RTC dołączona jest mała 3V bateria G2 CR2032, która podtrzymuje pracę PCF8563 po odłączeniu zasilania.
Złącze SV3 to typowe złącze ISP w standardzie Kanda, bez podłączonego zasilania VCC. W czasie programowania zegar może być cały czas podłączony do zasilacza.
Jeśli chodzi o połączenia poszczególnych pinów, to nie będę ich opisywał, wszystko jest opisane na schemacie. Wyjaśnienia mogą wymagać tylko wyjścia układu PCF8574 (złącze SV4).
Zaczynając od P0 jest to katoda 9, anoda 1, anoda 2, anoda 3, anoda 4, neonówka 1, neonówka 2 i buzzer.
Kolejny moduł to tranzystory, którymi załączane są poszczególne anody i katody wyświetlaczy, oraz neonówki. Schemat poniżej.
Tranzystory |
Katody załączane są przez tranzystory npn BF422, neonówki przez npn MPSA42, a anody z konieczności załączania napięć 170V załączane są dwustopniowo przez tranzystory npn MPSA42 i pnp MPSA92. Diody D1..D10 wraz z rezystorami R10, R11 obniżają napięcie na aktualnie niewybranych lampach poniżej napięcia zapłonu.
Kolejne dwa moduły to wyświetlacze. Schematy poniżej.
Wyświetlacz prawy |
Wyświetlacz lewy |
Rezystory dołączone do anod wyświetlaczy ograniczają prąd lampy. Ponieważ lampy są zasilane impulsowo, to można je trochę zmniejszyć np. do 15k.
Kolejny moduł to czujniki:
Czujniki |
Procesor ATtiny2313 jest opcjonalny i miałem na nim zrobić odbiór podczerwieni w standardzie RC5, ale ponieważ nie zdążyłem, to można go nie lutować, jak i elementów do niego dołączonych. To co należy polutować to układ DS18b20, czyli termometr z rezystorem podciągającym R8 oraz fotorezystor, rezystor R6 i potencjometr R7, które tworzą czujnik światła.
Ostatnie już moduły i w sumie najmniejsze, to PCB do której przylutowane są neonówki i druga, gdzie znajdują się przyciski do obsługi zegara. Schemat niżej.
Przyciski:
Przyciski |
Neonówki:
Neonówki |
Uwaga! Należy pamiętać, aby do neonówki dolutować szeregowo rezystor ograniczający prąd, a dopiero tak przygotowaną neonówkę wlutować w PCB. Nie podaję tu konkretnych wartości rezystorów, bo ich wielkość zależy od zastosowanych neonówek.
Program
Tak jak wspominałem na wstępie, program został napisany w języku C w środowisku programistycznym Eclipse Indigo z użyciem kompilatora avr-gcc. Program po kompilacji zajmuje 38.5% pamięci flash mikrokontrolera. Ustawienie fusebitów jest następujące: HIGH 0xC9, LOW 0xE4.
Kod jest dość długi, ale starałem się robić możliwie dużo komentarzy, więc myślę, że nie będzie trudny do przeanalizowania.
Starałem się, aby w przerwaniach nie umieszczać skomplikowanych obliczeń i oczywiście nie robić oczekiwania za pomocą poleceń _delay. Dlatego operacje wysyłania lub odbierania danych z RTC i czujnika temperatury DS18B20 są robione w pętli głównej programu, a w przerwaniach od timerów ustawiane są tylko odpowiednie flagi.
CZUJNIK NATĘŻENA ŚWIATŁA
W pętli głównej znajduje się jeszcze obsługa komparatora wbudowanego w ATmegie8. Zasada działania jest prosta. Porównywane są napięcia na wejściach AIN0 i AIN1. Jeśli AIN0 jest mniejsza od AIN1 to zmienna jasność jest ustawiana na 4, w przeciwnym wypadku na 20.Po włączeniu wyświetlacza ustawiana jest flaga_wl i zerowany jest licznik_wyl. Następnie co 256us występuje przerwanie od timera.
Jeśli flaga_wl jest ustawiona, to zwiększany jest licznik_wyl i jeśli osiągnie wartość większą od zmiennej jasność, nastąpi wyłączenie wyświetlacza i neonówek. Jeśli zmienna jasność ma wartość 4, to wyłączenie wyświetlacza nastąpi po około 1,3ms od czasu włączenia wyświetlacza, natomiast dla wartości jasność=20 wyłączenie nie nastąpi, bo wcześniej licznik_wyl zostanie wyzerowany w przerwaniu od timera 0.
W efekcie otrzymujemy proste sterowanie jasnością przez PWM. W dzień, kiedy natężenie światła jest duże, wyświetlacze świecą jasno, natomiast w nocy jasność wyświetlaczy jest obniżana, a dodatkowo załączana jest dioda LED podświetlająca przezroczystą obudowę.
TERMOMETR DS18B20 1-WIRE
Obsługa termometru realizowana jest w pętli głównej programu w ośmiu krokach. Licznik rozkazów rozkaz_1wire jest zwiększany za każdym razem kiedy zostaje ustawiona flaga wyslij_rozkaz w przerwaniu od timer0 co 4ms. Jeśli rozkaz_1wire = 4 ustawiana jest flaga_konwersji, która jest zerowana po upływie 1s. Odczytana temperatura umieszczana jest w dwóch bajtach MSB i LSB, a następnie konwertowana do postaci możliwej do wyświetlenia przez wywołanie funkcji convert_1wire().
Tak przygotowana temperatura po zamianie w funkcji makebcd() na postać BCD może zostać już wyświetlona. Obsługa protokołu komunikacyjnego 1-Wire jest standardowa, a przebiegi czasowe zgodne z tymi, które są podane w nocie katalogowej układu DS18B20. Odczyt temperatury realizują procedury:
void reset_1wire(void); void write_1wire(uint8_t data_1wire); uint8_t read_1wire(void);
ZEGAR RTC, PCF8574 I2C
Do obsługi zegara RTC jak i PCF8574 konieczne było wykorzystanie procedur obsługi I2C. Komunikacja realizowana jest sprzętowo, więc wszystko ogranicza się do ustawiania odpowiednich bitów w rejestrze TWCR i oczekiwania aż dane zostaną wysłane lub odebrane. Obsługę I2C realizują procedury:
void twistart(void); void twistop(void); void twiwrite(char data); char twiread(char ack);
OBSŁUGA KLAWISZY
Aby wyeliminować drgania styków użyłem licznika switch_delay, który ustawiony jest na 4, a przy naciśnięciu klawisza jest zmniejszany i jeśli osiągnie wartość 0, to następuje reakcja na naciśnięcie przycisku. Linie mikroprocesora do których podłączone są przyciski, czyli PC0..PC3 ustawione są jako wejścia z podciągnięciem do VCC. Naciśnięcie przycisku to podanie na wejście stanu niskiego. Przyciski należy kabelkami dolutować do złącza SV1 na PCB z tranzystorami.
PRZERWANIE TIMER0
Timer 0 został tak skonfigurowany aby przerwania były wywoływane co 4ms, co daje multipleksowanie z częstotliwością 62,5Hz. Częstotliwość ta wystarcza żeby mieć wrażenie, że wszystkie lampy świecą naraz. Tak jak już wspominałem w przerwaniu obsługiwane są klawisze, jak również ustawiane flagi odbioru danych z czujnika temperatury, jak i włączenia wyświetlaczy. Przy każdym wywołaniu przerwania zapalana jest kolejna lampa przez wybranie odpowiedniej anody i katody wyświetlacza. Ważne jest to, aby wyłączyć wyświetlacze na początku obsługi przerwania co eliminuje efekt ‘duchów’ na wyświetlaczu.MONTAŻ I URUCHOMIENE
Montaż jak zwykle zaczynamy od elementów najmniejszych, a na największych kończymy. Wyjaśnienia może wymagać sposób montaży tranzystora Q1. Jest to tranzystor w obudowie TO-220, gdzie środkowa nóżka drenu została przycięta przy obudowie, a wyprowadzenie drenu z tyłu obudowy zostało przykręcone do radiatora i dolutowane do PCB. Dzięki temu odstęp między padami jest większy i jest to rozwiązanie bezpieczniejsze przy napięciu 170V.Nietypowy jest też montaż tranzystorów BF422, gdzie środkową nóżkę trzeba wygiąć w stronę spłaszczonej części obudowy. Ogólnie starałem się, aby odległości między ścieżkami wysokonapięciowymi i pozostałymi były możliwie duże. Dodatkowo między poszczególnymi płytkami trzeba zrobić połączenia zasilania przewodami według przedstawionych schematów.
PODSUMOWANIE
Ogólnie jestem zadowolony z projektu, a wyświetlacze Nixie robią ogromne wrażenie zwłaszcza w półmroku lub całkowitej ciemności. To co chciałbym w przyszłości jeszcze zmienić to dopisać obsługę budzika dlatego w projekcie znajduje się buzzer z generatorem oraz może napisać obsługę RC5.Jeszcze słowo odnośnie obudowy. Całość została zaprojektowana w Corelu, a następnie wycięta z pleksi laserem. Przód to czarna pleksi 3mm, reszta obudowy to przezroczysta pleksi 4mm. Miejsca po cięciu laserem są gładkie i przezroczyste, więc wszystko wygląda estetycznie, a co najważniejsze chroni użytkowników przed niebezpiecznym napięciem znajdującym się w środku.
ZDJĘCIA
Zegar Nixie 1 |
Zegar Nixie 2 |
Zegar Nixie 3 - termometr |
Zegar Nixie 4 |
Zegar Nixie 5 |
Zegar Nixie - widok od góry |
Zegar Nixie - widok od tyłu |
Zegar Nixie - widok z boku |
Zegar Nixie - w częściach :-) |
PLIK ŹRÓDŁOWY
/* * main.c * * Created on: 27-02-2014 */ /*ZEGAR NIXIE*/ #define F_CPU 8000000UL // F_CPU na 8MHz #include <util/delay.h> #include <avr/io.h> #include <avr/interrupt.h> #include <math.h> /*deklarazcja zmiennych globalnych*/ volatile uint8_t sekundy,minuty,godziny, tryb; volatile uint8_t sekdzie,sekjed,mindzie,minjed,godzdzie,godzjed; volatile uint8_t pomoc,mux,pcf8574_data,maxi,flaga,bufor,a; volatile uint8_t zmiana_min,ustawienia,pomoc2,temp,switch_delay,licznik,licznik1,flaga1; volatile uint8_t tablica_a[] = {4,2,1,0,0,0,0,32,16,8}; volatile uint8_t tablica_b[] = {0,0,0,0,4,2,1,0,0,0}; volatile uint8_t i,j,tmp,odczyt_1wire,LSB,MSB,tempjed,tempdzie; volatile uint8_t wyslij_rozkaz, rozkaz_1wire,czas_konwersji,flaga_konwersji; volatile uint8_t jasnosc,flaga_wl,licznik_wyl,flaga_termometr,temperatura,temp_ulamek; volatile uint8_t zmiana_sek,lampa1,lampa2,lampa3,lampa4,temp2,temp3; #define PCF8563_ADRR 0xA2 #define PCF8574_ADRR 0x70 #define ACK 1 #define NOACK 0 // procedura transmisji sygnału START void twistart(void); // procedura transmisji sygnału STOP void twistop(void); // procedura transmisji bajtu danych void twiwrite(char data); //procedura odczytu bajtu danych char twiread(char ack); uint8_t makebcd(uint8_t dec); uint8_t makedec(uint8_t bcd); //procedury transmisji 1WIRE void reset_1wire(void); void write_1wire(uint8_t data_1wire); uint8_t read_1wire(void); uint8_t convert_1wire(void); int main(void){ /*wartosci poczatkowe zmiennych*/ switch_delay=4; maxi=100; pcf8574_data|=0x80;/*wylaczenie buzera*/ ustawienia=0; tryb=0; /*konfiguracja portow*/ DDRB=0xFF;/*wszystkie linie portu jako wyjscia*/ PORTB=0x00;//0xFF;/*wszystkie linie w stanie wysokim*/ DDRC=0x30;/*linie PC4 i PC5 jako wyjscia, pozostale linie jako wejscia*/ PORTC=0x0F;/*linie PC0..PC4 podciagniete do VCC, pozostale linie w stanie niskim*/ DDRD=0x3F;/*PD6 i PD7 jako wejscia, pozostale piny jako wyjscia*/ PORTD=0x00;//*wszystkie linie w stanie niskim*/ /*konfiguracja timerow*/ TCCR0|=(1<<CS02);/*prescaler 256, Timer0 zwiekszany co 32us*/ TIMSK|=(1<<TOIE0);/*odblokowanie przerwania od timer0*/ TCCR1B|=(1<<CS12);/*prescaler 256, Timer1 zwiekszany co 32us*/ TIMSK|=(1<<TOIE1);/*odblokowanie przerwania od timer1*/ TCCR2|=(1<<CS22)|(1<<CS21);/*prescaler 256, Timer2 zwiekszany co 32us */ TIMSK|=(1<<TOIE2);/*odblokowanie przerwania od timer2*/ /*globalne zezwolenie na przerwania*/ sei(); /*petla nieskonczona*/ while(1){ //komparator //zmiana jasnosci wyswietlaczy if(ACSR & (1<<ACO)){ jasnosc=4; //jeśli AIN0>AIN1 PORTD&=~0x20;// wlacz podswietlenie } else{ jasnosc=20; PORTD|=0x20;//wylacz podswietlenie } if (flaga & 0x01){ //jesli flaga ustawiona //Odczyt danych z RTC flaga&=~0x01;//wyzeruj flage twistart(); twiwrite(PCF8563_ADRR);//adres zegara RTC twiwrite(0x02); twistart(); twiwrite(0xA3); sekundy=twiread(ACK); minuty=twiread(ACK); godziny=twiread(NOACK); twistop(); minuty&=~0x80;//wyzerowanie bitu 7 godziny&=~0xC0;//wyzerowanie bitow 6 i 7 } if (flaga & 0x02){ //jesli flaga ustawiona (flaga=00000010) //wyslij dane do RTC flaga&=~0x02;//wyzeruj flage twistart(); twiwrite(PCF8563_ADRR);//adres zegara RTC twiwrite(0x02); twiwrite(0x00); twiwrite(minuty); twiwrite(godziny); twistop(); } if(wyslij_rozkaz==1){ wyslij_rozkaz=0; if(rozkaz_1wire==4){ if(czas_konwersji==250){ rozkaz_1wire++; flaga_konwersji=0; czas_konwersji=0; } } else rozkaz_1wire++; if(rozkaz_1wire==9) rozkaz_1wire=1; switch(rozkaz_1wire) { case 1: reset_1wire(); if(flaga_termometr==1) rozkaz_1wire=0; //jesli ds18b20 nie odpowie, //zacznij transmisje od poczatku break; case 2: write_1wire(0xCC); break; case 3: write_1wire(0x44); break; case 4: flaga_konwersji=1; break; case 5: reset_1wire(); break; case 6: write_1wire(0xCC); break; case 7: write_1wire(0xBE); break; case 8: LSB=read_1wire(); MSB=read_1wire(); temperatura=convert_1wire(); temperatura=makebcd(temperatura); break; } } } } /*OBSLUGA PRZERWANIA OD TIMER 1*/ //co 1s ISR(TIMER1_OVF_vect){ //skrocenie dlugosci licznika do 31250 TCNT1H=0x85; TCNT1L=0xED; //odtruwanie katod if(flaga1==1){ licznik1--;//zmniejsz licznik if(licznik1==0) flaga1=0;//wyzeruj flage } } /*OBSLUGA PRZERWANIA OD TIMER 2*/ //co 256us ISR(TIMER2_OVF_vect){ //skrocenie dlugosci licznika do 247 TCNT2=0xF7; if(flaga_wl==1){ licznik_wyl++; if(licznik_wyl>jasnosc){ licznik_wyl=0; flaga_wl=0; pcf8574_data&=~(0x1E); pcf8574_data&=~(0x60);//wylacznie neonowek //wyslanie danych do pcf8574 twistart(); twiwrite(PCF8574_ADRR); twiwrite(pcf8574_data); twistop(); } } } /*OBSLUGA PRZERWANIA OD TIMER 0*/ //co 4ms ISR(TIMER0_OVF_vect){ TCNT0=0x82;//skrocenie dlugosci licznika do 125 //wylaczenie wyswietlaczy PORTD&=~(0x07); PORTB&=~(0x3F); pcf8574_data&=~(0x1F); wyslij_rozkaz=1; if(flaga_konwersji==1) czas_konwersji++; /*sprawdzenie czy minuty sie zmienily*/ if(tryb==0){ // efekt odrtuwania katod if(zmiana_min!=minuty){ flaga1=1;//ustawienie flagi licznik1=5; } } //NEONOWKI /*sprawdzenie zmiany sekund*/ if(tryb==0){ sekundy&=~0x80;//wyzerowanie bitu 7 sekundy= makedec(sekundy); zmiana_sek=sekundy%2; if(zmiana_sek) pcf8574_data&=~(0x60); else pcf8574_data|=0x60; } if(tryb==1){ pcf8574_data&=~0x20;//wygaszenie neonowki gornej pcf8574_data|=0x40;//zapalenie naeonowki dolnej } //wyslanie danych do pcf8574 twistart(); twiwrite(PCF8574_ADRR); twiwrite(pcf8574_data); twistop(); //zamiana godziny z BCD na DEC minuty= makedec(minuty); godziny=makedec(godziny); /*OBSLUGA PRZYCISKOW*/ switch_delay--; if((PINC&0x04)==0){ //Ustawianie czasu_______zmiana ustawień______ if(switch_delay==0){ //licznik pomocniczy switch_delay tryb++; if(tryb==2) tryb=0; if(ustawienia!=0) tryb=0; } } else if((PINC&0x08)==0){ //Ustawianie czasu_______zmiana ustawień______ if(switch_delay==0){ //licznik pomocniczy switch_delay tryb=0; ustawienia++; if(ustawienia==3) ustawienia=0; } } else if((PINC&0x01)==0){ //Ustawianie czasu_______+___________ if(switch_delay==0){ //licznik pomocniczy switch_delay if(ustawienia==2){ minuty++; if(minuty==60) minuty=0; } if(ustawienia==1){ godziny++; if(godziny==24) godziny=0; } } flaga|=0x02;//ustawienie flagi wyslania danych do RTC } else if((PINC&0x02)==0){ //Ustawianie czasu_______-___________ if(switch_delay==0){ //licznik pomocniczy switch_delay if(ustawienia==2){ if(minuty==0) minuty=60; minuty--; } if(ustawienia==1){ if(godziny==0) godziny=24; godziny--; } } flaga|=0x02;//ustawienie flagi wyslania danych do RTC } else { switch_delay=4; } if(ustawienia==0) flaga|=0x01;//ustawienie flagi odczytu danych z RTC //zamiana godziny z DEC na BCD minuty= makebcd(minuty); godziny=makebcd(godziny); /*rozdzial godziny na jednosci i dziesiatki*/ minjed=minuty & 0x0F; mindzie=minuty; mindzie=mindzie>>4; godzjed=godziny & 0x0F; godzdzie=godziny; godzdzie=godzdzie>>4; /*rozdzielenie temperatury na jednosci i dziesiatki*/ tempjed=temperatura & 0x0F; tempdzie=temperatura; tempdzie=tempdzie>>4; /*wyswietlenie jednej cyfry na wyswietlaczu*/ mux++; if(mux==4){ mux=0; } a++; if(a==6){ licznik++; a=0; } /*WYBOR DANYCH DO WYSWIETLENIA*/ if (tryb==0){ //godzina lampa1=godzdzie;//na lampie 1 wyswietl dziesiatki godzin lampa2=godzjed;//na lampie 2 wyswietl jednosci godzin lampa3=mindzie;//na lampie 3 wyswietl dziesiatki minut lampa4=minjed;//na lampie 4 wyswietl jednosci minut } if (tryb==1){ //temperatura lampa1=tempdzie; lampa2=tempjed; lampa3=temp_ulamek; } if(licznik==10) licznik=0; switch(mux) { /*JEDNOSTKI MINUT*/ case 0: if(licznik1<=1){ //wystawienie na porty odpowiednich stanow katod wyswietlacza temp=tablica_a[lampa4];//minjed]; PORTB|=temp; temp=tablica_b[lampa4];//minjed]; PORTD|=temp; if(lampa4==3){ pcf8574_data|=0x01;//ustaw bit 0 w pcf8574 } else{ pcf8574_data&=~0x01;//zeruj bit 0 w pcf8574 } } if(licznik1>1){ temp=tablica_a[licznik]; PORTB|=temp; temp=tablica_b[licznik]; PORTD|=temp; } if(tryb==1) pcf8574_data&=~(0x10);//wylaczenie anody lampy 4 else pcf8574_data|=0x10;//zalaczenie anody lampy 4 break; /*DZIESIATKI MINUT*/ case 1: if(licznik1<=4){ //wystawienie na porty odpowiednich stanow katod wyswietlacza temp=tablica_a[lampa3]; PORTB|=temp; temp=tablica_b[lampa3]; PORTD|=temp; if(lampa3==3){ pcf8574_data|=0x01;//ustaw bit 0 w pcf8574 } else{ pcf8574_data&=~0x01;//zeruj bit 0 w pcf8574 } } if(licznik1>4){ temp=tablica_a[licznik]; PORTB|=temp; temp=tablica_b[licznik]; PORTD|=temp; } pcf8574_data|=0x08;//zalaczenie anody wyswietlacza dziesiatek minut break; /*JEDNOSTKI GODZIN*/ case 2: if(licznik1<=3){ //wystawienie na porty odpowiednich stanow katod wyswietlacza temp=tablica_a[lampa2]; PORTB|=temp; temp=tablica_b[lampa2]; PORTD|=temp; if(lampa2==3){ pcf8574_data|=0x01;//ustaw bit 0 w pcf8574 } else{ pcf8574_data&=~0x01;//zeruj bit 0 w pcf8574 } } if(licznik1>3){ temp=tablica_a[licznik]; PORTB|=temp; temp=tablica_b[licznik]; PORTD|=temp; } pcf8574_data|=0x04;//zalaczenie anody wyswietlacza jednostek godzin break; /*DZIESIATKI GODZIN*/ case 3: if(licznik1<=2){ //wystawienie na porty odpowiednich stanow katod wyswietlacza temp=tablica_a[lampa1]; PORTB|=temp; temp=tablica_b[lampa1]; PORTD|=temp; if(lampa1==3){ pcf8574_data|=0x01;//ustaw bit 0 w pcf8574 } else{ pcf8574_data&=~0x01;//zeruj bit 0 w pcf8574 } } if(licznik1>2){ temp=tablica_a[licznik]; PORTB|=temp; temp=tablica_b[licznik]; PORTD|=temp; } if(tryb==0){ if(lampa1==0) pcf8574_data&=~(0x02);//wylaczenie anody lampy 1 //jesli dziesiatki godzin beda rowne 0 to lampa bedzie wylaczona else pcf8574_data|=0x02;//zalaczenie anody lampy 1 } if(tryb==1) pcf8574_data|=0x02; break; } flaga_wl=1;//ustawienie flag, wyswietlacze wlaczone licznik_wyl=0;// wyzerowanie licznika odliczajacego czas do wylaczenia wyswietlaczy //zapamietanie obecej wartosci minut zmiana_min=minuty; pomoc2++; /*miganie wyswietlacza w trybie ustawien godziny*/ if(pomoc2==120) pomoc2=0; if(ustawienia==2) if(pomoc2<60) pcf8574_data&=~0x18; //w trybie ustawiania czasu wyswietlacz miga if(ustawienia==1) if(pomoc2<60) pcf8574_data&=~0x06; //wyslanie danych do pcf8574 twistart(); twiwrite(PCF8574_ADRR); twiwrite(pcf8574_data); twistop(); } /*I2C*/ // procedura transmisji sygnału START void twistart(void) { TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); while (!(TWCR & (1<<TWINT))); } // procedura transmisji sygnału STOP void twistop(void) { TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); while ((TWCR & (1<<TWSTO))); } // procedura transmisji bajtu danych void twiwrite(char data) { TWDR = data; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); } //procedura odczytu bajtu danych char twiread(char ack) { TWCR = ack ? ((1 << TWINT) | (1 << TWEN) | (1 << TWEA)) : ((1 << TWINT) | (1 << TWEN)) ; while (!(TWCR & (1<<TWINT))); return TWDR; } // konwersja liczby dziesiętnej na BCD uint8_t makebcd(uint8_t dec) { return ((dec / 10)<<4) | (dec % 10); } // konwersja liczby BCD na dziesiętną uint8_t makedec(uint8_t bcd) { return ((((bcd) >> 4) & 0x0F) * 10) + ((bcd) & 0x0F); } //1WIRE RESET void reset_1wire(void){ DDRD|=(1<<4);//PD4 jako wyjscie ----> PORTD&=~(1<<4);//GND na PD4 \__ _delay_us(500);//MASTER robi sygnal RESET, zwierajac linie danych do masy na min 480us DDRD &=~(1<<4);//PD4 jako wejscie----< _delay_us(65);//czas potrzebny na na zwarci lini danch do masy przez SLAVE flaga_termometr=PIND&0x10;//0-potwerdzenie obecosci przez slave, 0x10 -brak potwierdzenia _delay_us(435);//odczekanie jeszcze 435us bo minimalna dlugosc ramki to 480us _delay_us(5);//czas REC } //1WIRE WRITE void write_1wire(uint8_t data_1wire){ j=1; for(i=0;i<8;i++){ _delay_us(5);//czas REC tmp=data_1wire&j; if(tmp){ //wyslij 1 DDRD|=(1<<4);//PD4 jako wyjscie ----> PORTD&=~(1<<4);//GND na PD4 \__ _delay_us(5); //PORTD|=(1<<4);//VCC na PD4 DDRD &=~(1<<4);//PD4 jako wejscie ---< _delay_us(80); } else{ //wyslij 0 DDRD|=(1<<4);//PD4 jako wyjscie ----> PORTD&=~(1<<4);//GND na PD4 \__ _delay_us(100); DDRD &=~(1<<4);//PD4 jako wejscie ---< } j=j*2; } } //1WIRE READ uint8_t read_1wire(void){ j=1; odczyt_1wire=0; for(i=0;i<8;i++){ _delay_us(5);//czas REC DDRD|=(1<<4);//PD4 jako wyjscie PORTD&=~(1<<4);//GND na PD4 _delay_us(5); DDRD &=~(1<<4);//PD4 jako wejscie _delay_us(5); tmp=PIND&0x10; if(tmp) odczyt_1wire|=j; //jesli odczytana jedynak to ustaw bit j=j*2; _delay_us(80); } return odczyt_1wire; } //1WIRE CONVERT uint8_t convert_1wire(void){ temp_ulamek=0; if(LSB&0x08) temp_ulamek=temp_ulamek+5; if(LSB&0x04) temp_ulamek=temp_ulamek+2; if(LSB&0x02) temp_ulamek=temp_ulamek+1; if(LSB&0x01) temp_ulamek=temp_ulamek+1; MSB=MSB<<4; LSB=LSB>>4; return (LSB|MSB); }
DO POBRANIA
Pliki Eagle: nixie_eagle.rar (kopia)
Pliki Eclipse (kody źródłowe): Nixie_clock_program.rar (kopia)
Pliki Corel - obudowa: obudowa.rar (kopia)
Łał, nixie zawsze w modzie - super projekt :). Mógłbyś zdradzić gdzie kupiłeś lampy i ile za nie dałeś? Widzę tylko oferty na poziomie 10 zł/szt, co nie jest zbyt zachęcającą ceną.
OdpowiedzUsuńGratuluję efektu, w nocy musi to wyglądać genialnie...
Ja swoje kupiłem na znanym portalu aukcyjnym. LC-516 to jedne z mniejszych i tańszych lamp. Niestety trzeba się z tym pogodzić, że lampy trochę kosztują i na pewno tańsze już nie będą. Ale i tak warto wydać te pieniądze i mieć coś oryginalnego, bo kto ze znajomych może pochwalić się takim zegarem :) Warto też poszukać lamp nie używanych wcześniej, które na pewno posłużą dłużej.
UsuńPikny projekt i wykonanie, jest gdzieś wycena, koszty?
OdpowiedzUsuńCo do kosztów ciężko powiedzieć. Zegar powstawał w wolnych chwilach od dłuższego czasu. Obudowa z plexi ciętej laserem to koszt około 60zł, lampy w granicach 10zł za sztukę. Część elektroniki miałem, część dokupiłem. Ogólnie może nie wyszłoby tak drogo ale na same przesyłki trzeba sporo liczyć bo nie da się wszystkiego kupić w jednym sklepie.
UsuńPozwolę sobie odkopać. Nie chcę robić kryptoreklamy, ale mam wrażenie że strasznie przepłaciłeś za tę obudowę. Zlecałem większe zamówienia i cena rzadko kiedy przekraczała 30zł. Oczywiście dużo zależy od grubości i koloru pleksi, niemniej i tak proponuję zapoznać się z tym gościem: http://www.jklaser.pl/ . Zamówienia wysyłam mailowo w formie PDFa albo pliku SVG.
UsuńJest możliwość kupna wytrawionych pcb dwustronnych? Nigdy mi się ze sobą nie pokrywają gdy próbuję je wykonać :)
OdpowiedzUsuńZłożyłem moduł przetwornicy, logiki, tranzystorów i lewego modułu lamp. Mega zaprogramowana, szybki test i...obydwie lampy działają non stop podświetlając na raz wszystkie cyfry...to wina nie podłączenia wszystkich modułów czy po prostu coś źle zrobiłem?
OdpowiedzUsuńWitam, jest możliwość dostania schematu montażowego ?
OdpowiedzUsuń