;----------------------------------------------------------------------;
;  THERM4M.ASM  Shows Temperature from Thermistor on LCD, 4 MHz clock  ;
;----------------------------------------------------------------------;

;              555              V+         PIC16F84
;         .----------.          |       .-----------.
;  gnd ---|gnd    Vcc|--- V+   [R]     -|RA2     RA1|----[LCD E]       
;       .-|trig   dis|----------|      -|RA3     RA0|----[LCD RS]      
; RA4<--|-|out  thres|--.--{r}--'   in>-|RA4    OSC1|--|X|__ gnd    
;  V+ --|-|rst   cont|  |--|<---'   V+--|MCLR   OSC2|--|X|  X = 4 MHz 
;       | '----------'  |          gnd--|Vss     Vdd|--- V+   cer. res.
;       '---------------'   [LCD D4]----|RB0     RB7|-   
;       |    C              [LCD D5]----|RB1     RB6|-  V+ = 4.5 or 5V
;       '---||---gnd        [LCD D6]----|RB2     RB5|---[PB]--- gnd       
;     C =  0.03 mfd         [LCD D7]----|RB3     RB4|---[PB]--- gnd        
;    -{r}- = 33K                        '-----------'         
;    -|<- = 1n4148  [R] = Thermistor               -[PB]- = pushbutton

;     LCD pin connections:
;      1 - gnd     ground    2 - Vcc V+    3 - contrast 10K pot V+ & gnd
;      4 - RS  RA0 PIC(17)   5 - RW  gnd   6 - E   RA1 PIC(18) 
;      7 - D0   gnd      8 - D1  gnd       9 - D2 gnd        10 - D3 gnd       
;      11 - D4  RB0 (6)  12 - D5 RB1 (7)   13 - D6 RB2 (8)   14 - D7 (9)

           LIST P=16F84           ;  16F84 Runs at 4 MHz
           INCLUDE "p16f84.inc"
           __CONFIG _PWRTE_ON & _XT_OSC & _WDT_OFF  ; uses 4 MHz crystal
           ERRORLEVEL -224        ;  supress annoying message from tris
           ERRORLEVEL -302        ;  supress message from page change

;  Define Information
     #DEFINE RS PORTA, 0         ;  RA0 is RS line of LCD
     #DEFINE E  PORTA, 1          ;  RA1 is E line of LCD
                                  ;  RB0-RB3 are D4-D7 of LCD
;  Macro

EStrobe MACRO                   ;  Strobe the "E" Bit
  bsf    E
  bcf    E
 ENDM

            CBLOCK     0CH
                Temp            ; a temporary variable
                count           ; counter
                cntmsec         ; used in counting milliseconds 
                bin             ; binary number to be converted to BCD
                hundreds        ; BCD hundreds result
                tens_and_ones   ; BCD tens and ones result
                savetmr0        ; used to save value of tmr0
                dispvalue       ; used to hold temperature displayed
             ENDC
          
            ORG 0               ; start at location 0

            goto main           ; jump over to main routine       

;----------------------------------------------------------------------;
;                    Data for message to be output                     ;
;----------------------------------------------------------------------;
shomsg:                         ;  Message to Output
  addwf  PCL, f                 ;  Output the Characters
m0  dt     "TMR0 Value:", 0
m1  dt     "Temperature", 0

;----------------------------------------------------------------------;
;                        Ratios of Prescaler                           ;
;----------------------------------------------------------------------;
preratio:                          
  addwf  PCL, f                 ;  select offset using W
    dt     D'2',D'4',D'8',D'16',D'32',D'64',D'128'

;----------------------------------------------------------------------;
;                       Initialize the ports                           ;
;----------------------------------------------------------------------;
Init:
            clrf   PORTA
            clrf   PORTB

            movlw B'00010000'          ; RA4 input, others outputs
            tris PORTA
            movlw B'00110000'          ; RB4, RB5 input, others outputs
            tris PORTB
            movlw B'00100011'          ; pull-ups enabled                                    
                                       ; prescaler assigned to RA4
                                       ; prescaler set to 1:16
            option
            return

