Problem with 7 segment display

Steve2381

Senior Member
Hi all

Yes... Captain dodgy code is in the room again. Trying to use an 18m2 as a slave driver for some common anode , 4 digit led displays I found in the workshop... and its just not running fast enough.

Ignore the lack of serial input coding yet (although, that is going to slow it even further!)....


Code:
'Common Anode 4x 7 segment display driver.  Decoded from serial input - 18m2


setfreq m16

	'              -- --   -- --   -- --   -- --
	'B.0-A        |     | |     | |     | |     |        
	'B.1-B	                                  
	'B.2-C        |     | |     | |     | |     |       
	'B.3-D         -- --   -- --   -- --   -- --  
	'B.4-E        |     | |     | |     | |     |
	'B.5-F                                           
	'B.6-G        |     | |     | |     | |     |
	'              -- --   -- --   -- --   -- --  
	
	'C.5 - Colon
	
	'C.1 - Digit 1 +
	'C.0 - Digit 2 +
	'C.7 - Digit 3 +
	'C.6 - Digit 4 +.
	
Dirsb=%11111111					;Set pins.   1=Output  0=Input
Dirsc=%11111011

symbol digit1	= b0				'The received number for digit 1 via serial on c.2
symbol digit2	= b1				'The received number for digit 2 via serial on c.2
symbol digit3	= b2				'The received number for digit 3 via serial on c.2
symbol digit4	= b3				'The received number for digit 4 via serial on c.2

symbol serialin 	= c.2	                     'Serial input pin
symbol digit1com	= c.1 : high digit1com	'Set digit 1 common high (off)
symbol digit2com	= c.0 : high digit2com  'Set digit 2 common high (off)
symbol digit3com	= c.7 : high digit3com	'Set digit 3 common high (off)
symbol digit4com	= c.6 : high digit4com	'Set digit 4 common high (off)



EEPROM   0, (64,121,36,48,25,18,2,120,128,16,127,70,63,14,9,33,71,35,28,55,8,12)  

	 	'Character ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ,blank, C , - , F , H , d , L , o, degrees ,=,A,P )
	 	
'test number to display	
digit1=2
digit2=3
digit3=4
digit4=5
	 	
Main:

do

low digit1com
read digit1,pinsb

high digit1com:low digit2com
read digit2,pinsb

high digit2com:low digit3com
read digit3,pinsb

high digit3com:low digit4com
read digit4,pinsb

high digit4com

loop
It isn't multiplexing fast enough (if that is the right word). The commons of the display are controlled by 4x BC557 transistors via a 1k resistor to base (which may be the problem).

Any advice gratefully received.

Oh, and why doesn't "Let digit1 = RXfig DIG 0" work ? I get an error. Does the 'DIG' statement not work on an 18m2?
 

HertzHog

Member
"The X1 and X2 parts also support
<< ; shift left
>> ; shift right
*/ ; multiply (returns middle word of result)
DIG ; return the digit value
REV ; reverse a number of bits"

That is a way of saying it does NOT work on M2. Sorry!
 

xtech007

Senior Member
Curious!

Hi!
Welcome to the forum!
Out of curiosity, why not use a shift register or something similar?

With the chip mentioned looks like it would use most if not all pins available. I did something similar with a 28x1 will lookup code share it with the forum to display different ways to approach the same outcome!

Have you considered a Max7219, maybe for the price of the transistors you can get one!

You can drive 8 digit displays, also use the code feature. Or non-code that allows you to control the segments.Covered very well by Mr. Westaust past post!
 

Buzby

Senior Member
I've not got an M chip to try this on, so this is untested.

Basically what it does is read the pattern for the next digit while it is displaying the first.
You need to add a new variable to hold the segment pattern, and update that ready for the next digit.

Code:
symbol segments = b4
 	
Main:

read digit1,segments  ' Get pattern for digit 1

do
	pinsb = segments            ' Set segments for digit 1
	low digit1com                 ' Enable digit 1
	read digit2,segments       ' Get segments for digit 2
	high digit1com                ' Disable digit 1

	pinsb = segments            ' Set segments for digit 2          
	low digit2com                 ' Enable digit 2
	read digit3,segments       ' Get segments for digit 3  
	high digit2com                ' Disable digit 2

	pinsb = segments 
	low digit3com
	read digit4,segments 
	high digit3com

 	pinsb = segments 
	low digit4com
	read digit1,segments 
	high digit4com
