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.

JuneBug + LEDMUX

Status
Not open for further replies.

UTMonkey

New Member
Hi All,

LED Mux got me confused at first but the penny has dropped.

I am trying now to get the lights on this kit to come on simultaneously (or appear to).

Look at the following code (Created by Bill, smegged up by me)

list p=18F1320
include <p18F1320.inc>
CONFIG OSC = INTIO2, WDT = OFF, LVP = OFF, DEBUG = ON

LED macro x,y ; MACRO LED <PORTA>, <TRISA>
movlw x
movwf LATA ; LATA = x
movlw y
movwf TRISA ; TRISA = y
endm ; end macro


org 0 ; reset vector
bsf ADCON1, 0 ; make RA0 digital
START
LED1 LED b'00000001', b'10111110' ; LED <PORTA>, <TRISA>
LED3 LED b'01000000', b'00111111'
LED5 LED b'10000000', b'01111110'
goto START ; loop forever
END

I was hoping this would appear to turn on LED's 1,3 and 5, instead it appears to be turning them all on.

Am I missing something?

Regards

Mark
 
UTMonkey said:
LED Mux got me confused at first but the penny has dropped.
Isn't that fun? Took me a few minutes to figure out what was going on there too.

One note: When posting code, don't use quote. Use the Code tags. Before pasting your code, click on the # in the menu above the text entry box. Then paste your code. This holds (in theory at least) the formatting so your code is readable.

If someone doesn't beat me to it I'll load your code in my Junebug and have a look at it in the next half hour or so.

EDIT: Oh ya, here's a truth table I made. You may find it helpful for getting the Junebug LEDs to do what you want.
truth.jpg
 
Last edited:
It's commonly called Charlieplexing. Microchip has an app note on it and it's also seen in the PICkit 1.
You need to refresh the display faster than 50Hz to get them all lit.
It's also used on the Gooligum Christmas Star kit.
**broken link removed**
https://www.gooligum.com.au/
 

Attachments

  • PIC Tips n Tricks Hardware Techniques.pdf
    488.5 KB · Views: 436
Here's your code modified to multiplex 1,3 and 5 LEDs. It's quick and dirty so you can take it from there and improve it. 1,3 and 5 are bright at present, but the others are on dimly. That should be able to be fixed with some fiddling.

Code:
	list	p=18F1320
	include	<p18F1320.inc>
	CONFIG	OSC = INTIO2, WDT = OFF, LVP = OFF, DEBUG = ON

	cblock	0x00
		loop1
	endc

LED	macro	x,y	;MACRO LED <PORTA>, <TRISA>
	movlw	x
	movwf	LATA	;LATA = x
	movlw	y
	movwf	TRISA	;TRISA = y
	call	delay	;delay just long enough to multiplex LEDs so
			;they all look like they're on together
	endm		;end macro

	org	0	;reset vector
	bsf	ADCON1,0 ;make RA0 digital
START
LED1	LED	b'00000001',b'10111110'	;LED <PORTA>, <TRISA>
LED3	LED	b'01000000',b'00111111'
LED5	LED	b'10000000',b'01111110'
	goto	START		;loop forever

delay	movlw	0x0e
	movwf	loop1 
inner	decfsz	loop1,F 
	goto	inner
        return
	END
 
Last edited:
blueroomelectronics said:
I was on your site Futz, nice bunch of bots there.
Oh geez, I'm embarrassed. :p That obsolete old site is sorely in need of a full rewrite. Made that something like 4 or 5 years ago. It's pretty out of date.

It's a crappy old fashioned locked-tables design. Needs to be rewritten in 100% CSS/XHTML.

What I may do instead is just do a good Joomla template and use that. Makes changing stuff around SO easy. Just run it like a blog, sorta.
 
OK UTMOnkey, what we've been playing with is the newb way of multiplexing. Here's a much better way of doing it, using a timer interrupt. When you do it this way the "off" LED's don't light at all and the "on" LEDs are nice and bright.

In 'main' you can set which LED's get blinked by setting their bits in the variable "lednum". Bit-1 for LED1, Bit-2 for LED2 and so on. For LEDs 1, 3 and 5 you would set lednum=00101010. The (timer) interrupt service routine does all the actual LED turning on and off. You just tell it what you want displayed and for how long.

To make this work I had to kick the internal clock speed up to 8MHz from the dragging-slow default. Actually it could probably have been a bit slower, but why not use all the chip is capable of?

It's pretty well commented so you should be able to figure out what's happening. Follow along in your datasheet.

Have fun! :D

Code:
	list	p=18F1320
	include	<p18F1320.inc>
	CONFIG	OSC=INTIO2,WDT=OFF,MCLRE=ON,LVP=OFF

	cblock	0x00
		d1,d2,d3,lednum,ledcount
	endc

	org	0x0000
	goto	init

;*************************
;Interrupt Service Routine
	org	0x0008
ISR	tstfsz	lednum		;any LEDs on?
	goto	display		;yes, go display them
	clrf	LATA		;no, turn em all off
	goto	timdone		;and we're done
display	incf	ledcount,F	;increment led selector
	movlw	0x01		;is it 1?
	cpfseq	ledcount
	goto	led_2		;no, go to led_2
led_1	btfss	lednum,1	;LED 1 on?
	goto	timdone		;no, we're done
	bsf	LATA,0		;yes, display it
	bcf	LATA,6
	movlw	b'10000000'
	movwf	TRISA	
	goto	timdone		;done
led_2	movlw	0x02
	cpfseq	ledcount
	goto	led_3
	btfss	lednum,2
	goto	timdone
	bcf	LATA,0
	bsf	LATA,6
	movlw	b'10000000'
	movwf	TRISA	
	goto	timdone
led_3	movlw	0x03
	cpfseq	ledcount
	goto	led_4
	btfss	lednum,3
	goto	timdone
	bsf	LATA,6
	bcf	LATA,7
	movlw	b'00000001'
	movwf	TRISA	
	goto	timdone
led_4	movlw	0x04
	cpfseq	ledcount
	goto	led_5
	btfss	lednum,4
	goto	timdone
	bcf	LATA,6
	bsf	LATA,7
	movlw	b'00000001'
	movwf	TRISA	
	goto	timdone
led_5	movlw	0x05
	cpfseq	ledcount
	goto	led_6
	btfss	lednum,5
	goto	timdone
	bcf	LATA,0
	bsf	LATA,7
	movlw	b'01000000'
	movwf	TRISA	
	goto	timdone
led_6	btfss	lednum,6	;LED 6 on?
	goto	clearit		;no, we're done
	bsf	LATA,0		;yes, display it
	bcf	LATA,7
	movlw	b'01000000'
	movwf	TRISA	
clearit	clrf	ledcount	;reset led multiplex counter
timdone	bcf	INTCON,TMR0IF	;clear TMR0 flag
quit	retfie	FAST		;return
;*************************

init	bsf	OSCCON,IRCF2	;set to 8MHz clock
	bsf	OSCCON,IRCF1
	bsf	OSCCON,IRCF0
	clrf	TRISA		;make ports all outs
	clrf	TRISB
	clrf	LATA		;and zero them
	clrf	LATB
	setf	ADCON1		;make PORTA all digital
	clrf	ledcount
;init interrupts
	movlw	b'11001111'	;set up & enable Timer0
	movwf	T0CON
	bcf	RCON,IPEN	;disable priority interrupts
	bsf	INTCON,TMR0IE	;enable TIMER0 Interrupt
	bsf	INTCON,PEIE	;enable peripheral interrupts
	bsf	INTCON,GIE	;enable interrupts

main	movlw	b'00101010'	;turn on LEDs 1, 3 and 5
	movwf	lednum
	call	delay
	clrf	lednum		;turn em off again
	call	delay
	goto	main		;go again

delay	movlw	0x07		;half second blink delay
	movwf	d1
	movlw	0x2F
	movwf	d2
	movlw	0x03
	movwf	d3
delay_0	decfsz	d1,F
	goto	$+6
	decfsz	d2,F
	goto	$+6
	decfsz	d3,F
	goto	delay_0
	return

	END