;----------------------------------------------------------------------;
;                         Initialize the LCD                           ;
;----------------------------------------------------------------------;
initlcd:
  movlw D'40'
  call   nmsec                  ;  Wait 40 msecs before Reset
  bcf    RS                     ;  send an 8 bit instruction
  movlw  0x03                   ;  Reset Command
  call   NybbleOut              ;  Send the Nybble
  call   Dlay5                  ;  Wait 5 msecs before Sending Again
  EStrobe
  call Dlay160                  ;  Wait 160 usecs before Sending 2nd Time
  EStrobe
  call Dlay160                  ;  Wait 160 usecs before Sending 3rd Time
  bcf    RS                     ;  send an 8 bit instruction
  movlw  0x02                   ;  Set 4 Bit Mode
  call   NybbleOut              
  call Dlay160
  movlw  0x028                  ;  4 bit, 2 Line, 5x7 font
  call   SendINS
  movlw  0x010                  ;  display shift off
  call   SendINS
  movlw  0x001                  ;  Clear the Display RAM
  call   SendINS
  call   Dlay5                  ;  Note, Can take up to 4.1 msecs
  movlw  0x006                  ;  increment cursor
  call   SendINS
  movlw  0x00C                  ;  display on cursor off
  call   SendINS
  return

;----------------------------------------------------------------------;
;                Send the character in W out to the LCD                ;
;----------------------------------------------------------------------;
SendASCII
  addlw '0'                     ;  Send nbr as ASCII character
SendCHAR                        ;  Send the Character to the LCD
  movwf  Temp                   ;  Save the Temporary Value
  swapf  Temp, w                ;  Send the High Nybble
  bsf    RS                     ;  RS = 1
  call   NybbleOut
  movf   Temp, w                ;  Send the Low Nybble
  bsf    RS
  call   NybbleOut
  return

;----------------------------------------------------------------------;
;              Send an instruction in W out to the LCD                 ;
;----------------------------------------------------------------------;
SendINS                         ;  Send the Instruction to the LCD
  movwf  Temp                   ;  Save the Temporary Value
  swapf  Temp, w                ;  Send the High Nybble
  bcf    RS                     ;  RS = 0
  call   NybbleOut
  movf   Temp, w                ;  Send the Low Nybble
  bcf    RS
  call   NybbleOut
  return

;----------------------------------------------------------------------;
;              Send the nibble in W out to the LCD                     ;
;----------------------------------------------------------------------;
NybbleOut                       ;  Send a Nybble to the LCD
  movwf  PORTB                            
  EStrobe                       ;  Strobe out the LCD Data
  call Dlay160                  ;  delay for 160 usec
  return

;----------------------------------------------------------------------;
;                   Output the message on the LCD                      ;
;----------------------------------------------------------------------;
OutMessage:
  movwf  FSR                    ;  Point at first letter
OutLoop:
  movf   FSR, w                 ;  Get pointer into W
  incf   FSR, f                 ;  Set up for next letter
  call   shomsg                 ;  Get character to output
  iorlw  0                      ;  At the End of the Message?
  btfsc  STATUS, Z              ;  Skip if not at end
  return                        ;  Yes - Equal to Zero
  call   SendCHAR               ;  Output the ASCII Character
  goto   OutLoop                ;  Get the next character

;----------------------------------------------------------------------;
;                  Change binary nbr in bin to BCD                     ;
;----------------------------------------------------------------------;
binary_to_bcd                     ; by Scott Dattalo
  clrf hundreds
  swapf bin, W
  addwf bin, W
  andlw B'00001111'
  skpndc
    addlw 0x16
  skpndc
    addlw 0x06
  addlw 0x06
  skpdc
  addlw -0x06
  btfsc bin,4
    addlw 0x16 - 1 + 0x6
  skpdc
    addlw -0x06
  btfsc bin,5
    addlw 0x30
  btfsc bin, 6
    addlw 0x60
  btfsc bin,7
    addlw 0x20
  addlw 0x60
  rlf hundreds, f
  btfss hundreds, 0
    addlw -0x60
  movwf tens_and_ones
  btfsc bin,7
    incf hundreds, f
  return

;----------------------------------------------------------------------;
;                        time delay routines                           ;
;----------------------------------------------------------------------;

Dlay160:    movlw D'40'                ;  delay about 160 usec,(4/loop )
micro4      addlw H'FF'                ;  subtract 1 from 'W'
            btfss STATUS,Z             ;  skip when you reach zero
            goto micro4                ;  more loops
            return                     