loop
 

grim_reaper

Senior Member
Aside from all the very good answers already given, as a quick test to check if it's just the speed that's the issue, can't you just whack it up to 32MHz and see what happens? :D
I assume the 18M2 can handle 32MHz? I run a similar display off a 14M2 at that speed (via a MAX7219 however).
 

Buzby

Senior Member
I don't think whacking the speed up of the OPs code will make it better, it might even make it worse !.

Steve's code does this :

Code:
low digit1com         ' Enable digit1, but nothing to display on it yet.
read digit1,pinsb     ' Spend some time getting data from eeprom, then put to display
high digit1com        ' Disable digit1, this is done very quickly after pinsb loaded, so hardly any time for the data to show. Faster clock just means less display time !
low digit2com         ' Enable digit2, but pinsb are still holding data for digit1,
By rearranging so that the delay while reading the eeprom is used for the display duration of the previous digit, and only updating pinsb when no digit is enabled, there should be no ghosting and a bright display.
 

Steve2381

Senior Member
Thanks all.... I will have another go tonight.
Max7219 - they are for common cathode, not common anode displays. Yes, I believe you can work around it... but its not easy.
I know my code isn't all that great, but I did lift it off a clock code I found in here (the eeprom part).
As for a shift register.... that means nothing to me!


OK... Update:

I just tried Buzby's code.... better, but still not quite there... even at 32Mhz.
The first digit is significantly brighter than the other three digits, and I fear once the serial data is read for the four digits in the loop as well, I will be struggling.
I could play around with the 220R resistors I have protecting the LED segments to try and get the digits brighter, and add a delay to try and equal-out the first bright digit.

I will have a go with Lookup.
 
Last edited:

Buzby

Senior Member
Do the digits flicker with my code ?

The extra brightness of the first digit could be a good sign !.
It probably means there is room for a slight delay to be added.

Pleae post your full code and I'll try to fit it in.
 

Steve2381

Senior Member
Thanks. I do dread posting my code in here... I know its not all that great.

The lookup command is faster.

I have not tried sending any serial data from another Picaxe yet.. doesn't seem much point. Probably don't need the "AT" qualifier either.
Simply adding the 'go check the incoming data' line has resulted in a flickering display with very dim digits. I think by the time its read the data, the display will be all but off.

I don't think its feasible to constantly read the incoming serial data... hence the 'go and look for data' flag on pin b.7.


Code:
'Common Anode 4x 7 segment display driver.  Decoded from serial input
'December 2014

setfreq m32

	'              -- --   -- --   -- --   -- --
	'B.0-A        |     | |     | |     | |     |        
	'B.1-B	                 o                 
	'B.2-C        |     | |     | |     | |     |       
	'B.3-D         -- --   -- --   -- --   -- --  
	'B.4-E        |     | |     | |     | |     |
	'B.5-F                                           
	'B.6-G        |     | |     |o|     | |     |
	'              -- --   -- --   -- --   -- --  
	
	'C.2 - Colon
	
	'C.1 - Digit 1 +
	'C.0 - Digit 2 +
	'C.7 - Digit 3 +
	'C.6 - Digit 4 +.
	

Dirsb=%01111111					;Set pins.   1=Output  0=Input
Dirsc=%11011111

symbol digit1	= b0				'The received number for digit 1 via serial on c.2
symbol digit2	= b1				'The received number for digit 2 via serial on c.2
symbol digit3	= b2				'The received number for digit 3 via serial on c.2
symbol digit4	= b3				'The received number for digit 4 via serial on c.2

symbol serialin 	= c.5				'Serial input pin
symbol digit1com	= c.1 : high digit1com	'Set digit 1 common high (off)
symbol digit2com	= c.0 : high digit2com  'Set digit 2 common high (off)
symbol digit3com	= c.7 : high digit3com	'Set digit 3 common high (off)
symbol digit4com	= c.6 : high digit4com	'Set digit 4 common high (off)

symbol segments	= b4				'Segment pattern


'Characters ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ,blank, C , - , F , H , d , L , o, degrees ,=,A,P )
	 	
	
digit1=0
digit2=0
digit3=0
digit4=0
	 	
Main:

low 	c.2						'Switch on semi colon
	
