Forum: Compiler & IDEs Interrupt-Problem?


von Tobias Michaels (Gast)


Lesenswert?

Hi!
Ich habe ein Problem mit meinem Programm, kann aber den Fehler nicht
wirklich finden!


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

#define F_CPU            3686400      /* Hz */
#define UART_BAUD_RATE      9600      /* 9600 baud */
#define UART_BAUD_SELECT (F_CPU/(UART_BAUD_RATE*16l)-1)

#define max_data_len 9


unsigned char volatile receive_state;
unsigned char volatile packet_length;
unsigned char volatile data[max_data_len];
unsigned char volatile data_length;


const unsigned char msg_status_response[9] =
{0X68,0x39,0x00,0x09,0x00,0x3F,0x00,0x01,0x01};
const unsigned char msg_announce[3] = {0xFF,0x02,0x01};
const unsigned char msg_poll_response[3] =  {0xFF,0x02,0x00};

//XXX: use enum instead
#define state_sender_id 1
#define state_get_length 2
#define state_dest_id 3
#define state_get_data 4
#define state_packet_done 5

SIGNAL(SIG_UART0_RECV)
  // signal handler for receive complete interrupt
{
  unsigned char byte;



  byte = inp(UDR0);        //read byte for UART data buffer

  if (receive_state == state_get_length){
    packet_length = byte;
    receive_state = state_dest_id;
  }else if (receive_state == state_dest_id){ //waiting for
"CD-Changer"
    packet_length--;
    if (byte == 0x18){
      receive_state = state_get_data;
      data_length = 0;
    }
  }else if (receive_state == state_get_data){
    if (--packet_length > 0){
      data[(int)data_length++] = byte;
    }else{ //we get checksum
      //checksum is egal
      receive_state = state_packet_done;
    }
  }else { //standard: wait for sender_id=="Radio"
    receive_state = state_sender_id; //sischer is sischer
    if (byte == 0x68)
      receive_state = state_get_length;
  }

}

unsigned char ibus_send_byte(unsigned char byte)
{
  unsigned char  j,parity;
  parity=1;
  for (j=7;j>0;j--)
    parity += byte>>j & 0x01;
  while (bit_is_clear(UCSR0A,UDRE)) ; //wait until ready
  if (parity & 0x01) //Set Parity
    sbi(UCSR0B,TXB8);//
  else
    cbi(UCSR0B,TXB8);
  outp(byte,UDR0);

  while (bit_is_clear(UCSR0A,RXC));
  j = inp(UDR0); //get rec. byte
  if (j != byte)
    return 0;
  //contention in parity bit is egal
  //sei();
  return 1;
}


unsigned char __ibus_send(unsigned const char *buf, unsigned char
size){

  unsigned char i,checksum=0^0x18;

  if (!ibus_send_byte(0x18)){
    return 0;}

  outp(1<<PC2,PORTC);
  if (!ibus_send_byte(size+1)){

    return 0;}
  checksum ^= size+1;
  for (i=0;i<size;i++){
    checksum ^= buf[i];
    if (!ibus_send_byte(buf[i]))
      return 0;
  }
  if (!ibus_send_byte(checksum))
    return 0;

  return 1;
}

void ibus_send(unsigned const char *buf, unsigned char size){
  cli();
  while(!(__ibus_send(buf,size)));

}






void uart_init(void)
  /* initialize uart */
{
  /* enable RxD/TxD and ints */
  outp((1<<RXCIE)|(1<<TXCIE)|(1<<RXEN)|(1<<TXEN)|(1<<CHR9),UCSR0B);
  /* set baud rate */
  outp(UART_BAUD_SELECT, UBRR0);
}

int main(void)
{
  uart_init();
  outp(0xff,DDRC);
  sei();                 /* enable interrupts */
  receive_state=state_sender_id;
  //XXX: wait?
  ibus_send(msg_announce,3); //announce
      for (;;) {             /* loop forever */
    if (receive_state == state_packet_done){
      if (data[0]==0x01){ //poll -> respond.
        ibus_send(msg_poll_response,3);
        receive_state=state_sender_id;

      }
      if (data[0] == 0x38)
        if ((data[1]==0)||(data[1]==3)){
          //req stat||play
          ibus_send(msg_status_response,9);
          receive_state=state_sender_id;
        }

    }

  }
}


Das Problem tritt in der Funktion ibus_send_byte auf! Wenn ich hier das
unten auskommentierte sei() reinschreibe und die Interrupts wieder
aktiviere, dann sendet er ständig das gleihe Byte über den UART. Wenn
ich sei() auskommentiere, dann sendet er das Paket so, wie ich will.
Allerdings kann ich dann natürlich nichts empfangen, weil der Interrupt
für die Empfangsroutine ja nicht ausgelöst wird! Wenn ich sei();
drinlasse und :

while (bit_is_clear(UCSR0A,RXC));
  j = inp(UDR0); //get rec. byte
  if (j != byte)
    return 0;
auskommentiere,dann funktioniert es auch. Ich finde den Fehler einfach
nicht, da ich nicht weiss, wo da noch ein Interrupt ausgelöst werden
könnte, der mir dazwischenfunkt. Laufen tut das ganze auf nem Atmega
161!

Danke

Tobias Michaels

von Joerg Wunsch (Gast)


Lesenswert?

Nun, Du hast TXCIE gesetzt, aber wo ist der Interrupthandler für TXCIE?

Übrigens ist es sinnvoller, statt TXCIE lieber UDRIE zu benutzen: Du
kannst ja das nächste Zeichen bereits in den Puffer schieben, während
das aktuelle Zeichen gerade das Sende-Schieberegister verläßt.  Damit
ist
ein nahtloser Übergang zwischen zwei Zeichen ohne zusätzliche Pause
gewährleistet.

inp()/outp() sind »deprecated«, stattdessen bitte auf direkte
Portzuweisung umstellen.  Namen, die mit einem Unterstrich beginnen
(__ibus_send()) sind für die ``Implementation'' reserviert (also für
Compiler und Bibliothek), daher besser grundsätzlich nicht benutzen,
damit
es nicht zu Kollisionen mit der Bibliothek kommt.

von Tobias Michaels (Gast)


Lesenswert?

Ich habe das Programm komplett umstrukturiert und es läuft jetzt, wie es
soll, danke an alle die sich Gedanken drüber gemacht haben!

Tobi

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.