1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                                                                  ;
;                        Program: DS18B20 Digital Thermometer with .1 Degree Increments            ;
;                        Author:  Jake Sutherland                                                  ;
;                        Start Date: Sunday 16th May 2010                                          ;
;                        Finish Date: Wednesday 20th October 2010                                  ;
;                        Comments: June 2011 Revised program                                       ;
;                                                                                                  ;
;                                                                                                  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
        LIST            P=PIC16F628A
        INCLUDE         P16F628A.INC
        __config        _CP_OFF & DATA_CP_OFF & _LVP_OFF & _BODEN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF &  _INTRC_OSC_NOCLKOUT 
        errorlevel      -302    ;Eliminate bank warning
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                                                                  ;
;                                   PIC16F628A Microcontroller                                     ;
;                                            ____ ____                                             ;
; LED 7 Segment 10's CC       VREF/AN2/RA2 -| 1  - 18 |- RA1/AN1              LED 7 Segment 1's CC ;
; LED 7 Segment 100's CC      CPM1/AN3/RA3 -| 2    17 |- RA0/AN0             LED 7 Segment .1's CC ;
; DS18B20 I/O               CMP2/T0CKI/RA4 -| 3    16 |- RA7/OSC1/CLKIN                            ;
;                             VPP/MCLR/RA5 -| 4    15 |- RA6/OSC2/CLKOUT                           ;
;                                      VSS -| 5    14 |- VDD                                       ;
; Segment DP                       INT/RB0 -| 6    13 |- RB7/T1OSC1/ICSPDAT              Segment B ;
; Segment C                      DT/RX/RB1 -| 7    12 |- RB6/T1OSCO/T1CLKI/ICSPCLK       Segment A ;
; Segment D                      CK/TX/RB2 -| 8    11 |- RB5                             Segment F ;
; Segment E                       CCP1/RB3 -|_9____10_|- RB4/PGM                         Segment G ;
;                                                                                                  ;
;                                                                                                  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
CBLOCK  H'20'
HUNS                                    ; Jump pointer for Hundreds digit
TENS                                    ; Jump pointer for Tens digit
ONES                                    ; Jump pointer for Ones digit
DECI                                    ; Jump pointer for Decimal digit
THOU_COL                                ; 7 Segment Display Thousands Column, used within ISR
HUNS_COL                                ; 7 Segment Display Hundreds Column, used within ISR
TENS_COL                                ; 7 Segment Display Tens Column, used within ISR
ONES_COL                                ; 7 Segment Display Ones Column, used within ISR
COLSEL                                  ; Stores COLUMN SELECT information 
DIGIT                                   ; Used for Indirect Addressing in Interrupt Service Routine
TEMPLO_C                                ; BS18B20 Celsius Temperature Result Low Byte
TEMPHI_C                                ; BS18B20 Celsius Temperature Result High Byte
COUNT                                   ; For counting execution times in various routines
SHIFT                                   ; For storing data to shift into and out of the DS18B20
DELAYGPR1                               ; Used in delay subroutines
FLAGS                                   ;   -------X  Unused
                                        ;   ------0-  Celsius Temperature Negative Flag (0 = False 1 = True)
                                        ;   -----X--  Unused
                                        ;   ----X---  Unused
                                        ;   ---X----  Unused
                                        ;   --X-----  Unused
                                        ;   -X------  Unused
                                        ;   X-------  Unused
ENDC
 
W_ISR   EQU     H'70'                   ; For context saving. Ensures GPR is accesible from any Bank. See Memory Map of 628A
S_ISR   EQU     H'71'                   ; For context saving. Ensures GPR is accesible from any Bank. See Memory Map of 628A
P_ISR   EQU     H'72'                   ; For context saving. Ensures GPR is accesible from any Bank. See Memory Map of 628A
F_ISR   EQU     H'73'                   ; For context saving. Ensures GPR is accesible from any Bank. See Memory Map of 628A
 
 
        ORG     H'000'                  ; Processor reset vector location. On power up, the program jumps here
        GOTO    SETUP                   ; 
 
        ORG     H'004'                  ; Interrupt vector location. When an Interupt occurs, the program jumps here
  ; (Thanks Mike, K8LH for help with this ISR routine. Contact via Electro-Tech-Online.com)
  ; Save
        MOVWF   W_ISR                   ; Save W to W_ISR
        SWAPF   STATUS, W               ; Use SWAPF instruction so status bits don't change
        MOVWF   S_ISR                   ; Save Status to S_ISR
        CLRF    STATUS                  ; Switch to Bank 0
        MOVF    PCLATH, W               ; Move PCLATH to W register
        MOVWF   P_ISR                   ; Save PCLATH to P_ISR
        CLRF    PCLATH                  ; Force page 0
        MOVF    FSR, W                  ; Move FSR to W register
        MOVWF   F_ISR                   ; Save FSR to F_ISR
 
  ; Refresh display
        CLRF    PORTB                   ; Blank the display
        MOVF    PORTA, W                ; Move PORTA's current state to W
        ANDLW   B'11100000'             ; Clear ONLY Column Select Bits & leave upper nibble unchanged
        IORWF   COLSEL, W               ; Inclusive OR above with COLSEL register
        MOVWF   PORTA                   ; Leave upper nibble of PORTA unchanged & select new column
 
        MOVF    DIGIT, W                ; Column number (DIGIT is initialised to 0. Used for Indirect Addressing)
        ADDLW   THOU_COL                ; Add 'DIGIT' to 'THOU_COL' GPR address
        MOVWF   FSR                     ; FSR = THOU_COL + (0forTHOUS, 1forHUNS, 2forTENS & 3forONES) as they are in sequencial order in RAM
        MOVF    INDF, W                 ; W register now holds the jump pointer for the corresponding digit to be displayed
        CALL    SEGMENT_TABLE           ; Get 7 segment arrangement from SEGMENT_TABLE for corresponding digit
 
        BTFSC   COLSEL, 1               ; Is TENS Column active
        IORLW   B'00000001'             ; Yes, so activate TEN's column deciaml point
        MOVWF   PORTB                   ; NO, hide deciaml point and display new column
 
  ; Prepare for next column interrupt
        INCF    DIGIT, F                ; Increment DIGIT jump pointer (used when indirect addressing above)
        BCF     STATUS, C               ; Clear C bit of STATUS register
        RRF     COLSEL, F               ; Advance column select bit       
        BTFSS   STATUS,C                ; Was that the last column? (or, Is Carry Flag Set?)  
        GOTO    $+D'3'                  ; NO, do not reset DIGIT and COLumnSELect
        CLRF    DIGIT                   ; Reset DIGIT jump pointer
        BSF     COLSEL, 3               ; Reset column select to THOU_COL (1XXX) (00001000)
 
  ; RESTORE
        BCF     PIR1, TMR2IF            ; Clear TMR2 interrupt flag while still in Bank 0        
        MOVF    F_ISR, W                ; MOVE F_ISR to W
        MOVWF   FSR                     ; Restore FSR
        MOVF    P_ISR, W                ; MOVE P_ISR to W
        MOVWF   PCLATH                  ; Restore PCLATH
        SWAPF   S_ISR, W                ; Undo previous SWAPF, place result in W
        MOVWF   STATUS                  ; Restore STATUS
        SWAPF   W_ISR, F                ; Use SWAPF instruction so status bits don't change
        SWAPF   W_ISR, W                ; Undo previous SWAPF and restore W register
        RETFIE                          ; Return From Interrupt
 
  ; 7 Segment Display Arrangement Lookup
