What's the best code loop-structure to handle multiple tasks without interruption?

OLDmarty

Senior Member
Hi All,

I'm looking for help on the best way to structure code that has multiple tasks happening, while not interrupting or slowing the overall operation at any given time.
For example, i want to drive 16 LEDs using a 4x4 (Multiplexed) matrix (4 rows x 4 columns)
The LEDs in the matrix will be often changing states and/or flashing in various patterns.

The LED status and flash speeds will be dependent on settings of various pots and switches wired to the picaxe.
The LED patterns vary from switching approx 10-20 times per second down to say once per second, while other LEDs are just static ON or off.
Of course the 'ON' LEDs need to look like they're stable, not flickering due to the speed of the matrix scanning being interrupted by the code going to process a pot-change etc.

In my past attempts (long ago), while my projects have worked overall, i suffer too much interruption to the LEDs while adjusting pots and setting external switches to alternate values.

So, in all, i need to master how i use loops to monitor/switch everything cleanly.
Are there preferred ways to do this?

My loops in the past have always revolved around goto's & gosubs, i've never ventured into using DO loops or WAITs, WENDs etc...maybe this is what i'm lacking?

I haven't provided code my example, as this is just an open question about general structure and loop techniques that people prefer to use efficiently.

Any suggestions are greatly welcomed, i can only learn what i've been doing wrong all these years lol ;-)

Regards,
Marty.
 
Last edited:

premelec

Senior Member
More info

Hi OM - please be more specific about what your problem is - too slow? How much too slow? What PICAXEs and sped have you used... and it may be a hardware problem more than software - with two 8 bit latches [or 16 output pins] you can hold the data rather than multiplexing - and were you multiplexing? Perhaps post some code that doesn't work for you and be specific what... There isn't any general solution to such a floating inquiry --- My suggestion would to be formulate the bits at leisure then set the output lines. In early work with dimming LEDs I used latched DACs to avoid a variety of artifacts... serial output to the constant current latched DAC determined drivers...
 

OLDmarty

Senior Member
Hi OM - please be more specific about what your problem is - too slow? How much too slow? What PICAXEs and sped have you used... and it may be a hardware problem more than software - with two 8 bit latches [or 16 output pins] you can hold the data rather than multiplexing - and were you multiplexing? Perhaps post some code that doesn't work for you and be specific what... There isn't any general solution to such a floating inquiry --- My suggestion would to be formulate the bits at leisure then set the output lines. In early work with dimming LEDs I used latched DACs to avoid a variety of artifacts... serial output to the constant current latched DAC determined drivers...
Hi, Yes it's a multiplexed 4x4 LED matrix...
The problem is when i update the LED matrix fast enough to make the LEDs look 'static', they soon flicker when the code goes away to process a pot or button change.

I have no code to share, i'm just in the process of revisiting some old projects to bring them upto date and save pins/hardware.
I use 28x2 and 40x2 picaxes, but that's beside my point, it isn't slow hardware, it's *ME* not structuring loops within loops correctly, hence my question to ask what other people do.
I've always used external latches or larger (pic) devices to increase I/O pins, but this is all about NOT using external chips and seeing how busy a picaxe can operate before becoming very laggy with multiplexing.


So, back to my initial question, what methods or coding rules do people use to maintain efficient code processing without seemingly slowing down (flickering) LEDs?
 

BESQUEUT

Senior Member
Hi All,

I'm looking for help on the best way to structure code that has multiple tasks happening, while not interrupting or slowing the overall operation at any given time.
For example, i want to drive 16 LEDs using a 4x4 (Multiplexed) matrix (4 rows x 4 columns)
The LEDs in the matrix will be often changing states and/or flashing in various patterns.
...
Any suggestions are greatly welcomed, i can only learn what i've been doing wrong all these years lol ;-).
In your case, I alway use
https://en.wikipedia.org/wiki/Cooperative_multitasking
This is very powerfull, but need a different approach ; so it's difficult to explain...
- never use GOTO command,
- use only ONE main loop, (the scheduler),
- never use the PAUSE command (as TASKS have to release CPU as soon as possible to be "cooperative")
- instead, use the TIME variable (or other time keeper, or a simple counter) to schedule tasks in the future

If you are using M2 at nominal speed (not overclocking) you also can use Picaxe pseudo-multitasking.

In French (I can translate if necessary...)
Chenillard-méthode du lapin fou
 
Last edited:

OLDmarty

Senior Member
Not sure if i actually need true (or pseudo) "multitasking" as such, i just need to set out my loop(s) in an order from most-used tasks (update LEDs) to least-used tasks (read pots/switches) and process them all in a way that keep it running smooth and not flickering.
 

BESQUEUT

Senior Member
Not sure if i actually need true (or pseudo) "multitasking" as such, i just need to set out my loop(s) in an order from most-used tasks (update LEDs) to least-used tasks (read pots/switches) and process them all in a way that keep it running smooth and not flickering.
IHMO, you need...
But don't be afraid... It is different, not difficult...
Code:
[color=Navy]#picaxe [/color][color=Black]14m2[/color]

[color=Blue]symbol [/color][color=Black]lesJoueurs[/color][color=DarkCyan]=[/color][color=Purple]b0    [/color][color=Green]' chaque bit repr?sente un joueur[/color]
[color=Blue]symbol [/color][color=Black]Elimine[/color][color=DarkCyan]=[/color][color=Purple]b1       [/color][color=Green]' variable temporaire pour savoir si un joueur est elimine[/color]
[color=Blue]symbol [/color][color=Black]I[/color][color=DarkCyan]=[/color][color=Purple]b2[/color]
[color=Blue]symbol [/color][color=Black]Clignotant[/color][color=DarkCyan]=[/color][color=Purple]b3    [/color][color=Green]' Compteur pour faire clignoter les LEDs[/color]
[color=Blue]symbol [/color][color=Black]Tempo1[/color][color=DarkCyan]=[/color][color=Navy]10        [/color][color=Green]' Nombre de boucles pour faire clignoter les LEDs[/color]
[color=Blue]symbol [/color][color=Black]Tempo2[/color][color=DarkCyan]=[/color][color=Navy]20        [/color][color=Green]' a ajouster pour obtenir un clignotement ad?quat[/color]
[color=Blue]symbol [/color][color=Black]lesLEDs [/color][color=DarkCyan]=[/color][color=Purple]b5[/color]
[color=Blue]symbol [/color][color=Black]Volts[/color][color=DarkCyan]= [/color][color=Purple]b6[/color]
[color=Blue]symbol [/color][color=Black]LeBouton[/color][color=DarkCyan]=[/color][color=Purple]b7      [/color][color=Green]' le bouton qui a ?t? enfonc?, on z?ro si aucun bouton enfonce[/color]

[color=Blue]table ([/color][color=Navy]0[/color][color=Black],[/color][color=Navy]1[/color][color=Black],[/color][color=Navy]2[/color][color=Black],[/color][color=Navy]4[/color][color=Black],[/color][color=Navy]8[/color][color=Black],[/color][color=Navy]16[/color][color=Black],[/color][color=Navy]32[/color][color=Black],[/color][color=Navy]64[/color][color=Black],[/color][color=Navy]128[/color][color=Blue])

let [/color][color=Purple]dirsB [/color][color=DarkCyan]= [/color][color=Navy]%00111111[/color]
[color=Blue]let [/color][color=Purple]dirsC [/color][color=DarkCyan]= [/color][color=Navy]%00000000[/color]


[color=Blue]do
loop until [/color][color=Purple]pinC.3[/color][color=DarkCyan]=[/color][color=Navy]1                       [/color][color=Green]'attend pression sur "D?part" pour d?marrer[/color]
[color=Purple]outpinsB[/color][color=DarkCyan]=[/color][color=Navy]%00000000[/color]



[color=Blue]do
      readadc [/color][color=Navy]4[/color][color=Black],Volts                           [/color][color=Green]'lecture C.4 analogique vers b6
      [/color][color=Black]leBouton[/color][color=DarkCyan]=[/color][color=Black]Volts[/color][color=DarkCyan]/[/color][color=Navy]2[/color][color=DarkCyan]+[/color][color=Navy]11[/color][color=DarkCyan]/[/color][color=Navy]22
      [/color][color=Blue]if [/color][color=Black]leBouton[/color][color=DarkCyan]>[/color][color=Navy]0 [/color][color=Blue]then[/color]
[color=Green]'           lesLEDs=DCD leBouton
            [/color][color=Blue]readtable [/color][color=Black]leBouton, lesLEDs         [/color][color=Green]' DCD n'etant pas disponible sur un M2, on le simule
            [/color][color=Black]Elimine[/color][color=DarkCyan]=[/color][color=Black]lesLEDs [/color][color=DarkCyan]and [/color][color=Black]lesjoueurs
            [/color][color=Blue]if [/color][color=Black]Elimine[/color][color=DarkCyan]=[/color][color=Navy]0 [/color][color=Blue]then
                  [/color][color=Purple]outpinsB[/color][color=DarkCyan]=[/color][color=Black]lesLEDs
                  lesJoueurs[/color][color=DarkCyan]=[/color][color=Black]lesJoueurs [/color][color=DarkCyan]OR [/color][color=Black]lesLEDs    [/color][color=Green]' on coche le joueur qui a tente sa chance
                  [/color][color=Blue]gosub [/color][color=Black]Verdict
            [/color][color=Blue]endif
      endif

      inc [/color][color=Black]Clignotant                [/color][color=Green]' Ce module fait clignoter les joueurs restants en jeu
      [/color][color=Blue]if [/color][color=Black]Clignotant[/color][color=DarkCyan]= [/color][color=Black]Tempo1 [/color][color=Blue]then
            [/color][color=Purple]outpinsB[/color][color=DarkCyan]=NOT [/color][color=Black]lesJoueurs
      [/color][color=Blue]elseif [/color][color=Black]Clignotant[/color][color=DarkCyan]>[/color][color=Black]Tempo2 [/color][color=Blue]then
            [/color][color=Purple]outpinsB[/color][color=DarkCyan]=[/color][color=Navy]0
            [/color][color=Black]Clignotant[/color][color=DarkCyan]=[/color][color=Navy]0
      [/color][color=Blue]endif
loop[/color]


[color=Black]Verdict:
      [/color][color=Blue]do
            if [/color][color=Purple]pinC.4[/color][color=DarkCyan]=[/color][color=Navy]1 [/color][color=Blue]then  [/color][color=Green]' c'est gagne ! on repart au debut
                  [/color][color=Black]lesJoueurs[/color][color=DarkCyan]=[/color][color=Navy]0
                  [/color][color=Purple]outpinsB[/color][color=DarkCyan]=[/color][color=Navy]%00000000
                  [/color][color=Blue]exit
                  
            elseif [/color][color=Purple]pinC.3[/color][color=DarkCyan]=[/color][color=Navy]1 [/color][color=Blue]then          [/color][color=Green]' remet en route apres mauvaise reponse
                  [/color][color=Blue]if [/color][color=Black]lesJoueurs[/color][color=DarkCyan]=[/color][color=Navy]%00111111 [/color][color=Blue]then [/color][color=Green]' Mais il ne reste plus de joueurs !
                        [/color][color=Black]lesJoueurs[/color][color=DarkCyan]=[/color][color=Navy]0
                        [/color][color=Purple]outpinsB[/color][color=DarkCyan]=[/color][color=Navy]%00000000
                  [/color][color=Blue]endif
                  exit
            endif
      loop
return[/color]
You have to understand that there is only ONE CPU !
So if a "least-used tasks" monopolyse CPU (for example using a PAUSE command) it is not possible to make "most-used tasks" working...
 

BESQUEUT

Senior Member
Another one, english speaking :
Code:
[color=Navy]#Picaxe [/color][color=Black]20M2[/color]
[color=Navy]#No_Data    [/color]

[color=Blue]output B.0[/color][color=Black],[/color][color=Blue]B.1[/color][color=Black],[/color][color=Blue]B.2[/color][color=Black],[/color][color=Blue]B.3[/color][color=Black],[/color][color=Blue]B.4[/color][color=Black],[/color][color=Blue]B.5[/color][color=Black],[/color][color=Blue]B.6[/color][color=Black],[/color][color=Blue]B.7    
input C.0[/color][color=Black],[/color][color=Blue]C.1[/color][color=Black],[/color][color=Blue]C.2[/color][color=Black],[/color][color=Blue]C.3[/color][color=Black],[/color][color=Blue]C.4[/color][color=Black],[/color][color=Blue]C.5[/color][color=Black],[/color][color=Blue]C.6[/color][color=Black],[/color][color=Blue]C.7

Symbol [/color][color=Black]SwitchFor [/color][color=DarkCyan]= [/color][color=Purple]pinC.0[/color]
[color=Blue]Symbol [/color][color=Black]SwitchRev [/color][color=DarkCyan]= [/color][color=Purple]pinC.1[/color]

[color=Blue]Symbol [/color][color=Black]Motor_Forward[/color][color=DarkCyan]=[/color][color=Blue]B.0
Symbol [/color][color=Black]Motor_Backward[/color][color=DarkCyan]=[/color][color=Blue]B.1
Symbol [/color][color=Black]Ramper[/color][color=DarkCyan]=[/color][color=Blue]B.2

Symbol [/color][color=Black]Active[/color][color=DarkCyan]=[/color][color=Navy]1[/color]

[color=Blue]Symbol [/color][color=Black]RelayDelay[/color][color=DarkCyan]=[/color][color=Navy]1 [/color][color=Green]'s[/color]
[color=Blue]Symbol [/color][color=Black]RampDelay[/color][color=DarkCyan]=[/color][color=Navy]5 [/color][color=Green]'s[/color]
[color=Blue]Symbol [/color][color=Black]RunningDelay[/color][color=DarkCyan]=[/color][color=Navy]20 [/color][color=Green]'s[/color]
[color=Blue]Symbol [/color][color=Black]StoppingDelay[/color][color=DarkCyan]=[/color][color=Navy]6 [/color][color=Green]'s[/color]

[color=Blue]symbol [/color][color=Black]Direction[/color][color=DarkCyan]=[/color][color=Purple]b1[/color]
[color=Blue]symbol [/color][color=Black]UP[/color][color=DarkCyan]=[/color][color=Navy]1[/color]
[color=Blue]Symbol [/color][color=Black]DOWN[/color][color=DarkCyan]=[/color][color=Navy]2[/color]

[color=Blue]Symbol [/color][color=Black]State[/color][color=DarkCyan]=[/color][color=Purple]b2[/color]
[color=Blue]Symbol [/color][color=Black]Stopped[/color][color=DarkCyan]=[/color][color=Navy]0[/color]
[color=Blue]Symbol [/color][color=Black]BeforeRamp[/color][color=DarkCyan]=[/color][color=Navy]1[/color]
[color=Blue]Symbol [/color][color=Black]Ramping[/color][color=DarkCyan]=[/color][color=Navy]2[/color]
[color=Blue]Symbol [/color][color=Black]Running[/color][color=DarkCyan]=[/color][color=Navy]3[/color]
[color=Blue]symbol [/color][color=Black]Stopping[/color][color=DarkCyan]=[/color][color=Navy]4[/color]
[color=Blue]symbol [/color][color=Black]StopThenRamp[/color][color=DarkCyan]=[/color][color=Navy]5[/color]


[color=Black]Main:
      [/color][color=Blue]low B.0[/color][color=Black], [/color][color=Blue]B.1[/color][color=Black],[/color][color=Blue]B.2
      [/color][color=Black]Direction[/color][color=DarkCyan]=[/color][color=Black]Stopped
      State[/color][color=DarkCyan]=[/color][color=Black]Stopped
      [/color][color=Purple]Time[/color][color=DarkCyan]=[/color][color=Navy]0
      [/color][color=Blue]do
            if [/color][color=Black]SwitchFor[/color][color=DarkCyan]=[/color][color=Black]Active [/color][color=Blue]then
                  if [/color][color=Black]switchRev[/color][color=DarkCyan]=[/color][color=Blue]ON then [/color][color=Green]' Hey Dude ! What are you doing ?
                        [/color][color=Blue]GOSUB [/color][color=Black]GoStop
                  [/color][color=Blue]else
                        GOSUB [/color][color=Black]GoUP
                  [/color][color=Blue]endif
            else
                  if [/color][color=Black]switchRev[/color][color=DarkCyan]=[/color][color=Black]Active [/color][color=Blue]then
                        GOSUB [/color][color=Black]GoDOWN
                  [/color][color=Blue]else
                        GOSUB [/color][color=Black]GoStop
                  [/color][color=Blue]endif
            endif
            GOSUB [/color][color=Black]LookAtWatch
      [/color][color=Blue]loop
                  

                  [/color]

[color=Black]GoUP:
      [/color][color=Blue]select case [/color][color=Black]Direction
      [/color][color=Blue]case [/color][color=Black]Stopped
            [/color][color=Blue]high [/color][color=Black]Motor_Forward
            state[/color][color=DarkCyan]=[/color][color=Black]BeforeRamp : [/color][color=Purple]Time[/color][color=DarkCyan]=[/color][color=Navy]0
      [/color][color=Blue]case [/color][color=Black]DOWN
            [/color][color=Blue]low [/color][color=Black]Motor_Backward
            state[/color][color=DarkCyan]=[/color][color=Black]StopThenRamp : [/color][color=Purple]Time[/color][color=DarkCyan]=[/color][color=Navy]0
      [/color][color=Blue]endselect
      [/color][color=Black]Direction[/color][color=DarkCyan]=[/color][color=Black]UP
      [/color][color=Blue]RETURN
      
      [/color]
[color=Black]GoDOWN:
      [/color][color=Blue]select case [/color][color=Black]Direction
      [/color][color=Blue]case [/color][color=Black]Stopped
            [/color][color=Blue]high [/color][color=Black]Motor_Backward
            state[/color][color=DarkCyan]=[/color][color=Black]BeforeRamp : [/color][color=Purple]Time[/color][color=DarkCyan]=[/color][color=Navy]0
      [/color][color=Blue]case [/color][color=Black]UP
            [/color][color=Blue]low [/color][color=Black]Motor_Forward
            state[/color][color=DarkCyan]=[/color][color=Black]StopThenRamp : [/color][color=Purple]Time[/color][color=DarkCyan]=[/color][color=Navy]0
      [/color][color=Blue]endselect
      [/color][color=Black]Direction[/color][color=DarkCyan]=[/color][color=Black]DOWN
      [/color][color=Blue]RETURN
      [/color]
[color=Black]GoStop:
      [/color][color=Blue]low [/color][color=Black]Motor_Forward,Motor_Backward,Ramper
      [/color][color=Blue]if [/color][color=Black]Direction [/color][color=DarkCyan]<> [/color][color=Black]Stopped [/color][color=Blue]then
            [/color][color=Black]State[/color][color=DarkCyan]=[/color][color=Black]Stopping : [/color][color=Purple]Time[/color][color=DarkCyan]=[/color][color=Navy]0
      [/color][color=Blue]endif
      RETURN
      
      [/color]
[color=Black]LookAtWatch:
      [/color][color=Blue]select case [/color][color=Black]State
      [/color][color=Blue]case [/color][color=Black]BeforeRamp
            [/color][color=Blue]if [/color][color=Purple]Time[/color][color=DarkCyan]>[/color][color=Black]RelayDelay [/color][color=Blue]then
                  high [/color][color=Black]Ramper
                  State[/color][color=DarkCyan]=[/color][color=Black]Ramping : [/color][color=Purple]Time[/color][color=DarkCyan]=[/color][color=Navy]0
            [/color][color=Blue]endif 
      
      case [/color][color=Black]Ramping
            [/color][color=Blue]if [/color][color=Purple]Time[/color][color=DarkCyan]>[/color][color=Black]RampDelay [/color][color=Blue]then
                  [/color][color=Black]State[/color][color=DarkCyan]=[/color][color=Black]Running : [/color][color=Purple]Time[/color][color=DarkCyan]=[/color][color=Navy]0
            [/color][color=Blue]endif
            
      case [/color][color=Black]Running
            [/color][color=Blue]if [/color][color=Purple]Time[/color][color=DarkCyan]>[/color][color=Black]RunningDelay [/color][color=Blue]then
                  low [/color][color=Black]Motor_Forward,Motor_Backward,Ramper
                  State[/color][color=DarkCyan]=[/color][color=Black]Stopping : [/color][color=Purple]Time[/color][color=DarkCyan]=[/color][color=Navy]0
            [/color][color=Blue]endif
      
      case [/color][color=Black]Stopping
            [/color][color=Blue]if [/color][color=Purple]Time[/color][color=DarkCyan]>[/color][color=Black]StoppingDelay [/color][color=Blue]then
                  [/color][color=Black]State[/color][color=DarkCyan]=[/color][color=Black]Stopped
                  Direction[/color][color=DarkCyan]=[/color][color=Black]Stopped
                  [/color][color=Blue]endif
      endselect[/color]
Note that in that code :
- "most-used tasks" ( better say : premium priority tasks = read switches) are in the main loop,
- "least-used tasks" are scheduled by "look at watch"
 

hippy

Technical Support
Staff member
There are two options for having a LED multiplex program which has to do other things as well; (1) put the extra at the start or end of having done a multiplex cycle, (2) intermingle the extra within the multiplex cycle.

Because the best multiplex with be - set a LED, pause, turn the LED off, set another LED, pause, repeated - those pauses are well suited to doing other things. The only requirement is that it doesn't take too long so you may have to spread the extra across multiple pauses. For example, while outputting one row; read the ADC, after outputting another; convert that ADC to a speed and so on.

A lot comes down to the design of the multiplex. If multiple LED's can be set at each time, there will be fewer steps in a multiplex cycle which makes it faster and less likely to suffer flicker, can have larger pauses between each step, allow more to be done.

The fastest 4x4 will be something like this -

Code:
Do
  pinsB = row1 : High ROW1_ENABLE : PAUSE 2 : Low ROW1_ENABLE
  pinsB = row2 : High ROW2_ENABLE : PAUSE 2 : Low ROW2_ENABLE
  pinsB = row3 : High ROW3_ENABLE : PAUSE 2 : Low ROW3_ENABLE
  pinsB = row4 : High ROW4_ENABLE : PAUSE 2 : Low ROW4_ENABLE
Loop
 

BESQUEUT

