1
\$\begingroup\$

I was wondering, will this actualy work? (when timer / prescaler set) It saves RAM by not using extra variables. Are the better ways of doing this?

// Microchip PIC10F222

while (1) {  //main loop
   while ((TMR0 ^ TMR0-1)& 4) {  // execute @ 1/4 speed of TMR0 (whenever TMR0 Bit 3 has just toggled)
   // high speed stuff
   }

   while ((TMR0 ^ TMR0-1)& 128) {   // execute @ 1/128 speed of TMR0
   // low speed stuff (toggle blinking led's) 
   }
}

Next idea:

I Don't like the idea of waisting processor time , or being dependent on exact timing

I'm not sure about the TMR0-2. I asume If TMR0=0 TMR0-2 will be 254.

// Microchip PIC10F222

While(1) { //main loop
    // Full speed 
    if (TMR0&1) {  //skip, eccept for TMR0 odd numbers.
       // 1/1 timer speed. (Not nececairily used)
       // this code may run in one pass with either one of the loops below. 
       if ((TMR0 ^ TMR0-2)& 64) {    
          // 1/32 timer speed,(state machines, one step each pass.)   
          // do not exceed TMR0 period
          }
       if ((TMR0==255) {     
          // 1/128 timer speed. (toggle blinking led's, wachdogg)
          // do not exceed TMR0 period
          }
    TMR0++; //TMR0 will be even, preventing passing trough this loop
            //until the timer increments itself, 
            //(Doubeling timer speed in the process)
    }
}
\$\endgroup\$
5
  • 3
    \$\begingroup\$ No, it will retrigger if your high speed stuff runs too fast, and miss high speed stuff if the low speed stuff is too slow. \$\endgroup\$
    – user16324
    Commented Jul 10, 2014 at 11:03
  • \$\begingroup\$ Not much comes to mind, what Brian said is correct and with a single timer solutions I can think of would need an extra variable, although you'd only need a single byte of RAM. \$\endgroup\$
    – PeterJ
    Commented Jul 10, 2014 at 11:15
  • \$\begingroup\$ I get it, But that's just what I try to avoid. \$\endgroup\$
    – D.J.W.
    Commented Jul 10, 2014 at 11:19
  • \$\begingroup\$ Depending on how fast TMR0 clocks, you can work around my comment on retriggering; just guarantee every path through "high speed stuff" is slower than TMR0 clock (with NOPs if necessary). Unfortunately as written, this guarantees that "low speed stuff" never executes. \$\endgroup\$
    – user16324
    Commented Jul 10, 2014 at 11:28
  • \$\begingroup\$ If you're set on doing it the first way but need to avoid double triggers, you could increment TMR0 after the high-speed stuff and it will only happen once. I'm not sure why that would be a while loop, though. \$\endgroup\$
    – krs013
    Commented Jul 12, 2014 at 2:18

2 Answers 2

1
\$\begingroup\$

The PIC10F222 has no interrupts, only 2 levels of call stack, and very little memory. Techniques that are appropriate for more powerful chips may be inefficient or not work at all. To avoid 'wasting' cycles while waiting for a bit toggle you can inline code to do other things while you wait (eg. do high speed stuff while for waiting for low speed bit toggle).

To detect when a bit changes you need to wait until the bit is in one state, then wait again for it to change to the other state. The following code executes high speed stuff whenever TMR0 bit 1 changes from low to high, and executes low speed stuff whenever bit 6 changes from low to high. No RAM is used.

If all your 'stuff' completes within the current high speed time slot then it will be perfectly synchronized with the timer, with no wasted cycles. If it takes too long and the bit change is missed then it will have to wait for the next one. If some 'Stuff' is taking too long then you may be able to split it up into two or more parts, and do each part in a different time slot.

// Microchip PIC10F222
#include <pic.h>

main ()
{
   while (1) {  
      while (TMR0 & 64) {   // wait until bit 6 goes low. 
         while (TMR0 & 2) { // wait until bit 1 goes low 
         }
         while (!(TMR0 & 2)){ // wait until bit 1 goes high
         }
         // while waiting for bit 6, do high speed stuff
      }
      while (!(TMR0 & 64)){ // wait until bit 6 goes high
         while (TMR0 & 2) { // wait until bit 1 goes low
         }
         while (!(TMR0 & 2)){ // wait until bit 1 goes high
         }
         // while waiting for bit 6, do high speed stuff again
      }
      // do low speed stuff
   }
}
\$\endgroup\$
1
  • \$\begingroup\$ Very interesting solution. Also, I didn't know about the lack of interrupts. \$\endgroup\$
    – krs013
    Commented Jul 15, 2014 at 21:13
0
\$\begingroup\$

Like Brian said, if your high speed stuff finished before the timer increments, it will run multiple times (if that's what you want, then I'm not sure what kind of processing you're doing), and if something takes too long, you'll miss future events. Also, your processor will still be screaming through this while loop 100% of the time, which isn't great for power consumption. If you plan on having other code in your loop, that could also cause you to miss events.

As I understand it, a vastly better way to do things like this is to implement event-driven programming. Have a variable store pending tasks as bits, and your main loop will service them as soon as the bits are raised. Your timer can set those bits in an interrupt, or if you don't like interrupts, the main loop can poll the timer each rotation like this:

while(1)
{
    if (sys_event & 0x01)
    {
        // High speed task, executed with a higher priority
    }
    else if (sys_event & 0x02)
    {
        // Low speed task, executed with a lower priority
    }
    // More events, in order of priority

    if (TMR0 >= 0x04)
    {
        sys_event |= 0x01; // Raise high-speed flag
        TMR0 = 0;          // Reset timer

        if(--slow_wait == 0)   // Counter for slow event
        {
            sys_event |= 0x02; // Raise low-speed flag
            slow_wait = 32;    // Reset slow count
        }
    }
}

I suppose that's one extra variable for the slow_wait counter, but the lesson here is that polling something asynchronous like the timer can be a bad idea since you might get multiple triggers or miss events. Again, this implementation works even better if TMR0 triggers an interrupt. If the PIC you're using supports low-power or standby modes (I'm used to the MSP430, so forgive me if I'm going the wrong way with this), you can have the processor shut down to wait for some event to service, and just have the interrupt wake it up when there's something to do.

One thing that is important to this implementation (and any non-preemptive multitasking system) is that the event service routines should be quick. If it needs to happen a lot or continuously, then retrigger the event frequently (even each time) and give it a low priority (that way it always happens if there's nothing else to be done, but other events can happen with little latency). Even then, though, make that code return quickly.

I hope that helps, my apologies if I didn't really understand the gist of your question.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.