Projecten
- Inhoudsopgave
- 1. Inleiding
- 2. PIC18f1320 + DS18B20 temperatuur sensor
- 3. Nixie Tube Clock
- 4. PIC3COM Webserver
- 5. PIC18F4550 USB
- 6. picprog
Nixie Tube Clock
De Nixie Tube Klok is een digitale klok met als display een Nixie Tube. De werking van deze klok kan onderverdeeld worden in twee grote blokken, namelijk de hardware en de software.
Hardware
Hier wordt stap voor stap de opbouw van de hardware beschreven. Het verhaal begint toen ik in mijn verzameling van oude onderdelen een Nixie Tube vond en eens wou testen of ik deze een cijfer kon laten tonen.
Voeding
Een Nixie Tube heeft een hoge spanning nodig. De eerste stap is dus om een voldoende hoge spanning te genereren. Door gebruik te maken van onderstaand schema, wordt een voldoende hoge gelijkspanning aangemaakt en is het mogelijk om bv. het cijfer 8 te laten oplichten.
Wanneer alles is aangesloten, kan inderdaad een digit van van de Nixie Tube getoond worden.
Digits schakelen
Best wel tof om het cijfer 8 op te laten lichten. Maar echt plezant zou zijn als we de digits kunnen aansturen door een PIC®-microcontroller. Een microcontroller kan echter geen hoge spanningen schakelen. Omdat ik nog een aantal mosfets had liggen heb ik deze gebruikt als elektronische schakelaar waarmee dan later de microcontroller de digits kan schakelen.
Dit alles is verder opgebouwd op de gaatjes print. Door nu de ingang van een bepaalde MOSFET hoog te maken, zal de desbetreffende digit getoond worden.
Afgewerkte klok
Hieronder zie je het afgewerkte schema van de Nixie Klok. Klik op de afbeelding om het schema als PDF te downloaden.
Zoals je ziet is er een PIC 16F648A microcontroller aan toegevoegd. Ook is er nu een knop aanwezig waarmee de tijd in te stellen is. Via ingang RA4 loopt de klok gesynchroniseerd met de 50HZ netfrequentie.
Onderstaande youtube-video toont de Nixie Klok in actie.
Software
Zonder software zal de Nixie klok niet veel doen. Hieronder vind je de broncode van de Nixie klok die voldoende van commentaar is voorzien om de werking te kunnen snappen.
Enkel bijzondere kenmerken:
- interne clock wordt gebruikt, met een duizelwekkende snelheid van 48Khz 😉
- het meeste tijd wordt door de microcontroller besteed aan het wachten op een nul-doorgang van de 50HZ netfrequentie. Via die nuldoorgang wordt de klok gesynchroniseerd met de netfrequentie, waardoor de klok juist blijft lopen.
; ------------------------------------------------------------------------------ ; ; Single Nixie Clock v0.0.4 ; ; ------------------------------------------------------------------------------ ; ; Written by : ; ; Jan Wagemakers : Donated to the Public Domain ; ; ------------------------------------------------------------------------------ LIST p=PIC16F648A INCLUDE "p16f648a.inc" errorlevel -302 ; __CONFIG _CP_OFF&_DATA_CP_OFF&_LVP_OFF&_BODEN_OFF&_MCLRE_OFF&_PWRTE_ON&_WDT_OFF&_INTOSC_OSC_NOCLKOUT ; ------------------------------------------------------------------------------ ; Define variables ; ------------------------------------------------------------------------------ cblock h'20' menu ; 0 = display clock ; 1 = menu H(high) ; 2 = menu H(low) ; 3 = menu M(high) ; 4 = menu M(low) submenu ; 0 = menu ; 1 = submenu HZ50counter ; Count the 50HZ pulse tick ; 1/2sec tick synchronized with 50HZ buttonr ; count how long button is released buttonp ; count how log button is pressed number ; number to display on Nixie DL ; used in number to digit conversion DH ; used in number to digit conversion S ; Seconds in Binary (only used internal) H ; Hours in BCD M ; Minutes in BCD Hstep1 ; Hours in BCD at the moment DisplayCounter = 1 Mstep1 ; Minutes in BCD at the moment DisplayCounter = 1 Delay ; used in sleep routine DisplayCounter ; Display what part of the clock? endc ; ------------------------------------------------------------------------------ ; Let's start ; ------------------------------------------------------------------------------ org h'0000' ; ------------------------------------------------------------------------------ ; Init PIC input output ; ------------------------------------------------------------------------------ bcf STATUS, RP1 bsf STATUS, RP0 ; select bank 1 bcf PCON, OSCF ; CLK=48Khz movlw b'11111000' ; 1 = input 0 = output movwf TRISA ; set input/output PORTA clrf TRISB ; PORTB = output bcf STATUS, RP0 ; select bank 0 movlw h'07' ; turn comparators off movwf CMCON ; ------------------------------------------------------------------------------ ; Reset some variables ; ------------------------------------------------------------------------------ clrf H clrf M clrf S clrf tick clrf menu clrf submenu clrf buttonp clrf buttonr clrf DisplayCounter ; ------------------------------------------------------------------------------ ; Loop : everything is done is this loop ; ------------------------------------------------------------------------------ Loop: ; ------------------------------------------------------------------------------ ; Start clock menu routine ; ------------------------------------------------------------------------------ btfsc PORTA, D'3' ; IF RA3 <> 0 THEN ... goto released ; ... button is not pressed ELSE ... pressed: ; ... button is pressed incf buttonp, F movlw D'2' ; check how long key is pressed subwf buttonp, w btfss STATUS, Z goto chkkey_done ; not long enough, go away ; ---------------------------------------------------------------------- ; button is pressed long enough ; ---------------------------------------------------------------------- clrf buttonp ; reset counter ; movf submenu, w ; menu or submenu? btfss STATUS, Z goto psubmenu ; ---------------------------------------------------------------------- ; button pressed : menu routine (:menu) ; ---------------------------------------------------------------------- incf menu, F movlw D'5' subwf menu, w btfsc STATUS, Z clrf menu ; if menu = 5 then menu = 0 ; movf menu, W movwf number call number_to_digit ; display menu number bsf PORTA, D'2' ; display menu number with : ; goto chkkey_done ; go away ; ---------------------------------------------------------------------- ; button pressed : submenu routine ; ---------------------------------------------------------------------- psubmenu: ; ---------------------------------------------------------------------- ; IF menu=1 THEN H = H + 0x10 ; ---------------------------------------------------------------------- movlw D'1' subwf menu, w btfss STATUS, Z goto XH movlw H'10' addwf H, F ; ---------------------------------------------------------------------- ; IF menu=2 THEN H++ XH: ; ---------------------------------------------------------------------- movlw D'2' subwf menu, w btfsc STATUS, Z incf H, F ; ---------------------------------------------------------------------- ; IF menu=3 THEN M = M + 0x10 ; ---------------------------------------------------------------------- movlw D'3' subwf menu, w btfss STATUS, Z goto XM movlw H'10' addwf M, F ; ---------------------------------------------------------------------- ; IF menu=4 THEN M++ XM: ; ---------------------------------------------------------------------- movlw D'4' subwf menu, w btfsc STATUS, Z incf M, F ; ---------------------------------------------------------------------- ; Check for overflow of digits ; ---------------------------------------------------------------------- movlw B'11110000' btfsc M, D'3' btfss M, D'1' goto check1 andwf M, f ; IF M(low) = 10 then M(low) = 0 check1: movlw B'00001111' btfsc M, D'6' btfss M, D'5' goto check2 andwf M, f ; IF M(high) = 10 then M(high) = 0 check2: movlw B'11110000' btfsc H, D'3' btfss H, D'1' goto check3 andwf H, f ; IF H(low) = 10 then H(low) = 0 check3: movlw B'00001111' btfsc H, D'5' btfss H, D'4' goto check4 andwf H, f ; IF H(high) = 3 then H(high) = 0 check4: btfss H, D'5' ; IF H(high) = 2 AND ... goto check5 movlw B'00001111' andwf H, w ; w = H(low) sublw D'3' ; ... H(low) > 3 then ... btfss STATUS, C clrf H ; .... reset H because for ex. ... ; .... 25:00 is false check5: ; ---------------------------------------------------------------------- ; Display the right digit on the Nixie ; ---------------------------------------------------------------------- disp_digit: ; ----------------------------------------------------------------------- ; IF menu = 1 THEN display H(high) ; ----------------------------------------------------------------------- movlw B'11110000' andwf H, w movwf number swapf number, F ; number = H(high) movlw D'1' subwf menu, w btfsc STATUS, Z call number_to_digit ; ----------------------------------------------------------------------- ; IF menu = 2 THEN display H(low) ; ----------------------------------------------------------------------- movlw B'00001111' andwf H, w movwf number ; number = H(low) movlw D'2' subwf menu, w btfsc STATUS, Z call number_to_digit ; ----------------------------------------------------------------------- ; IF menu = 3 THEN display M(high) ; ----------------------------------------------------------------------- movlw B'11110000' andwf M, w movwf number swapf number, F ; number = M(high) movlw D'3' subwf menu, w btfsc STATUS, Z call number_to_digit ; ----------------------------------------------------------------------- ; IF menu = 41 THEN display M(low) ; ----------------------------------------------------------------------- movlw B'00001111' andwf M, w movwf number ; number = M(low) movlw D'4' subwf menu, w btfsc STATUS, Z call number_to_digit ; goto chkkey_done ; and done. ; ---------------------------------------------------------------------- ; END button pressed ; ---------------------------------------------------------------------- released: incf buttonr, F movlw D'2' subwf buttonr, w btfss STATUS, Z goto chkkey_done ; ---------------------------------------------------------------------- ; button is released long enough ; ---------------------------------------------------------------------- clrf buttonr ; reset counter ; movf menu, W btfsc STATUS, Z goto clock ; if menu = 0 then display normal clock ; movf submenu, w ; menu or submenu btfss STATUS, Z goto rsubmenu ; ---------------------------------------------------------------------- ; button released : menu routine (:menu --> digit) ; ---------------------------------------------------------------------- rmenu: bsf submenu, D'1' ; enter submenu goto disp_digit ; Mmmm, spaghetti code ;-) ; ---------------------------------------------------------------------- ; button released : submenu routine ; ---------------------------------------------------------------------- rsubmenu: clrf menu clrf submenu clrf DisplayCounter ; exit menu/submenu ; ---------------------------------------------------------------------- ; Let's end the button/menu/submenu routine ; ---------------------------------------------------------------------- chkkey_done: movf menu, W btfsc STATUS, Z goto clock ; if menu = 0 then display normal clock goto HZ50 ; ------------------------------------------------------------------------------ ; Start normal clock routine ; ------------------------------------------------------------------------------ clock: incf DisplayCounter, F ; ---------------------------------------------------------------------- ; IF DisplayCounter = 1 THEN ; Display Nothing AND ; Hstep1 = H Mstep1 = M ; ---------------------------------------------------------------------- movlw d'1' subwf DisplayCounter, w btfsc STATUS, Z call cls_and_saveHM ; ---------------------------------------------------------------------- ; IF DisplayCounter = 2 THEN ; Display Hstep1(high) ; ---------------------------------------------------------------------- movlw B'11110000' andwf Hstep1, w movwf number swapf number, F ; number = Hstep1(high) movlw d'2' subwf DisplayCounter, w btfsc STATUS, Z call number_to_digit ; ---------------------------------------------------------------------- ; IF DisplayCounter = 3 THEN ; Display Nothing ; ---------------------------------------------------------------------- movlw d'3' subwf DisplayCounter, w btfsc STATUS, Z call cls ; ---------------------------------------------------------------------- ; IF DisplayCounter = 4 THEN ; Display Hstep1(low) ; ---------------------------------------------------------------------- movlw B'00001111' andwf Hstep1, w movwf number ; number = Hstep1(low) movlw d'4' subwf DisplayCounter, w btfsc STATUS, Z call number_to_digit ; ---------------------------------------------------------------------- ; IF DisplayCounter = 5 THEN ; Display Nothing ; ---------------------------------------------------------------------- movlw d'5' subwf DisplayCounter, w btfsc STATUS, Z call cls ; ---------------------------------------------------------------------- ; IF DisplayCounter = 6 THEN ; Display : ; ---------------------------------------------------------------------- movlw d'6' subwf DisplayCounter, w btfsc STATUS, Z bsf PORTA, D'2' ; display : ; ---------------------------------------------------------------------- ; IF DisplayCounter = 7 THEN ; Display Nothing ; ---------------------------------------------------------------------- movlw d'7' subwf DisplayCounter, w btfsc STATUS, Z call cls ; ---------------------------------------------------------------------- ; IF DisplayCounter = 8 THEN ; Display Mstep1(high) ; ---------------------------------------------------------------------- movlw B'11110000' andwf Mstep1, w movwf number swapf number, F ; number = Mstep1(high) movlw d'8' subwf DisplayCounter, w btfsc STATUS, Z call number_to_digit ; ---------------------------------------------------------------------- ; IF DisplayCounter = 9 THEN ; Display Nothing ; ---------------------------------------------------------------------- movlw d'9' subwf DisplayCounter, w btfsc STATUS, Z call cls ; ---------------------------------------------------------------------- ; IF DisplayCounter = 10 THEN ; Display Mstep1(low) ; ---------------------------------------------------------------------- movlw B'00001111' andwf Mstep1, w movwf number ; number = Mstep1(low) movlw d'10' subwf DisplayCounter, w btfsc STATUS, Z call number_to_digit ; ---------------------------------------------------------------------- ; IF DisplayCounter = 11 THEN ; Display Nothing AND ; DisplayCounter = 0 ; ---------------------------------------------------------------------- movlw d'11' subwf DisplayCounter, w btfsc STATUS, Z call cls_and_crlf_DisplayCounter ; ------------------------------------------------------------------------------ ; Synchronize with 50HZ __+--+__+--+__ ; ------------------------------------------------------------------------------ HZ50: clrf HZ50counter HZ50islow: call zzz ; sleep a while btfss PORTA, d'4' goto HZ50islow HZ50ishigh: call zzz ; sleep a while btfsc PORTA, d'4' goto HZ50ishigh ; incf HZ50counter, F ; Do every 1/50 sec. : 50HZcounter++ movlw d'25' subwf HZ50counter, w ; 25 * 1/50 seconds -> 1/2 second btfss STATUS, Z goto HZ50islow ; incf tick, F ; Do every 1/2 second : tick = tick + 1 movlw d'2' subwf tick, w btfss STATUS, Z goto Loop ; IF tick = 2 then tick = 0 and ... clrf tick ; else just go to loop ; ------------------------------------------------------------------------------ ; INC clock sec, min, hour ; ------------------------------------------------------------------------------ incf S, F ; Do every second : S = S + 1 movlw d'60' subwf S, w btfss STATUS, Z goto Loop clrf S ; IF S = 60 THEN S = 0 and ... ; ---------------------------------------------------------------------- ; OK, it's time to update the clock by 1 minute ; ---------------------------------------------------------------------- incf M, f ; M = M + 1 movlw D'6' btfsc M, D'3' btfss M, D'1' goto Mok ; IF M(low) = 10 THEN addwf M, f ; M(low) = 0 AND M(high)++ Mok: movlw H'60' subwf M, w btfss STATUS, Z goto Loop clrf M ; IF M(BCD) = 60 THEN M = 0 and ... ; ---------------------------------------------------------------------- ; OK, it's time to update the clock by 1 hour ; ---------------------------------------------------------------------- incf H, F ; ... H = H + 1 movlw D'6' btfsc H, D'3' btfss H, D'1' goto Hok ; IF H(low) = 10 THEN addwf H, f ; H(low) = 0 AND H(high)++ Hok: movlw H'24' subwf H, w btfsc STATUS, Z clrf H ; IF H(BCD) = 24 THEN H = 0 goto Loop ; ------------------------------------------------------------------------------ ; ------------------------------------------------------------------------------ ; Subroutines ; ------------------------------------------------------------------------------ cls_and_crlf_DisplayCounter: clrf DisplayCounter goto cls cls_and_saveHM: movf H, w movwf Hstep1 movf M, w movwf Mstep1 cls: clrf PORTB ; Display nothing clrf PORTA return ; number_to_digit: movf number, w BTFSC STATUS, Z ; if number = 0 then number = 10 movlw D'10' movwf number movlw b'00000001' movwf DL clrf DH ; DH:DL = 0000000000000001 dountilzero: decfsz number, F goto isnotzero movf DL, w movwf PORTB movf DH, w movwf PORTA return isnotzero: BCF STATUS, C rlf DL, F rlf DH, F goto dountilzero ; zzz: ; zzz zzz zzz zzz (sleep) movlw D'4' movwf Delay zloop: decfsz Delay, F goto zloop return ; ; ---------------------------------------------------------------------------- end ; ----------------------------------------------------------------------------