Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC16F628A-Temp sensor-7 Seg Multiplexing issue :(

Status
Not open for further replies.
I had my wisdon teeth out friday and saw it as a great oportunity to get stuck into making a Thermometer on my week off.

I am 99% there. I have a somewhat 'simple' but MASSIVELY confusing issue and I cannot rectify it.
Please help.

My situation:
I read the datasheet for the DS18B20 direct to digital Temperature Sensor over & over & over & over & over while waiting for the part to arrive.
Getting my head around Dallas's "1-Wire" communication was a challenge, but I grasped it and start coding.

The part arrived, Built the circuit, smoothed out some bugs and its working. To an extent.

I have tested the timing and communication with the Temp Sensor and am reading data from it sucesfully.

I am using 12-bit resolution as I want to have the display display to 1 decimal place. i.e, 25.4
12-bit resolution gives increments of 0.0625 degrees C. Which i can round to the neartest .1 of a degree.

MY DILEMA comes when trying to display the number on a 3 digit 7 Segment display which I am multiplexing.
I am Calling 3 Tables, 1 for each of the digits of the display.

I have tried everything I can think of and want to ask someone to check it out.
The assembly code is heavily commented to show what I am trying to do.
The display only display the 2 LS digits, then if i physically swap position of the DIGIT_ONES and DIGIT_TENS routines the display does something else.

(The code is too long to paste here so I have placed it here, click to view. PIC16F628A - DS18B20 Digital Thermometer)
 

Attachments

  • Schematic.jpg
    Schematic.jpg
    140 KB · Views: 1,166
I would suggest you multiplex the displays using a timer interrupt, which makes the process totally transparent.

If you check my tutorials, there are two that do this - the double 7 segment one, and the 8x8 LED matrix.

There's also no need for multiple tables, the same table can decode each digit.
 
There's also no need for multiple tables, the same table can decode each digit.
I can't think how.

Let me explain what i'm doing at the moment.
I am using 1 8-bit GPR and using that when calling both the one's and ten's digit tables.
Thing is, the 8 bits are the MSB's of a 12 bit number where each bit represents .0625 of a degree.
i.e, 0011 1001 0001 ; 913 x .0625 = 57.0625°C
(GPR = 0011 1001)
Code:
MOVF    GPR, W
CALL    DIGIT_ONES
: returns a 7,
then;
Code:
MOVF    GPR, W
CALL    DIGIT_TENS
: returns a 5.

And the same for the .1's DIGIT;
I MOVe the 4 LSB's of the 12-bit number into its own register, and mask the upper 4 bits, then use that when calling the DIGIT_DECIMAL routine.
i.e, (GPR = 0000 0001)
Code:
MOVF    GPR, W
CALL    DIGIT_DECIMAL
: returns a 1 (to display after the decimal point; 0.0625 rounded up to nearest number)

So how would you use only 1 table?
From a 12-bit number (0.0625 degree resolution) to a 2 digit + 1 decimal place display
 
Hi Jake,

You're starting out with a sign extended two's complement 12-bit number formatted like this;
Code:
S = sign bit
I = integer (7-bits, 0..127)
F = fraction (4-bits, X16, .0625 increments)

SSSSSIII IIIIFFFF
I think Nigel is suggesting that you use simple math to convert the temperature into decimal "tens", "ones", and "tenths", something like this perhaps;
Code:
;********************************
;  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            ; 
;
Now with "tens" (packed BCD "hundreds" and "tens"), "ones", and "tenths" variables containing decimal values of 0..9, use an interrupt driven display driver to refresh the displays from those variables entirely in the background. Can I show you an example display driver?

Regards, Mike
 
Last edited:
if i physically swap position of the DIGIT_ONES and DIGIT_TENS routines the display does something else.
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):
instead of
Code:
ADDWF PCL,f
maybe something like:
Code:
  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:

Sorry my assembler's very rusty..
 
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;

Code:
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
 
Last edited:
Yes, keep it simple - you only need a table to map the 7 segment bits to your connections.
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;
Ok, I understand that principle.
My assembly skills are just short or doing the 'simple math'.
but I will step through Mike's example code a couple of posts above and write down what each code does so i cant get my head around it.
I think this way is possibly a much better way than using 3 tables.


Can I show you an example display driver?
Please do, Mike. I would appreciate it.
 
Mike, I am using a PIC16F628A therefore I cannot use instructions SKPNZ, SKPNDC & BC.

You could try adding the following macros:

Code:
SKPNZ macro
   BTFSC STATUS,Z
   endm

SKPNDC macro
   BTFSC STATUS,DC
   endm

; branch on carry?
BC macro label
    BTFSC STATUS,C
    GOTO label
    endm
 
