Turning lights on based on a number

Discussion in 'Programmer's Corner' started by MCrowe, Jul 12, 2011.

  1. MCrowe

    Thread Starter Member

    May 29, 2011
    69
    0
    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: Jul 12, 2011
  2. R!f@@

    AAC Fanatic!

    Apr 2, 2009
    8,750
    759
    Why don't u come up with something and post it. From there u'll get better options and replies
     
  3. MCrowe

    Thread Starter Member

    May 29, 2011
    69
    0
    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...
     
  4. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    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?
     
  5. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    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).
     
  6. MCrowe

    Thread Starter Member

    May 29, 2011
    69
    0
    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
     
  7. John P

    AAC Fanatic!

    Oct 14, 2008
    1,632
    224
    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.
     
  8. MCrowe

    Thread Starter Member

    May 29, 2011
    69
    0
    Sorry, I don't know what >> means.
     
  9. John P

    AAC Fanatic!

    Oct 14, 2008
    1,632
    224
    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.
     
  10. MCrowe

    Thread Starter Member

    May 29, 2011
    69
    0
    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?
     
  11. MCrowe

    Thread Starter Member

    May 29, 2011
    69
    0
    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,
     
  12. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    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.
     
  13. MMcLaren

    Well-Known Member

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

    Code ( (Unknown Language)):
    1.  
    2. ;
    3. loop
    4.         call    getADC          ; read ADC, left justified result
    5.         banksel ADRESH          ;
    6.         movf    ADRESH,W        ;
    7.         banksel adcval          ; bank 0
    8.         movwf   adcval          ;
    9. ;
    10. ;  prep led pattern
    11. ;
    12.         movlw   b'11100000'     ; pattern '11100000 00000000 0000'
    13.         movwf   led+0           ;
    14.         clrf    led+1           ;
    15.         clrf    led+2           ;
    16. ;
    17. ;  shift pattern right 0 to 17 times
    18. ;
    19.         movlw   15              ;
    20. div15   subwf   adcval,F        ; adcval = adcval - 15
    21.         skpnc                   ; borrow? no, skip, else
    22.         goto    cont            ; branch (done)
    23.         rrf     led+2,F         ; shift led array
    24.         rrf     led+1,F         ;
    25.         rrf     led+0,F         ;
    26.         goto    div15           ;
    27. cont
    28.         call    output          ; refresh led outputs
    29.         goto    loop            ;
    30.  
     
    Last edited: Jul 13, 2011
  14. MCrowe

    Thread Starter Member

    May 29, 2011
    69
    0
    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.
     
  15. MCrowe

    Thread Starter Member

    May 29, 2011
    69
    0
    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.
     
  16. MCrowe

    Thread Starter Member

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

    Code ( (Unknown Language)):
    1.  
    2. LEDshift
    3. ; Lighting single light based on A2D value on PORTD. A2D value max=255.
    4.    movlw b'01111111'        ; pattern for LEDs'01111111 (1's are off)
    5.    movwf led
    6. ;
    7. ; shift pattern right 0 to 7 times
    8. ;
    9.    div32 movlw d'32'       ; Closet you can get to 8. so one light always stays on but doesnt flicker.
    10.    subwf ADCno3,F          ; Subtract 32 from ADCno3
    11.    btfss STATUS,C          ; check if a 'borrow' occured
    12.    goto GetOut             ; if borrow occured (less than 0) branch out.
    13.    rrf led,F               ; Rotate right through Carry.
    14.    goto div32              ; No borrow, continue subtracting and rotating.
    15. GetOut
    16.    MOVFW led               ; Move result into PortD
    17.    MOVWF PORTD
    18. return
    19.  
    I know I know its not that exciting but I liked it. And so simlpe. :)
     
    Last edited: Jul 14, 2011
  17. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    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
     
  18. MCrowe

    Thread Starter Member

    May 29, 2011
    69
    0
    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.

    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?
     
  19. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Oops! Sorry! You're correct. Should be;

    Code ( (Unknown Language)):
    1.  
    2. loop
    3.         call    getADC          ; read ADC, left justified result
    4.         banksel ADRESH          ;
    5.         movf    ADRESH,W        ;
    6.         banksel adcval          ; bank 0
    7.         movwf   adcval          ;
    8. ;
    9. ;  prep led pattern
    10. ;
    11.         movlw   b'11100000'     ; pattern '11100000 00000000 0000'
    12.         movwf   led+0           ;
    13.         clrf    led+1           ;
    14.         clrf    led+2           ;
    15. ;
    16. ;  shift pattern right 0 to 17 times
    17. ;
    18.         movlw   15              ;
    19. div15   subwf   adcval,F        ; adcval = adcval - 15
    20.         skpnc                   ; borrow? no, skip, else
    21.         goto    cont            ; branch (done)
    22.         rrf     led+0,F         ; shift led array
    23.         rrf     led+1,F         ;
    24.         rrf     led+2,F         ;
    25.         goto    div15           ;
    26. cont
    27.         call    output          ; refresh led outputs
    28.         goto    loop            ;
    29.  
    So how's it going?

    Regards, Mike
     
    Last edited: Jul 16, 2011
  20. John P

    AAC Fanatic!

    Oct 14, 2008
    1,632
    224
    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.
     
Loading...