ThermoPIC

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