0
\$\begingroup\$

So here is the basis of my code, I have an array of different instructions for the prescribed LEDs to follow.

The led will blink for the prescribed number of times in an interrupt before they stop and increment the array value, which will lead to the second set of instructions in the arrays for the led.

Here is my problem, as the program executes the first set of instructions from the array, when ab = 0, it works just fine, however when I execute the second set of instruction, when ab = 1, the led I am trying to infinitely blinks without stopping

I have tried everything to stop the led, from boolean if statements, to disabling interrupts but nothing is working.

In the program there is a variable which I have to reset to zero which is the x_counter (working with just the x-axis to keep it simple), so that the second set of instructions can happen

However I suspect that it is the reason why it continue to loop on forever.

Any ideas on how to fix this problem? Here is my code:

 /////EDITED///Again////////////////

                /*
         * avr_cnc.c
         *
         * Created: 2015-04-01 6:13:58 AM
         *  Author: Alvi
         */ 


        #include <avr/io.h>    
        #include <stdio.h>
        #include <util/delay.h> 
        #include <avr/interrupt.h>  
        //axis bools

        //////////////////
        // x-axis
        #define stp_x_led PB0
        #define dir_x_led PB1  

        ////////////// 
        // y-axis
        #define stp_y_led PD6
        #define dir_y_led PD7 

        ////////////  
        // z-zxis  
        #define stp_z_led PD4 
        #define dir_z_led PD5

        // PORTB 
        #define led_portx PORTB
        //////////// 
        /// PORTD
        #define led_portyz PORTD 
        ///////////  
        // PORTC 
        //#define led_portz PORTC 
        // DDR////////
        #define led_x_ddr DDRB  
        #define led_y_ddr DDRD 
        #define led_z_ddr DDRD
        #define F_CPU 16000000UL 

        int axis[] = {1,1};
        int direction[] = {1,0};
        int steps[] = {20,20}; 
        int entries = sizeof(axis)/sizeof(int) - 1; 
        int ab = 0; 
        int vay = 1; 

        static volatile int x_counter = 0; 
        static volatile int x_boolean = 1; 
        static volatile int y_counter = 0; 
        static volatile int y_boolean = 1;
        static volatile int z_counter = 0; 
        static volatile int z_boolean = 1;  
        ////////////////// 

        int direction_ab; 
        int steps_ab;  



        int main(void)
        {  

            ////// DDR setups /////////////////////////////////////////////////
            led_x_ddr |= ((1 << stp_x_led) | (1 << dir_x_led));   
            led_y_ddr |= ((1 << stp_y_led) | (1 << dir_y_led)); 
            led_z_ddr |= ((1 << stp_z_led) | (1 << dir_z_led));
            /////////////////////////////////////////////////////////// 


            TCCR1B |= (1 << WGM12);  // configuring timer 1 for ctc mode
            OCR1A = 4678;
            TIMSK1 |= (1 << OCIE1A); // enable ctc interrupt

            TCCR1B |= ((1 << CS12) | (1<< CS10)); //Start at 1024 prescaler 

            sei(); //Enable global interrupts

             //Sets ctc compare value to 1hz at 1mhz AVR clock, with prescaler of 64
            while(1)  
            {    


            }          

        } //end of main loop


        ISR(TIMER1_COMPA_vect)
        {   
            ///////Define which stepper, direction and how many steps in this code
            stepper_protocol(axis[ab],steps[ab],direction[ab]);  

            ////////////////////////////////////////////////////////////////////
        }

         stepper_protocol(enable,steps_ab,direction_ab){ 

            // checks if user enabled x-axis 

            if (ab < entries){
            if (enable == 1){
                //direction
                if (direction_ab == 1){ 
                    led_portx |= (1 << dir_x_led); 
                } 
                else if (direction_ab == 0){ 
                    led_portx &= ~ (1 << dir_x_led); 
                } 
                ///////////////////////////////
                //stepper logic 

                led_portx ^= (1 << stp_x_led);
                   if (x_counter >= steps_ab){ 

                        led_portx = (0 << stp_x_led);   
                        led_portx = (0 << dir_x_led);
                        x_boolean = 0;  
                        ab++; 
                        x_counter = 0;  
                    }     
                    if (x_boolean == 1){
                        x_counter ++;
                    }

            //////////////////////////////
            }   


            // checks if user enabled y-axis 
            else if (enable == 2){
                //directjion
                if (direction_ab == 1){ 
                    led_portyz |= (1 << dir_y_led); 
                } 
                else if (direction_ab == 0){ 
                    led_portyz &= ~ (1 << dir_y_led); 
                }  
                ///////////////////////////////
                //stepper logic
                led_portyz ^= (1 << stp_y_led);
                    if (y_counter >= steps_ab){ 
                        led_portyz &= ~ (1 << stp_y_led);  
                        y_boolean = 0;  
                        //vay = 1; 
                        ab ++;
                    }      
                if (y_boolean == 1){
                y_counter ++;
                }   
                //////////////////////////////
            } 

             // checks if user enabled z-axis 
            else if (enable == 3){
                //direction
                if (direction_ab == 1){ 
                    led_portyz |= (1 << dir_z_led); 
                } 
                else if (direction_ab == 0){ 
                    led_portyz &= ~ (1 << dir_z_led); 
                } 
                ///////////////////////////////
                //stepper logic
                led_portyz ^= (1 << stp_z_led);
                    if (z_counter >= steps_ab){ 
                        led_portyz &= ~ (1 << stp_z_led);  
                        z_boolean = 0; 
                        //vay = 1; 
                        ab ++;
                    }      
                if (z_boolean == 1){
                z_counter ++;
                }    

                //////////////////////////////
            }  
        } 
    }        
