1

(Arduino) Hello I don't know where I am going wrong here, please advise.

In the end I want to step a bipolar motor, HIGH/LOW, using Timer0 with OCR0A and OCR0B interrupts to adjust the motors step interval and duty cycle. Eventually I would like to do the same thing with a second motor and Timer2.

The idea is that the interrupt at OCR0A triggers step LOW and the interrupt at OCR0B triggers step HIGH. This breaks down into the TCNT count from 0 to OCR0B is the LOW phase and TCNT count from OCR0B to OCR0A is the HIGH phase. Both phases together make up the motor step interval which would be between TCNT0=0 and OCR0A ISR Clear. The duty cycle is determined by value between OCR0B and OCR0A, the duration of the HIGH phase.

My first test was to use Serial.println() to return "LOW" or "HIGH" from the corresponding ISRs to the computer to see if the step sequence is in the correct AB-AB pattern. It is not. The step sequence starts out correctly but after 7(seven) OCR0B ISR interrupts in sequence the OCR0B ISR ceases to repeat while the ISR for OCR0A prints repeatedly. The following is the code:

 ISR(TIMER0_COMPA_vect) { Serial.println("HIGH");} //end ISR COMPA//

 ISR(TIMER0_COMPB_vect) { Serial.println("LOW"); } //end ISR COMPB//
                        
 int long  SPEED_A  = 200; // OCR0B->OCR0A is HIGH PHASE // trigger LOW  // clear to 0 //

 int long  SPEED_B  = 150; // 0->OCR0B is LOW PHASE      // trigger HIGH
                        
   void setup()
   {  
      noInterrupts();             // disable interrupts
                     
      OCR0A   = SPEED_A;          // interrupt A compare to TCNT0 value each tick // 0-255

      OCR0B   = SPEED_B;          // interrupt B compare to TCNT0 value each tick // 0-255

      TCCR0A  |= ( 1 << COM0A1);  // clear counter on match // OCR0A

      TIMSK0  |= ( 1 << OCIE0A);  // enable timer compare interrupt A

      TIMSK0  |= ( 1 << OCIE0B);  // enable timer compare interrupt B

      interrupts();               // enable interrupts

      Serial.begin(9600);         // serial

   }  //END setup///

 void loop() { } //END loop//

The Serial return is as follows:

LOW HIGH LOW HIGH LOW HIGH LOW HIGH LOW HIGH LOW HIGH LOW HIGH HIGH HIGH HIGH ...

Why does the ISR for OCR0B stop executing?

2
  • 1
    flash an LED instead of printing ... if you still want to print, do not do any printing inside an ISR function ... set a flag inside one ISR ... clear the flag inside the other ISR ... print the state of the flag inside the loop() function
    – jsotola
    Feb 11, 2022 at 2:33
  • Thank you for the comment, I noticed I was misunderstanding the math of what 1 period equated to microsecond wise and the LED 100% helped me see the issue. I need to include global variable to count the ticks or 'OCR0A revolutions' to time the intervals correctly. Feb 11, 2022 at 8:02

1 Answer 1

5

Don't do serial prints inside an ISR. Ever. They require interrupts to work, and inside the ISR interrupts are off. For a while the attempts to print will fill up a buffer which is emptied by another ISR, however when that buffer fills the Serial.print will block. And if it blocks inside an ISR waiting for an interrupt it will block forever. Thus it stops printing.

As Jstola suggested in a comment under the question, turn an LED on and off, or something like that.

I can't explain your 7 prints perfectly, but printing HIGH and LOW repeatedly, with their corresponding carriage-return/linefeeds, would, after 7 turns (7 x 11 = 77), pretty-much fill up the serial buffer which is 64 bytes.

So, you are sending around 77 bytes, some would have "escaped" before the buffer filled up, and when you filled it with 64 bytes, it stops.

Your results would change slightly if you made the baud rate higher, say 115200 baud, which I always use, but still, you should not print inside an ISR.

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.