Sfruttando le librerie HotStuff, Neptune e Chrono è stato possibile realizzare un termomentro digitale per la misurazione della temperatura nel range 0 - 128 gradi Celsius.
Il progetto prevede l'utilizzo di un PIC 16F628, di un modulo 18S20 e di un LCD con controller Samsung KS0070B. Pochi sono i componenti "di contorno" per far funzioanre il tutto. Il software con cui è stato il PIC è riportato di seguito.
;**************************************************
;
; Applicazione Termometro (0 - 128 °C)
;
; Marco Tinari 2012
;**************************************************
; maschera i warnings per la scelta del banco ram
errorlevel -302, -205
; fissa i parametri di compilazione
processor 16F628a
radix dec
; includi le definizione per il processore
#include P16F628a.inc
; stabilisci i valori per i fuses
__config _XT_OSC & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _BODEN_OFF & _LVP_OFF
;definizione dei valori usati
Lcd_EN EQU 0
Lcd_RS EQU 3
Lcd_BIT4 EQU 4
Lcd_BIT5 EQU 5
Lcd_BIT6 EQU 6
Lcd_BIT7 EQU 7
HOT_PinPortIn EQU 3
HOT_PinPortOut EQU 4
; registri di lavoro
cblock 020H
w_save : 1
us_counter : 1
ms_counter : 1
Lcd_Temp : 1
Lcd_Counter : 1
Lcd_Cells : 40
Lcd_Cursor : 1
Hot_Work : 1
Hot_Byte : 1
Temperatura : 2
Centinaia : 1
Decine : 1
Unita : 1
MezzoGrado : 1
endc
; definizione macro
PHW: MACRO ; salva accumulatore come se fosse in stack
MOVWF w_save
ENDM
PLW: MACRO ; recupera accumulatore come se fosse in stack
MOVFW w_save
ENDM
ORG 0H ; vettore di reset
StartUp
GOTO ColdStart
ORG 05H ; inizio On-Chip program memory
ColdStart
CALL SelectB1 ; seleziona il Bank 1
BSF TRISA,HOT_PinPortIn
BCF TRISA,HOT_PinPortOut
CALL SelectB0
MOVLW 7
MOVWF CMCON ; Comparators off, all pins digital I/O
CALL LcdInit ; inizializza il display
CALL LcdClear
MOVLW 'T'
MOVWF Lcd_Temp
CALL LcdOutChar
MOVLW 'e'
MOVWF Lcd_Temp
CALL LcdOutChar
MOVLW 'm'
MOVWF Lcd_Temp
CALL LcdOutChar
MOVLW 'p'
MOVWF Lcd_Temp
CALL LcdOutChar
MOVLW 'e'
MOVWF Lcd_Temp
CALL LcdOutChar
MOVLW 'r'
MOVWF Lcd_Temp
CALL LcdOutChar
MOVLW 'a'
MOVWF Lcd_Temp
CALL LcdOutChar
MOVLW 't'
MOVWF Lcd_Temp
CALL LcdOutChar
MOVLW 'u'
MOVWF Lcd_Temp
CALL LcdOutChar
MOVLW 'r'
MOVWF Lcd_Temp
CALL LcdOutChar
MOVLW 'a'
MOVWF Lcd_Temp
CALL LcdOutChar
MOVLW ':'
MOVWF Lcd_Temp
CALL LcdOutChar
MOVLW ' '
MOVWF Lcd_Temp
CALL LcdOutChar
MOVLW '+'
MOVWF Lcd_Temp
CALL LcdOutChar
mainloop
CALL OW_InitAndSkip ; inizializza la sonda e skip rom
MOVLW 0x44 ; temperature read command
MOVWF Hot_Byte
CALL OW_WriteByte
CALL Delay1sec
CALL OW_InitAndSkip ; inizializza la sonda e skip rom
MOVLW 0xBE ; read scratchpad command
MOVWF Hot_Byte
CALL OW_WriteByte
CALL OW_ReadByte ; leggi il byte LSB della temperatura
MOVF Hot_Byte, w
MOVWF Temperatura
CALL OW_ReadByte ; leggi il byte MSB della temperatura
MOVF Hot_Byte
MOVWF Temperatura+1
CALL OverZeroTemp
CALL Delay1sec
GOTO mainloop
OverZeroTemp
CLRF Centinaia
CLRF Decine
MOVFW Temperatura
MOVWF Unita
CLRF MezzoGrado ; tieni conto dei 0.5 gradi
MOVLW 5
BTFSC Unita, 0
MOVWF MezzoGrado
MOVLW 0x30
ADDWF MezzoGrado, f
BCF STATUS, C ; dividi per due
RRF Unita, f
TogliCentinaia
MOVLW 100 ; conta quante centinaia ci sono
SUBWF Unita, w
BTFSS STATUS, C ; salta se C=1 cioè risultato zero o positivo
GOTO TogliDecine
MOVWF Unita
INCF Centinaia
GOTO TogliCentinaia
TogliDecine
MOVLW 10 ; conta quante decine ci sono
SUBWF Unita, w
BTFSS STATUS, C ; salta se C=1 cioè risultato zero o positivo
GOTO SoloUnita
MOVWF Unita
INCF Decine
GOTO TogliDecine
SoloUnita
MOVLW 0x30 ; porta i digit nel range ASCII
ADDWF Centinaia,f
ADDWF Decine, f
ADDWF Unita, f
MOVLW 14 ; portati al 14mo carattere
CALL LcdCurPos
MOVFW Centinaia
MOVWF Lcd_Temp
CALL LcdOutChar
MOVFW Decine
MOVWF Lcd_Temp
CALL LcdOutChar
MOVFW Unita
MOVWF Lcd_Temp
CALL LcdOutChar
MOVLW '.'
MOVWF Lcd_Temp
CALL LcdOutChar
MOVFW MezzoGrado
MOVWF Lcd_Temp
CALL LcdOutChar
RETURN
;*****************************************
;* *
;* Libreria HOTLIB *
;* subroutines di controllo *
;* per 18S20 *
;* *
;* by Marco Tinari - Roma 10/09/2012 *
;* *
;*****************************************
; scrivi '1' sul bus One-Wire
OW_WriteOne: BCF PORTA, HOT_PinPortOut
CALL Delay8us
BSF PORTA, HOT_PinPortOut
CALL Delay82us
RETURN
; scrivi '0' sul bus One-Wire
OW_WriteZero: BCF PORTA, HOT_PinPortOut
CALL Delay82us
BSF PORTA, HOT_PinPortOut
RETURN
; scrivi sul bus One-Wire il contenuto di Hot_Byte
OW_WriteByte: MOVLW 0x08
MOVWF Hot_Work ; conta per 8 bit
OW_Write8Bit RRF Hot_Byte, f ; considera il bit LSB
BTFSS STATUS, C
GOTO OW_loop0
CALL OW_WriteOne ; era 1 mandalo su One-Wire
GOTO OW_loop1
OW_loop0 CALL OW_WriteZero ; era 0 mandalo su One-Wire
OW_loop1 DECFSZ Hot_Work, f
GOTO OW_Write8Bit
RETURN
; leggi un byte dal bus One-Wire e memorizzalo in Hot_Byte
OW_ReadByte: CLRF Hot_Byte ; pulisci per il byte da ricevere
MOVLW 0x08
MOVWF Hot_Work ; conta per 8 bit
OW_Read8Bit BCF PORTA, HOT_PinPortOut ; impulso -_- per ricevere il bit
NOP
NOP
BSF PORTA, HOT_PinPortOut
CALL Delay8us ; attendi 8 usec
BSF STATUS, C
BTFSS PORTA, HOT_PinPortIn
BCF STATUS, C
RRF Hot_Byte ; memorizza il bit nel byte
CALL Delay82us ; attendi per il prossimo bit
DECFSZ Hot_Work, f
GOTO OW_Read8Bit
RETURN
; inizializza i dispositivi One-Wire
OW_Initialize: BCF PORTA, HOT_PinPortOut ; tieni la linea a zero
CALL Delay500us ; per circa 600
CALL Delay101us ; microsecondi
BSF PORTA, HOT_PinPortOut ; rilascia la linea
CALL Delay82us ; attendi circa 80 microsecondi
CLRF Hot_Byte ; supponi che ci sia una risposta
BTFSC PORTA, HOT_PinPortIn ; salta se la linea è a zero
DECF Hot_Byte ; non c'è nessuno: errore
CALL Delay500us ; comunque attendi circa 600
GOTO Delay101us ; microsecondi
OW_InitAndSkip: CALL OW_Initialize ; inizializza la sonda
MOVLW 0xCC ; skip rom command
MOVWF Hot_Byte
CALL OW_WriteByte
GOTO Delay1ms
;*****************************************
;* *
;* subroutines controllo lcd *
;* TS2020 - 1 KS0070B *
;* *
;* by Marco Tinari - Roma 26/05/2012 *
;* *
;*****************************************
;**********************************************************************
; Manda il byte in W al display 4 bit per volta
;**********************************************************************
LcdSendByte: MOVWF Lcd_Temp
BCF PORTB,Lcd_BIT4 ;prepara per i primi 4 bit
BCF PORTB,Lcd_BIT5
BCF PORTB,Lcd_BIT6
BCF PORTB,Lcd_BIT7
BTFSC Lcd_Temp,4
BSF PORTB,Lcd_BIT4
BTFSC Lcd_Temp,5
BSF PORTB,Lcd_BIT5
BTFSC Lcd_Temp,6
BSF PORTB,Lcd_BIT6
BTFSC Lcd_Temp,7
BSF PORTB,Lcd_BIT7
BSF PORTB,Lcd_EN ;toggle di 1 ms su EN
CALL Delay1ms
BCF PORTB,Lcd_EN
CALL Delay1ms
BCF PORTB,Lcd_BIT4 ;prepara per i successivi 4 bit
BCF PORTB,Lcd_BIT5
BCF PORTB,Lcd_BIT6
BCF PORTB,Lcd_BIT7
BTFSC Lcd_Temp,0
BSF PORTB,Lcd_BIT4
BTFSC Lcd_Temp,1
BSF PORTB,Lcd_BIT5
BTFSC Lcd_Temp,2
BSF PORTB,Lcd_BIT6
BTFSC Lcd_Temp,3
BSF PORTB,Lcd_BIT7
LcdHalfSend: BSF PORTB,Lcd_EN ;toggle di 1 ms su EN
CALL Delay1ms
BCF PORTB,Lcd_EN
CALL Delay1ms
RETURN
;**********************************************************************
; Manda un carattere visualizzabile a LCD
;**********************************************************************
LcdSendData: BSF PORTB,Lcd_RS
CALL LcdSendByte
CALL Delay1ms
RETURN
;**********************************************************************
; Manda un comando a LCD
;**********************************************************************
LcdSendCmd: BCF PORTB,Lcd_RS
CALL LcdSendByte
CALL Delay1ms
CALL Delay1ms
RETURN
;**********************************************************************
; Inizializzazione di LCD - controller KS0070B
;**********************************************************************
LcdInit: CALL SelectB1 ; seleziona il Bank 1
BCF TRISB,Lcd_EN ; imposta i giusti pin in output
BCF TRISB,Lcd_RS
BCF TRISB,Lcd_BIT4
BCF TRISB,Lcd_BIT5
BCF TRISB,Lcd_BIT6
BCF TRISB,Lcd_BIT7
CALL SelectB0 ; seleziona il Bank 0
BCF PORTB,Lcd_RS
BCF PORTB,Lcd_EN
CALL Delay50ms ; imposta il display
; FUNCTION SET
BCF PORTB,Lcd_BIT4 ; 0 richiesto
BSF PORTB,Lcd_BIT5 ; 1 richiesto
BCF PORTB,Lcd_BIT6 ; 0 richiesto
BCF PORTB,Lcd_BIT7 ; 0 richiesto
CALL LcdHalfSend
CALL LcdHalfSend ; ripeti
BCF PORTB,Lcd_BIT4 ; non considerato
BCF PORTB,Lcd_BIT5 ; non considerato
BSF PORTB,Lcd_BIT6 ; F=1 5x10 dots
BSF PORTB,Lcd_BIT7 ; N=1 2-line mode
CALL LcdHalfSend
CALL Delay50ms
; DISPLAY ON/OFF CONTROL
BCF PORTB,Lcd_BIT4 ; 0 richiesto
BCF PORTB,Lcd_BIT5 ; 0 richiesto
BCF PORTB,Lcd_BIT6 ; 0 richiesto
BCF PORTB,Lcd_BIT7 ; 0 richiesto
CALL LcdHalfSend
BCF PORTB,Lcd_BIT4 ; B=0 blink off
BCF PORTB,Lcd_BIT5 ; C=0 cursor off
BSF PORTB,Lcd_BIT6 ; D=1 display on
BSF PORTB,Lcd_BIT7 ; 1 richiesto
CALL LcdHalfSend
CALL Delay50ms
; CLEAR DISPLAY
BCF PORTB,Lcd_BIT4 ; 0 richiesto
BCF PORTB,Lcd_BIT5 ; 0 richiesto
BCF PORTB,Lcd_BIT6 ; 0 richiesto
BCF PORTB,Lcd_BIT7 ; 0 richiesto
CALL LcdHalfSend
BSF PORTB,Lcd_BIT4 ; 1 richiesto
BCF PORTB,Lcd_BIT5 ; 0 richiesto
BCF PORTB,Lcd_BIT6 ; 0 richiesto
BCF PORTB,Lcd_BIT7 ; 0 richiesto
CALL LcdHalfSend
CALL Delay50ms
; ENTRY MODE SET
BCF PORTB,Lcd_BIT4 ; 0 richiesto
BCF PORTB,Lcd_BIT5 ; 0 richiesto
BCF PORTB,Lcd_BIT6 ; 0 richiesto
BCF PORTB,Lcd_BIT7 ; 0 richiesto
CALL LcdHalfSend
BCF PORTB,Lcd_BIT4 ; SH=0 entire shift off
BSF PORTB,Lcd_BIT5 ; ID=1 increment mode
BSF PORTB,Lcd_BIT6 ; 1 richiesto
BCF PORTB,Lcd_BIT7 ; 0 richiesto
CALL LcdHalfSend
RETURN
;**********************************************************************
; Pulisce il display ed le celle associate in ram
;**********************************************************************
LcdClear: MOVLW 40 ; considera i 40 caratteri
MOVWF Lcd_Counter
MOVLW Lcd_Cells ; punta la prima cella per LCD
MOVWF FSR
MOVLW 020H ; metti 'spazio' in W
LcdClr1 MOVWF INDF ; pulisci la cella
INCF FSR,1 ; avanza di un carattere
DECFSZ Lcd_Counter,1
GOTO LcdClr1
CLRW ; azzera il cursore di LCD
MOVWF Lcd_Cursor
MOVLW 01H ; manda un Clear Display a LCD
GOTO LcdSendCmd
;**********************************************************************
; Posiziona il cursore al n-esimo carattere con n in W
;**********************************************************************
LcdCurPos: MOVWF Lcd_Cursor ; memorizza la posizione nel puntatore RAM
IORLW b'10000000' ; prepara il comando SET DDRAM
GOTO LcdSendCmd ; manda il comando
;**********************************************************************
; Visualizza il carattere in LcdTemp ed avanza di uno il cursore
;**********************************************************************
LcdOutChar: MOVLW Lcd_Cells ; punta la prima cella per LCD
ADDWF Lcd_Cursor, w ; sommaci il displacement
MOVWF FSR ; mettilo nel registro di indirizzamento ind.
MOVFW Lcd_Temp ; prendi il carattere
MOVWF INDF ; memorizzalo nella cella lcd
INCF Lcd_Cursor, f ; sposta avanti il cursore
GOTO LcdSendData ; visualizza il carattere
;**********************************************************************
; Visualizza i caratteri presenti nelle 40 celle Lcd_Cells
;**********************************************************************
LcdRefresh: MOVLW 01H ; manda un Clear Display a LCD
CALL LcdSendCmd
MOVLW 20 ; considera i primi 20 caratteri
MOVWF Lcd_Counter
MOVLW Lcd_Cells ; punta la prima cella per LCD
MOVWF FSR
LcdRefr1: MOVF INDF,0 ; leggi il carattere
CALL LcdSendData
INCF FSR,1 ; avanza di un carattere
DECFSZ Lcd_Counter,1
GOTO LcdRefr1 ; ripeti per il primo blocco
MOVLW 0C0H ; spostati sui secondi 8 chars di LCD
CALL LcdSendCmd
MOVLW 20 ; ripeti per il secondo blocco
MOVWF Lcd_Counter
MOVLW Lcd_Cells+20 ; punta la nona cella per LCD
MOVWF FSR
LcdRefr2: MOVF INDF,0 ; leggi il carattere
CALL LcdSendData
INCF FSR,1 ; avanza di un carattere
DECFSZ Lcd_Counter,1
GOTO LcdRefr2 ; ripeti per il secondo blocco
RETURN
SelectB0: bcf STATUS, RP1 ; seleziona il bank 0
bcf STATUS, RP0
return
SelectB1: bcf STATUS, RP1 ; seleziona il bank 1
bsf STATUS, RP0
return
;**********************************************************************
; Converti il contenuto di W in due caratteri ASCII e mandali in output su LCD
;**********************************************************************
LcdByteOut: PHW ; salva il valore
SWAPF w_save, w ; scambia MSB con LSB
ANDLW b'00001111' ; prendi solo MSB
CALL HalfOut ; e visualizzala
PLW ; recupera il valore originale
ANDLW b'00001111' ; prendi solo LSB
HalfOut MOVWF Lcd_Temp
MOVLW 0x30 ; porta il valore nel range dei numerici ASCII
ADDWF Lcd_Temp, f
MOVLW 0x3A ; controlla che non sia oltre il '9'
SUBWF Lcd_Temp, w ; (Lcd_Temp - W) ---> W
BTFSS STATUS, C ; salta se C=1 cioè risultato zero o positivo
GOTO LowerThanHexA
MOVLW 7 ; offset per
ADDWF Lcd_Temp, f ; portare il valore nel range 'A' - 'F'
LowerThanHexA GOTO LcdOutChar ; visualizza il valore
;*****************************************
;* *
;* Libreria CHRONO *
;* subroutines di ritardo per *
;* 16F628A @ 4 MHz *
;* *
;* by Marco Tinari - Roma 11/08/2012 *
;* *
;*****************************************
;ritardo di 8 microsecondi
;compresa la CALL chiamante
Delay8us: GOTO $+1
GOTO $+1
RETURN
;ritardo di 15 microsecondi
;compresa la CALL chiamante
Delay15us: CALL Delay8us
NOP
GOTO $+1
RETURN
;ritardo di 50 microsecondi
;compresa la CALL chiamante
Delay50us: MOVLW 14
Entry1 MOVWF us_counter
Delay50us1 DECFSZ us_counter,1
GOTO Delay50us1
NOP
NOP
NOP
RETURN
;ritardo di 82 microsecondi
;compresa la CALL chiamante
Delay82us: CALL Delay50us
CALL Delay15us
CALL Delay15us
RETURN
;ritardo di 101 microsecondi
;compresa la CALL chiamante
Delay101us: MOVLW 30
GOTO Entry1
;ritardo di 500 microsecondi
;compresa la CALL chiamante
Delay500us: MOVLW 163
GOTO Entry1
;ritardo di 1 millisecondo
;compresa la CALL chiamante
Delay1ms: CALL Delay500us
GOTO Delay500us
;ritardo di 50 millisecondi
;compresa la CALL chiamante
Delay50ms: MOVLW 49
Entry2 MOVWF ms_counter
Delay50ms1 CALL Delay1ms
DECFSZ ms_counter,1
GOTO Delay50ms1
CALL Delay500us
MOVLW 112 ; ritarda altri 347 usec
CALL Entry1
NOP ; ulteriore 1 usec
RETURN
;ritardo di 1 decimo di secondo
;compresa la CALL chiamante
Delay1decs: MOVLW 198
MOVWF ms_counter
CALL Delay50ms
CALL Delay500us
CALL Delay50us
NOP
RETURN
;ritardo di 5 decimi di secondo
;più 2+1us per la CALL chiamante e return
Delay5decs: CALL Delay1decs
CALL Delay1decs
CALL Delay1decs
CALL Delay1decs
CALL Delay1decs
RETURN
;ritardo di 1 secondo
;più 4+2+2us per la CALL chiamante e return
Delay1sec: CALL Delay5decs
GOTO Delay5decs
END