How to blink 8 LEDs at different rates- concurrently?


Closed Thread
Results 1 to 15 of 15
  1. #1
    Join Date
    May 2007
    Posts
    604

    Default How to blink 8 LEDs at different rates- concurrently?

    To do the equivalent of the code below with each LED blinking at a different rate - except that all 8 LEDs must blink concurrently.
    Code:
    PORTB = 0
    TRISB = 0
    
    MAIN:
    
    LOOP1:
      TOGGLE PORTB.0
      PAUSE 500
    GOTO LOOP1
    
    LOOP2:
      TOGGLE PORTB.1
      PAUSE 220
    GOTO LOOP2
    
    LOOP3:
      TOGGLE PORTB.2
      PAUSE 380
    GOTO LOOP1
    
    LOOP4:
      TOGGLE PORTB.3
      PAUSE 750
    GOTO LOOP4
    
    LOOP5:
      TOGGLE PORTB.4
      PAUSE 170
    GOTO LOOP5
    
    LOOP6:
      TOGGLE PORTB.5
      PAUSE 400
    GOTO LOOP6
    
    LOOP7:
      TOGGLE PORTB.6
      PAUSE 620
    GOTO LOOP7
    
    LOOP8:
      TOGGLE PORTB.7
      PAUSE 130
    GOTO LOOP8
    
    GOTO MAIN
    Last edited by rmteo; - 25th April 2010 at 17:10.

  2. #2
    Join Date
    Nov 2003
    Location
    Wellton, U.S.A.
    Posts
    5,924


    Did you find this post helpful? Yes | No

    Default

    You want them all to come on at the same time and drop out at different rates?
    Code:
    PORTB = %11111111
    PAUSE XXX
    PORTB = %11111110
    PAUSE XXX
    PORTB = %11111100
    ...
    LOOP OVER...
    Something like that?
    Dave
    Always wear safety glasses while programming.

  3. #3
    Join Date
    Jul 2003
    Posts
    2,358


    Did you find this post helpful? Yes | No

    Default

    Have as many LED's as you have pins...
    Code:
    	LoopALED var BYTE
    	LoopBLED var BYTE
    	LoopCLED var BYTE
    	LoopDLED var BYTE
    	LoopELED var BYTE
    	LoopFLED var BYTE
    	LoopGLED var BYTE
    	LoopHLED var BYTE
    	'
    	LoopACON con 50
    	LoopBCON con 22
    	LoopCCon con 38
    	LoopDCon con 75
    	LoopECon con 17
    	LoopFCon con 40
    	LoopGCon con 62
    	LoopHCon con 13
    	'
    	TRISB=0
    Loop:
    	If LoopALED=0 then
    		LoopALED=LoopACON
    		Toggle PortB.0
    		else
    		LoopALED=LoopALED-1
    		endif
    	'
    	If LoopBLED=0 then
    		LoopBLED=LoopBCON
    		Toggle PortB.1
    		else
    		LoopBLED=LoopBLED-1
    		endif
    	'
    	If LoopCLED=0 then
    		LoopCLED=LoopCCON
    		Toggle PortB.2
    		else
    		LoopCLED=LoopCLED-1
    		endif
    	'
    	If LoopDLED=0 then
    		LoopDLED=LoopDCON
    		Toggle PortB.3
    		else
    		LoopDLED=LoopDLED-1
    		endif
    	'
    	If LoopELED=0 then
    		LoopELED=LoopECON
    		Toggle PortB.4
    		else
    		LoopELED=LoopELED-1
    		endif
    	'
    	If LoopFLED=0 then
    		LoopFLED=LoopFCON
    		Toggle PortB.5
    		else
    		LoopFLED=LoopFLED-1
    		endif
    	'
    	If LoopGLED=0 then
    		LoopGLED=LoopGCON
    		Toggle PortB.6
    		else
    		LoopGLED=LoopGLED-1
    		endif
    	'
    	If LoopHLED=0 then
    		LoopHLED=LoopHCON
    		Toggle PortB.7
    		else
    		LoopHLED=LoopHLED-1
    		endif
    	'
    	Pause 10
    	Goto Loop
    Homework Done! Melanie's off down the pub...

    Now repeat the above (excluding definitions) in less than 8 Lines of Code... (yes it can be done)!

  4. #4
    Join Date
    May 2007
    Posts
    604


    Did you find this post helpful? Yes | No

    Default

    mack, the LEDs need to blink all at the same time, so that will not work.

    Mel, use arrays and a for-next loop - along these lines?
    Code:
    Loop:
    for x = 0 to 7
      If LoopLED[x] = 0 then
        LoopLED[x] = LoopCON[x]
        Toggle PORTB.x
      else
        LoopLED[x] = LoopLED[x]-1
      endif  
    next x
    Pause 10
    Goto Loop

  5. #5
    Join Date
    Jul 2003
    Posts
    2,358


    Did you find this post helpful? Yes | No

    Default

    Yes, pretty much, but I don't think PortB.x will work, so...

    Code:
    	ShadowPortB=0
    Loop:
    	for x = 0 to 7
    		If LoopLED[x] = 0 then
    			LoopLED[x] = LoopCON[x]
    			ShadowPortB.0(x)=ShadowPortB.0(x)^1
    			else
    			LoopLED[x] = LoopLED[x]-1
    			endif  
    		next x
    	PortB=ShadowPortB
    	Pause 10
    	Goto Loop
    Where ShadowPort is a BYTE.

  6. #6
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Just to be different ...
    And because she said "less than 8 Lines of Code" ...

    Code:
    TRISB = 0
    Main:
        x = (x + 1) // 8
        PORTB.0(x) = !(LoopLED(x) < LoopCON(x))
        LoopLED(x) = (LoopLED(x) + 1) // (LoopCON(x) << 1)
        if x=7 THEN PAUSE 10
    GOTO Main
    DT

  7. #7
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    OUCH!

    After running my loop in the SIM.
    I realized the timing was Waaaayyyyy OFF.
    Fortunately, the other examples were "OFF" too ... just not as far.

    I've always said PAUSE is the worst statement in the BASIC language.
    It got me again.

    Here's a version that should compensate ...
    It uses the CCP module in "Compare" mode to create a precise 10mS interval.
    So when you give a delay value of 50, it actually takes 500mS, on the nose.

    Sorry, it's more than 8 lines now.
    Code:
    DEFINE OSC 4
    DEFINE BLINKYFREQ 100  ; 10mS periods
    
    DATA 50,22,38,75,17,40,62,13  ; default periods for each Output
    ;----------------------------------------------------------------
    CCPR1val  CON EXT      : @CCPR1val = (OSC*1000000/4)/ BLINKYFREQ
    CCPR1     VAR WORD EXT : @CCPR1 = CCPR1L
    Timer1    VAR WORD EXT : @Timer1 = TMR1L
    CCPIF     VAR PIR1.2
    
    LoopLED   VAR BYTE[8]
    LoopCON   VAR BYTE[8]
    x         VAR BYTE
    
    ;----[Initialize]------------------------------------------------
    FOR x = 0 to 7         ; load the periods from EEPROM
        READ x, LoopCON(x)
    NEXT X
    ;-- setup CCP1 and Start Timer1 --
    CCPR1   = CCPR1val     ; set compare value
    CCP1CON = %00001011    ; compare mode, special event 
    Timer1  = 0            ; clear Timer1
    T1CON.0 = 1            ; start Timer1
    
    TRISB = 0              ; PORTB all OUTPUT
    
    ;----[Main Program Loop]----------------------------------------
    Main: 
        x = (x + 1) // 8
        PORTB.0(x) = !(LoopLED(x) < LoopCON(x))
        LoopLED(x) = (LoopLED(x) + 1) // (LoopCON(x) << 1)
        IF x != 7 THEN Main
      Waiting: IF !CCPIF THEN Waiting
        CCPIF = 0
    GOTO Main
    Cheers,
    Last edited by Darrel Taylor; - 26th April 2010 at 04:59. Reason: Minor modifications
    DT

  8. #8
    Join Date
    Jul 2003
    Posts
    2,358


    Did you find this post helpful? Yes | No

    Default

    Personally, I'd have reduced PAUSE by a couple of clicks *smiles*

  9. #9
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default

    Darrel, that algorithm is slick!

    Does PBP allow assignments in expressions like C? For example;

    Code:
    while(1)
    { x = (x+1)&7;
      portb ^= ((!(LoopLED[x]=(LoopLED[x]+1)%LoopCON[x])) << x);
      delay_us(2500);
    }

  10. #10
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Thanks Mike.
    Quote Originally Posted by Mike, K8LH View Post
    Does PBP allow assignments in expressions like C? ...
    Nope, not even a +=

    However, your x = (x+1)&7 takes much less time than my x = (x + 1) // 8 (Modulus) approach.
    What was I thinking?

    Cool, thanks!
    DT

  11. #11
    Join Date
    Feb 2003
    Posts
    432


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Darrel Taylor View Post
    Thanks Mike.

    Nope, not even a +=

    However, your x = (x+1)&7 takes much less time than my x = (x + 1) // 8 (Modulus) approach.
    What was I thinking?

    Cool, thanks!
    DOH!!! The problem with working with so many different languages is that you can misread code. I took " //8 " to be a comment (Javascript style) that you were going to do it 8 times LOL
    Keith

    www.diyha.co.uk
    www.kat5.tv

  12. #12
    Join Date
    Jan 2006
    Location
    Istanbul
    Posts
    1,185


    Did you find this post helpful? Yes | No

    Default

    If "8 lines" is about the loop part, then here is my code.


    Think like a politician. Is is not less then 8?



    Code:
    <font color="#000080"><b>EEPROM </b></font><font color="#FF0000">0</font>,[<font color="#FF0000">50</font>,<font color="#FF0000">22</font>,<font color="#FF0000">38</font>,<font color="#FF0000">75</font>,<font color="#FF0000">17</font>,<font color="#FF0000">40</font>,<font color="#FF0000">62</font>,<font color="#FF0000">13</font>]
              <font color="#000080"><i>'RB0 - RB7 time intervals
        
    </i></font>Time    <font color="#000080"><b>VAR BYTE</b></font>[<font color="#FF0000">8</font>]
    Timer   <font color="#000080"><b>VAR BYTE</b></font>[<font color="#FF0000">8</font>]
    Temp    <font color="#000080"><b>VAR BYTE
    </b></font>Preload <font color="#000080"><b>VAR WORD
    </b></font>T1CON = <font color="#FF0000">%00000000   </font><font color="#000080"><i>' 1:1 @4Mhz
    </i></font>TMR1IF <font color="#000080"><b>VAR </b></font>PIR1.<font color="#FF0000">0   </font><font color="#000080"><i>' An alias for overflow bit.
    </i></font>TMR1ON <font color="#000080"><b>VAR </b></font>T1CON.<font color="#FF0000">0
    
    
    </font>Begin:
        Preload = <font color="#FF0000">55543 </font><font color="#000080"><i>'Timer1 preload value for excat 10ms. interval.
        </i><b>FOR </b></font>Temp = <font color="#FF0000">0 </font><font color="#000080"><b>TO </b></font><font color="#FF0000">7
            </font><font color="#000080"><b>READ </b></font>Temp ,Time[Temp]  <font color="#000080"><i>'Fill time-intervals.
            </i></font>Timer[Temp] = <font color="#FF0000">0        </font><font color="#000080"><i>'Clear timer array.
        </i><b>NEXT </b></font>Temp
    
    T:
        TMR1IF = <font color="#FF0000">0
        </font>TMR1L = Preload.LowByte
        TMR1H = Preload.HighByte
        TMR1ON = <font color="#FF0000">1
        
    </font>Start:
    
        <font color="#000080"><b>IF </b></font>TMR1IF <font color="#000080"><b>THEN </b></font>INT_TMR       ' 1 line. 
    
        <font color="#000080"><b>GOTO </b></font>Start
        
    
    INT_TMR:
        TMR1ON = <font color="#FF0000">0
        </font><font color="#000080"><b>FOR </b></font>Temp = <font color="#FF0000">0 </font><font color="#000080"><b>TO </b></font><font color="#FF0000">7
            </font><font color="#000080"><b>IF </b></font>Timer[Temp] = Time[Temp] <font color="#000080"><b>THEN 
                </b></font>PORTB.<font color="#FF0000">0</font>[Temp] = PORTB.<font color="#FF0000">0</font>[Temp] ^<font color="#FF0000">1
                </font>Timer[Temp] = <font color="#FF0000">0
            </font><font color="#000080"><b>ENDIF
            </b></font>Timer[Temp] = Timer[Temp] + <font color="#FF0000">1
        </font><font color="#000080"><b>NEXT </b></font>Temp   
        
        <font color="#000080"><b>GOTO </b></font>T    
    
    <font color="#000080"><b>END
    
    
    
    </b></font>
    "If the Earth were a single state, Istanbul would be its capital." Napoleon Bonaparte

  13. #13
    Join Date
    May 2007
    Posts
    604


    Did you find this post helpful? Yes | No

    Default

    I am working on the skeleton of a generic task handler that will manage say 16 tasks concurrently. The LEDs are just simulating tasks that occur at set intervals. One of the tasks will be a seconds counter (with an interval of 1000mS) that is the basis of a RTC (good to the accuracy/stability of the HS crystal clock) and accurate timing is therefore an important concern. So using any kind of Pause or Delay function would not work.

    Using a hardware timer is really the only way to do it. However, the timer also has to account for whatever time is used up by instruction cycles - which can vary depending on conditional branches and time spent in each task. DT's method of using a CCP in compare mode solves this problem nicely. Thanks.

  14. #14
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  15. #15
    Join Date
    May 2007
    Posts
    604


    Did you find this post helpful? Yes | No

    Default

    No I have not seen that link, thanks for pointing it out. I looked at Salvo and several other co-operative and pre-emptive RTOSes. Salvo is actually quite nice and has a small footprint. However, at $1,500 for a full-source license, it is somewhat pricey for my current needs - although it must be said that compared to some other commercial (particularly the pre-emptive ones such Avix, CMX, etc.) products, you could still call it a bargain. There are several free (and/or open source) pre-emptive systems for higher end devices but I find them extremely cumbersome to use and very resource hungry. The few that I looked at required about 20K ROM and 5-6K RAM for a useable configuration. I am also wanting something that can be easily ported to other devices/platforms (such as PIC24/dsPIC33 and 32-bit ARM Cortex M0/M3) and can be implemented using only a high level language (whether BASIC or C).

    I have implemented what is basically a time-sliced task handler that will do 16 tasks in about 250 bytes of ROM and 75 bytes of RAM - additional tasks require 2 bytes of RAM per task. Small enough to run on a PIC12/16 - reducing the number of tasks could reduce the ROM (and RAM) footprint even further. Works fine - as I mentioned in a previous post, I have an application where an RTC is implemented using one of the tasks as an accurate seconds counter.

Members who have read this thread : 3

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts