mikrocontroller.net

Forum: Compiler & IDEs Interrupt-Problem?


Autor: Tobias Michaels (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Tobias Michaels (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.