Last edited:
So can you/anyone explain, in words (not code, i will do it once i have a way) how to use simple math to acheive the coversion for the 'fraction' nibble.(4xLSB of 12-bit number)

So, the hex number in the table below is the lower nibble of the TempLo register, the equivelent temp in the next column. how can i use simple math to convert the hex number to the corresponding number to display, so i can use that to call a table with the 7 segement arrangement in it?


Code:
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
 
Jake,

If you haven't done so already, may I suggest you learn how to use the MPLAB "simulator" and "watch" window. If you simulate the small section of code from my earlier listing you'll see that it produces the following "tenths" values from the four fraction bits in "templo";

Code:
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
Code:
;
;  "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          ;
I should mention that those 37 lines of code in my previous post are the entire main program loop. The only things missing are the display driver interrupt routine, your GetTemp subroutine that puts data in TempHi:TempLo, and your program initialization code.

I apologize. The "skpz" (skip zero), "skpnz" (skip not zero), "skpc" (skip carry), "skpnc" (skip not carry) instructions are assembler pseudo opcodes which you can find in <help><mpasm assembler>. They produce "btfss STATUS,x" or "btfsc STATUS,x) instructions when compiled. I find them more intuitive then the bit test instructions.

I'm workin' on an example display driver for you Sir.

Regards, Mike
 
Last edited:
Jake,

I apologize again. I just realized that you are 'stepping' through the code but you're lookin' for an explanation of what that little routine is doing.

That brilliant little routine came from Mike (Pommie) and I'm afraid I just don't have the skills to explain the math very well. Basically he came up with a few lines of code to deal with a 4-bit "whole" or "integer" value which is actually representing 1/16ths.

Regards, Mike
 
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.
 
Code:
;  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


Did you see my version of the above routine of yours....
Code:
        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

I like yours better haha
 
I suspect you haven't played with interrupts very much yet so this example program may seem very alien to you at first.

There's an initialization section that sets up Timer 2 interrupts and then there's the actual ISR (interrupt service routine). The code at the beginning and end of the ISR simply saves and restores main program context (WREG, STATUS, FSR, etc.). The code in-between is the display driver code and it uses two variables, "column" and "colsel", to help reduce ISR "overhead". The "column" variable contains a value of 0, 1, or 2 and we use it as an index to indirectly access the "tens", "ones", or "tenths" variables which must be located sequencially in RAM memory. The "colsel" variable is a column select bit mask with a value of '00000100' (RA2), '00000010' (RA1), or '00000001' (RA0) that we use to select or turn on a column (digit).

The (untested) example program is complete except for your DS18B20 "one-wire" routines to read the temperature. I've inserted "dummy" code that puts the 12-bit value for 22.0°C into the TempHi:TempLo variable.

We will try to help with any questions you may have.

Regards, Mike

Code:
;******************************************************************
;*                                                                *
;*  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
 
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 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.
You're entitled to be as picky as you like (lol).

Easiest way to get the rounded decimal values you want is to probably just use a 16 element lookup table using the 0..15 fraction as the index.

Regards, Mike

Code:
;
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
 
Last edited:
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.

that makes sense becasue the ONES and DECIMAL display but the TEN column did not. Thanks for that.

I have scapped that idea of using long tables, its a bad idea to begin with.

I suspect you .................

Regards, Mike

Thanks verrry much for that.
I have used interrupts and timers, but only once or twice.

While you were working on that, i was trying to put together a BIN to DEC routine and just finished it. colin55 gave me the idea (thanks col) of decrementing the binary number and counting how many times it goes past 10, then saving the left overs in the ones wreg.

i wanted this project to have some of my own code in it at least haha.
here it is below, and with pommie's permission i will steal his fraction routine, and with your permission use your interrupt routine and 12-bit shuffle routine that was about 3.5 times as short as my attempt.
I think I have everything to put it all together. Big cut and paste job now lol... I will post my result be it good or disarterous :D

... i didnt finish commentint it, its 3 am, im going to bed lol. but it works. see attatchment
Code:
        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
 

Attachments

  • DSC07506.JPG
    DSC07506.JPG
    152.4 KB · Views: 237
hi Jake,
All thats required for the 12bit conversion into decimal is this.
Instead of multiplying the 12bit number by 0.0625,have you considered multiplying the 12number by 10d and dividing by 16d [inverse of 0.0625]
Taking your example of 0x391 from your program, times 0x0a = 0x23AA divide by 0x10, gives 570, residual 6.

A standard 16bit to ASCII [or Decimal] will convert this hex number to use as pointers for a single Table, 0 thru 9
 
Last edited:
Status
Not open for further replies.

Latest threads

Back
Top