PDA

View Full Version : Darrel's interrupts in a 7 segment display



ardhuru
- 28th February 2009, 07:41
I have a design with a 3 digit 7 segment multiplexed display that showed a certain value. The circuit and the code worked fine while the display was about the only thing the PIC had to do.

Now, I tried to use Darrel's "DT_INTS-14.bas" as I need a few other things done in the code as well.

The chip is a 16F887.

My observations; the display flickers a lot; changing the prescaler to 1:1 is still bad, but better than other settings. Pre-loading TMR1 with any value seems to have no effect.

What am I doing wrong?


ANSEL = 0
ANSELH = 0
CM1CON0.7 = 0
CM2CON0.7 = 0

TRISA = 0
TRISB = 0
TRISC = 0
TRISD = 0
TRISE = 0

N VAR BYTE

SEGDEF VAR BYTE

INCLUDE "DT_INTS-14.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP.bas" ' Include if using PBP interrupts

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _DISP, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

T1CON = $1
; Prescaler = 8, TMR1ON
@ INT_ENABLE TMR1_INT ; enable Timer 1 interrupts

Main:


'********************
TMR1H = %11111111
TMR1L = %11110111
'********************

toggle stat_LED
pause 500

GOTO Main

'---[TMR1 - interrupt handler]--------------------------------------------------
DISP: N = 1
GOSUB BIN2SEG
PORTC = SEGDEF
PORTE = 6
PAUSE 3

N = 2
GOSUB BIN2SEG
PORTC = SEGDEF
PORTE = 5
PAUSE 3

N = 3
GOSUB BIN2SEG
PORTC = SEGDEF
PORTE = 3
PAUSE 3

@ INT_RETURN

BIN2SEG:LookUp n,[132,175,193,137,170,152,144,143,128,136,210,251],SEGDEF

Return

Darrel Taylor
- 28th February 2009, 20:54
My observations; the display flickers a lot; changing the prescaler to 1:1 is still bad, but better than other settings. Pre-loading TMR1 with any value seems to have no effect.
Blinky?? No doubt!

Assuming a 4Mhz OSC, your interrupt frequency is ~15Hz (~65.5ms).
Then each digit is shown for ~3ms for a total of 9ms out of that 65.5.
With the third digit left ON, that one's probably very bright.

What am I doing wrong?
For one, you need to reload the Timer in the Interrupt Handler, not the Main loop.
The interrupt frequency should be at least 300Hz, 1Kz is better.


DISP:
T1CON.0 = 0 ; stop timer
TMR1H = %11111100
TMR1L = %00011111
T1CON.0 = 1 ; restart timer

And in the handler, only turn on 1 digit per interrupt. Don't pause, don't gosub.

nomad
- 1st March 2009, 11:29
ahhhh, there's the kick i needed.
I also am working on a 3digit 7seg led display, using modified code
(read: massively mangled stolen code :P)
and was doing the same thing..
(pausing, and calling/gosubing the bin2seg lookup)



MOVF _led1data,W
call bin2seg
MOVWF PORTD
bsf _led1digit
call dly7seg
bcf _led1digit

movf _led2data,W
call bin2seg
movwf PORTD
bsf _led2digit
call dly7seg
bcf _led2digit

movf _led3data,W
call bin2seg
movwf PORTD
bsf _led3digit
call dly7seg
bcf _led3digit


so some ideas i was wrestling with just got answered?..

1)thinking should look digits up in the main loop? and use the already "lookedup" variables in the interupt routine.

2)now the one digit per interrupt, I had thought about, but couldn't figure out how to do. (put on back burner, until I saw this)
little trickier.. without a gosub?

would something like this work? (seems long way no?)



if digitloop=3 then digitloop=0 'only three digits
digitloop=digitloop+1 'next digit

if digitloop=1 goto digit1 'which digit we displaying?
endif
if digitloop=2 goto digit2
endif


digit3: 'wasn't 1 or 2 so must be 3!
PORTC = SEGDEF3 'output "prelookedup" data
PORTE = 3 'turn digit on
goto dispdone 'goto finish

digit2: 'doing digit 2
PORTC = SEGDEF2 'output "prelookedup" data
PORTE = 5 'turn digit on
goto dispdone 'goto finish

digit1: 'doing digit1
PORTC = SEGDEF1 'output "prelookedup" data
PORTE = 6 'turn digit on
goto dispdone 'goto finish


DISPDONE: 'reload timer
T1CON.0 = 0 ; stop timer
TMR1H = %11111100
TMR1L = %00011111
T1CON.0 = 1 ; restart timer
@ INT_RETURN 'exit int routine


on the right track?
should the timer be stopped at the beginning of the routine?

now in the main, will we need 3 lookup tables? can lookup into an array? or how about...



