- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
Ergebnis 1 bis 6 von 6

Thema: UART, Sprungtabelle und Systemabstürze...

  1. #1
    Erfahrener Benutzer Begeisterter Techniker Avatar von PCMan
    Registriert seit
    05.08.2006
    Ort
    Munich
    Beiträge
    311

    UART, Sprungtabelle und Systemabstürze...

    Anzeige

    Praxistest und DIY Projekte
    Hallo Leute,
    mal wieder komme ich nicht weiter und möchte nun mal die Experten an die harte Nuss lassen.

    Ich möchte meinen AVR mit dem PC kommunizieren lassen. Dazu verwende ich das Terminalprogram puTTY.
    Ich möchte, dass mein AVR empfangene Befehle erkennt und ausführt.

    Im Großen und Ganzen realisiere ich das mit P.Fleuries UART-Library.
    Dort habe ich aber in der uart.c einige Modifikationen vorgenommen.

    Zunächst etwas Code:
    Code:
    volatile struct {
    ... jede Menge zeugs...
    
    	uint8_t command_ptr;
    	char command[255];
    } system;
    
    
    // Die Kommandostruktur
    char p_unknown[] PROGMEM = "Unbekannter Befehl: ";
    typedef struct 
    {
       void (*func)(uint8_t);      // Zeiger auf die auszuführende Funktion
       //uint8_t arg;                // das Argument, das mitübergeben wird
       uint8_t arg;
       char text[255]; // Text, maximal TEXT_LEN Zeichen lang
    } command_t;
    
    //Sprungtabelle: welche Funktion mit welchem Parameter bei welchem eingegangenem Befehl?
    
    const command_t commands[] PROGMEM =
    {
       { execute, 1, "ping" },
       { execute, 2, "help" }
    };
    
    ... 
    
    //zunächst alles beim alten...
    SIGNAL(UART0_RECEIVE_INTERRUPT)
    /*************************************************************************
    Function: UART Receive Complete interrupt
    Purpose:  called when the UART has received a character
    **************************************************************************/
    {
        unsigned char tmphead;
        unsigned char data;
        unsigned char usr;
        unsigned char lastRxError;
     
     
        /* read UART status register and UART data register */ 
        usr  = UART0_STATUS;
        data = UART0_DATA;
        
        /* */
    #if defined( AT90_UART )
        lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
    #elif defined( ATMEGA_USART )
        lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
    #elif defined( ATMEGA_USART0 )
        lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) );
    #elif defined ( ATMEGA_UART )
        lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
    #endif
            
        /* calculate buffer index */ 
        tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK;
        
        if ( tmphead == UART_RxTail ) {
            /* error: receive buffer overflow */
            lastRxError = UART_BUFFER_OVERFLOW >> 8;
        }else{
            /* store new index */
            UART_RxHead = tmphead;
            /* store received data in buffer */
            UART_RxBuf[tmphead] = data;
        }
        UART_LastRxError = lastRxError;   
    
    //AB HIER MODIFIZIERT
    	uint8_t c = uart_getc(); //es wurde Zeichen empfangen, dann hole es ab!
    
    	if (!(c & UART_NO_DATA) && !( c & UART_FRAME_ERROR ) && !( c & UART_OVERRUN_ERROR ) && !( c & UART_BUFFER_OVERFLOW )&& c != 0) //es wurde ein Zeichen empfangen und kein Fehler o.Ä.
    	{
    		uart_putc(c); //zeichen ausgeben
    
    		if (c == 13) //es wurde Enter-Taste im puTTY gedrückt.
    		{
    			uart_puts("\n\r"); //neue Zeile in puTTY
    			system.command[system.command_ptr]='\0'; 
          		system.command_ptr = 0;
    			lcd_clrscr();
    			lcd_puts((char*)system.command);
    			const command_t * cmd = commands;
    			uint8_t i;
       			for (i=0; i < sizeof(commands) / sizeof(command_t); i++)
       			{
          			// Ist das der gesuchte String?
          			if (strcmp_P ((char*)system.command, cmd->text))
        				{
            				// Nein, dann weitersuchen
    					cmd++;
            				continue;
        				}
        				else
        				{
          				// Ja
          				uint8_t (*func)(uint8_t), arg;
    
          				// Dann Funktionszeiger und Argument besorgen,
          				func = (uint8_t(*)(uint8_t)) pgm_read_word (& cmd->func);
          				arg  = (uint8_t)         pgm_read_word (& cmd->arg);
          				// Funktion ausführen und deren Wert zurückliefern 
          				func (arg);
          				break;
          			}
       			}
       			if (i==2) //es wurden alle Befehle abgegrast, aber der richtige war nicht dabei
    			{ 
    				uart_puts_P("Unbekannter Befehl: "); //<- HIER ENTSTEHT DER FEHLER
    				uart_puts((char*)system.command);
    				uart_puts("\n\r#");
    			}
    		}
    		else
    		{
    			system.command[system.command_ptr] = c;
    			system.command_ptr++;
    		}
    		
    	}
    	
    }
    Es kommen keine Warnings nach dem Kompilieren.
    Wenn ich nun folgendes in putty eingebe:
    "ping": ich erhalte wie erwartet antwort
    "ping.": Meldung dass Befehl nicht gefunden wurde
    "ping.." (oder irgendetwas anderes was mehr als 7 Zeichen hat führt zum Absturz des Programmes. Ich weiß aber, dass die Codezeilen ausgeführt werden, aber ich weiß nicht, warum nix über den UART rausgesendet wird.

    Ich hoffe ihr habt ein paar Ideen,
    Grüße Simon

    P.S.: ATMega32, 12MHz

  2. #2
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Dein Problem ist, dass du uart_puts im Receive-Interrupt aufrufst.
    Wenn der Puffer nämlich voll ist, wartet die Funktion, bis wieder Platz im Puffer ist. Es wird aber kein Platz frei, wenn nichts gesendet wird, und das wird es nicht, so lange der Receive-Interrupt noch bearbeitet wird. Wenn du also mehr Zeichen versuchst zu senden, als der Sendepuffer groß ist, hast du einen schönen Dead-Lock.

    Es ist überhaupt eine reichlich schlechte Idee, das ganze Geraffel in den Receive-Interrupt zu stopfen.
    MfG
    Stefan

  3. #3
    Erfahrener Benutzer Begeisterter Techniker Avatar von PCMan
    Registriert seit
    05.08.2006
    Ort
    Munich
    Beiträge
    311
    Hi sternst,
    ich würde ja gerne einen anderen Weg gehen als das alles in die interrupt routine zu stopfen. Aber wie soll ich erkennen, wann den ein befehl ankam? Ich meine alles in der main-Endlosschleife dauernd abzutasten ist doch verbrauchte Leistung, oder?
    Bin natürlich offen für Vorschläge.
    Grüße Simon

  4. #4
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Zitat Zitat von PCMan
    Ich meine alles in der main-Endlosschleife dauernd abzutasten ist doch verbrauchte Leistung, oder?
    Was machst du denn aktuell in der main-Endlosschleife anderes, als Leistung zu verbraten?
    MfG
    Stefan

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    1) die ISR-Routinen würde ich unverändert lassen.
    2) Sooo lange dauert eine Auswertung in main() auch nicht, wenn man's richtig anstellt
    3) Falls die Zeichen zu flott ankommen, kann man sie über ne FIFO puffern, ein Beispiel dazu ist im wiki.

    Ob ein kompletter Befehl angekommen ist, kannst du erkennen, indem jeder Befehl zB mit einem Zeichen wie # endet oder jeder Befehl ne bestimmte länge hat.

    Ich würd allerdings ne 'inkrementelle' Erkennung vorschlagen, d.h. es gibt keine eigene Schleife für die Erkennung uneterhalb von main, sondern wenn ein neues Zeichen ankommt geht die Erkennung um dieses 1 Zeichen weiter.

    Dazu muss man sich den Status der Erkennung merken (wieviel Zeichen sind schon da, etc.). Dein main()-Schleife muss dazu nicht-blockierend aufgebaut sein, also ohne wait() und so üblen Kram.
    Disclaimer: none. Sue me.

  6. #6
    Erfahrener Benutzer Begeisterter Techniker Avatar von PCMan
    Registriert seit
    05.08.2006
    Ort
    Munich
    Beiträge
    311
    hallo ihr beiden,
    alles klar, dann werd' ich mal umstrukturieren. Jetzt versteh ich wenigstens auch, wo der Fehler lag.
    Habt vielen Dank,
    Simon

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad