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.
As I said before, you don't have to convert bin to decimal. Just decrement the file and incr the table pointer file.

You can use one routine that shifts the file 4 places right, (stores the result) masks to leave the 4 lowest bits, decrements the file and increments a table pointer, call the table and output the value.
Call a delay and clear the display.
Call the routine again and increment to the next display.
Repeat 3 times and you have a scan routine as well as a conversion routine.
 
Last edited:
If I'm using a timer interrupt, and need to execute time crucial routines in the normal program (non ISR)...
Is it better at the begining of the time crucial routine to stop the timer, and start it again after the routine is finished, or is it better to mask interrupts during the routine.

If the latter, if the timer overflows during the routine, will the program still be interrupted when the interrupts are once again enabled?

Does this make sense?
 
im missing something. wheres 0x391
As this program/system will display temperature to 1 decimal place, the lower nibble of the LSbyte
; is used for the decimal number, (xxxxxxxx xxxx0000). While the upper nibble of the LSbyte and the
; lower nibble MBbyte are used for the whole number, (xxxx0000 0000xxxx).
; Note that 12-bit resolution gives increments of 0.0625�C per bit
;
; Example, 0000 0011 1001 0001 ; 913 x .0625 = 57.0625�C
; (MS byte) (LS byte)
;

hi Jake,
0000 0011 1001 0001 binary is 0x0391. [decimal 913]
 
I thought you were referring to the post above that where i loaded a dummy 25.0... I didnt read your post clearly, sorry my mistake.

No problem.
Did you follow what I was suggesting in my post regarding the 'times 0x0a' and then divide by '0x10'
 
Last edited:
Yes, I understood the principle but had already written a routine to do the conversion.
It's working and although its probably twice as long as your X 10 / 16 idea, i'm proud of it a dont want to go through that again.
But I will use it next time I think.

This is what I finished up with to get a 2 Digit Deciaml number. NO 100's... need another routine to over when 10's = 10
Code:
REARRANGE_RESULT  ; This routine rearranges the 2 Temperature result bytes into useable data
; After the DS18B20 finishes a Temperature Conversion, the 12-bit result is stored in two 8-bit 
; registers. Providing the temperature is a positive number (in Degrees C) the upper nibble of the 
; MSbyte (SCRATCHPAD_BYTE1) will always be 0000. (0000xxxx xxxxxxxx)
; As this program/system will display temperature to 1 decimal place, the lower nibble of the LSbyte
; is used for the decimal number, (xxxxxxxx xxxx0000). While the upper nibble of the LSbyte and the 
; lower nibble MBbyte are used for the whole number, (xxxx0000 0000xxxx). 
; Note that 12-bit resolution gives increments of 0.0625°C per bit
;
;                     Example, 0000 0011  1001 0001 ;    913 x .0625 = 57.0625°C 
;                              (MS byte)  (LS byte)
;
; So, this routine re-arranges the nibbles of both bytes so that tables can be used to obtain 
; numbers to display.
; i.e. The MSbyte is used for the 1's and 10's digit (57), and the LSbyte is used for the rounded
; decimal digit (.1)
; Note that the upper nibble of the LSbyte is masked. 
;
;     Data after rearrangement 0011 1001  0000 0001  
;                              (MS byte)  (LS byte)
;
        MOVF    SCRATCHPAD_BYTE0, W     ; MOVE Temperature LSbyte to W
        MOVWF   TEMPLO                  ; MOVE W to Temp0 GPR
        MOVF    SCRATCHPAD_BYTE1, W     ; MOVE Temperature MSbyte to W
        MOVWF   TEMPHI                  ; MOVE W to Temp0 GPR
                                        ; EXAMPLE, TEMPHI = 0000 0001  TEMPLO = 1001 0001
        MOVLW   0XF0                    ; W = 1111 0000
        ANDWF   TEMPLO, W               ; F = 1001 0001   W = 1001 0000,
        IORWF   TEMPHI, F               ; F = 0000 0001   F = 1001 0001
        SWAPF   TEMPHI, F               ; F = 1001 0001   F = 0001 1001=TEMPHI
        MOVLW   0X0F                    ; W = 0000 1111
        ANDWF   TEMPLO, F               ; W = 1001 0001   F = 0000 0001=TEMPLO
        
        
