Turning lights on based on a number

Thread Starter

MCrowe

Joined May 29, 2011
69
I want to have a row of 20 lights (LEDs maybe) and be able to turn on 3 of them in a row based on a number in my PIC (for arguments sake I'll saying using the ADC with a Pot).

I want it so when you turn the pot the three lights that are on move up and down the string of lights.

Does any one have any possible idea about how this could be done. I really can't think of any ideas at all. I obviously don't want to do a compare for every possible sequence of lights. Well not if I don't have to.

(edit): I'm using a PIC 16f877a, 4mhz crystal (irrelevant?), and programming in assembly. Probably the only thing that really matters is I'm using a Pic. Cheers.
 
Last edited:

Thread Starter

MCrowe

Joined May 29, 2011
69
Just asking for opinions as I don't have any useful ideas.

I want the light to turn on based off the number, not just cycle through. It's possible there is an IC out there that could be adapted for this use but I can't find anything. Oh yeah, prob should have mentioned I'm using a PIC 16f877a...
 

Markd77

Joined Sep 7, 2009
2,806
Few questions:
Are these groups of three controlled so you can have 1,2,3 on, 2,3,4 on etc. or 1,2,3 on, 4,5,6 on etc? Basically do you have 3 LEDs connected to each pin or 1 LED on each pin?
Which ports will you be using and do any of them have pins you can't use for the LEDs?
Also do you plan on multiplexing or just the simple case with an LED on each pin?
 

ErnieM

Joined Apr 24, 2011
8,377
On a 40 pin device you are sure to find 20 IO pins to hang the LEDs off of. A PIC is just fine directly turning 3 of these on at a time; if you want to turn more on then you would need a driver to handle the current.

Assuming with the pot one way you want the lowest 3 on, followed by very lowest off and next higher one on... that is 20-3 + 1 = 18 states, or 0 to 17. You got lucky as 255 / 17 = 15 exactly, so you can take the A2D output, divide by 15 (or subtract 15 until you get zero and count how many times yo do so) to get the state from the A2D.

Unfortunately, these 20 LEDs will not be in any sort of useful order when looking at the port registers that drive them. Gonna take a bit of code to untangle the state number into the correct LED pin drives. It's simple code, just a lot of it as there are basically 20 special cases (each LED pin).
 

Thread Starter

MCrowe

Joined May 29, 2011
69
ErnieM is right with what I want to do. Turn on led 1,2,3 then turn on 2,3,4 and so on. I came to pretty much the same conclusion. I think I need to check the condition for each LED. Say do a test on all 20 LED's checking if the ADC number fell within a range that turned on that LED. And the LED numbers would overlap so it turned 3 on at once. Gunna be some crappy code but I can't see any other way. Such a simple problem with such a crappy solution. Lol. Thank for the depots any how. If any one thinks of some amazing solution that I haven't seen let me know. Cheers
 

John P

Joined Oct 14, 2008
2,026
Seems to me that this really isn't difficult. You have 18 different states. Figure out the state as has already been suggested. Let the state be S, with value 0-17.

Then using a 3-byte quantity, do the equivalent to:
output = 7 << S;

Then

portb = output & 0xFF;
portc = (output >> 8) & 0xFF;
portd = (output >> 16) & 0xFF;

Only 4 bits of portd will be used. If you just grab bytes of the 3-byte quantity "output" you don't actually have to do any right-shifting.

How's this difficult? It looks pretty trivial.
 

John P

Joined Oct 14, 2008
2,026
It's C language syntax and means "Shift right a certain number of places", or "shift left" if it's <<.

Note that a multi-byte shift is easy in the PIC processors, because the C bit holds the bit that shifts out of one byte, and also the bit that shifts into the next. You just have to be sure that you know what the C bit holds when you shift the first byte.
 

Thread Starter

MCrowe

Joined May 29, 2011
69
John if possible could you explain how your idea would work? I don't understand how I would use the number I got from the A2D to select which bits to shift... Or what bits I would be shifting?
 

Thread Starter

MCrowe

Joined May 29, 2011
69
Hey wait, I think I get it. So you have 20 bits, with 3 'ONs' in a row. Like 00000111000000000000. And then just work out a number, such as 255/15 and use that to work out the number of times you shift the bits. If you started the calculation subroutine with the three ON bit to the left, you would simply shift right, between 0 and 17 times.

I know the calculations will be slightly more difficulty doing it all in assbley but I think I can make that work. Thank heap,
 

ErnieM

Joined Apr 24, 2011
8,377
Hrmmm... yes you could arrange then on Ports B,C and D. My preference is to leave RB6 & 7 dedicated to ICSP but they can be used for other things too.

Take a peek at the "RLR" (Rotate Left f through Carry) instruction, as a rotate is a shift. and this command can shift the port bits directly.

That's gonna cut down the code to a just a hand full of lines.
 

MMcLaren

Joined Feb 14, 2010
861
Assuming all variables in bank 0, here's one way you might do it;

Rich (BB code):
;
loop
        call    getADC          ; read ADC, left justified result
        banksel ADRESH          ;
        movf    ADRESH,W        ; 
        banksel adcval          ; bank 0
        movwf   adcval          ;
;
;  prep led pattern
;
        movlw   b'11100000'     ; pattern '11100000 00000000 0000'
        movwf   led+0           ;
        clrf    led+1           ;
        clrf    led+2           ;
;
;  shift pattern right 0 to 17 times
;
        movlw   15              ;
div15   subwf   adcval,F        ; adcval = adcval - 15
        skpnc                   ; borrow? no, skip, else
        goto    cont            ; branch (done)
        rrf     led+2,F         ; shift led array
        rrf     led+1,F         ;
        rrf     led+0,F         ;
        goto    div15           ;
cont
        call    output          ; refresh led outputs
        goto    loop            ;
 
Last edited:

Thread Starter

MCrowe

Joined May 29, 2011
69
Yeah thats the one. That does look simple. Thanks MMcLaren. Much better than the only thing I could think of originally which was to do a compare on each number. Or a slightly more thought out approach was to use shift registers, (I invented them in my mind but they seem so obvious Im sure they actually exist) So you pulse it a certain number of times and thats were it shifts the high bit too?? Lol. They have to exist, just imagine the applications... that way, if I could get my mythical shift register type thing with 20 outputs, I wouldn't need 3 ports just for lights. (I should stop now, and do more research, I cant figure out how this thing would decide wheather the bits were high or low.)

OK, now as that was obviously too easy (the code, not reading my rambling post). How do I go about dimming the LED's as well. Lol. I have some ideas, just not sure how valid they are. I was thinking that if the MC was sinking the current, then I could run each LED through a PWM controlled H-bridge IC. Will that actually work.

So I would only have one H-Bridge connected to all LED's.. Yeah, of course it will work. Ok I've convinced myself it will. Cheers.
 

Thread Starter

MCrowe

Joined May 29, 2011
69
WIKIPEDIA-> see, of course they existed....
In digital circuits, a shift register is a cascade of flip flops, sharing the same clock, which has the output of any one but the last flip-flop connected to the "data" input of the next one in the chain, resulting in a circuit that shifts by one position the one-dimensional "bit array" stored in it, shifting in the data present at its input and shifting out the last bit in the array,

I could so use one of them.
 

Thread Starter

MCrowe

Joined May 29, 2011
69
Ya it works.
Just a simple little program to light a single ligth in PORTD based on value read in from A2D converter...

Rich (BB code):
LEDshift
; Lighting single light based on A2D value on PORTD. A2D value max=255.
   movlw b'01111111'        ; pattern for LEDs'01111111 (1's are off)
   movwf led