Dlay5:      movlw 5                    ;  delay for 5 milliseconds
            goto $ + 2
msec250:    movlw D'250'               ;  delay for 250 milliseconds
                ;*** N millisecond delay routine ***
nmsec:      movwf cntmsec              ;  delay for N (in W) millisec
msecloop:   movlw D'248'               ;  1 usec for load
            call micro4                ;  this instruction takes 995 usec
            nop                        ;  1 usec 
            decfsz cntmsec,f           ;  1 usec, (2 if skip taken)
            goto msecloop              ;  2 usec here makes 995+5=1 msec
            return 

;----------------------------------------------------------------------;
;                Display binary value in W in decimal                  ;
;----------------------------------------------------------------------;
DispDec
              movwf bin
              call binary_to_bcd
              movf hundreds, W
              call SendASCII
              swapf tens_and_ones, W
              andlw H'F'
              call SendASCII
              movf tens_and_ones, W
              andlw H'F'
              call SendASCII
              return


;----------------------------------------------------------------------;
;                           The Main routine                           ;
;----------------------------------------------------------------------;
main:
       call Init               ; initialize ports, set up timer
       call initlcd            ; initialize the LCD
       movlw H'80'             ; position at 1st line column 0
       call SendINS
       movlw m0 -2             ; send 'TMR0 Value:' message
       call OutMessage
       movlw H'C0'
       call SendINS            ; position at 2nd line column 0
       movlw m1 -2             ; send 'Temperature:' message
       call OutMessage
sholoop:
       movlw H'8C'             ; position at 1st line column 12
       call SendINS
       bcf INTCON, T0IF        ; clear timer zero interrupt flag
       clrf TMR0               ; zero TMR0
       call msec250            ; wait a total of one second
       call msec250
       call msec250
       call msec250
       movf TMR0, W            ; retrieve timer zero
       movwf savetmr0          ; save the value
       btfsc INTCON, T0IF      ; check if timer overflowed
       goto overload           ; yes, display 'OVR'
       call DispDec            ; display TMR0 value
       movlw H'CD'             ; position at  2nd line column 13
       call SendINS
       movlw 2                 ; set up PCLATH to page 2
       movwf PCLATH
       movlw D'32'             ; 1st table value is for tmr0 = 32
       subwf savetmr0, W       ; subtract 32 from tmr0 value
       call temptable          ; get temperature
       movwf dispvalue         ; save it in display value
       swapf dispvalue, W      ; get hi nibble in W
       andlw H'0F'             ; lowest 4 bits
       call SendASCII          ; display it
       movf dispvalue, W       ; get lo nibble in W
       andlw H'0F'             ; lowest 4 bits
       call SendASCII          ; display it
       goto sholoop            ; repeat forever
overload
       movlw 'O'               ; output 'OVR'
       call SendCHAR
       movlw 'V'
       call SendCHAR
       movlw 'R'
       call SendCHAR
       goto sholoop            ; and continue

       org H'200'
temptable:                     ; get temperature to display
       addwf PCL, f            
    dt 11,12,12,13,14,14,15,16,16,17,18,18,19,20,20,21,22,22,23,24,24,25
    dt 26,26,27,27,28,29,29,30,31,31,32,32,33,34,34,35,35,36,36,37,38,38
    dt 39,39,40,40,41,41,42,42,43,44,44,45,45,46,46,47,47,48,48,49,49,50
    dt 50,51,51,52,52,53,53,54,54,54,55,55,56,56,57,57,58,58,59,59,59,60
    dt 60,61,61,62,62,63,63,63,64,64,65,65,65,66,66,67,67,68,68,68,69,69
    dt 70,70,70,71,71,71,72,72,73,73,73,74,74,75,75,75,76,76,76,77,77,78
    dt 78,78,79,79,79,80,80,81,81,81,82,82,82,83,83,83,84,84,84,85,85,85
    dt 86,86,87,87,87,88,88,88,89,89,89,90,90,90,91,91,91,92,92,92,93,93
    dt 93,94,94,95,95,95,96,96,96,97,97,97,98,98,98,99,99,99,00,00,00,01
    dt 01,01,02,02,03,03,03,04,04,04,05,05,05,06,06,06,07,07,08,08,08,09
    dt 09,09,10,10

       end