Senior Member
On the hippy's way :
Code:
[color=Blue]symbol [/color][color=Black]row1[/color][color=DarkCyan]=[/color][color=Purple]b0[/color]
[color=Blue]symbol [/color][color=Black]row2[/color][color=DarkCyan]=[/color][color=Purple]b1[/color]
[color=Blue]symbol [/color][color=Black]row3[/color][color=DarkCyan]=[/color][color=Purple]b2[/color]
[color=Blue]symbol [/color][color=Black]row4[/color][color=DarkCyan]=[/color][color=Purple]b3[/color]

[color=Blue]Do
  [/color][color=Purple]pinsB [/color][color=DarkCyan]= [/color][color=Black]row1 : [/color][color=Blue]High [/color][color=Black]ROW1_ENABLE : [/color][color=Blue]gosub [/color][color=Black]Task1 : [/color][color=Blue]Low [/color][color=Black]ROW1_ENABLE
  [/color][color=Purple]pinsB [/color][color=DarkCyan]= [/color][color=Black]row2 : [/color][color=Blue]High [/color][color=Black]ROW2_ENABLE : [/color][color=Blue]gosub [/color][color=Black]Task2 : [/color][color=Blue]Low [/color][color=Black]ROW2_ENABLE
  [/color][color=Purple]pinsB [/color][color=DarkCyan]= [/color][color=Black]row3 : [/color][color=Blue]High [/color][color=Black]ROW3_ENABLE : [/color][color=Blue]gosub [/color][color=Black]Task3 : [/color][color=Blue]Low [/color][color=Black]ROW3_ENABLE
  [/color][color=Purple]pinsB [/color][color=DarkCyan]= [/color][color=Black]row4 : [/color][color=Blue]High [/color][color=Black]ROW4_ENABLE : [/color][color=Blue]gosub [/color][color=Black]Task4 : [/color][color=Blue]Low [/color][color=Black]ROW4_ENABLE[/color]
[color=Blue]Loop[/color]

[color=Black]Task1:
   readc [/color][color=Blue]C.1[/color][color=Black], [/color][color=Blue]Pot
   [/color][color=Black]Time1[/color][color=DarkCyan]=[/color][color=Blue]Pot[/color][color=DarkCyan]/[/color][color=Navy]2
     [/color][color=Blue]gosub [/color][color=Black]LookAtWatch
   [/color][color=Blue]Return
   [/color]
[color=Black]Task2:
   readc [/color][color=Blue]C.2[/color][color=Black], [/color][color=Blue]Pot
   [/color][color=Black]Time2[/color][color=DarkCyan]=[/color][color=Blue]Pot[/color][color=DarkCyan]*[/color][color=Navy]4[/color][color=DarkCyan]+[/color][color=Navy]1
     [/color][color=Blue]gosub [/color][color=Black]LookAtWatch
   [/color][color=Blue]Return
   [/color]
[color=Black]Task3:
   [/color][color=Blue]if C.2[/color][color=DarkCyan]=[/color][color=Navy]1 [/color][color=Blue]then
            [/color][color=Purple]bit8[/color][color=DarkCyan]=[/color][color=Navy]0
         [/color][color=Blue]else
            [/color][color=Purple]bit7[/color][color=DarkCyan]=[/color][color=Navy]1
        [/color][color=Blue]endif
     gosub [/color][color=Black]LookAtWatch
   [/color][color=Blue]Return
   [/color]
[color=Black]Task4:
   [/color][color=Blue]if C.3[/color][color=DarkCyan]=[/color][color=Navy]1 [/color][color=Blue]then
            [/color][color=Purple]bit9[/color][color=DarkCyan]=[/color][color=Navy]0
      [/color][color=Blue]else
            toggle [/color][color=Purple]bit5
     [/color][color=Blue]endif
   gosub [/color][color=Black]LookAtWatch
   [/color][color=Blue]Return
   [/color]
[color=Black]LookAtWatch:
   [/color][color=Blue]inc [/color][color=Black]Counter1
   [/color][color=Blue]if [/color][color=Black]Counter1[/color][color=DarkCyan]>[/color][color=Black]Time1 [/color][color=Blue]then
         [/color][color=Purple]bit3[/color][color=DarkCyan]=[/color][color=Navy]1
         [/color][color=Purple]bit14[/color][color=DarkCyan]=[/color][color=Navy]0
         [/color][color=Black]Counter1[/color][color=DarkCyan]=[/color][color=Navy]0
   [/color][color=Blue]endif
   
   Inc [/color][color=Black]Counter2[/color][color=DarkCyan]>[/color][color=Black]Time2 [/color][color=Blue]then
         [/color][color=Purple]bit13[/color][color=DarkCyan]=[/color][color=Navy]1
         [/color][color=Purple]bit25[/color][color=DarkCyan]=[/color][color=Navy]0
         [/color][color=Black]Counter2[/color][color=DarkCyan]=[/color][color=Navy]0
   [/color][color=Blue]endif
return[/color]
Note that the PAUSE command is replaced by the GOSUB/RETURN stuff witch is a minimal constant timing.
Tasks 1, 2, 3 & 4 must have as equal as possible durations.
It is not necessary to Look at watch in each task.
If Task1 & 2 are too long (due to readADC), you can look at watch only within Task3 & 4.

If you need more precise timing, use an interrupt (maybe external) to inc counters.
 
Last edited:

hippy

Technical Support
Staff member
If you need more precise timing, use an interrupt (maybe external) to inc counters.
That's a good idea anyway. Then you can have your routines pretty much however long you want and the interrupts will regularly keep the matrix updated in the background. Run the PICAXE as fast as it can and jitter and variance in how long any row or LED is on for will be reduced. There should be no observable flicker and no pulsating.

One can use PWMOUT to trigger an interrupt on another pin. An interrupt every 2.5ms would be 400Hz. It should be possible to use SETTIMER COUNT as well.
 

BESQUEUT

Senior Member
...the interrupts will regularly keep the matrix updated in the background. Run the PICAXE as fast as it can and jitter and variance in how long any row or LED is on for will be reduced. There should be no observable flicker and no pulsating.
+1 for running Picaxe as fast as possible !
Doable, but not so easy...
You have to "wait a little" between enabling and disabling a row...
But you cannot use a pause within the interrupt.
(If you do so, you have to cover the full time span, so there will be no time for main program...)
So each interrupt will :
- disable row N
- inc N
- copy row N to pinsB
- enabled row N
- (auxiliary : inc time counters)

You have to set the interrupt frequency to 4 times the suited refresh rate.
Chronogram.jpg
 
Last edited:

hippy

Technical Support
Staff member
Doable, but not so easy...
You have to "wait a little" between enabling and disabling a row...
But you cannot use a pause within the interrupt.
I would use a state machine so each interrupt turns off the previous row, sets the next row and enables that, then let the rest of the program run as the pause ...

Code:
Interrupt:
  Select Case b7
    Case 0 : Low ROW_ENABLE3 : pinsB = row0 : High ROW_ENABLE0
    Case 1 : Low ROW_ENABLE0 : pinsB = row1 : High ROW_ENABLE1
    Case 2 : Low ROW_ENABLE1 : pinsB = row2 : High ROW_ENABLE2
    Case 3 : Low ROW_ENABLE2 : pinsB = row3 : High ROW_ENABLE3
  End Select
  b7 = b7 + 1 // 4
Interrupt_Enable:
  :
  Return
That could probably be done faster with a BRANCH or ON-GOTO.

If using an external input for interrupt it would need to change the interrupt level between 0 and 1 to get interrupts only on rising / falling edges.
 

BESQUEUT