SEGMENT_TABLE  ; This routine assigns on/off arrangement to the 7 Segment Display
        ADDWF   PCL, F
             ;    BAFGEDCp    JUMP   B|A|F|G|E|D|C|p   DISPLAY
        RETLW   B'11101110' ;   0    B|A|F|-|E|D|C|-      0
        RETLW   B'10000010' ;   1    B|-|-|-|-|-|C|-      1
        RETLW   B'11011100' ;   2    B|A|-|G|E|D|-|-      2
        RETLW   B'11010110' ;   3    B|A|-|G|-|D|C|-      3
        RETLW   B'10110010' ;   4    B|-|F|G|-|-|C|-      4
        RETLW   B'01110110' ;   5    -|A|F|G|-|D|C|-      5
        RETLW   B'01111110' ;   6    -|A|F|G|E|D|C|-      6
        RETLW   B'11000010' ;   7    B|A|-|-|-|-|C|-      7
        RETLW   B'11111110' ;   8    B|A|F|G|E|D|C|-      8
        RETLW   B'11110110' ;   9    B|A|F|G|-|D|C|-      9
        RETLW   B'00000000' ;  10    -|-|-|-|-|-|-|-    BLANK
        RETLW   B'00010000' ;  11    -|-|-|G|-|-|-|-      -
        RETURN
 
  ; Program Orgiginates Here
SETUP  ; This rountine sets up the Microcontroller's Inputs and Outputs
        MOVLW   H'07'                   ; Turn Comparators off and enable pins for I/O functions
        MOVWF   CMCON                   ;
        BSF     STATUS, RP0             ; Bank 1
        MOVLW   B'01010000'             ; RA<7><5><3:0> Output, RA<6><4> Input
        MOVWF   TRISA                   ;
        CLRF    TRISB                   ; RB<7:0> Outputs
        BCF     STATUS, RP0             ; Bank 0
 
        CLRF    PORTA
        CLRF    PORTB
 
ONE_OFF_INITIALISE
  ; Clear ALL Bank 0 RAM from 0X20 - 0X7F (96 bytes)
        BCF     STATUS, IRP             ; Indirect addressing Bank 0/1
        MOVLW   H'20'                   ; Initialise pointer to RAM
        MOVWF   FSR                     ; (File Select Register)
        CLRF    INDF                    ; Clear Register indirectly
        INCF    FSR, F                  ; Increment pointer
        BTFSS   FSR, 7                  ; All done?
        GOTO    $-D'3'                  ; No, Clear next byte
 
  ; Initialise Column Select
        BSF     COLSEL, 3               ; Set column select to THOU_COL (1XXX) (00001000)
 
  ; Setup TMR2 for 0.0005s or 500uS Interrupts
        CLRF    TMR2                    ; Clear TMR2 register
        BSF     STATUS, RP0             ; Bank 1
        MOVLW   B'00000010'             ;   00000010
        MOVWF   PIE1                    ;   -------0  Disable TMR1IE - TMR1 Overflow Interrupt Enable bit
                                        ;   ------1-  Enable  TMR2IE - TMR2 to PR2 Match Interrupt Enable bit
                                        ;   -----0--  Disable CCP1IE - CCP1 Interrupt Enable bit
                                        ;   ----X---  Unused
                                        ;   ---0----  Disable TXIE - USART Transmit Interrupt Enable bit
                                        ;   --0-----  Disable RCIE - USART Receive Interrupt Enable bit
                                        ;   -0------  Disable CMIE - Comparator Interrupt Enable bit
                                        ;   0-------  Disable EEIE - EE Write Complete Interrupt Enable bit
        BCF     STATUS, RP0             ; Bank 0
        CLRF    PIR1                    ; Clear Peripheral Interrupt Flags
        MOVLW   B'00000001'             ;   00000001
        MOVWF   T2CON                   ;   ------01  Prescale 1:4
                                        ;   -----0--  TMR2 OFF
                                        ;   -0000---  Postscale 1:1
                                        ;   0-------  Unused
        BSF     STATUS, RP0             ; Bank 1
        MOVLW   D'250'                  ; 
        MOVWF   PR2                     ; Interrupt every 0.001s or 1mS
        BCF     STATUS, RP0             ; Bank 0
        BSF     INTCON, GIE             ; Enable Global Interrupts
        BSF     INTCON, PEIE            ; Enable Peripheral Interrupts
        BSF     T2CON, TMR2ON           ; Start TMR2
 
        GOTO    GET_TEMP
 
  ; Dallas DS18B20 Temperature Sensor 'One Wire' Communication Routines
