Search code examples
cavravr-gccproteus

Invalid opcode 0xFFFF at PC=0xBE78 in Proteus simul when i call the ISR(USART_RX_vect){}


I write a code for ATmega328P(Arduino NANO). It will control a servo motor and pump using the Bluetooth module HC-10. Compiler compiles the code without mistakes, but the simulation doesn't work. The same problem happened when i call a functions without "inline" keyword. Ok but what's wrong now with ICR interrupt? I am a beginner on this way so can someone help me?

This is a code:

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

enum {
  SERVO_MAX_RIGHT   = 500,
  SERVO_MAX_LEFT    = 248,
  SERVO_MID         = 375,
  BAUD              = 9600,
  FOSC              = 16000000,
  MYUBRR            = FOSC/16/BAUD-1,
  BUT_L             = 97,           // Turn left button number (ASCII)
  BUT_R             = 100,
  BUT_M             = 115,
};

struct button {
unsigned char leftOn;
unsigned char rightOn;
unsigned char moveOn;
unsigned char pressed;
} button;

static inline void portInit() {
  DDRC &= ~(1<<DDC0);               // Set buttons ports direction to input  
  DDRC &= ~(1<<DDC1);                 
  DDRC &= ~(1<<DDC2);                
  PORTC |= (1<<PORTC0);             // Apply 5v voltage to buttons ports 
  PORTC |= (1<<PORTC1);
  PORTC |= (1<<PORTC2);

  DDRB |= (1<<PB0);                 // Set output direction for Pump port pin
  PORTB &= ~(1<<PB0);               // Set 0V for Pump port
  DDRB |= (1<<PB1);                 // Set output direction for Servo port pin 
  PORTB &= ~(1<<PB1);               // Set 0V for servo port 
}

static inline void timerInit() {
  unsigned char sreg;

  TCCR1A |= (1<<COM1A1);            // Set the non-invert mode PWM 
  TCCR1A &= ~(1<<COM1A0); 
  TCCR1A &= ~(1<<WGM10);            // Set the Fast PWM bit mode 
  TCCR1A |= (1<<WGM11);
  TCCR1B |= (1<<WGM12);
  TCCR1B |= (1<<WGM13);
  TCCR1B |= (1<<CS10);              // Set the prescaler CLKi/o/64
  TCCR1B |= (1<<CS11);
  TCCR1B &= ~(1<<CS12);

  sreg = SREG;                      // Disable global interrupt flag 
  cli();
  ICR1 = 5000;                      // Set the pulse width 

  SREG = sreg;                      // Restore global interrupt flag 
}

static inline void uartInit(unsigned int ubrr) {
  UBRR0H = (unsigned char) (ubrr>>8); // Set the BAUD rate in USART baud Rate 
  UBRR0L = (unsigned char)ubrr;     // Registers (to low & high)
  UCSR0B = 0b10011000;              // Set the RX&TX&Interrupt Rx enable
  UCSR0C = ~(1<<USBS0);             // Set the 1 stop bit                       
  UCSR0C = ~(1<<UCSZ02);            // Set the 8 bit package settings
  UCSR0C = (1<<UCSZ01);             
  UCSR0C = (1<<UCSZ00);
}

static inline void uart_send(char* str) {
  while(*str) {
    while(UCSR0A & (1<<UDRE0)) {    // While UDR is ready to recieve new data
      UDR0 = *str;
      str++;
    }
  }
}

static inline void uart_boatControl(unsigned char read) {
  uint8_t val;
  if(read) {
    val = UDR0;
    switch(val) {
      case BUT_L:
        OCR1A = SERVO_MAX_LEFT; 
        break;
      case BUT_R:
        OCR1A = SERVO_MAX_RIGHT;
        break;
      case BUT_M:
        PORTB = (1<<PB0);
        break;
      default:
        OCR1A = SERVO_MID;
        PORTB = ~(1<<PB0);
    }

  }
}

ISR(USART_RX_vect){

  button.pressed = UCSR0A & (1<<RXC0);
  uart_boatControl(button.pressed); 

}

int main(void)  
{
  portInit();
  timerInit();

  OCR1A = SERVO_MID;                // Set the Servo to midle (0 degree) 
  _delay_ms(500);

  uartInit(MYUBRR);

  while(1) {
    button.leftOn = (!(PINC&(1<<PC0)));
    button.rightOn = (!(PINC&(1<<PC1)));
    button.moveOn = (!(PINC&(1<<PC2)));

    if (button.leftOn) {
      OCR1A = SERVO_MAX_LEFT; 
    } else if (button.rightOn) {
      OCR1A = SERVO_MAX_RIGHT;
    } else if (button.moveOn) {
      PORTB |= (1<<PB0);
    } else {
      OCR1A = SERVO_MID;
      PORTB &= ~(1<<PB0);
    }
  }

  return 0;
}