Senior Member
I would use a state machine so each interrupt turns off the previous row, sets the next row and enables that, then let the rest of the program run as the pause ....
we share exactly the same ideas (I did add a chronogram in post #11)

That could probably be done faster with a BRANCH or ON-GOTO.
Or maybe something like :
Code:
[color=Blue]symbol X[/color][color=DarkCyan]=[/color][color=Navy]20 [/color][color=Green]' starting adresse for raw values. 4 little endians have to be set to 1[/color]

[color=Blue]Interrupt: [/color][color=Green]' assuming rows and cols are on port B
  [/color][color=Purple]b7 [/color][color=DarkCyan]= [/color][color=Purple]b7 [/color][color=DarkCyan]+ [/color][color=Navy]1 [/color][color=DarkCyan]// [/color][color=Navy]4
  [/color][color=Purple]b8[/color][color=DarkCyan]=ncd [/color][color=Purple]b7 [/color][color=DarkCyan]+ [/color][color=Navy]%11110000
  [/color][color=Purple]ptr[/color][color=DarkCyan]=[/color][color=Purple]b7[/color][color=DarkCyan]+[/color][color=Blue]X
  [/color][color=Purple]pinsB[/color][color=DarkCyan]=[/color][color=Purple]b8 [/color][color=DarkCyan]And [/color][color=Purple]@ptr
  [/color][color=Black]Interrupt_Enable:
  [/color][color=Blue]return[/color]
Note that there will be no delay between each raw enabling... so flickerring is minimal.
 
Last edited:

hippy

Technical Support
Staff member
Thanx guys, something for me to ponder ;-)
I think the basic message is it can be done. I would say get it working, flickery or not, and then optimise and try various schemes to see which deliver the best results if needed.

Though having said that I would probably put the row enables on bits 7-4 of Port B and put the LED columns in bits 3-0 thing as BESQUEUT suggests and there are some additional clever tricks with 'ptr' and 'bptr'. By ensuring the row enable bits are set within the LED data things can be simplified quite a lot. There are many ways to skin this cat ...

Code:
#Picaxe 28X2

Symbol BASE = 256  - 4 ; Use RAM $FC-$FF

Symbol ROW0 = BASE + 0
Symbol ROW1 = BASE + 1
Symbol ROW2 = BASE + 2
Symbol ROW3 = BASE + 3

Main:
  b0 = %00010000 + %1111 : Poke ROW0, b0
  b0 = %00100000 + %0101 : Poke ROW1, b0
  b0 = %01000000 + %0011 : Poke ROW2, b0
  b0 = %10000000 + %0001 : Poke ROW3, b0

  dirsB = $FF
  bPtr  = ROW0
  Gosub Interrupt_Enable
  Do
   :
  Loop

Interrupt:
  pinsB = 0
  pinsB = @bPtrInc
  bPtr  = bPtr Or BASE
Interrupt_Enable:
  :
  Return
 

tmfkam

Senior Member
As much as I admire Besqueut and Hippy's work, I'd go with Premelec's suggestion.

I recently had to design a unit that has four seven segment LED displays showing scrolling text messages of varying lengths. I originally designed this by common-ing the (cathode) segments for individual displays then switching each display anode on individually so that it appeared as if all four seven segment displays were lit simultaneously. This worked up until the point that I was asked for the display to show a countdown of some pulses that were 10mS high, 10mS low, 10mS high... Whilst keeping count of the pulses to ensure that exactly the correct number of pulses had been received, exactly matching a variable value request. Back to the drawing board.

I then daisy-chained four 74HC595 chips together to drive the display. I can now update all four displays in well under 100uS (~18uS per display?) leaving plenty of time to sit around and wait for those 10mS pulses. If there is any delay, the displays don't flicker or fade, as once the data written to them has been latched, the displays stay on - permanently. The multiplexed displays were less bright as each seven segment display is essentially being energised for only 25% of the time, potentially less still if you have other processing to take care of in between, unless you can spilt your 'additional' processing perfectly evenly in time between each refresh cycle. Yes, the electronics are slightly more complex, but the programming is much more elegant, has far more time to check those all important pulses, the displays are far brighter, I have more pins on the processor free and I have less (zero!) ghosting between elements.
 

hippy

Technical Support
Staff member
Even more elegant ...

Code:
Main:
  b0 = %00010000 + %1111
  b1 = %00100000 + %0101
  b2 = %01000000 + %0011
  b3 = %10000000 + %0001

  dirsB = $FF
  Gosub Interrupt_Enable
  Do
   :
  Loop

Interrupt:
  pinsB = 0
  pinsB = @bPtrDec
  bPtr  = bPtr & 3
Interrupt_Enable:
  :
  Return
 

BESQUEUT

Senior Member
Even more elegant ...

Code:
Main:
  b0 = %00010000 + %1111
  b1 = %00100000 + %0101
  b2 = %01000000 + %0011
  b3 = %10000000 + %0001

  dirsB = $FF
  Gosub Interrupt_Enable
  Do
   :
  Loop

Interrupt:
  pinsB = 0
  pinsB = @bPtrDec
  bPtr  = bPtr & 3
Interrupt_Enable:
  :
  Return
Waouhhh ! Very clever and elegant !
IMHO : pinsB=0
is useless...
 

hippy

Technical Support
Staff member
IMHO : pinsB=0
is useless...
It depends on the hardware, whether there is any ghosting caused when the row enables change. It guarantees the previous enable is cleared before another is set. Some PICAXE don't set all pins simultaneously so one could end up with the LED lines changing before the strobe does. It can be removed if it has no adverse effects.

The "=@bPtrDec" can also be an "=@bPtrInc", it just ended as a Dec when I was testing the code.
 

premelec

Senior Member
Great discussion... I know multiplexing is being thought of mostly; In my case i find even very fast multiplexing has annoying strobing with eye motion... only the LEDs that change really need updating - e.g. in a seven segment display "0" and "8" are quite close... :) So there may be other ways to handle a display that are more pleasing... whatever works for you...
 

OLDmarty

Senior Member
Thanx for all the extra examples guys, really appreciate it. I just need some time to wire up a test board and try codes etc.

The whole aim of my question (perhaps not made clear) was to also NOT use external drivers/latches.
The other option instead of led matrix was driving multiple 7seg displays as recently mentioned.

I've seen terrible projects with 8x 7seg digits seemingly ok, until a pot is adjusted and the 7segs strobe noticeably.

Overall, i wanted to know what preferred methods programmers use when it comes to nesting loops and how to interlace them in order of importance, like loop 1 (main) is the housekeeping loop, loop2 is the led matrix data, loop 3 and 4 read posts & switches, then a preferred structure of how loop1,2,3&4 would nest together for fastest (least interruptions) code operation.

Thanx again,
Marty.
 

BESQUEUT

Senior Member
Overall, i wanted to know what preferred methods programmers use when it comes to nesting loops and how to interlace them in order of importance, like loop 1 (main) is the housekeeping loop, loop2 is the led matrix data, loop 3 and 4 read posts & switches, then a preferred structure of how loop1,2,3&4 would nest together for fastest (least interruptions) code operation.
My answer is till #4
Do not forget : there is only ONE CPU !
If CPU is monopolized by a "loop" the others are stuck...
Have only one (main) loop : the scheduler and maybe :
- a led matrix task,
- a read pot task
- a read switches task
- a calculation task...
Each task must be "collaborative" : IE : no loop, no wait, no pause...
 

OLDmarty

Senior Member
My answer is till #4
Do not forget : there is only ONE CPU !
If CPU is monopolized by a "loop" the others are stuck...
Have only one (main) loop : the scheduler and maybe :
- a led matrix task,
- a read pot task
- a read switches task
- a calculation task...
Each task must be "collaborative" : IE : no loop, no wait, no pause...
Thanx, i have taken that all onboard, more reading/research for me and i'll move forward ;-)
 