;
; shift pattern right 0 to 7 times
;
   div32 movlw d'32'       ; Closet you can get to 8. so one light always stays on but doesnt flicker.
   subwf ADCno3,F          ; Subtract 32 from ADCno3
   btfss STATUS,C          ; check if a 'borrow' occured
   goto GetOut             ; if borrow occured (less than 0) branch out.
   rrf led,F               ; Rotate right through Carry.
   goto div32              ; No borrow, continue subtracting and rotating.
GetOut
   MOVFW led               ; Move result into PortD
   MOVWF PORTD
return
I know I know its not that exciting but I liked it. And so simlpe. :)
 
Last edited:

MMcLaren

Joined Feb 14, 2010
861
... that way, if I could get my mythical shift register type thing with 20 outputs, I wouldn't need 3 ports just for lights. ...
Yes, a shift register is one way. Then there's multiplexing. There's also something called Charlieplexing using I/O pin tri-state capability.

Regards...

Youtube Demo
 

Attachments

Thread Starter

MCrowe

Joined May 29, 2011
69
Hey MMcLaren, Am I correct in assuming the right shift part of your routine should be the other way round... I.e. shift led+0 then led+1 then led+2. As your shifting right, the 'ON' goes through carry and into next led bank / byte. cheers.

Assuming all variables in bank 0, here's one way you might do it;

Rich (BB code):
           ;
;
;  shift pattern right 0 to 17 times
;
        movlw   15              ;
div15   subwf   adcval,F        ; adcval = adcval - 15
        skpnc                   ; borrow? no, skip, else
        goto    cont            ; branch (done)
        rrf     led+2,F         ; shift led array
        rrf     led+1,F         ;
        rrf     led+0,F         ;
        goto    div15           ;
           ;
Just though id post it here, as long as im correct in case someone tries to copy it and cant figure out why it doesn't work. or will it work, but opposite? Actually, now I think about it, it would work, just, different? Was that delibrate on your part? Am I missing something?
 

MMcLaren

Joined Feb 14, 2010
861
Oops! Sorry! You're correct. Should be;

Rich (BB code):
loop
        call    getADC          ; read ADC, left justified result
        banksel ADRESH          ;
        movf    ADRESH,W        ; 
        banksel adcval          ; bank 0
        movwf   adcval          ;
;
;  prep led pattern
;
        movlw   b'11100000'     ; pattern '11100000 00000000 0000'
        movwf   led+0           ;
        clrf    led+1           ;
        clrf    led+2           ;
;
;  shift pattern right 0 to 17 times
;
        movlw   15              ;
div15   subwf   adcval,F        ; adcval = adcval - 15
        skpnc                   ; borrow? no, skip, else
        goto    cont            ; branch (done)
        rrf     led+0,F         ; shift led array
        rrf     led+1,F         ;
        rrf     led+2,F         ;
        goto    div15           ;
cont
        call    output          ; refresh led outputs
        goto    loop            ;
So how's it going?

Regards, Mike
 
Last edited:

John P

Joined Oct 14, 2008
2,026
That loop-and-shift routine (assuming you get it the right way round) is what I was talking about earlier, but I was thinking in C terms because I don't normally write in assembly. I'm impressed by how compact it works out to be in assembly!

But could you save a little time by calculating the number of places to shift as a number 0-17, and then count down using the DECFSZ instruction? It looks as if it's made to count loops.
 
Top