lookup digit1,(64,121,36,48,25,18,2,120,128,16,127,70,63,14,9,33,71,35,28,55,8,12),segments				'Retrieve required value to display character/number


do

	pinsb = segments            		
	low digit1com  																'Switch digit 1 on              	
	lookup digit2,(64,121,36,48,25,18,2,120,128,16,127,70,63,14,9,33,71,35,28,55,8,12),segments			'Retrieve required value to display character/number
	high digit1com 																'Switch digit 1 off               

	pinsb = segments            	          
	low digit2com    															               	
	lookup digit3,(64,121,36,48,25,18,2,120,128,16,127,70,63,14,9,33,71,35,28,55,8,12),segments  			'Retrieve required value to display character/number
	high digit2com 																'Switch digit 2 off               	

	pinsb = segments 
	low digit3com   															
	lookup digit4,(64,121,36,48,25,18,2,120,128,16,127,70,63,14,9,33,71,35,28,55,8,12),segments			'Retrieve required value to display character/number
	high digit3com																'Switch digit 3 off

 	pinsb = segments 
	low digit4com   																' 
	lookup digit1,(64,121,36,48,25,18,2,120,128,16,127,70,63,14,9,33,71,35,28,55,8,12),segments 			'Retrieve required value to display character/number
	high digit4com																'Switch digit 4 off

	if pinb.7 = 1 then gosub rxdata:	'If data flag goes high, then check for new values
	
loop

rxdata:

	serin [50],c.5,N4800_16,("AT"),digit1,digit2,digit3,digit4		'Confirm the request is real by matching "AT" and then obtain value
 

Buzby

Senior Member
Let's get the display working nicely first, we can add the serial later.

The bright first digit is because the digit is lit longer than the others, due to the loop end taking some time.
This would seem to indicate that if we match the display duration for each digit there should be even brightness.

Put a 'Pause 10' after each 'Low digitcom', and comment out the pinb.7 test, we will do something like this later.
 

hippy

Technical Support
Staff member
It should be possible to drive a four-digit byte-wide multiplexed 7-segment display using an M2 at 32MHz without flicker. I can't remember all the details but my code in the following thread worked for eight digits on a 28X1 and 28X2 at 8MHz ...

http://www.picaxeforum.co.uk/showthread.php?11723-Multiplexed-7-Seg-Display

The basic trick I used there was ...

Do
pinsc = digit1 : PulsOut DIGIT_1, PULSE_MIN
pinsc = digit2 : PulsOut DIGIT_2, PULSE_MIN
pinsc = digit3 : PulsOut DIGIT_3, PULSE_MIN
pinsc = digit4 : PulsOut DIGIT_4, PULSE_MIN
Loop

Only update 'digit1' etc variables when the data changes which is initiated by interrupt. The display blanks briefly when data is updated.
 

Buzby

Senior Member
Hi hippy,

I've had sufficient brightness at a multiplex ratio of 1:16, so this 1:4 display should be a doddle.

Once we get the display steady we can tidy the code ( just one lookup, not four ), and add the serial

Cheers,

Buzby
 

Steve2381

Senior Member
I have already added the pause Buzby... yes that equals out the displays. They are about half brightness I would say with no flicker (without any serial data line)
I realised the 4x Lookup statements were next to shave, but I am still looking at the most efficient way of doing that.
 

Buzby

Senior Member
This was going to be my next suggestion.

Adjust the value of DisplayDuration to get the best compromise between brightnesss and flicker.


Code:
'Common Anode 4x 7 segment display driver.  Decoded from serial input
'December 2014



	'              -- --   -- --   -- --   -- --
	'B.0-A        |     | |     | |     | |     |        
	'B.1-B	                 o                 
	'B.2-C        |     | |     | |     | |     |       
	'B.3-D         -- --   -- --   -- --   -- --  
	'B.4-E        |     | |     | |     | |     |
	'B.5-F                                           
	'B.6-G        |     | |     |o|     | |     |
	'              -- --   -- --   -- --   -- --  
	
	'C.2 - Colon
	
	'C.1 - Digit 1 +
	'C.0 - Digit 2 +
	'C.7 - Digit 3 +
	'C.6 - Digit 4 +.