DS18B20_RESET  ; This routine Resets the DS18B20
        CALL    DQ_LL                   ; Force the DQ Line to Logic Low
        MOVLW   (D'480'-5)/5            ; Reset pulse must be held a minimum of 480uS. 
        CALL    DELAY                   ; For delays from 10uS to 1285uS. Example, MOVLW D'10' for 10uS, MOVLW D'500' for 500uS. (D'n'-5)/5; n must be divisable by 5
        CALL    DQ_HIZ                  ; Release DQ Line
        MOVLW   (D'60'-5)/5             ; Wait for recovery
        CALL    DELAY                   ; 
        BTFSC   PORTA, 4                ; Test for 'Presence Pulse'
        GOTO    DS18B20_RESET           ; If not present, Reset
        MOVLW   (D'420'-5)/5            ; Must wait a minmum of 480uS from when DQ line is released before moving on
        CALL    DELAY                   ; 
        RETURN                          ;
 
DS18B20_READ_BYTE  ; This routine reads a byte of data from the DS18B20
        MOVLW   H'08'                   ; Amount of bits to shift out
        MOVWF   COUNT                   ; Store in COUNT GPR
        CALL    DS18B20_READ_BIT        ; Read bit
        RRF     SHIFT, F                ; Rotate bit out of carry into SHIFT GPR
        DECFSZ  COUNT, F                ; Decrement COUNT
        GOTO    $-D'3'                  ; If not zero, read next bit
        MOVF    SHIFT, W                ; If zero, move SHIFT GPR to W
        RETURN                          ;
 
DS18B20_READ_BIT  ; This routine reads one bit of data from the DS18B20
        BCF     INTCON, GIE             ; Disable Global Interrupts
        CALL    DQ_LL                   ; Force the DQ Line to Logic Low
        CALL    DQ_HIZ                  ; Release DQ Line
        BSF     STATUS, C               ; Preset Carry Flag
        BTFSS   PORTA, 4                ; Test DQ Line
        BCF     STATUS, C               ; If zero, Clear Carry Flag
        BSF     INTCON, GIE             ; Enable Global Interrupts
        MOVLW   (D'60'-5)/5             ; Wait for Time Slot to end
        CALL    DELAY                   ; 
        RETURN                          ;
 
DS18B20_WRITE_BYTE  ; This routine writes a byte of data to the DS18B20
        MOVWF   SHIFT                   ; Move data to shift into DS18B20 to SHIFT GPR
        MOVLW   D'08'                   ; Amount of bits to shift in
        MOVWF   COUNT                   ; Store in COUNT GPR
        RRF     SHIFT, F                ; Rotate valid data into Carry Flag
        CALL    DS18B20_WRITE_BIT       ; Write bit
        DECFSZ  COUNT, F                ; Decrement COUNT
        GOTO    $-D'3'                  ; If not zero, read next bit
        RETURN                          ; If zero, RETURN
 
DS18B20_WRITE_BIT  ; This routine writes one bit of data to the DS18B20
        BCF     INTCON, GIE             ; Disable Global Interrupts
        CALL    DQ_LL                   ; Force the DQ Line to Logic Low
        BTFSS   STATUS, C               ; Test Carry Flag
        GOTO    $+D'2'                  ; If zero, leave DQ Line Logic Low
        CALL    DQ_HIZ                  ; If not zero, release DQ Line to Logic High
        MOVLW   (D'60'-5)/5             ; Hold Logic Low, write 0
        CALL    DELAY                   ; 
        CALL    DQ_HIZ                  ; If not zero, release DQ Line to Logic High, write 1
        BSF     INTCON, GIE             ; Enable Global Interrupts
        RETURN                          ; 
 