HOW_MANY_TENS  ; This routine counts how many 10's are in the TEMPHI register
        INCF    TEMPHI                  ; Preload TEMPHI + 1
        CLRF    TENS                    ; TENS GPR = 0000 0000
        MOVLW   D'246'                  ; MOVE Decimal'246' 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 
        DECF    TEMPHI, F               ; DECement TEMPHI register
        BTFSC   STATUS, Z               ; Test Zero bit if Zero to see if last instruction = 0000 0000
        GOTO    HOW_MANY_ONES           ; IS 0, number less than 10 so GOTO HOW_MANY_ONES to count the ones
        BCF     STATUS, Z               ; Clear Zero bit of STATUS register 
        INCF    ONES, F                 ; Effects Zero bit, therefore we can test if Zero. Remember, using ONES GPR as a countup register for now
        BTFSS   STATUS, Z               ; Test Zero bit if Zero to see if last instruction = 0000 0000
        GOTO    $-D'7'                  ; NOT 0, GOTO here - 7 instructions
        INCF    TENS, F                 ; INCrement TENS register which represents 10 per increment. Will use this to CALL table
        GOTO    $-D'11'                 ; TENS INCremented in previous instruction, GOTO here - 11 instructions

HOW_MANY_ONES  ; This routine counts how many 1's are in the TEMPHI register
        MOVLW   D'246'                  ; Because the ONES register is preloaded with D'246' to begin with & then INCremented every time TEMPHI is DECremented, we can
        SUBWF   ONES, F                 ; simply SUBtract D'246' from the ones register to see how many ones are left over, then use this when calling the table
		                                ; TENS holds amount of tens (i.e. 0000 0010 = 2x10) ONES holds amount of ones (i.e. 0000 0101 = 5x1)

So that is the shuffle/ rearrange 12 bit number routine and binary to decimal routine. the very last comment explains the output.

out of curiosity how many instructions roughly would your x10 /16 routine take?
 
hi,
out of curiosity how many instructions roughly would your x10 /16 routine take?

A 16*8 subr is here, 69 cycles and the divide by 16 is shift Right's.



The attached asm fragment shows the binary to decimal convert for a '0 to 9' segment Table.
 

Attachments

  • jake2.asm
    1.5 KB · Views: 192
I have more problems!!

So I got my Temp sensor fully working, without interrupts (interrupt to used as a display driver/refresher for the multiplexed 7 segment later on)
I even added a 100's column to display the temp to the top end of the range and also worked out how to interpet negative figures (invert + 1, anyone who has used one of these will probably know what i mean).
The 100's column digit also displays a - sign when the temp is in negative.
So I am reading and interpreting temperatures of the the DS18b20's full range.

So at the moment I have a routine that multiplexes the display in the normal program loop with some delays thrown in there so its visible.
The program executes as follows;
- Temperature is read from the Dallas DS18B20 and stored in the SCRATCHPAD_BYTE0 and SCRATCHPAD_BYTE1 GPR's

- Then the data is interpretted, determined whether neg or pos, shuffled around and stored in TEMPHI and TEMPLO GPRS as a positive number

- The data is then converted to binary (BIN_TO_DEC routine) with the result in the following format;
; HUNS GPR holds amount of hundreds (i.e. 0000 0010 = 2x100), TENS GPR holds amount of tens (i.e. 0000 0010 = 2x10) & ONES GPR holds amount of ones (i.e. 0000 0101 = 5x1)

- Then the HUNS and TENS are blanked if zero OR if negative temp a - sign is placed in the HUNS. (BLANK_IF_ZERO routine) *Note that the numebrs in the HUNS TENS ONES and TENTHS gpr's are jump pointers for the 2 tables.

- I then have a routine called LOAD_ARRANGEMENTS. what this does is call the table using the jump pointers in the HUNS TENS ONES and TENTHS, and returns and stores the 7 segment arrangement for the corresponding column in the HUNS_ARRANGEMENT, TENS_ARRANGEMENT, ONES_ARRANGEMENT and TENTHS_ARRANGEMENT so that these registers can be used later in the ISR so I wont need to call tables in the ISR.

- Then, temporarily, (while no ISR) i have a multiplex routine that moves xxx_ARRANGEMENT to PORTB and momentarily enables the appropriate segment display.

Then the whole program loops and it works perrrfectly.