n=1 'to be replaced with digit1 variable (N=N1)
gosub bin2seg
segdef1=segdef
n=2 'digit2
gosub bin2seg
segdef2=segdef
n=3 'digit3
gosub bin2seg
segdef3=segdef

BIN2SEG:
LookUp n,[132,175,193,137,170,152,144,143,128,136,210,251],SEGDEF
return


(I was attempting mine in assembly, but so as not to hijack the thread, did this way)

Darrel Taylor
- 1st March 2009, 19:26
You guys always make me hungry. I LOVE spaghetti.
Just not in my code. :D



Main:
FOR Value = 0 TO 999
GOSUB SetDisp
PAUSE 500
NEXT Value
GOTO Main

'---[Set 7-seg patterns to WORD value]--------------------------------------
SetDisp:
FOR Idx = 2 to 0 STEP -1
Temp = Value DIG Idx
LookUp Temp,[132,175,193,137,170,152,144,143,128,136,210,251],Temp
SEGDEF(Idx) = Temp
NEXT Idx
RETURN

'---[TMR1 - interrupt handler]----------------------------------------------
DISP:
T1CON.0 = 0 ; stop timer
TMR1H = %11111100
TMR1L = %00011111
T1CON.0 = 1 ; restart timer

PORTE = %111 ; turn off all digits to prevent ghosting
PORTC = SEGDEF(digitloop) ; put segment pattern to pin
PORTE = ~(DCD digitloop) ; turn on the digit

digitloop = digitloop + 1 ; prepare for next digit
IF digitloop = 3 then digitloop = 0
@ INT_RETURN

Completely untested ...

nomad
- 2nd March 2009, 03:06
WOW... how simple to put the digitloop at the end, MUCH cleaner. less if'ing
was looking at it backwards lol , maybe I should try standing on my head..

and I started to do a loop (for) deal, but cant use val(x) in the lookup, and went all off the other way. lol.. shoulda figured out/stuck with the original idea.


THANKS! looks shweet cant wait to test :)

Think you solved both our problems!

ardhuru
- 2nd March 2009, 13:56
Wow, worked the first time, Darrel.

Now, if I want to bit bang (I've already commited the hardware UART to something else) a couple of parameter values over the serial port, where in the code you've shown would the line go?

I've been struggling with this, with no success; or is this normal when one is using TMR0?

Regards,

Anand

ardhuru
- 2nd March 2009, 13:58
[QUOTE=ardhuru;70828]; or is this normal when one is using TMR0?

/QUOTE]

Sorry, TMR1, I mean.

Darrel Taylor
- 2nd March 2009, 19:59
Wow, worked the first time, Darrel.
Great! I guess my internal simulator is still working. :)


a couple of parameter values over the serial port

If it's only a couple values every now and then, just turn off the interrupts before using the SEROUT? statement.
Depending on the baudrate and amount of data, it may cause a small blink in the display.
<br>

Charles Linquis
- 3rd March 2009, 01:26
If you set your interrupt time to 1.5mSec or so, you can send one character at 9600 baud between interrupts. Just don't try to do too much else in that period!

boroko
- 9th August 2014, 00:37
Hi all,
I'm having trouble understanding something in this example code. Maybe someone can explain.
Main:
FOR Value = 0 TO 999
GOSUB SetDisp
PAUSE 500
NEXT Value
GOTO Main

'---[Set 7-seg patterns to WORD value]--------------------------------------
SetDisp:
FOR Idx = 2 to 0 STEP -1
Temp = Value DIG Idx
LookUp Temp,[132,175,193,137,170,152,144,143,128,136,210,251],Temp
SEGDEF(Idx) = Temp
NEXT Idx
RETURN
The biggest question is why is there 12 data points in the table? I am assuming that the actual numbers are because of the wiring of the digits with this specific LED as I can not figure out a segment pattern. After that, I fall down on why 12 instead of 8 unless it involves positioning the decimal point somehow. I wonder, if with the original wiring, this would be clearer to me. I would think that you would line up the segments in order with the port pins in order.

Thanks
Mark

boroko
- 9th August 2014, 03:57
Another observation that this is a specific solution to the OP's issue is that can't be just cut-n-pasted without thinking it through:
PORTE = %111 ; turn off all digits to prevent ghosting
PORTC = SEGDEF(digitloop) ; put segment pattern to pin
PORTE = ~(DCD digitloop) ; turn on the digit
my application is common cathode and it uses a ULN2803 as a driver for the cathodes of the digits. If I hadn't looked at it and tried to understand it, I could have easily have turned on ALL BUT ONE of the displays instead of ONE AT A TIME. Mine is also, 8 digits, so it matters a bit more for the PIC pin. Not a complaint in any way, more of a way to close the loop for anyone looking at it later. BTW: very slick way to step through the digits. Learned something new today.
Mark