DQ_HIZ  ; This routine forces the DQ Line to an Input / High Impedance state
        BSF     STATUS, RP0             ; Bank 1
        BSF     TRISA, 4                ; Make Pin 3 an input, Pullup resistor forces line to logic 1, unless DS18B20 pulls it low
        BCF     STATUS, RP0             ; Bank 0
        RETURN
 
DQ_LL  ; This routine forces the DQ Line to Logic Low
        BCF     PORTA, 4                ; Clear output latch
        BSF     STATUS, RP0             ; Bank 1
        BCF     TRISA, 4                ; Make Pin 3 an output
        BCF     STATUS, RP0             ; Bank 0
        RETURN
 
DELAY  ; This routine can provide delays from 10uS to 1285uS depending on the number moved to the Working register prior to calling the delay
        MOVWF   DELAYGPR1               ; Move integer to GPR
        NOP                             ; No Operation
        NOP                             ; No Operation
        DECFSZ  DELAYGPR1, F            ; Decrement GPR and place back in itself
        GOTO    $-D'3'                  ; Not finished, GOTO here - 3 instructions
        RETURN                          ; Finished, Return
 
GET_TEMP
        CALL    DS18B20_RESET           ; Reset
        MOVLW   H'CC'                   ; Skiprom
        CALL    DS18B20_WRITE_BYTE      ; Skiprom
        MOVLW   H'44'                   ; Convert T
        CALL    DS18B20_WRITE_BYTE      ; Convert T
 
        CALL    DS18B20_READ_BIT        ; Initiate Read Time Slots
        BTFSS   STATUS, C               ; DS18B20 transmits a 0 while the temperature conversion is in progress and a 1 when the conversion is done
        GOTO    $-D'2'                  ; Transmitting 0 therefore NOT done
 
        CALL    DS18B20_RESET           ; Reset
        MOVLW   H'CC'                   ; Skiprom
        CALL    DS18B20_WRITE_BYTE      ; Skiprom
        MOVLW   H'BE'                   ; Read Scratchpad
        CALL    DS18B20_WRITE_BYTE      ; Read Scratchpad
 
        CALL    DS18B20_READ_BYTE       ; Move Scrachpad Byte 0 to W
        MOVWF   TEMPLO_C                ; Store in Celsius TEMPLO GPR
        CALL    DS18B20_READ_BYTE       ; Move Scrachpad Byte 1 to W
        MOVWF   TEMPHI_C                ; Store in Celsius TEMPHI GPR
 