OLDmarty

Senior Member
Each task must be "collaborative" : IE : no loop, no wait, no pause...
OK, after further reading over the weekend, i clearly don't know how to convert my code to be "collaborative"

I have a lot of trouble NOT using goto's and pauses and not entirely sure how i implement timers or whatever is needed for the delays. (i've never played with timer functions before)

Consider the following (untested) code, while the code may or may not work correctly, it's the general CONCEPT i wish to restructure.
The example concept is:
button1 (when pressed) will make an LED flash once-per-second (1000mS)
button2 (when pressed) will make an LED flash twice-per-second (500mS)

The program would constantly loop, flashing the LED and monitoring the buttons for any changes

Code:
symbol button1 = b.0		;1.0 second button is on PortB.0 pin 
symbol button2 = b.1		;0.5 second button is on PortB.0 pin 
symbol LED = b.7		;LED is on PortB.7 pin 

dirsb = %10000000		;set Port B as C.7 as OUTPUT and set B.0 to B.6 as INPUTs


LED = low			;make sure LED is off at the beginning

main:

if button1 bit B0 set then		;if bit0=1(set)
 	gosub LED_1sec			;then goto LED flash routine
 	else				;keep reading the buttons
goto main


if button2 bit B1 set then		;if bit0=1(set)
 	gosub LED_1sec			;then goto LED flash routine
 	else				;keep reading the buttons
goto main



LED_1sec:				;LED flashed at once per second (1000mS)
	high LED			;turn ON the LED
    	pause 1000			;leave LED on for 1 second
	low LED				;turn OFF the LED
    	pause 1000			;leave LED off for 1 second
	return	


LED_halfsec:				;LED flashed at twice per second (500mS)
	high LED			;turn ON the LED
    	pause 500			;leave LED on for 1/2 second
	low LED				;turn OFF the LED
    	pause 500			;leave LED off for 1/2 second
	return
 
Last edited:

lbenson

Senior Member
One way:
Code:
#picaxe 20M2
symbol bFlashRate = bit0 ' 0=500ms, 1=1000ms

setfreq m32 ' time ticks every 500ms
bFlashRate = 1 ' flashrate of 1000ms

main:
  do
    if pinb.0 = 1 then : bFlashRate = 1 : endif
    if pinb.1 = 1 then : bFlashRate = 0 : endif
    if bFlashRate = 0 and time > 0 then
      toggle b.7
      time = 0
    endif
    if bFlashRate = 1 and time > 1 then
      toggle b.7
      time = 0
    endif
  loop
Or

Code:
#picaxe 20M2

main:
  do
    if pinb.0 = 1 then : setfreq m4 : endif  ' 1000ms per tick
    if pinb.1 = 1 then : setfreq m32 : endif ' 500ms per tick
    if time > 0 then
      toggle b.7
      time = 0
    endif
  loop
 

hippy

Technical Support
Staff member
The example concept is:
button1 (when pressed) will make an LED flash once-per-second (1000mS)
button2 (when pressed) will make an LED flash twice-per-second (500mS)
The big question is can both buttons be pushed, both LED's be flashing, at the same time, or is it always neither, one or the other ?

I would spec such an example so it had one LED flashing once per second, the other three times per second. That forces a more generic solution than one which may work only for the specific example and is not applicable to much else.
 

BESQUEUT

Senior Member
The big question is can both buttons be pushed, both LED's be flashing, at the same time, or is it always neither, one or the other ?

I would spec such an example so it had one LED flashing once per second, the other three times per second. That forces a more generic solution than one which may work only for the specific example and is not applicable to much else.
+1 for more "generics" specs...
- Buttons press are ON/OFF : after button1 is pressed, (and released) LED1 start flashing,
- Next press on Button1 will stop LED1 flashing,
- idem for button2. So we can have : no led flashing, one or the other, or both...
- Too easy to have 500 ms and 2X500ms. idem for 3 times a second : you can have timing for 3 times a second for one LED and for the other, flash 1 time for 3...
- We can say : 310 ms So there is no GCD...
- next we will add reading a potar or an LDR and make LED3 flashing in compliance...

No time now for test code, but maybe this night ...
 
Last edited:

hippy

Technical Support
Staff member
For generic code I would deal with the outputs by using pinX.Y= to set the pins. That then allows, in a loop ..

Code:
If led1Enabled = 1 Then
  PIN_LED1 = led1FlashFlag
Else
  PIN_LED1 = 0
End If
If led2Enabled = 1 Then
  PIN_LED2 = led1FlashFlag
Else
  PIN_LED2 = 0
End If
Or the more optimised ...

Code:
PIN_LED1 = led1Enabled & led1FlashFlag
PIN_LED2 = led2Enabled & led2FlashFlag
Then separate code can set 'ledXEnabled' and 'ledXFlashFlag' as appropriate. For example -

Code:
If button1 <> lastButton1 Then
  lastButton1 = button1
  If button1 = 1 Then
    led1Enable = led1Enable ^ 1
  End If
End If
Which can be optimised to -

Code:
led1Enable = button1 ^ lastButton1 & button1 ^ led1Enable
lastButton1 = button1
That just leaves setting the LED flashing variables at the right rate ...

Code:
  Pause PAUSE_TIME
  :
  led1Time = led1Time + PAUSE_TIME
  If led1Time >= LED1_FLASH_TIME Then
    led1Time = 0
    led1FlashFlag = led1FlashFlag ^ 1
  End If
 

hippy

Technical Support
Staff member
Code:
#Picaxe 20M2

Symbol PAUSE_TIME      = 10

Symbol LED1_FLASH_TIME = 100 ; Toggles every 100ms
Symbol LED2_FLASH_TIME = 310 ; Toggles every 310ms

Symbol lastButton1     = bit0
Symbol lastButton2     = bit1
Symbol led1Enable      = bit2
Symbol led2Enable      = bit3
Symbol led1FlashFlag   = bit4
Symbol led2FlashFlag   = bit5

Symbol led1Time        = w1
Symbol led2Time        = w2

Symbol BUTTON1         = pinC.1 ; C.1 => B.6 LED
Symbol BUTTON2         = pinC.0 ; C.0 => B.7 LED

Symbol PIN_LED1        = pinB.6
Symbol PIN_LED2        = pinB.7

Symbol DIR_LED1        = dirB.6
Symbol DIR_LED2        = dirB.7

DIR_LED1 = 1
DIR_LED2 = 1

Do
  ; Button handling
  led1Enable  = button1 ^ lastButton1 & button1 ^ led1Enable
  led2Enable  = button2 ^ lastButton2 & button2 ^ led2Enable
  lastButton1 = button1
  lastButton2 = button2
  ; Flash timing
  Pause PAUSE_TIME
  led1Time = led1Time + PAUSE_TIME // LED1_FLASH_TIME
  led2Time = led2Time + PAUSE_TIME // LED2_FLASH_TIME
  led1FlashFlag = led1Time Max 1 ^ 1 ^ led1FlashFlag
  led2FlashFlag = led2Time Max 1 ^ 1 ^ led2FlashFlag
  ; Output
  PIN_LED1 = led1Enable & led1FlashFlag
  PIN_LED2 = led2Enable & led2FlashFlag
Loop
 

BESQUEUT

Senior Member
Code:
#Picaxe 20M2

Symbol PAUSE_TIME      = 10

Symbol LED1_FLASH_TIME = 100 ; Toggles every 100ms
Symbol LED2_FLASH_TIME = 310 ; Toggles every 310ms

