I can't think how.There's also no need for multiple tables, the same table can decode each digit.
MOVF GPR, W
CALL DIGIT_ONES
MOVF GPR, W
CALL DIGIT_TENS
MOVF GPR, W
CALL DIGIT_DECIMAL
S = sign bit
I = integer (7-bits, 0..127)
F = fraction (4-bits, X16, .0625 increments)
SSSSSIII IIIIFFFF
;********************************
; main.loop *
;********************************
Loop
call GetTemp ; get new temperature reading
;
; TempHi:TempLo -> BBBBBHHH IIIIFFFF (HHH IIII = Integer 0..125)
;
AbsFunc
bcf negflag ; clear "neg" flag
btfss TempHi,7 ; negative temperature?
goto BinPrep ; no, branch, else
comf TempLo,F ; two's compliment it
comf TempHi,F ;
incf TempLo,F ;
skpnz ;
incf TempHi,F ;
bsf negflag ; indicate "negative"
;
; put the 7-bit Integer temperature (0..127) in WREG and
; leave the 4-bit fraction in TempLo
;
BinPrep
movlw 0xF0 ; W = 11110000
andwf TempLo,W ; W = LLLL0000, F = LLLLFFFF
iorwf TempHi,F ; F = LLLL0HHH
swapf TempHi,W ; W = 0HHHLLLL, 0..125
;
; tens = packed BCD hundreds and tens
; ones = 0..9
;
Bin2Bcd
clrf tens ;
decf tens,F ; preset 'tens' to -1
div10 movwf ones ;
incf tens,F ; bump 'tens', 0x00..0x25
movlw 6 ; using "packed bcd" format
addwf tens,W ; bcd "digit carry"?
skpndc ; no, skip, else
movwf tens ; adjust 'tens'
movlw 10 ; ones = ones - 10
subwf ones,W ; borrow?
bc div10 ; no, branch, else, fall thru'
;
; "tenths" = fraction * 10 / 16
;
movlw 0x0F ;
andwf TempLo,F ;
movf TempLo,W ;
addwf TempLo,F ; *2, C=0
rlf TempLo,F ; *4, C=0
addwf TempLo,F ; *5, C=0
rlf TempLo,F ; *10
swapf TempLo,W ; pseudo divide by 16
andlw 0x0F ;
movwf tenths ;
goto Loop ;
;
Just from reading that, I'd take a wild stab: your tables are crossing 256byte boundaries. You can either align your tables, or calculate the full PC (instead of just PCL):if i physically swap position of the DIGIT_ONES and DIGIT_TENS routines the display does something else.
ADDWF PCL,f
MOVLW tableStart>>8 ; high part of the table start address
MOVWF PCLATH ; THE HIGH PART OF THE PC
ADDWF PCL,W ; CALCULATE JUMP/OFFSET
BTFSS STATUS,C
INCF PCLATH ; ADD THE CARRY
MOVWF PCL ; DO THE JUMP
tableStart:
I think Nigel is suggesting that you use simple math to convert the temperature into decimal "tens", "ones", and "tenths",
segtbl ; map B|A|F|G|E|D|C|P
addwf PCL,F ; |B0
retlw b'11101110' ; "0" B|A|F|-|E|D|C|- |B0
retlw b'10000010' ; "1" B|-|-|-|-|-|C|- |B0
retlw b'11011100' ; "2" B|A|-|G|E|D|-|- |B0
retlw b'11010110' ; "3" B|A|-|G|-|D|C|- |B0
retlw b'10110010' ; "4" B|-|F|G|-|-|C|- |B0
retlw b'01110110' ; "5" -|A|F|G|-|D|C|- |B0
retlw b'01111110' ; "6" -|A|F|G|E|D|C|- |B0
retlw b'11000010' ; "7" B|A|-|-|-|-|C|- |B0
retlw b'11111110' ; "8" B|A|F|G|E|D|C|- |B0
retlw b'11110110' ; "9" B|A|F|G|-|D|C|- |B0
Yes, keep it simple - you only need a table to map the 7 segment bits to your connections.
Ok, I understand that principle.I agree. Once you have simple math that produces 0..9 values for your "hundreds", "tens", "ones", and "tenths" variables, all you need is a single table (array) for the 7-segment data patterns;
Please do, Mike. I would appreciate it.Can I show you an example display driver?
Mike, I am using a PIC16F628A therefore I cannot use instructions SKPNZ, SKPNDC & BC.
SKPNZ macro
BTFSC STATUS,Z
endm
SKPNDC macro
BTFSC STATUS,DC
endm
; branch on carry?
BC macro label
BTFSC STATUS,C
GOTO label
endm
DECIMAL HEXADECIMAL TEMPERATURE-EQUIV NUMBER-TO-DISPLAY
0 0000 0 0
1 0001 0.0625 0.1
2 0010 0.1250 0.1
3 0011 0.1875 0.2
4 0100 0.2500 0.3
5 0101 0.3125 0.3
6 0110 0.3750 0.4
7 0111 0.4375 0.4
8 1000 0.5000 0.5
9 1001 0.5625 0.6
10 1010 0.6250 0.6
11 1011 0.6875 0.7
12 1100 0.7500 0.8
13 1101 0.8125 0.8
14 1110 0.8750 0.9
15 1111 0.9375 0.9
DECIMAL HEXADECIMAL TEMPERATURE-EQUIV TENTHS
0 0000 0 0
1 0001 0.0625 0
2 0010 0.1250 1
3 0011 0.1875 1
4 0100 0.2500 2
5 0101 0.3125 3
6 0110 0.3750 3
7 0111 0.4375 4
8 1000 0.5000 5
9 1001 0.5625 5
10 1010 0.6250 6
11 1011 0.6875 6
12 1100 0.7500 7
13 1101 0.8125 8
14 1110 0.8750 8
15 1111 0.9375 9
;
; "tenths" = fraction * 10 / 16 (Pommie's fraction routine)
;
movlw 0x0F ;
andwf TempLo,F ;
movf TempLo,W ;
addwf TempLo,F ; *2, C=0
rlf TempLo,F ; *4, C=0
addwf TempLo,F ; *5, C=0
rlf TempLo,F ; *10
swapf TempLo,W ; pseudo divide by 16
andlw 0x0F ;
movwf tenths ;
; PUT THE 7-BIT INTEGER TEMPERATURE (0..127) IN WREG AND
; LEAVE THE 4-BIT FRACTION IN TEMPLO
;
BINPREP
MOVLW 0XF0 ; W = 11110000
ANDWF TEMPLO,W ; W = LLLL0000, F = LLLLFFFF
IORWF TEMPHI,F ; F = LLLL0HHH
SWAPF TEMPHI,W ; W = 0HHHLLLL, 0..125
MOVF SCRATCHPAD_BYTE0, W ; MOVE Temperature LSbyte to W
MOVWF TEMP0 ; MOVE W to Temp0 GPR
MOVF SCRATCHPAD_BYTE1, W ; MOVE Temperature MSbyte to W
MOVWF TEMP1 ; MOVE W to Temp0 GPR
RLF TEMP0 ; Roate Data bit 7 of TEMP0 Left into carry
RLF TEMP1 ; Rotate Carry into bit 0 of TEMP1
RLF TEMP0 ;
RLF TEMP1 ; Repeat 4 times until upper nibble of TEMP0
RLF TEMP0 ; is now in lower nibble of TEMP1, and lower
RLF TEMP1 ; nibble of TEMP1 is now in the upper nibble
RLF TEMP0 ; of TEMP1
RLF TEMP1 ;
MOVF SCRATCHPAD_BYTE0, W ; Reload TEMP0 with original Temperature LSbyte
MOVWF TEMP0 ;
MOVLW B'00001111' ; MOVE H'0F' to W
ANDWF TEMP0, F ; Mask upper nibble of TEMP0
;******************************************************************
;* *
;* Filename: 16F628A DS18B20.asm *
;* Author: Mike McLaren, K8LH *
;* Date: 21-May-10 *
;* *
;* *
;* *
;* MPLab: 8.50 (tabs = 8) *
;* MPAsm: 5.35 *
;* *
;******************************************************************
include "P16F628A.inc"
errorlevel -302 ; suppress bank warnings
list st=off ; suppress symbol table
radix dec ; default radix = decimal
__CONFIG _LVP_OFF&_WDT_OFF&_INTOSC_OSC_NOCLKOUT&_MCLRE_OFF
;--< variables >---------------------------------------------------
column equ 0x20 ; column number, 0..2
colsel equ 0x21 ; column select bit
huns equ 0x22 ; huns, 0..1
tens equ 0x23 ; tens, 0..9
ones equ 0x24 ; ones, 0..9
tenths equ 0x25 ; tenths, 0..9
TempLo equ 0x26 ;
TempHi equ 0x27 ;
flags equ 0x28 ;
w_isr equ 0x70 ;
s_isr equ 0x71 ;
p_isr equ 0x72 ;
f_isr equ 0x73 ;
;--< constants >---------------------------------------------------
#define negflag flags,0 ; "negative" flag bit
;******************************************************************
; reset vector *
;******************************************************************
org 0x000
vReset
clrf STATUS ; force bank 0, IRP = 0 |B0
goto Init ; |B0
;******************************************************************
; interrupt vector, 1 msec Timer 2 interrupts *
;******************************************************************
org 0x004
vInt
movwf w_isr ; save WREG |B?
swapf STATUS,W ; don't change STATUS bits |B?
movwf s_isr ; save STATUS reg |B?
clrf STATUS ; bank 0 |B0
movf PCLATH,W ; |B0
movwf p_isr ; save PCLATH |B0
clrf PCLATH ; force page 0 |B0
movf FSR,W ; |B0
movwf f_isr ; save FSR |B0
bcf PIR1,TMR2IF ; clear TMR2 interrupt flag |B0
;
; refresh display
;
clrf PORTB ; blank the display |B0
movf PORTA,W ; |B0
andlw b'11111000' ; clear column select bits |B0
iorwf colsel,W ; 00000100,00000010, or 00000001 |B0
movwf PORTA ; select new column |B0
movf column,W ; column number, 0..2 |B0
addlw tens ; add to 'tens' address |B0
movwf FSR ; FSR = &tens, &ones, or &tenths |B0
movf INDF,W ; WREG = 0..9 |B0
call segtable ; get segment data |B0
btfsc colsel,1 ; 2nd column? no, skip, else |B0
iorlw 1 ; set "decimal point" bit |B0
movwf PORTB ; display new column |B0
;
; prepare for next column interrupt
;
incf column,F ; bump column number |B0
clrc ; |B0
rrf colsel,F ; advance column select bit |B0
skpnc ; last column? no, skip, else |B0
bsf colsel,2 ; reset to column 1 (00000100) |B0
skpnc ; last column? no, skip, else |B0
clrf column ; reset column number |B0
;
; restore context
;
movf f_isr,W ; |B0
movwf FSR ; restore FSR |B0
movf p_isr,W ; |B0
movwf PCLATH ; restore PCLATH |B0
swapf s_isr,W ; |B0
movwf STATUS ; restore STATUS |B?
swapf w_isr,f ; don't change STATUS bits |B?
swapf w_isr,W ; restore WREG |B?
retfie ; |B?
;
; segment data table (caveat, non-boundary tolerant)
;
segtable ; map B|A|F|G|E|D|C|P
addwf PCL,F ; |B0
retlw b'11101110' ; "0" B|A|F|-|E|D|C|- |B0
retlw b'10000010' ; "1" B|-|-|-|-|-|C|- |B0
retlw b'11011100' ; "2" B|A|-|G|E|D|-|- |B0
retlw b'11010110' ; "3" B|A|-|G|-|D|C|- |B0
retlw b'10110010' ; "4" B|-|F|G|-|-|C|- |B0
retlw b'01110110' ; "5" -|A|F|G|-|D|C|- |B0
retlw b'01111110' ; "6" -|A|F|G|E|D|C|- |B0
retlw b'11000010' ; "7" B|A|-|-|-|-|C|- |B0
retlw b'11111110' ; "8" B|A|F|G|E|D|C|- |B0
retlw b'11110110' ; "9" B|A|F|G|-|D|C|- |B0
;******************************************************************
; main.init *
;******************************************************************
Init
bsf STATUS,RP0 ; bank 1 |B1
clrf TRISA ; porta all outputs |B1
clrf TRISB ; portb all outputs |B1
bcf STATUS,RP0 ; bank 0 |B0
clrf PORTB ; clear portb output latches |B0
;
; init program variables
;
clrf column ; column = 0 (1st column) |B0
movlw b'00000100' ; column select bit mask |B0
movwf colsel ; |B0
clrf tens ; |B0
clrf ones ; |B0
clrf tenths ; |B0
clrf TempLo ; |B0
clrf TempHi ; |B0
;
; setup TMR2 for 1 msec periodic interrupts (4 MHz clock)
;
clrf TMR2 ; clear TMR2 register |B0
bsf STATUS,RP0 ; bank 1 |B1
clrf PIE1 ; mask all peripheral irqs |B1
bsf PIE1,TMR2IE ; except for TMR2 irq |B1
bcf STATUS,RP0 ; bank 0 |B0
clrf PIR1 ; clear peripheral irq flags |B0
movlw b'00000001' ; '00000001' |B0
; '0-------' unused
; '-0000---' postscale 1
; '-----0--' TMR2 off
; '------01' prescale 4
movwf T2CON ; for 4-usec ticks (4-MHz clk) |B0
bsf STATUS,RP0 ; bank 1 |B1
movlw d'250'-1 ; 250 X 4-usec ticks = 1-msec |B1
movwf PR2 ; for 1-msec interrupts |B1
bcf STATUS,RP0 ; bank 0 |B0
bsf INTCON,GIE ; enable global irqs |B0
bsf INTCON,PEIE ; enable peripheral irqs |B0
bsf T2CON,TMR2ON ; start TMR2 |B0
;******************************************************************
; main.loop *
;******************************************************************
Loop
;
; dummy GetTemp code puts 22.0°C value in TempHi:TempLo vars
;
movlw 0x0B ; |B0
movwf TempHi ; |B0
movlw 0x00 ; |B0
movwf TempLo ; |B0
;
; TempHi:TempLo -> BBBBBHHH IIIIFFFF (HHH IIII = Integer 0..125)
;
AbsFunc
bcf negflag ; clear "neg" flag |B0
btfss TempHi,7 ; negative temperature? |B0
goto BinPrep ; no, branch, else |B0
comf TempLo,F ; two's compliment it |B0
comf TempHi,F ; |B0
incf TempLo,F ; |B0
skpnz ; |B0
incf TempHi,F ; |B0
bsf negflag ; indicate "negative" |B0
;
; put the 7-bit Integer temperature (0..127) in WREG and
; leave the 4-bit fraction in TempLo
;
BinPrep
movlw 0xF0 ; W = 11110000 |B0
andwf TempLo,W ; W = LLLL0000, F = LLLLFFFF |B0
iorwf TempHi,F ; F = LLLL0HHH |B0
swapf TempHi,W ; W = 0HHHLLLL, 0..125 |B0
;
; 8-bit binary to 3 digit half-packed BCD (isochronous)
;
; input: WREG, 0..255 (0x00..0xFF)
; output: huns, 0..2
; tens, 0..9
; ones, 0..9
;
clrf huns ; |B0
clrf tens ; |B0
addlw -200 ; W = W - 200 |B0
rlf huns,F ; pick up Carry result |B0
btfss huns,0 ; borrow? no, skip, else |B0
addlw 200 ; add 200 back |B0
addlw -100 ; subtract 100 |B0
rlf huns,F ; pick up Carry result |B0
btfss huns,0 ; borrow? no, skip, else |B0
addlw 100 ; add 100 back |B0
addlw -80 ; |B0
rlf tens,F ; |B0
btfss tens,0 ; |B0
addlw 80 ; |B0
addlw -40 ; |B0
rlf tens,F ; |B0
btfss tens,0 ; |B0
addlw 40 ; |B0
addlw -20 ; |B0
rlf tens,F ; |B0
btfss tens,0 ; |B0
addlw 20 ; |B0
addlw -10 ; |B0
rlf tens,F ; |B0
btfss tens,0 ; |B0
addlw 10 ; |B0
movwf ones ; |B0
;
; "tenths" = fraction * 10 / 16
;
movlw 0x0F ; |B0
andwf TempLo,F ; |B0
movf TempLo,W ; |B0
addwf TempLo,F ; *2, C=0 |B0
rlf TempLo,F ; *4, C=0 |B0
addwf TempLo,F ; *5, C=0 |B0
rlf TempLo,F ; *10 |B0
swapf TempLo,W ; pseudo divide by 16 |B0
andlw 0x0F ; |B0
movwf tenths ; |B0
goto Loop ; |B0
;******************************************************************
; subroutines *
;******************************************************************
;******************************************************************
end
You're entitled to be as picky as you like (lol).I have just stepped through Pommie's fraction routine with pen and paper putting a 111 in templo, and i got 4 as the answer and i must say, how on earth did he come up with that!
It's pretty dam good.
I would be better if it rounded more accurately but when the DS18B20 only guarantees +/-.5 degrees accuracy I should stop being so anal and picky!
It's very nice work.
;
fracdigit
andlw 0x0F ;
addwf PCL,F ;
retlw 0 ; 0.0000 -> 0
retlw 1 ; 0.0625 -> 1
retlw 1 ; 0.1250 -> 1
retlw 2 ; 0.1875 -> 2
retlw 3 ; 0.2500 -> 3
retlw 3 ; 0.3125 -> 3
retlw 4 ; 0.3750 -> 4
retlw 4 ; 0.4375 -> 4
retlw 5 ; 0.5000 -> 5
retlw 6 ; 0.5625 -> 6
retlw 6 ; 0.6250 -> 6
retlw 7 ; 0.6875 -> 7
retlw 8 ; 0.7500 -> 8
retlw 8 ; 0.8125 -> 8
retlw 9 ; 0.8750 -> 9
retlw 9 ; 0.9375 -> 9
hi Jake,
Ref the program you posted.
When your program CALLs DIGIT_TENS, the ADDWF PCL,F sends it straight to CALL REARRANGE_RESULT, it does this 6 times then the STACK over flows.
I suspect you .................
Regards, Mike
MOVLW B'00011001' ; LOAD DUMMY DECIMAL 25
MOVWF TEMP_HI
BIN_2_DEC
CLRF TENS ; TENS GPR = 0000 0000
MOVLW D'245' ; MOVE Decimal'245' to W
MOVWF ONES ; Store in ONES GPR (I would end up moving this register to ONES register anyway so here I'm using it as a 'count up' register
BCF STATUS, Z ; Clear Zero bit of STATUS register
INCF ONES, F ; Effects Zero bit, therefore we can test if Zero
BTFSC STATUS, Z ; Test Zero bit if Zero
GOTO $+6 ; IS 0, INCrement TENS register which represents 10 per increment. Will use this to CALL table
BCF STATUS, Z ; NOT 0
DECF TEMP_HI, F ;
BTFSC STATUS, Z ;
GOTO ONES_ ; IS 0
GOTO $-D'8' ; NOT 0 BCF STATUS, Z
INCF TENS, F ;
GOTO $-D'12' ; NOT 0 MOVLW D'246'\
ONES_
MOVLW D'245'
SUBWF ONES, F
BLANK_TENS_IFZERO
BCF STATUS, Z
INCF TENS, F
DECF TENS, F
BTFSS STATUS, Z
GOTO $+3
MOVLW B'00001010'
MOVWF TENS
MULTIPLEX_DISPLAYS
MOVF ONES, W ; MOVE Temperature MSbyte to W
CALL TABLE ; CALL routine to obtain 1's digit
MOVWF PORTB ; MOVE result to PORTB
BSF PORTB, 0 ; DP ON (because DP is apart of the 1's 7 segment digit)
BSF PORTA, 1 ; Activate Ones Digit
GOTO $+1 ; Time wasting to maintain constant brightness when multiplexing
BCF PORTB, 0 ; DP OFF
BCF PORTA, 1 ; Deactivate Ones Digit
GOTO $+1 ; Time wasting to maintain constant brightness when multiplexing
MOVF TENS, W ; MOVE Temperature MSbyte to W
CALL TABLE ; CALL routine to obtain 10's digit
MOVWF PORTB ; MOVE result to PORTB
NOP ; Time wasting to maintain constant brightness when multiplexing
BSF PORTA, 2 ; Activate Tens Digit
GOTO $+1 ; Time wasting to maintain constant brightness when multiplexing
NOP ; Time wasting to maintain constant brightness when multiplexing
BCF PORTA, 2 ; Deactivate Tens Digit
GOTO MULTIPLEX_DISPLAYS ; Loop
TABLE ; This routine assigns on/off arrangement to the 7 Segment Display FOR THE .1'S COLUMN!
ADDWF PCL, F
; BAFGEDCx BINARY Temp Rounded Temp
RETLW B'11101110' ; 0000 0.0000 0.0
RETLW B'10000010' ; 0010 0.1250 0.1
RETLW B'11011100' ; 0011 0.1875 0.2
RETLW B'11010110' ; 0101 0.3125 0.3
RETLW B'10110010' ; 0110 0.3750 0.4
RETLW B'01110110' ; 1000 0.5000 0.5
RETLW B'01111110' ; 1010 0.6250 0.6
RETLW B'11000010' ; 1011 0.6875 0.7
RETLW B'11111110' ; 1101 0.8125 0.8
RETLW B'11110110' ; 1111 0.9375 0.9
RETLW B'00000000' ; BLANK
RETURN
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?