Solution

  • I found the solution for ISR(). In my code there are no mistakes when i call the function after main() function. But when i try to find the right way to program, i did it the other way. Perhaps someone will be interested.

    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    
    enum {
      SERVO_MAX_RIGHT   = 655,
      SERVO_MAX_LEFT    = 527,          // 248 default
      SERVO_MID         = 400,
      BAUD              = 9600,
      FOSC              = 16000000,
      MYUBRR            = FOSC/16/BAUD-1,
      BUT_L             = 97,           // Turn left button number (ASCII)
      BUT_R             = 100,
      BUT_M             = 115,
    };
    
    struct butt {
      unsigned char leftOn;
      unsigned char rightOn;
      unsigned char moveOn;
    } butt;
    
    static inline void portInit(); 
    static inline void timerInit(); 
    static inline void uartInit
      (unsigned int ubrr);
    static inline void uart_send(char* str); 
    static inline void uart_boatControl
      (unsigned char data);
    static inline void analog_boatControl(unsigned char bL,
      unsigned char bR, unsigned char mv);
    
    int main(void)  
    {
      portInit();
      timerInit();
    
      OCR1A = SERVO_MID;                // Set the Servo to midle (0 degree) 
      _delay_ms(500);
    
      uartInit(MYUBRR);
      
      PORTD &= ~(1<<PD7);
      while(1) {
        uart_boatControl(UDR0);
     }
      return 0;
    }
    
    static inline void portInit() {
      DDRC &= ~(1<<DDC0);               // Set buttons ports direction to input  
      DDRC &= ~(1<<DDC1);                 
      DDRC &= ~(1<<DDC2);                
      PORTC |= (1<<PORTC0);             // Apply 5v voltage to buttons ports 
      PORTC |= (1<<PORTC1);
      PORTC |= (1<<PORTC2);
    
      DDRB |= (1<<PB0);                 // Set output direction for Pump port pin
      PORTB &= ~(1<<PB0);               // Set 0V for Pump port
      DDRB |= (1<<PB1);                 // Set output direction for Servo port pin 
      PORTB &= ~(1<<PB1);               // Set 0V for servo port 
                                        
      DDRD |= (1<<PD7);
    }
    
    static inline void timerInit() {
      unsigned char sreg;
    
      TCCR1A |= (1<<COM1A1);            // Set the non-invert mode PWM 
      TCCR1A &= ~(1<<COM1A0); 
      TCCR1A &= ~(1<<WGM10);            // Set the Fast PWM bit mode 
      TCCR1A |= (1<<WGM11);
      TCCR1B |= (1<<WGM12);
      TCCR1B |= (1<<WGM13);
      TCCR1B |= (1<<CS10);              // Set the prescaler CLKi/o/64
      TCCR1B |= (1<<CS11);
      TCCR1B &= ~(1<<CS12);
    
      sreg = SREG;                      // Disable global interrupt flag 
      cli();
      ICR1 = 5000;                      // Set the pulse width 
    
      SREG = sreg;                      // Restore global interrupt flag 
    }
    
    static inline void uartInit
      (unsigned int ubrr) {
      UBRR0H = (unsigned char) (ubrr>>8); // Set the BAUD rate in USART baud Rate 
      UBRR0L = (unsigned char)ubrr;     // Registers (to low & high)
      UCSR0B = 0b10011000;              // Set the RX&TX&Interrupt Rx enable
      UCSR0C &= ~(1<<USBS0);             // Set the 1 stop bit                       
      UCSR0C &= ~(1<<UCSZ02);            // Set the 8 bit package settings
      UCSR0C |= (1<<UCSZ01);             
      UCSR0C |= (1<<UCSZ00);
    }
    
    static inline void uart_send(char* str) {
      while(*str) {
        while(UCSR0A & (1<<UDRE0)) {    // While UDR is ready to recieve new data
          UDR0 = *str;
          str++;
        }
      }
    }
    
    static inline void uart_boatControl
      (unsigned char data) {
      
      while(!(UCSR0A & (1<<RXC0))) {
      };
      
      while(UCSR0A & (1<<RXC0)) {
        switch(UDR0) {
          case BUT_L:
            OCR1A = SERVO_MAX_LEFT; 
            break;
          case BUT_R:
            OCR1A = SERVO_MAX_RIGHT;
            break;
          case BUT_M:
            PORTB = (1<<PB0);
            break;
          default:
            OCR1A = SERVO_MID;
            PORTB &= ~(1<<PB0);
          }
        }
      }
    
    static inline void analog_boatControl(unsigned char bL,
      unsigned char bR, unsigned char mv) {
    
      if (bL) {
        OCR1A = SERVO_MAX_LEFT; 
      } else if (bR) {
        OCR1A = SERVO_MAX_RIGHT;
      } else if (mv) {
        PORTB |= (1<<PB0);
      } else {
        OCR1A = SERVO_MID;
        PORTB &= ~(1<<PB0);
      }
    
    }