So then I wanted to use interrupts to drive the multiplexed display.
I am using timer2 interrupts to interrupt the program.
I tried tweeking, (and It looks good to me) Mikes (Mike, K8LH) routine from above that uses Indirect Addressing to get the xxx_ARRNGEMENTS (HUNS, TENS....) from the RAM (they are in sequencial order starting at 0x20.

But it didn't work.

Now to back track, i commented out the tmr2 interrupt setup, and all the enable and disable GIE bits there were, plus i brought back my temporary multiplex routine and tried again.
and it still did weird things.

Now, at this stage, I have NOTHING that should be interrupting the program and making it jump the the intterrupt vector address but I know it is becasue I placed a goto instruction telling the program to goto the very bottom of the program where I have set some indictors to let me know if the program is there (simply lights up the 7 segment display). but when I comment out the rest of the ISR and leave the GOTO, it works.

It is like there is something in the ISR that make the program jump to the ISR because when the ISR's not there it works fine.

So here's the program (its to big to paste here) PIC16F628A - DS18B20 Digital Thermometer
I've got the tmr2 comment out, and am using a temporary multiplex routine to display the temp.
It doesnt work but as soon as I coment out the ISR it works.
But I shouldn't have anything in the program that make it go to the ISR.
even if i stick a BCF INTCON,GIE at the top. same thing happens.

Any ideas?
 
Hi Jake,

You really should take time to learn how to use the MPLAB simulator and watch window.

Look at the .LST file to see where your two tables are located. Move them to the beginning of program memory space after the interrupt vector so that they sit in the first 256 words of program memory space.

Also found one mistake in your ISR.

Cheerful regards, Mike
 
I know I know, I really need to learn how to properly use mplab, I will make it a priority.

Also found one mistake in your ISR.
yeah......
Are you just going to leave me hanging :D haha
Would you be so kind and share it with me please....
 
Well, you disabled interrupts so I thought you were more concerned with your 'runaway' program which I suspect is a PCLATH problem with your tables.

First ISR problem. If you have segment data in the "arrangement" array then I think you want to use the address of HUNS_ARRANGEMENT as your base array address, don't you?

Code:
; Refresh display
        CLRF    PORTB                   ; Blank the display
        MOVF    PORTA, W                ; MOVE PORTA's current state to W
        ANDLW   B'11110000'             ; Clear ONLY Column Select Bits & leave upper nibble unchanged
        IORWF   COLSEL, W               ; Inclusive OR above with COLSEL register
        MOVWF   PORTA                   ; Leave upper nibble of PORTA unchanged & select new Column
                
        MOVF    DIGIT, W                ; Column number, 0..3
        [COLOR=Red]ADDLW   HUNS_ARRANGEMENT[/COLOR]        ; Add to 'HUNS_ARRANGEMENT' address
        MOVWF   FSR                     ; FSR = HUNS + 0forHUNS, 1forTENS, 2forONES & 3forTENTHS as they are in sequencial order in RAM
        MOVF    INDF, W                 ; W register now holds 7 Segment arrangement for corresponding digit
        
        BTFSC   COLSEL, 1               ; Are we display ONES Column
        IORLW   B'00000001'             ; YES, so display deciaml point
        MOVWF   PORTB                   ; NO, hide deciaml point and display new column
Second ISR problem. The DIGIT column select variable should contain '00001000' (1st column), or '00000100' (2nd column), or '00000010' (3rd column), or '00000001' (4th column) so when you advance the bit by shifting right you can test for "last column" by testing the Carry flag bit in the STATUS register.
Code:
; Prepare for next column interrupt
        BCF     STATUS, C               ; Clear C bit of STATUS register
        RRF     COLSEL, F               ; Advance column select bit       
        INCF    DIGIT, F                ; INCrement Digit jump pointer (used when indirect addressing above)
        [COLOR=Red]BTFSS   STATUS,C[/COLOR]                ; Was that the last column?   
        GOTO    $+4                     ; NO, do not reset DIGIT and COLumnSELect
        CLRF    DIGIT                   ; Reset Digit jump pointer
[COLOR=Red];       CLRF    COLSEL                  [/COLOR][COLOR=Red]; Clear COLumnSELect  <- unneccessary, COLSEL already 0[/COLOR]
        BSF     COLSEL, 3               ; Reset COLumnSELect to Hundreds column 1 (00001000)
Now that you're using four columns you can simplify that last section of code a bit;
Code:
; Prepare for next column interrupt
        [COLOR=RoyalBlue]INCF    DIGIT, F                ; INCrement Digit jump pointer (used when indirect addressing above)
        BCF     DIGIT,2                 ; range 0..3, inclusive (pseudo DIGIT = DIGIT % 4)
        BCF     STATUS, C               ; Clear C bit of STATUS register
        RRF     COLSEL, F               ; Advance column select bit       
        [/COLOR][COLOR=RoyalBlue]BTFSC   STATUS,C                ; shifted last column bit into Carry? no, skip, else
        BSF     COLSEL, 3               ; Reset COLumnSELect to Hundreds column 1 (00001000)  [/COLOR]
 
Last edited:
Only just caught up with this thread. However, if anyone wants an explanation of how that fractional code works I'll write one up. It's actually quite simple.

If you want it to do proper rounding then you need to add the equivalent of 0.5 in 4.4 format.
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
        [COLOR="red"]movlw   8               ;=0.5 in 4.4 format
        addwf   TempLo,F        ;add it[/COLOR]  
        swapf   TempLo,W        ; pseudo divide by 16
        andlw   0x0F            ;
        movwf   tenths          ;

Mike.
 
Jake,

Here's my (untested) version of your program if you're interested. Four digits with 'rounding', "minus" sign, leading zero suppression, and a reasonably compact version of the "one-wire" routines Mike (Pommie) and I came up with awhile ago. Some 215 words of progam memory and 16 bytes of RAM in all.

Cheerful regards, Mike

<> fixed a couple errors in the program listing
 

Attachments

  • 16F628A DS18B20.txt
    19.4 KB · Views: 232
Last edited:
Code:
        MOVF    DIGIT, W                ; Column number, 0..3
        ADDLW   [COLOR="red"]HUNS_ARRANGEMENT[/COLOR]        ; Add to 'HUNS_ARRANGEMENT' address
        MOVWF   FSR                     ; FSR = HUNS + 0forHUNS, 1forTENS, 2forONES & 3forTENTHS as they are in sequencial order in RAM
        MOVF    INDF, W                 ; W register now holds 7 Segment arrangement for corresponding digit
I originally had this: which was right (as 0x20 is the location for HUNS_ARRANGEMENT) but changed it to a lable and changed it incorectly.
Code:
        MOVF    DIGIT, W                ; Column number
        ADDLW   [COLOR="red"]0x20[/COLOR]                    ; Add to 'HUNS' GPR address
        MOVWF   FSR                     ; FSR = HUNS + 0forHUNS, 1forTENS, 2forONES & 3forTENTHS as they are in sequencial order in RAM
        MOVF    INDF, W                 ; W register now holds 7 Segment arrangement for corresponding digit
Ok, so thats fixed.



And my advance routine:
Even though longer than need be, It should've still worked.
Tesing the 3rd bit of DIGIT reg will tell the program when to reset DIGIT and COLSEL. (when DIGIT = 0000 0100 = 4 = too many, reset.) shown below;
Code:
;  ; Prepare for next column interrupt
        BCF     STATUS, C               ; Clear C bit of STATUS register < not needed
        RRF     COLSEL, F               ; Advance column select bit       
        INCF    DIGIT, F                ; INCrement Digit jump pointer (used when indirect addressing above)
        BTFSS   DIGIT, 3                ; Was that the last column?   
        GOTO    $+4                     ; NO, do not reset DIGIT and COLumnSELect
        CLRF    DIGIT                   ; Reset Digit jump pointer
        CLRF    COLSEL                  ; Clear COLumnSELect register
        BSF     COLSEL, 3               ; Reset COLumnSELect to Hundreds column 1 (00001000)
But I have changed it to use your routine , which is shorter, but that shouldn't have been an issue.
Code:
        INCF    DIGIT, F                ; INCrement Digit jump pointer (used when indirect addressing above)
        BCF     STATUS, C               ; Clear C bit of STATUS register
        RRF     COLSEL, F               ; Advance column select bit       
        BTFSS   STATUS,C                ; Was that the last column? (or, Is Carry Flag Set?)  
        GOTO    $+3                     ; NO, do not reset DIGIT and COLumnSELect
        CLRF    DIGIT                   ; Reset Digit jump pointer
        BSF     COLSEL, 3               ; Reset COLumnSELect to Hundreds column 1 (00001000)
so thats fixed.
(and that shorter code you have writen in blue... Will that work? where and when does DIGIT get reset to zero. DIGIT being the jump pointer when indirect addressing, it doesnt look like it does, and it needs to be)



I have also moved the 2 tables to the top of the program (well, just under the ISR)
BECAUSE i think i have just understood what is meant when everyone has been telling me they may go beyond the 255 boundbry.
I was reading the mid-range ref. man. and, please correct me if im wrong (but It would definitly explain why my program was jumping to the ISR when no interrupts were enabled) if the table is placed where it will be either side of the where the PCL will overflow from 255 to 0, ADDingWF PCL will make the program jump to somewhere near the top of the program.
I recall a thread titled "tables beyond the 255 word boundry) and I'm guessing PCLATH would have to modified too.
SO, thats fixed (by moving the tables up)



So MORE is working than before.
I have this working: PIC16F628A - DS18B20 Digital Thermometer
TMR2 setup is commented out and I am using the 'in program loop' multiplex routine.
and its works fine.
I have left the BSF INTCON,GIE and BCF INTCON,GIE instructions thoughout the program in, and nothing is commented out except for TMR2 setup.
But I want to use the interrupt.
but when I comment out the multiplex routine and bring back the TMR2 setup, On POWER-UP all I get is a 0 displayed in the decimal colum.
i.e. - - - 0
and its really bright, which tells me none of porta is polling/scrolling though.

I think I may have my Global Interrupt Enables and Disables is worng spots, (causing incorrect reading of the temp from the ds18b20)
But even if they were and the temp sensor was returning a 0, I would get - - 0.0 displayed if the interrupt was working.
 
And my advance routine: Even though longer than need be, It should've still worked.
Tesing the 3rd bit of DIGIT reg will tell the program when to reset DIGIT and COLSEL. (when DIGIT = 0000 0100 = 4 = too many, reset.) shown below;
Code:
; 
; Prepare for next column interrupt

        BCF     STATUS, C               ; Clear C bit of STATUS register < not needed
        RRF     COLSEL, F               ; Advance column select bit       
        INCF    DIGIT, F                ; INCrement Digit jump pointer (used when indirect addressing above)
        [COLOR=Red]BTFSS   DIGIT, 3[/COLOR]                ; Was that the last column?   
        GOTO    $+4                     ; NO, do not reset DIGIT and COLumnSELect
        CLRF    DIGIT                   ; Reset Digit jump pointer
        CLRF    COLSEL                  ; Clear COLumnSELect register
        BSF     COLSEL, 3               ; Reset COLumnSELect to Hundreds column 1 (00001000)
You're actually testing the fourth bit which would test for the transition from 7 (00000111) to 8 (00001000).

The right most binary column is bit 0. You want to test for the transition from 3 (00000011) to 4 (00000100) so you want to test bit 2 (the third column).

... that shorter code you have writen in blue... Will that work? where and when does DIGIT get reset to zero?
We can use this simple two instruction increment / modulo function when the variable value range is a binary weighted value minus 1 (0..1, 0..3, 0..7, 0..15, 0..31, etc.). Here's a quick-n'-dirty analysis;

Code:
;
; 1st 'bump' -> 00000000 + 1 = 00000001, clear bit 2 -> 00000[COLOR=RoyalBlue]0[/COLOR]01, result 1
; 2nd 'bump' -> 00000001 + 1 = 00000010, clear bit 2 -> 00000[COLOR=RoyalBlue]0[/COLOR]10, result 2
; 3rd 'bump' -> 00000010 + 1 = 00000011, clear bit 2 -> 00000[COLOR=RoyalBlue]0[/COLOR]11, result 3
; 4th 'bump' -> 00000011 + 1 = 00000100, clear bit 2 -> 00000[COLOR=RoyalBlue]0[/COLOR]00, result 0
;
        [COLOR=RoyalBlue]incf    DIGIT,F         ; DIGIT = (DIGIT + 1) % 4
        bcf     DIGIT,2         ; [/COLOR]
I would use the label instead of a fixed address just to keep myself out of trouble later.

Code:
        MOVF    DIGIT, W        ; Column number
        ADDLW   [COLOR=red]0x20[/COLOR]            ; Add to 'HUNS' GPR address
        MOVWF   FSR             ; FSR = ...
        MOVF    INDF, W         ; W register now holds 7 Segment arrangement for corresponding digit
Ok, so thats fixed.
Cheerful regards, Mike
 
Last edited:
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top