2
\$\begingroup\$

I have a program that varies the step time and duty cycle for a 6 step commutation sequence. It takes an 8-bit ADC result and stores it as the TMR0 value, when TMR0 overflows, the ISR selects the next sequence.

I have 2 problems:

  1. This only works at low INTOSC frequencies, where UART will not work, and
  2. I don't get a large enough step range.

Any general ideas on how to create a larger ranged delay at a higher frequency? My first idea is to use a nested loop, still using a TMR0 value, then putting that inside of a loop the steps the inverse of TMR0 times...

\$\endgroup\$
6
  • \$\begingroup\$ What microcontroller platform? Which toolchain? \$\endgroup\$
    – jippie
    Commented Feb 23, 2013 at 22:17
  • \$\begingroup\$ pic18 & breadboard \$\endgroup\$ Commented Feb 23, 2013 at 22:25
  • \$\begingroup\$ Can you give us a rough indication of the relationship you need between ADC value and step rate? From the sounds of it, it's step frequency = k/(255-ADC). What is the value of k? \$\endgroup\$ Commented Feb 24, 2013 at 0:24
  • \$\begingroup\$ sure, if I'm looking for 302.5 RPM, I get 5.04 RPS * 12 poles = 60 Hz, so k = .0166. This gives me my delay in uS, which could be plugged into a delay_uS function, but I'd like to use a timer/ counter so as not to waste cycles. \$\endgroup\$ Commented Feb 24, 2013 at 3:22
  • \$\begingroup\$ I'm not sure I understand the example you gave. So 60Hz = 0.0166 / (255-254.9997). That can't be right because an 8-bit ADC can't give a value of 254.9997. Sorry to be picky about this, but if I can understand it, then I can give you a good answer. \$\endgroup\$ Commented Feb 24, 2013 at 16:40

1 Answer 1

2
\$\begingroup\$

One way to approach the problem would be to introduce some additional variables that keep track of the timer interval and how many times it's been called so that a fixed number of interrupts may be ignored. For example the following C pseudo-code to slow the execution time down by a factor of 10.

uint_8 ticks_left, timer_interval;

void my_isr()
{
    ticks_left--;
    if (ticks_left == 0)
    {
         disable_timer();
         // Move to next ADC etc
    } else
         setup_timer(timer_interval);
    }
}

void main()
{
    timer_interval = your_calculated_value;
    ticks_left = 10;
    setup_timer(timer_interval);
}

It won't be perfectly accurate because of the (probably less than 10 cycle) instruction delay between the interrupt and the new timer value being set, although if that's a concern you could check the assembler output to find the number of cycles it will take and reset the timer to a slightly lower value in the ISR if that's likely to be a problem.

\$\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.