Symbol lastButton1     = bit0
Symbol lastButton2     = bit1
Symbol led1Enable      = bit2
Symbol led2Enable      = bit3
Symbol led1FlashFlag   = bit4
Symbol led2FlashFlag   = bit5

Symbol led1Time        = w1
Symbol led2Time        = w2

Symbol BUTTON1         = pinC.1 ; C.1 => B.6 LED
Symbol BUTTON2         = pinC.0 ; C.0 => B.7 LED

Symbol PIN_LED1        = pinB.6
Symbol PIN_LED2        = pinB.7

Symbol DIR_LED1        = dirB.6
Symbol DIR_LED2        = dirB.7

DIR_LED1 = 1
DIR_LED2 = 1

Do
  ; Button handling
  led1Enable  = button1 ^ lastButton1 & button1 ^ led1Enable
  led2Enable  = button2 ^ lastButton2 & button2 ^ led2Enable
  lastButton1 = button1
  lastButton2 = button2
  ; Flash timing
  Pause PAUSE_TIME
  led1Time = led1Time + PAUSE_TIME // LED1_FLASH_TIME
  led2Time = led2Time + PAUSE_TIME // LED2_FLASH_TIME
  led1FlashFlag = led1Time Max 1 ^ 1 ^ led1FlashFlag
  led2FlashFlag = led2Time Max 1 ^ 1 ^ led2FlashFlag
  ; Output
  PIN_LED1 = led1Enable & led1FlashFlag
  PIN_LED2 = led2Enable & led2FlashFlag
Loop
Beautifull !
But M. Marty may say :
- there is till a pause command,
- main loop does not run as fast as possible,

310 ms per toggle is 1.61 Hz
100 ms per toggle is 5 Hz
I just test this code with a 18M2 (AXE049). I found :
0.726Hz that is 0.69 s per toggle for a LED
2.252 Hz that is 0.22 s per toggle for the other.
IMHO, that is right as the 10ms pause does not take into account the main loop time.

So here is my contribution :
Code:
[color=Navy]#Picaxe [/color][color=Black]18M2[/color]
[color=Navy]#simspeed 200
#no_data[/color]



[color=Blue]setfreq m32
Symbol LOOP_TIME      [/color][color=DarkCyan]= [/color][color=Navy]1449[/color]
[color=Blue]Symbol LED1_FLASH_TIME [/color][color=DarkCyan]= [/color][color=Navy]100000[/color][color=DarkCyan]/[/color][color=Blue]LOOP_TIME       [/color][color=Green]; Toggles every 100ms ==> 5 Hz[/color]
[color=Blue]Symbol LED2_FLASH_TIME [/color][color=DarkCyan]= [/color][color=Navy]310000[/color][color=DarkCyan]/[/color][color=Blue]LOOP_TIME             [/color][color=Green]; Toggles every 310ms ==> 1.6 Hz

'setfreq m4
'Symbol LOOP_TIME      = 11592
'Symbol LED1_FLASH_TIME = 100000/LOOP_TIME ; Toggles every 100ms ==> 5 Hz
'Symbol LED2_FLASH_TIME = 310000/LOOP_TIME ; Toggles every 310ms ==> 1.6 Hz[/color]


[color=Blue]Symbol [/color][color=Purple]lastButton1     [/color][color=DarkCyan]= [/color][color=Purple]bit0[/color]
[color=Blue]Symbol [/color][color=Purple]lastButton2     [/color][color=DarkCyan]= [/color][color=Purple]bit1[/color]
[color=Blue]Symbol [/color][color=Purple]led1Enable      [/color][color=DarkCyan]= [/color][color=Purple]bit2[/color]
[color=Blue]Symbol [/color][color=Purple]led2Enable      [/color][color=DarkCyan]= [/color][color=Purple]bit3[/color]
[color=Blue]Symbol [/color][color=Purple]led1FlashFlag   [/color][color=DarkCyan]= [/color][color=Purple]bit4[/color]
[color=Blue]Symbol [/color][color=Purple]led2FlashFlag   [/color][color=DarkCyan]= [/color][color=Purple]bit5[/color]

[color=Blue]Symbol [/color][color=Purple]led1Time        [/color][color=DarkCyan]= [/color][color=Purple]w1[/color]
[color=Blue]Symbol [/color][color=Purple]led2Time        [/color][color=DarkCyan]= [/color][color=Purple]w2[/color]

[color=Blue]Symbol [/color][color=Purple]BUTTON1         [/color][color=DarkCyan]= [/color][color=Purple]pinC.6 [/color][color=Green]; C.1 => B.6 LED[/color]
[color=Blue]Symbol [/color][color=Purple]BUTTON2         [/color][color=DarkCyan]= [/color][color=Purple]pinC.7 [/color][color=Green]; C.0 => B.7 LED[/color]

[color=Blue]Symbol [/color][color=Purple]PIN_LED1        [/color][color=DarkCyan]= [/color][color=Purple]pinB.1[/color]
[color=Blue]Symbol [/color][color=Purple]PIN_LED2        [/color][color=DarkCyan]= [/color][color=Purple]pinB.2[/color]

[color=Blue]Symbol [/color][color=Purple]DIR_LED1        [/color][color=DarkCyan]= [/color][color=Purple]dirB.1[/color]
[color=Blue]Symbol [/color][color=Purple]DIR_LED2        [/color][color=DarkCyan]= [/color][color=Purple]dirB.2



DIR_LED1 [/color][color=DarkCyan]= [/color][color=Navy]1[/color]
[color=Purple]DIR_LED2 [/color][color=DarkCyan]= [/color][color=Navy]1[/color]

[color=Blue]Do
  [/color][color=Green]; Button handling
  [/color][color=Purple]led1Enable  [/color][color=DarkCyan]= [/color][color=Purple]button1 [/color][color=DarkCyan]^ [/color][color=Purple]lastButton1 [/color][color=DarkCyan]& [/color][color=Purple]button1 [/color][color=DarkCyan]^ [/color][color=Purple]led1Enable
  led2Enable  [/color][color=DarkCyan]= [/color][color=Purple]button2 [/color][color=DarkCyan]^ [/color][color=Purple]lastButton2 [/color][color=DarkCyan]& [/color][color=Purple]button2 [/color][color=DarkCyan]^ [/color][color=Purple]led2Enable
  lastButton1 [/color][color=DarkCyan]= [/color][color=Purple]button1
  lastButton2 [/color][color=DarkCyan]= [/color][color=Purple]button2
  
  [/color][color=Green]; Flash timing
  [/color][color=Purple]led1Time [/color][color=DarkCyan]= [/color][color=Purple]led1Time [/color][color=DarkCyan]+ [/color][color=Navy]1 [/color][color=DarkCyan]// [/color][color=Blue]LED1_FLASH_TIME
  [/color][color=Purple]led2Time [/color][color=DarkCyan]= [/color][color=Purple]led2Time [/color][color=DarkCyan]+ [/color][color=Navy]1 [/color][color=DarkCyan]// [/color][color=Blue]LED2_FLASH_TIME
  [/color][color=Purple]led1FlashFlag [/color][color=DarkCyan]= [/color][color=Purple]led1Time [/color][color=DarkCyan]Max [/color][color=Navy]1 [/color][color=DarkCyan]^ [/color][color=Navy]1 [/color][color=DarkCyan]^ [/color][color=Purple]led1FlashFlag
  led2FlashFlag [/color][color=DarkCyan]= [/color][color=Purple]led2Time [/color][color=DarkCyan]Max [/color][color=Navy]1 [/color][color=DarkCyan]^ [/color][color=Navy]1 [/color][color=DarkCyan]^ [/color][color=Purple]led2FlashFlag
  
  [/color][color=Green]; Output
  [/color][color=Purple]PIN_LED1 [/color][color=DarkCyan]= [/color][color=Purple]led1Enable [/color][color=DarkCyan]& [/color][color=Purple]led1FlashFlag
  PIN_LED2 [/color][color=DarkCyan]= [/color][color=Purple]led2Enable [/color][color=DarkCyan]& [/color][color=Purple]led2FlashFlag[/color]