Then, just for fun, change main like this:
Code:
main	movlw	b'00101010'	;turn on LEDs 1, 3 and 5
	movwf	lednum
	call	delay
	movlw	b'01010100'	;turn on LEDs 2, 4 and 6
	movwf	lednum
	call	delay
	clrf	lednum		;turn em off again
	call	delay
	goto	main		;go again

Another variation:
Code:
main	movlw	b'00000010'	;turn on LED 1
	movwf	lednum
roll	rlncf	lednum,F
	call	delay
	goto	roll		;go again
You'll notice it blinks up to LED 6 and then counts 2 more beats while nothing happens as the 1 gets rotated thru the two unused bits (bit-7 and bit-0). When the 1 gets back to bit-1 it gets displayed again. That might not have made much sense but once you see it you'll understand.

-----------------------

Hahaha! Thought of another one. It's a binary counter that counts from 1 to $3f (binary 111111). You have to turn your Junebug around and look at it from the other side for this to display correctly. I'll leave it for you to fix that.
Code:
main	movlw	0x02		;turn on LED 1
	movwf	lednum
roll	incf	lednum,F
	movlw	0x7f		;is lednum > $7e?
	cpfseq	lednum
	goto	rollcnt		;no, continue
	movlw	0x01		;yes, start over
	movwf	lednum
rollcnt	call	delay
rollagn	goto	roll		;go again
 
Last edited:
This is great, thanks Futz & Bill.

I suppose I still have the question, why do all lamps come on? is this a shortcoming (if thats the right word) of charlieplexing? can someone explain the phenomenon?

One last question, what "speed" does my code run at?

Thanks for the samples, this is a great "leg up"

Mark
 
Last edited:
Futz, Sorry another question.

Could the interrupt service handle ALL the LED work, leaving the main code to do something else?
 
The interrupt service routine is no different than any other part of your code. You need to call it 50Hz * 6 (LEDs) so 300 times a second is about right. Then you need shadow register (6 bits to hold the LED state, this is the only register you should use within your main code) and a modulo 6 counter to determine which LED to service. A table is one way to hold the port & tris registers for each LED.
 
UTMonkey said:
Could the interrupt service handle ALL the LED work, leaving the main code to do something else?
That's what it's doing in the above program. You just set what LEDs you want on or off and have your program go do something else. The LED's refresh constantly and automatically, every time that timer rolls over, no matter what your program is doing (unless it's disabling interrupts :D ).

Change lednum's value and the LED's change. They'll stay that way until you tell them to do something different.
 
Last edited:
UTMonkey said:
I suppose I still have the question, why do all lamps come on? is this a shortcoming (if thats the right word) of charlieplexing? can someone explain the phenomenon?
Look very carefully at the Junebug schematic, what pins those LEDs connect to and how they're all connected. Do it while studying the code. You'll soon see what's going on. It's confusing at first, but not so very complex.

One last question, what "speed" does my code run at?
I believe the default internal clock speed is 31.25KHz. That's why I bumped it up in my code to 8MHz. 31.25KHz is too slow to do the interrupt thing.

Here's the controls for that:
osc.jpg
As you can see, the internal clock can be set for a range of speeds from 31KHz up to 8MHz.
 
Last edited:
UTMonkey said:
I suppose I still have the question, why do all lamps come on? is this a shortcoming (if thats the right word) of charlieplexing? can someone explain the phenomenon?
They all come on because you're just not going fast enough. They're probably coming on in my interrupt version, but so briefly that you can't see them.

I've modified the non-interrupt version so it runs quick enough to have the in between LEDs not light at all. Bumped clock speed to 8MHz and changed a couple little things. I didn't bother to calculate the delay loop speed precisely to minimize cpu useage. I just plugged in a number and it worked, so good enough. :D

Here it is:
Code:
	list	p=18F1320
	include	<p18F1320.inc>
	CONFIG	OSC = INTIO2, WDT = OFF, LVP = OFF

	cblock	0x00
		loop1
	endc

LED	macro	x,y		;MACRO LED <PORTA>, <TRISA>
	movlw	x
	movwf	LATA		;LATA = x
	movlw	y
	movwf	TRISA		;TRISA = y
	call	delay		;delay just long enough to multiplex LEDs so
				;they all look like they're on together
	endm			;end macro

	org	0x00		;reset vector