symbol digit1	= b0	'The received number for digit 1 via serial on c.2
symbol digit2	= b1	'The received number for digit 2 via serial on c.2
symbol digit3	= b2	'The received number for digit 3 via serial on c.2
symbol digit4	= b3	'The received number for digit 4 via serial on c.2

symbol serialin 	= c.5	'Serial input pin

symbol digit1com	= c.1 'Set digit 1 common high (off)
symbol digit2com	= c.0 'Set digit 2 common high (off)
symbol digit3com	= c.7 'Set digit 3 common high (off)
symbol digit4com	= c.6 'Set digit 4 common high (off)


'Segment and pattern workspace
symbol segments	= b4	
symbol pattern1   = b5
symbol pattern2   = b6
symbol pattern3   = b7
symbol pattern4   = b8
symbol value      = b9

' Constants	 	
symbol DisplayDuration = 10  ' mS duration for each digit

' ================
' Code starts here
' ================

' Run fast !
setfreq m32

' Set pins.   1=Output  0=Input
Dirsb=%01111111				
Dirsc=%11011111

' Disable all digits
high digit1com
high digit2com
high digit3com
high digit4com

'Switch on semi colon
low 	c.2	
	
' Supply some test values	
digit1 = 6
digit2 = 5
digit3 = 4
digit4 = 3

' Convert values to patterns
Gosub ConvertDigits
						 

' =====================
' main loop starts here
' =====================	 	
Main:

do
	pinsb = pattern1            		
	low digit1com 
	pause DisplayDuration 
	high digit1com 																	'Switch digit 1 on              	
	
	pinsb = pattern2
	low digit2com 
	pause DisplayDuration 
	high digit2com 																	'Switch digit 1 on              	
				
	pinsb = pattern3
	low digit3com 
	pause DisplayDuration 
	high digit3com 																	'Switch digit 1 off               

	pinsb = pattern4
	low digit4com 
	pause DisplayDuration 
	high digit4com 	
	
loop


' ======================
' Subroutines start here
' ======================


' RXdata
' ======
rxdata:

	serin [50],c.5,N4800_16,("AT"),digit1,digit2,digit3,digit4		'Confirm the request is real by matching "AT" and then obtain value
	
return

' Convert digits to patterns
' ==========================
ConvertDigits:
	value = digit1 : gosub Value2Seg : pattern1 = segments	 
	value = digit2 : gosub Value2Seg : pattern2 = segments	 
	value = digit3 : gosub Value2Seg : pattern3 = segments	 
	value = digit4 : gosub Value2Seg : pattern4 = segments	 
return

' Get segments for current value
' ==============================
Value2Seg:
'     Characters  ( 0 , 1 , 2, 3, 4, 5,6, 7 , 8 , 9,spc,C ,- ,F ,H,d ,L , o,dg,= ,A,P )
	lookup value,(64,121,36,48,25,18,2,120,128,16,127,70,63,14,9,33,71,35,28,55,8,12),segments		
return
 

Steve2381

Senior Member
Basically it doesn't need the pause in the first digits routine at all now (pattern1) and the DisplayDuration needs to be set at 1 to obtain an equal brightness display. We are at about 50% brightness, which can be brought back brighter up with a smaller segment resistor I think (or no resistor)
I tried to avoid lots of variable name changing as I thought that would slow things down. Evidently not!

I assume the trick is now to jump out the loop as soon as data is received and then gosub ConvertDigits... but as quickly as possible.
Really wish they made a max7219 for common anode!
 

Buzby

Senior Member
DisplayDuration of 1 ?. That seems low, I was expecting about 15 or 20 to give the best results.

Longer DisplayDuration values give more time during the digit display portions, time which can be used to do the serial work without disrupting the loop.