[color=Blue]Loop[/color]
I have measured a loop time of 1449 us at 32 mHz

I think that you can insert the #18 code
Code:
  pinsB = 0
  pinsB = @bPtrDec
  bPtr  = bPtr & 3
directly in the main loop without any flickering.
But the interupt is also a good way (if not needed for another purpose).
 
Last edited:

BESQUEUT

Senior Member
If using M2 4mHz, you also can use pseudo-multitasking (not collaborative !):
Code:
[color=Navy]#picaxe [/color][color=Black]18m2[/color]
[color=Navy]#simtask [/color][color=Blue]all[/color]
[color=Navy]#simspeed 100
#no_data[/color]

[color=Blue]Symbol [/color][color=Purple]lastButton1     [/color][color=DarkCyan]= [/color][color=Purple]bit0[/color]
[color=Blue]Symbol [/color][color=Purple]lastButton2     [/color][color=DarkCyan]= [/color][color=Purple]bit1[/color]
[color=Blue]Symbol [/color][color=Purple]led1Enable      [/color][color=DarkCyan]= [/color][color=Purple]bit2[/color]
[color=Blue]Symbol [/color][color=Purple]led2Enable      [/color][color=DarkCyan]= [/color][color=Purple]bit3[/color]



[color=Blue]Symbol [/color][color=Purple]BUTTON1         [/color][color=DarkCyan]= [/color][color=Purple]pinC.6 [/color][color=Green]; C.1 => B.6 LED[/color]
[color=Blue]Symbol [/color][color=Purple]BUTTON2         [/color][color=DarkCyan]= [/color][color=Purple]pinC.7 [/color][color=Green]; C.0 => B.7 LED[/color]

[color=Blue]Symbol LED1        [/color][color=DarkCyan]= [/color][color=Blue]B.1
Symbol LED2        [/color][color=DarkCyan]= [/color][color=Blue]B.2

Symbol [/color][color=Purple]DIR_LED1        [/color][color=DarkCyan]= [/color][color=Purple]dirB.1[/color]
[color=Blue]Symbol [/color][color=Purple]DIR_LED2        [/color][color=DarkCyan]= [/color][color=Purple]dirB.2[/color]



[color=Blue]start0:
suspend [/color][color=Navy]1[/color]
[color=Blue]suspend [/color][color=Navy]2[/color]

[color=Purple]DIR_LED1 [/color][color=DarkCyan]= [/color][color=Navy]1[/color]
[color=Purple]DIR_LED2 [/color][color=DarkCyan]= [/color][color=Navy]1[/color]

[color=Blue]do
      if [/color][color=Purple]button1[/color][color=DarkCyan]<>[/color][color=Purple]lastbutton1 [/color][color=Blue]then
            if [/color][color=Purple]button1[/color][color=DarkCyan]=[/color][color=Navy]1 [/color][color=Blue]then
                  if [/color][color=Purple]led1Enable[/color][color=DarkCyan]=[/color][color=Navy]0 [/color][color=Blue]then
                        [/color][color=Purple]led1Enable[/color][color=DarkCyan]=[/color][color=Navy]1
                        [/color][color=Blue]resume [/color][color=Navy]1
                  [/color][color=Blue]else
                        [/color][color=Purple]led1Enable[/color][color=DarkCyan]=[/color][color=Navy]0
                        [/color][color=Blue]suspend [/color][color=Navy]1
                        [/color][color=Blue]low LED1
                  endif
            endif
      endif

      if [/color][color=Purple]button2[/color][color=DarkCyan]<>[/color][color=Purple]lastbutton2 [/color][color=Blue]then
            if [/color][color=Purple]button2[/color][color=DarkCyan]=[/color][color=Navy]1 [/color][color=Blue]then
                  if [/color][color=Purple]led2Enable[/color][color=DarkCyan]=[/color][color=Navy]0 [/color][color=Blue]then
                        [/color][color=Purple]led2Enable[/color][color=DarkCyan]=[/color][color=Navy]1
                        [/color][color=Blue]resume [/color][color=Navy]2
                  [/color][color=Blue]else
                        [/color][color=Purple]led2Enable[/color][color=DarkCyan]=[/color][color=Navy]0
                        [/color][color=Blue]suspend [/color][color=Navy]2
                        [/color][color=Blue]low LED2
                  endif
            endif
      endif

      [/color][color=Purple]lastButton1 [/color][color=DarkCyan]= [/color][color=Purple]button1
      lastButton2 [/color][color=DarkCyan]= [/color][color=Purple]button2[/color]
[color=Blue]loop



start1:
do
      toggle LED1
      pause [/color][color=Navy]100[/color]
[color=Blue]loop

start2:
do
      toggle LED2
      pause [/color][color=Navy]310[/color]
[color=Blue]loop[/color]
 

BESQUEUT

Senior Member
Note that with #30 code LEDx_FLASH_TIME must be a multiple of PAUSE_TIME
If not, LedxTime is never zero, and no flash occur.
So, it is difficult to adjust PAUSE_TIME to take into account the LOOP_TIME.
 

hippy

Technical Support
Staff member
So, it is difficult to adjust PAUSE_TIME to take into account the LOOP_TIME.
The trick there is to keep PAUSE_TIME so the LEDx_FLASH_TIME values are multiples of it, and then actually adjust the PAUSE time in the loop so the loop takes as long as PAUSE_TIME claims. So PAUSE_TIME may be 10 but the program may contain "PAUSE 8", may have extra PAUSEUS etc to make it more accurately up to that loop time.

To have it run as fast as possible, simply take out the PAUSE and PAUSE_TIME, adjust LEDx_FLASH_TIME to be whatever is needed.
 

BESQUEUT

Senior Member
To have it run as fast as possible, simply take out the PAUSE and PAUSE_TIME, adjust LEDx_FLASH_TIME to be whatever is needed.
YES : that is what I did for #31 proposal. As PE6 can make calculations in the symbol pre-process command, that is not a big deal.

The trick there is to keep PAUSE_TIME so the LEDx_FLASH_TIME values are multiples of it, and then actually adjust the PAUSE time in the loop so the loop takes as long as PAUSE_TIME claims. So PAUSE_TIME may be 10 but the program may contain "PAUSE 8", may have extra PAUSEUS etc to make it more accurately up to that loop time.
Tried this with no success : to achieve 100 ms with 10 ms increments, you need at least 10 loops. Even without any pause, I was not able to achieve 100 ms toggle. Have I missed something ?

At end, IMHO, there is no need to fix a known main loop time. I prefer to use it as it is. My time unit is not ms, but the main loop Time.
 
Last edited:

hippy

Technical Support
Staff member
Tried this with no success : to achieve 100 ms with 10 ms increments, you need at least 10 loops. Even without any pause, I was not able to achieve 100 ms toggle. Have I missed something ?
Not sure. If the program takes longer than the loop time you want you will either have to run the PICAXE faster or use a loop time which is longer and adjust other timing for that.

Because the loop has no conditional branches ( IF-ELSE etc ) its execution time should be fairly consistent but I never measured it, never tested the code outside of simulation.
 
Top