DISPLAY_TEMP	
        BCF     FLAGS, 1                ; Clear Negative Flag
        BTFSS   TEMPHI_C, 7             ; Test if Temperature is negative (2's complement format)
        GOTO    REARRANGE_DATA          ; NOT Negative, skip 'Undo 2's Complement'
        BSF     FLAGS, 1                ; Set Negative Flag; used later
 
 ;  Undo 2's Complement. When the Temperature is Negative, the DS18B20 outputs the 2's Complement. This routine converts the negative data into its positive equivalent
                                        ; Example Negative Temperature            TEMPHI = 1111 1110  TEMPLO = 0110 1110 = -25.1250 (see datasheet)
        COMF    TEMPLO_C, F             ; Invert TEMPLO 
        COMF    TEMPHI_C, F             ; Invert TEMPHI
        INCFSZ  TEMPLO_C, F             ; Increment TEMPLO once; After inverting the data, add one to acheive equivalent positive number (see 2's complement)
        GOTO    $+D'2'                  ; No overflow skip next instruction
        INCF    TEMPHI_C, F             ; Overflow occured, increment upper byte
                                        ; Example Negative Temperature AFTER undo TEMPHI = 0000 0001  TEMPLO = 1001 0010 = +25.1250
 
REARRANGE_DATA ; This routine rearranges the 2 Temperature result bytes into useable data.
 ; EXPLANATION:
 ; * After the DS18B20 finishes a Temperature Conversion, the 12-bit result is stored in two 8-bit 
 ;   registers as a 16-bit sign-extended two?s complement number.
 ; * The 5 MSb's of the MSB (TEMPHI_C) indicate a negative or positive temperature.
 ; * The output data follows this format (12-bit resolution; 0.0625 degrees celsius increments);
 ;
 ;         SSSS SNNN : NNNN FFFF      Where S = Sign (0 = Positive 1 = Negative)
 ;                                          N = Number, &
 ;                                          F = Fraction (16 X 0.0625 increments = 1)
 ;
 ;   After communication with the DS18B20 the output data is held in two 8 bit registers called 
 ;   TEMPHI_C & TEMPLO_C in the following format TEMPHI_C = SSSS SNNN : TEMPLO_C = NNNN FFFF
 ;         
 ;             Example;  0000 0011  1001 0001  =  (D'913' X 0.0625)  =  57.0625 Degrees Celsius
 ;
 ; * This 6 instruction routine below rearranges the 4 nibbles of TEMPHI_C & TEMPLO_C so the data 
 ;   is easy to work with. 
 ; * The MSB (TEMPHI_C) will be used for the 'whole' number i.e. 1's, 10's & 100's digits (57);
 ;   and the LSB (TEMPLO_C) will be used for the decimal digit (.1's) with the upper nibble of the 
 ;   LSB masked. (These are infact the sign bits, but we have already handled negative data and 
 ;   created a Flag (FLAGS, 1) for negative temperatures.
 ;
 ;     Example above, after rearrangement 0011 1001  0000 0001  (see below)
 ;
                                        ; Example before; TEMPHI_C = 0000 0011  TEMPLO_C = 1001 0001   = 57.0625 Degrees Celsius
 
        MOVLW   B'11110000'             ; W = 1111 0000
        ANDWF   TEMPLO_C, W             ; F = 1001 0001  W = 1001 0000
        IORWF   TEMPHI_C, F             ;                F = 0000 0011   F = 1001 0011
        SWAPF   TEMPHI_C, F             ;                                F = 1001 0011   F = 0011 1001 (New TEMPHI_C)
        MOVLW   B'00001111'             ; W = 0000 1111
        ANDWF   TEMPLO_C, F             ; F = 1001 0001  F = 0000 0001 (New TEMPLO_C)
 
                                        ; Example after;  TEMPHI_C = 0011 1001  TEMPLO_C = 0000 0001
                                        ;                 = D'57' (X 1.0) = 57  = D'1' (X 0.0625) = 0.0625  = 57.0625 Degrees Celsius
 
BIN_TO_DEC_C  ; This routine converts the 8-bit number held in TEMPHI_C to Decimal and stores it in 3 GPR's; HUNS, TENS & ONES
 ; Example 225;
 ; HUNS holds amount of hundreds (i.e. 0000 0010 = 2x100)
 ; TENS holds amount of tens (i.e. 0000 0010 = 2x10)
 ; ONES holds amount of ones (i.e. 0000 0101 = 5x1)
 ; These registers are then used as jump pointers when calling digits to display
 
        INCF    TEMPHI_C                ; Preload TEMPHI + 1
        CLRF    HUNS                    ; HUNS = 0000 0000
 
        MOVLW   D'246'                  ; MOVE Decimal'246' to W
        MOVWF   TENS                    ; TENS GPR = 1111 0101
        MOVWF   ONES                    ; ONES GPR = 1111 0101
        DECFSZ  TEMPHI_C, F             ; Decement TEMPHI register
        GOTO    $+D'2'                  ; NOT 0, skip next instruction
        GOTO    $+D'7'                  ; IS 0, TEMPHI = 0000 0000, skip next 6 instructions and calculate how many tens and hundreds
        INCFSZ  ONES, F                 ; Increment ONES register, skip if 0
        GOTO    $-D'4'                  ; NOT 0, GOTO here - 4 instructions
        INCFSZ  TENS, F                 ; IS 0, Increment TENS register skip if 0
        GOTO    $-D'7'                  ; GOTO here - 7 instructions & reset the ONES register to D'246'
        INCF    HUNS, F                 ; TENS overflowed, Increment HUNS
        GOTO    $-D'10'                 ; GOTO here - 10 instructions & reset the ONES and TENS registers to D'246'
 
        SUBWF   TENS, F                 ; W still holds D'246 so subract it from TENS register to determine how many 'TENS'
        SUBWF   ONES, F                 ; W still holds D'246 so subract it from ONES register to determine how many 'ONES'
 
FRACTION_ROUND  ; This routine rounds the fraction portion of the Temperature data to the nearest .1
; Provided by & used with his permission from 'Pommy'. Contact via Electro-Tech-Online.com
; Examples
; TENTHS = Fraction                           * 10 / 16
; TENTHS = 00000100 ( D'4' * 0.0625 = 0.2500 Degrees C) * 10 / 16 = 3
; TENTHS = 00001001 ( D'9' * 0.0625 = 0.5625 Degrees C) * 10 / 16 = 6
; TENTHS = 00001101 (D'13' * 0.0625 = 0.8125 Degrees C) * 10 / 16 = 8
        MOVLW   B'00001111'             ;
        ANDWF   TEMPLO_C, F             ;
        MOVF    TEMPLO_C, W             ;
        ADDWF   TEMPLO_C, F             ; *2, C=0
        RLF     TEMPLO_C, F             ; *4, C=0
        ADDWF   TEMPLO_C, F             ; *5, C=0
        RLF     TEMPLO_C, F             ; *10
        MOVLW   B'00001000'             ; 
        ADDWF   TEMPLO_C, F             ; Rounding
        SWAPF   TEMPLO_C, W             ; Pseudo divide by 16
        ANDLW   B'00001111'             ; 
        MOVWF   DECI                    ; 
 
  ; Leading zero suppression & minus (-) sign if Temperature Negative
        MOVF    HUNS, W                 ; MOVF instruction affects Z bit of STATUS register 
        BTFSC   STATUS, Z               ; Does HUNS = 0? 
        MOVLW   B'00001010'             ; Yes, jump Pointer for blank arrangement
 
        BTFSC   FLAGS, 1                ; Is Temperature Negative?
        MOVLW   B'00001011'             ; Yes, jump Pointer for '-' arrangement
        MOVWF   HUNS                    ; 
 
        BTFSS   STATUS, Z               ; Does HUNS = not 0?
        GOTO    $+D'5'                  ; Yes, do not blank TENS
        MOVF    TENS, W                 ; MOVF instruction affects Z bit of STATUS register 
        BTFSC   STATUS, Z               ; Does TENS = 0? 
        MOVLW   B'00001010'             ; Yes, jump Pointer for blank arrangement
        MOVWF   TENS                    ; 
 
  ; This routine would not be needed if interrupts were disabled for the whole BIN_TO_DEC routine. So this is added to minimise the amount of time interrupts are disabled to minimise flicker. 
        BCF     INTCON, GIE             ; Disable Interrupts
        MOVF    HUNS, W
        MOVWF   THOU_COL
        MOVF    TENS, W
        MOVWF   HUNS_COL
        MOVF    ONES, W
        MOVWF   TENS_COL
        MOVF    DECI, W
        MOVWF   ONES_COL
        BSF     INTCON, GIE             ; Enable Interrupts
 
        GOTO    GET_TEMP
END