\$\endgroup\$
9
  • \$\begingroup\$ Some quick points while I was looking at the code: (1) You call sei() inside an interrupt. This is a VERY BAD idea and can if you're not careful lead to stack overflows. (2) Calling functions from ISRs is not good practice as it leads to excessive bloat during interrupt entry and exit. (3) You change global variables in an interrupt (because you change them in the function you call from the interrupt) but haven't marked them as 'volatile' which means they could get optimised away. \$\endgroup\$ May 9, 2015 at 3:18
  • \$\begingroup\$ Note that (3) is a direct result of (2) and the fix of marking them volatile will make the function much less efficient as all those variables will have to be loaded and stored to the SRAM every time you access them. \$\endgroup\$ May 9, 2015 at 3:20
  • \$\begingroup\$ I have to utilize functions in interrupts since I will also be running two leds(motors) at the same time and I simply cannot do that with delays since delays disrupt the whole system, unless there is an alternative way you can recommend me? \$\endgroup\$
    – Redrachet2
    May 9, 2015 at 3:59
  • \$\begingroup\$ also in the edits I make all the my boolean and counter variables to volatile but it still produces the same result \$\endgroup\$
    – Redrachet2
    May 9, 2015 at 4:00
  • \$\begingroup\$ You currently have the LED in your function toggling every time the ISR occurs - you always pass enable = 1, so the LED will always toggle. 'enable' is a local variable in the function so setting it = 0 when the x_counter reaches steps_ab will do nothing because the value will be lost when the function returns. \$\endgroup\$ May 9, 2015 at 4:14

1 Answer 1

1
\$\begingroup\$

some of the more obvious problems with the code.

'ab' is not being incremented during the ISR,

so the interrupt continues forever
should turn OFF the timer & associated interrupt when 'ab' exceeds/equals 'entries'
(not every interrupt, just the timer interrupt)

fails to clear the timer interrupt pending flag at the end of the ISR, resulting in:

 the ISR will immediately re-execute, 
 rather than waiting for the timer to produce another interrupt event.

Is the interrupt rate slow enough to allow time for the CNC (or whatever) device to complete the step before the next interrupt occurs?

\$\endgroup\$
1
  • \$\begingroup\$ yes I have tried similair code like this with a stepper motor and a quicker interrupt it is able to move quite nicely. For the stepper motor, the ideal time for when an interrupt flag occurs would be around 10 ms, this gives a smooth rotation, so yes a stepper motor would be able to execute a step before the next interrupt \$\endgroup\$
    – Redrachet2
    May 10, 2015 at 16:58

Your Answer

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

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