EarlyBird2
- 9th August 2014, 22:19
Hi all,
I'm having trouble understanding something in this example code. Maybe someone can explain.
Main:
FOR Value = 0 TO 999
GOSUB SetDisp
PAUSE 500
NEXT Value
GOTO Main

'---[Set 7-seg patterns to WORD value]--------------------------------------
SetDisp:
FOR Idx = 2 to 0 STEP -1
Temp = Value DIG Idx
LookUp Temp,[132,175,193,137,170,152,144,143,128,136,210,251],Temp
SEGDEF(Idx) = Temp
NEXT Idx
RETURN
The biggest question is why is there 12 data points in the table? I am assuming that the actual numbers are because of the wiring of the digits with this specific LED as I can not figure out a segment pattern. After that, I fall down on why 12 instead of 8 unless it involves positioning the decimal point somehow. I wonder, if with the original wiring, this would be clearer to me. I would think that you would line up the segments in order with the port pins in order.

Thanks
Mark

As I can not resist a challenge even if it is only an academic exercise to me.

------- GFEDCBA

0 132 10000100
1 175 10101111
2 193 11000001
3 137 10001001
4 170 10101010
5 152 10011000
6 144 10010000
7 143 10001111
8 128 10000000
9 136 10001000
F 210 11010010
- 251 11111011


Looking at the bit pattern for :-

0 the active segments are 0 and inactive 1 in a 0 the central cross bar is inactive therefore this is C
6 the only inactive segment is top right therefore this is E
5 the inactive segments are top right and bottom left so bottom left is D
9 confirms bottom left is D
3 top left and bottom left inactive so top left is A
2 top left and bottom right inactive so bottom right is G
7 top left centre bottom left and bottom inactive so bottom is B

which leaves F is the top segment giving this pattern

-F-
A E
-C-
D G
-B-


251 is the centre bar obviously used for - (minus)
210 converting the bit pattern gives F

Having decoded this pattern it makes no sense to me as the normal segment pattern is

7412

Leaving the question why connect a 7 segment display in this no standard way?

Dave
- 11th August 2014, 12:04
Well Actually Steve, The display's may have been wired that way in the schematic originally. Makes no difference. As far as the table is concerned, to generate all 16 hexidecimal characters the table would be 16 entries wide. in the past I have generated tables with all 16 entries as well as lower case "c,n o r". Thats 20. Ther is no standard way if you get my drift. It's completely up to the circuit designer.

EarlyBird2
- 12th August 2014, 07:44
Well Actually Steve, The display's may have been wired that way in the schematic originally. Makes no difference. As far as the table is concerned, to generate all 16 hexidecimal characters the table would be 16 entries wide. in the past I have generated tables with all 16 entries as well as lower case "c,n o r". Thats 20. Ther is no standard way if you get my drift. It's completely up to the circuit designer.

In my post I decoded the lookup table to work out the display pattern and the wiring. I intuitively did not like the resultant pattern and wondered why choose that pattern. Internet searches revealed a commonly followed trend of port.0-port.7 connected to a-g respectively.

From Wikipedia


7413


LED-based 7-segment display which cycles through the common glyphs of the ten decimal numerals and the six hexadecimal "letter digits" (A–F)
Hexadecimal digits can be displayed on seven-segment displays. A combination of uppercase and lowercase letters is used for A–F;[6] this is done to obtain a unique, unambiguous shape for each hexadecimal digit (otherwise, a capital D would look identical to an 0 and a capital B would look identical to an 8). Also the digit 6 must be displayed with the top bar lit to avoid ambiguity with the letter b.Which implies that there are two ways to wire up a seven segment display one for g-a encoding and one for a-g encoding. But as you say no one has to follow these commonly used encodings, which do dictate the circuit to be used.

The inclusion of "-" and "F" in the encoding makes me think that the original code was probably for displaying temperatures. Also the codes are eight digits which includes the DP reinforcing the idea of a temperature display. I wonder if the original project was wired in the same way, that is assuming this is recycled code.

Can anyone see any advantage in this scheme?

-F-
A E
-C-
D G
-B-

I can not and surely the wiring will be like spaghetti.

richard
- 12th August 2014, 10:04
most obvious reason would be to make the easiest possible (construction wise ) homebrew pcb layout . ie reduce the need for a ds board or even just minimise via's

EarlyBird2
- 12th August 2014, 10:42
most obvious reason would be to make the easiest possible (construction wise ) homebrew pcb layout . ie reduce the need for a ds board or even just minimise via's

Yes it just has me wondering as I can not see any obvious benefit. As I will never use these I am going to stop worrying about it.

boroko
- 17th August 2014, 02:06
intriguing discussion, but you're right... a rabbit trail. Mine works, I'm moving on.
Mark