1. 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.
    Dismiss Notice

PIC16F628A-Temp sensor-7 Seg Multiplexing issue :(

Discussion in 'Microcontrollers' started by jakeselectronics, May 19, 2010.

  1. jakeselectronics

    jakeselectronics Member

    Joined:
    May 2, 2009
    Messages:
    401
    Likes:
    5
    Location:
    Macedon Ranges, Australia
    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)
     

    Attached Files:

  2. Nigel Goodwin

    Nigel Goodwin Super Moderator Most Helpful Member

    Joined:
    Nov 17, 2003
    Messages:
    39,331
    Likes:
    653
    Location:
    Derbyshire, UK
    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.
     
  3. jakeselectronics

    jakeselectronics Member

    Joined:
    May 2, 2009
    Messages:
    401
    Likes:
    5
    Location:
    Macedon Ranges, Australia
    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 (text):
    MOVF    GPR, W
    CALL    DIGIT_ONES
    : returns a 7,
    then;
    Code (text):
    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 (text):
    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
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA

    Hi Jake,

    You're starting out with a sign extended two's complement 12-bit number formatted like this;
    Code (text):

    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 (text):
    ;********************************
    ;  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: May 21, 2010
  6. dougy83

    dougy83 Well-Known Member

    Joined:
    May 18, 2008
    Messages:
    2,677
    Likes:
    215
    Location:
    Brisbane, Australia
    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 (text):
    ADDWF PCL,f
    maybe something like:
    Code (text):
      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..
     
  7. Nigel Goodwin

    Nigel Goodwin Super Moderator Most Helpful Member

    Joined:
    Nov 17, 2003
    Messages:
    39,331
    Likes:
    653
    Location:
    Derbyshire, UK
    Yes, keep it simple - you only need a table to map the 7 segment bits to your connections.
     
  8. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    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 (text):
    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: May 21, 2010
  9. jakeselectronics

    jakeselectronics Member

    Joined:
    May 2, 2009
    Messages:
    401
    Likes:
    5
    Location:
    Macedon Ranges, Australia
    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.


    Please do, Mike. I would appreciate it.
     
  10. jakeselectronics

    jakeselectronics Member

    Joined:
    May 2, 2009
    Messages:
    401
    Likes:
    5
    Location:
    Macedon Ranges, Australia
    Mike, I am using a PIC16F628A therefore I cannot use instructions SKPNZ, SKPNDC & BC.
     
  11. dougy83

    dougy83 Well-Known Member

    Joined:
    May 18, 2008
    Messages:
    2,677
    Likes:
    215
    Location:
    Brisbane, Australia
    You could try adding the following macros:

    Code (text):
    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: May 20, 2010
  12. jakeselectronics

    jakeselectronics Member

    Joined:
    May 2, 2009
    Messages:
    401
    Likes:
    5
    Location:
    Macedon Ranges, Australia
    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 (text):
    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
     
  13. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    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 (text):

    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 (text):

    ;
    ;  "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: May 21, 2010
    • Like Like x 1
  14. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    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
     
  15. jakeselectronics

    jakeselectronics Member

    Joined:
    May 2, 2009
    Messages:
    401
    Likes:
    5
    Location:
    Macedon Ranges, Australia
    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.
     
  16. jakeselectronics

    jakeselectronics Member

    Joined:
    May 2, 2009
    Messages:
    401
    Likes:
    5
    Location:
    Macedon Ranges, Australia
    Code (text):
    ;  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 (text):
            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
     
  17. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    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 (text):
    ;******************************************************************
    ;*                                                                *
    ;*  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
     
     
    • Like Like x 1
  18. ericgibbs

    ericgibbs Well-Known Member Most Helpful Member

    Joined:
    Jan 4, 2007
    Messages:
    21,240
    Likes:
    645
    Location:
    Ex Yorks' Hants UK
    ONLINE
    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.
     
  19. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    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 (text):
    ;
    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: May 21, 2010
  20. jakeselectronics

    jakeselectronics Member

    Joined:
    May 2, 2009
    Messages:
    401
    Likes:
    5
    Location:
    Macedon Ranges, Australia
    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.

    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 (text):
            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
     

    Attached Files:

  21. ericgibbs

    ericgibbs Well-Known Member Most Helpful Member

    Joined:
    Jan 4, 2007
    Messages:
    21,240
    Likes:
    645
    Location:
    Ex Yorks' Hants UK
    ONLINE
    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: May 21, 2010

Share This Page