init	bsf	OSCCON,IRCF2	;set to 8MHz clock
	bsf	OSCCON,IRCF1
	bsf	OSCCON,IRCF0
	setf	ADCON1		;make RA0 digital
	clrf	TRISA
	clrf	TRISB
	clrf	LATA
	clrf	LATB

START
LED1	LED	b'00000001',b'10000000'	;LED <PORTA>, <TRISA>
led2	LED	b'00000000',b'00000000'	;all off
LED3	LED	b'01000000',b'00000001'
led3	LED	b'00000000',b'00000000'
LED5	LED	b'10000000',b'01000000'
led6	LED	b'00000000',b'00000000'
	goto	START			;loop forever

delay	movlw	0xff
	movwf	loop1 
inner	decfsz	loop1,F 
	goto	inner
        return

	END

Trouble with doing it this way is that your program spends all its time flicking LEDs. If it goes and does something else the LEDs stop until it comes back and buzzes them again.

With the timer interrupt, the LEDs are handled in "background", in little time-slices taken out of main program runtime. It's pretty much how your Windows or Linux computer multitasks. The CPU really only does one thing at a time (assuming a single-core CPU). All the different programs are just given a slice of time each and the CPU rotates thru those slices very quickly so you get the illusion that everything is happening at the same time.
 
Last edited:
Just responding for UTMonkey's benefit, Bill. I know you know this. :p

blueroomelectronics said:
You need to call it 50Hz * 6 (LEDs) so 300 times a second is about right.
Timer0 does that.

Then you need shadow register (6 bits to hold the LED state, this is the only register you should use within your main code)
lednum

and a modulo 6 counter to determine which LED to service.
ledcount
 
For the sake of the thread I shall fill in some of the blanks for people who have no idea what the issue was and try to tell you what caused it ('cos I think I worked it out).

The JuneBug has a great pin saving feature allowing you to light any of 6 LEDS via 3 pins. (It's a technique Bill called "CharliePlexing").

I wanted to get LED's 3 and 5 lit simultaneously (or at least appear that way), the code I hope would do it is below. A snippet of the circuit is attached as well.
Code:
LED		macro	x,y                        ; MACRO LED <PORTA>, <TRISA>
		movlw	x
		movwf	LATA                       ; LATA  = x
		movlw	y
		movwf	TRISA                      ; TRISA = y
		endm                                ; end macro       


		org		0                          ; reset vector
		bsf		ADCON1, 0                  ; make RA0 digital 
		bsf		TRISB, 0
START
LED3	LED		b'01000000', b'00111111'
LED5	LED		b'10000000', b'01111110'
		
		goto	START

Instead what happened is that LED's 3,4 and five would light up, although LED 4 would be only slightly dimmer.

The reason? to find the answer lets assume that LED 3 is Lit and LED 5 is "about" to be lit.

As the MACRO indicates the first thing that happens is that LATA changes from b'01000000' to b'10000000', this means effectively that the path of current changes, from originally flowing through LED3 to flowing back to RA6 through LED4 (making it light) before getting to the TRISA b'01111110' which changes the outputs.

This is only brief, but enough to make LED 4 light.

Futz and Bill have made suggestions to solve the problem by introducing accurate timing by interrupts (though I am yet to grasp that bit).

I hope this makes sense, if anyone has any comments please feel free.

Regards

Mark
 

Attachments

  • CharliePlexing.jpg
    CharliePlexing.jpg
    25.2 KB · Views: 127
Last edited:
UTMonkey said:
As the MACRO indicates the first thing that happens is that LATA changes from b'01000000' to b'10000000', this means effectively that the path of current changes, from originally flowing through LED3 to flowing back to RA6 through LED4 (making it light) before getting to the TRISA b'01111110' which changes the outputs.

This is only brief, but enough to make LED 4 light.
Oh, that explains it! :D I hadn't figured that out, but my suggestion to "just go faster" was a fine cure. Now that you know this, you can fix it and still go slow?
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top