What is the highest DisplayDuration you can use without flicker ?. ( Don't include any serial stuff yet. )
 

Steve2381

Senior Member
OK. A low number, or a higher number for the delay results in uneven digits.
So, I have tweeked around and got them back equal brightness using two different timings, but at the threshold of flickering.

I added an exit routine, just to see what impact that had on flickering.

Code:
'Common Anode 4x 7 segment display driver.  Decoded from serial input
'December 2014

setfreq m32

	'              -- --   -- --   -- --   -- --
	'B.0-A        |     | |     | |     | |     |        
	'B.1-B	                 o                 
	'B.2-C        |     | |     | |     | |     |       
	'B.3-D         -- --   -- --   -- --   -- --  
	'B.4-E        |     | |     | |     | |     |
	'B.5-F                                           
	'B.6-G        |     | |     |o|     | |     |
	'              -- --   -- --   -- --   -- --  
	
	'C.2 - Colon
	
	'C.1 - Digit 1 +
	'C.0 - Digit 2 +
	'C.7 - Digit 3 +
	'C.6 - Digit 4 +.
	

Dirsb=%01111111					;Set pins.   1=Output  0=Input
Dirsc=%11011111

symbol digit1	= b0				'The received number for digit 1 via serial on c.2
symbol digit2	= b1				'The received number for digit 2 via serial on c.2
symbol digit3	= b2				'The received number for digit 3 via serial on c.2
symbol digit4	= b3				'The received number for digit 4 via serial on c.2
symbol segments	= b4				'Segment pattern
symbol pattern1   = b5
symbol pattern2   = b6
symbol pattern3   = b7
symbol pattern4   = b8
symbol value      = b9

symbol digit1com	= c.1 : high digit1com	'Set digit 1 common high (off)
symbol digit2com	= c.0 : high digit2com  'Set digit 2 common high (off)
symbol digit3com	= c.7 : high digit3com	'Set digit 3 common high (off)
symbol digit4com	= c.6 : high digit4com	'Set digit 4 common high (off)

symbol flag		= pinb.7			'Data ready flag
symbol serialin 	= c.5				'Serial input pin

symbol DisplayDuration = 15			'mS duration for 1st digit
symbol DisplayDuration1 = 50			'mS duration for 2nd,3rd and 4th digits
digit1=1
digit2=2
digit3=3
digit4=4
	 	
low 	c.2						'Switch on semi colon

Main:	

Gosub ConvertDigits

do
	pinsb = pattern1            		
	low digit1com 
	pause DisplayDuration
	high digit1com 																             	
	
	pinsb = pattern2
	low digit2com 
	pause DisplayDuration1 
	high digit2com 																             	
				
	pinsb = pattern3
	low digit3com 
	pause DisplayDuration1
	high digit3com 																	          

	pinsb = pattern4
	low digit4com 
	pause DisplayDuration1
	high digit4com 
	
	if flag=1 then exit	
	
loop

serin [50],serialin,N4800_16,("AT"),digit1,digit2,digit3,digit4		'Confirm the request is real by matching "AT" and then obtain value 

goto main


' Convert digits to patterns
' ==========================
ConvertDigits:
	value = digit1 : gosub Value2Seg : pattern1 = segments	 	
	value = digit2 : gosub Value2Seg : pattern2 = segments	 
	value = digit3 : gosub Value2Seg : pattern3 = segments	 
	value = digit4 : gosub Value2Seg : pattern4 = segments	 
return


' Get segments for current value
' ==============================

Value2Seg:
'     Characters  ( 0 , 1 , 2, 3, 4, 5,6, 7 , 8 , 9,spc,C ,- ,F ,H,d ,L , o,dg,= ,A,P )
	lookup value,(64,121,36,48,25,18,2,120,128,16,127,70,63,14,9,33,71,35,28,55,8,12),segments		
return
 

hippy

Technical Support
Staff member
Code:
pinsb = pattern1            		
low digit1com 
pause DisplayDuration
high digit1com
Given all digits are displayed in the same way, and presuming only when the digitXcom is low; there would be no obvious reason why the first digit should be brighter than the others if each had the same pause time, or why it needs a considerably reduced pause time to balance that brightness.

But, you describe the digitXcom lines as connected to common anode displays which infers active high control to enable those digits, rather than active low as presumed.

I think there is some mis-match between what you have and how you are controlling the displays.

What I suspect you are describing as flickering is really ghost images of other digits being displayed across the digits.
 

Steve2381

Senior Member
Mmm... don't think so. My test routine seems to update the displays fine. I don't know why the first digit is brighter either. I assumed due to the do/loop.
I have swapped the display commons around to make sure it wasn't the BC557 making the difference. Its low on the control lines to switch the display digit on.
I can actually slow the delay to pause60 and still be OK. Above that, the displays flicker, but only the illuminated segments.... no sign of ghosting

Update...

Well spotty Hippy. Just changed out the display and its that. Now all the displays are equal using the same timings. That was new out of the tube that display.... grrr
 
Top