mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ATmega Regelung mit schneller Werteausgabe auf UART


Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, ich versuch es mal verständlich zu erläutern, schonmal ein Danke 
fürs lesen.....


Aufbau :

Eine bewegliche Platte kann auf zwei Achsen (X,Y) über Servos gekippt 
werden. Auf der Platte ist ein IR Touchpad geschraubt, das Seriell 
(UART0 ,9600Baud) die Position einer rollenden Kugel an den ATmega644P 
übermittelt.
Das soll/wird über einen Software PID Regler geregelt. Ziel ist das 
halten der Kugel auf eine festgelegte Sollposition auf der Platte 
(Positionsregelung).

Zur Darstellung wurde eine VB.net Oberfläche entwickelt, die alle Werte 
der beiden Regler (x- & y-achse) darstellen kann, sowie die vom 
Controller Empfangenen Daten des Touchpads (Kugelposition etc.)
Die Daten werden vom Controller über den zweiten Serielle Port (UART1) 
an den PC gesendet.



Problem :

Wird die Hauptprogrammschleife des Controllers ausgeführt, ohne die 
Daten an den PC zu senden, reagiert die Regelung ( Das verstellen der 
Motoren in abhängigkeit zur Kugelposition ) annähernd Verzögerungsfrei.
Werden jedoch während der Hauptschleife zusätzlich noch die Daten an den 
PC versendet, merkt man einen deutliches "Motorstottern" , da der 
Controller wesentlich länger braucht, bis er wieder an den punkt 
gelangt, an dem er die aktuelle Kugelposition abfragen kann.Somit 
"verpennt" er Zwischenschritte die er eigentlich einstellen sollte, was 
das ganze sehr stotternd und unsauber macht.



Frage :

Wie kann dem ganzen abhilfe geschaffen werden. unsere überlegungen sind 
folgende :

- Den Prozessortakt erhöhen ( momentan auf 14,7456MHz )

- Die Baudrate erhöhen, damit die Daten schneller übertragen werden, 
brachte jedoch keine Besserung.

- Die Daten nicht alle auf einmal in der Schleife zu übertragen, sondern 
maximal 4 pro Schleife ( Das ist nicht Sinn des Programms, Datenansicht 
sollte möglichst Synchron laufen)

- Unwichtige Daten nur alle 10 Durchläufe senden ( Macht dann jeden 
10ten durchlauf Ruckend, is auch nicht gewünscht)

- Einen zweiten Controller verwenden, der sich um die PC-Kommunikation 
kümmert ( Das klingt doch schicker )

Und hier an diesem Punkt stellen sich jetzt diese Fragen :
Wie am besten die Kommunikation realisieren, so das der 
Regler-Controller in seiner Arbeit möglichst wenig gestört wird. SPI 
wird scheinbar ja auch durch den UART realisiert, fällt damit Flach.

Wie würde es mit einer parallelen Datenübertragung an zwei PORTS 
aussehen, die über Interrupts gesteuert werden würde ?
Pro zu übertragenden Signal wären das 5 bytes , Eins für die 
Funktionsnummer und 4 für einen FLOAT Wert.
Das wäre mit meinem jetzigen Wissenstand wohl die schnellste und 
unterbrechungsfreiste Methode. Was meint ihr dazu ?



Danke für eure Hilfe
gruss Maggus ;)

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da wir ja nicht wissen wie es bis jetzt gelöst ist (eventuell 
Quelltext?) kann man nur raten. Der µC ist bestimmt schnell genug für 
die aufgabe. Das senden Verbraucht keine nennenswerte rechenzeit. Das 
Problem wird vermutlich sein, das eine Zeichenkette auf einmal gesenden 
wird - in der Zeit regelt er vermutlich nicht.
Man könnte die Zeichen die zu senden sind, in einen art Ringbuffer 
stecken und über den Interrupt versenden lassen.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wie kann dem ganzen abhilfe geschaffen werden.

Die seriellen Daten gar nicht in einer Schleife verschicken, sondern in 
einen Ringpuffer schreiben und Interrupt gesteuert verschicken.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus wrote:
> Wie am besten die Kommunikation realisieren, so das der
> Regler-Controller in seiner Arbeit möglichst wenig gestört wird.

Nicht darauf warten, dass die UART Kommunikation abgeschlossen wird.
Sprich die UART Übertragung findet im Hintergrund interrupt gesteuert 
statt.

Einen 2-ten Prozessor einzusetzen klingt zwar schick, öffnet aber einen 
neuen Sack voll Problemen.

Autor: aha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie schnell ist denn der Regelungsalgorithmus ? Zykluszeit in ms ? Ist 
der in Float oder in Integer ? Die Kommunikation sollte nicht ausmachen, 
den die kann im hintergrund laufen. 9600 baud, und auch 38400 ist nicht 
alle welt. Da sollte noch einiges an Leistung uebrig sein.

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eben hat es klickt gemacht !


Damit der Empfangspuffer auf der PC Seite nicht volläuft, hab ich eine 
kleine Pausenzeit an das Ende der Sendefunktion angehängt. Die wartet 
knapp 40ms bis die nächste gesendet wird....

Wenn ich die rausmache dann funktioniert es ohne stottern (PATSCH!!X°)


Hier mal die SendeFunktion damit ihr versteht wovon ich rede


*
*  Sendet eine PC-Frame an die Windows Bedienoberfläche
*
*  Param:    FC    =  Funktionscode für Geräteindex in Hex , siehe Protokoll Beschreibung
*        value  =  Float Wert, der Gesendet werden soll
*
*/
void KOM_sendInfo(unsigned char FC,float value)
{

  fToSend.fDato = value;

  // Startbyte
  uart_putc(0x02);
  // Funktionscode
  uart_putc(FC);
  // Daten
  uart_putc(fToSend.byte.Drei); // Höchstes Byte
  uart_putc(fToSend.byte.Zwei);
  uart_putc(fToSend.byte.Eins);
  uart_putc(fToSend.byte.Null); //Niedrigstes Byte
  // Checksumme
  uart_putc(0xFF);
  // Endbyte 1
  uart_putc(0x03);
  // Endbyte 2
  uart_putc(0x00);
  
  // Kleine Pause, damit Windows zeit für die Datenauswertung hat, bevor
  // die Nächsten Daten geschickt werden. Ansonsten droht ein Empfangspuffer
  // Überlauf im Windows bei zu kleiner Wartezeit!
  
  //zeit(WAITFORWINDOWS);      // <------------ DER ÜBELTÄTER


}



Zum senden wird die Uart Bibliothek von Peter Fleury benutzt, die aus 
dem Internet bezogen werden kann
http://homepage.hispeed.ch/peterfleury/uartlibrary.zip

Wenn ich die Daten ungehindert an den PC senden lasse, läuft mir dessen 
Empfangspuffer voll.
Aber die Zwangspause in die Interruptroutine von Peter Fleury schreiben 
, wird wahrscheinlich das selbe problem hervorrufen wie am Anfang 
beschrieben.
Das abarbeiten der Hauptschleife wird jedesmal durch die pause 
unterbrochen werden, da Interruptroutinen ja nicht parallel zur 
Hauptschleife ablaufen.....

Ich denke ich sollte das Problem auf der Windows Seite versuchen zu 
lösen, durch z.b. effektiveren Quellcode.


Da sieht man mal wieder, das man manchmal andere braucht um seinen 
eigenen Kram zu verstehen :D

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich denke ich sollte das Problem auf der Windows Seite versuchen zu
> lösen, durch z.b. effektiveren Quellcode.
ja das denke auch auch, bei 9600baud sollte auch ein 286 sich noch 
langweile, vermutlich ist die Gui und das auslesen der RS232 in dem 
gleichen Thread.

Du hast aber immer noch ein kleines Problem mit

sendInfo

in der Zeit wo die 9Byte gesendet werden, kannt du nichts anders machen 
(die meisten zeit wartet der µC nur damit der puffer leer wird!) das 
könnte man zwar mit einer höhere baud rate etwas verbessern aber der 
Tipp von oben mit dem Ringpuffer ist die bessere lösung.

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gibt es dafür ein Beispiel ? ich kann mir nicht wirklich etwas 
vorstellen, ausswer das die Daten über die Hauptschleife gesammelt 
werden und am Ende verschickt werden.

ich glaube das Peter Fleury das genau so wie ihr meint auch gelöst 
hat...

/*************************************************************************
Function: uart_putc()
Purpose:  write byte to ringbuffer for transmitting via UART
Input:    byte to be transmitted
Returns:  none          
**************************************************************************/
void uart_putc(unsigned char data)
{
    unsigned char tmphead;

    
    tmphead  = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
    
    while ( tmphead == UART_TxTail ){
        ;/* wait for free space in buffer */
    }
    
    UART_TxBuf[tmphead] = data;
    UART_TxHead = tmphead;

    /* enable UDRE interrupt */
    UART0_CONTROL    |= _BV(UART0_UDRIE);

}/* uart_putc */



SIGNAL(UART0_TRANSMIT_INTERRUPT)
/*************************************************************************
Function: UART Data Register Empty interrupt
Purpose:  called when the UART is ready to transmit the next byte
**************************************************************************/
{
    unsigned char tmptail;

    
    if ( UART_TxHead != UART_TxTail) {
        /* calculate and store new buffer index */
        tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK;
        UART_TxTail = tmptail;
        /* get one byte from buffer and write it to UART */
        UART0_DATA = UART_TxBuf[tmptail];  /* start transmission */
    }else{
        /* tx buffer empty, disable UDRE interrupt */
        UART0_CONTROL &= ~_BV(UART0_UDRIE);
    }
}




ich verstehe das jetz so :

1.In der "uart_putc" schiebe ich das zu sendende zeichen in den 
Ringpuffer sobald Platz vorhanden ist, und gibt durch das Aktivieren des 
interrupts das "SendeSignal" für den Controller.
2.Der Controller Sendet..
3.Wurde das zeichen gesendet wird "SIGNAL(UART0_TRANSMIT_INTERRUPT)" 
ausgelöst. hier wird geprüft ob noch zeichen zum sendenvorhanden sind. 
Falls ja, wird das nächste in das Senderegister geschrieben.


Meiner Meinung nach könntet ihr doch genau das gemeint haben, oder ?

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja stimmt, wird schon so gemacht.

Ich kannte den code von Peter Fleury nicht.

Autor: Mike J. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Code von Fleury ist schon sehr gut.
Mach den Ringbuffer doch größer (von 32byte auf 128) und erhöhe die 
Übertragungsrate.
An dem PC liegt es jedenfalls nicht.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Mike J.
> Mach den Ringbuffer doch größer (von 32byte auf 128)

Das pauschal zu sagen macht überhaupt keinen sinn, es werden im Block 
9Byte gesendet diese Passen 3mal in den Puffer. Da wir nicht wissen wie 
oft diese Daten pro sekunden gesendet werden sollen kann man auch keine 
abschätzung der Puffer größe machen. Wenn mehr daten in den Puffer 
geschrieben werden als gesendet werden können, dann kann man in auch 
gleich auf 100Mbyte erhöhen und hat immer noch nichts gekonnt.

Autor: Mike J. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wenn mehr daten in den Puffer
> geschrieben werden als gesendet werden können, dann kann man in auch
> gleich auf 100Mbyte erhöhen und hat immer noch nichts gekonnt.
das ist klar, deshalb sagte ich auch:
>> und erhöhe die Übertragungsrate

Er soll das aber erst mal probieren, dann sieht er dass es daran lag und 
ist glücklich.
Wenn er weiß woran es liegt kann er an der Stelle ansetzen und seinen 
Code weiter optimieren. Also Puffer verkleinern, Übertragungsrate so 
weit senken wie möglich.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mike J. wrote:
>> Wenn mehr daten in den Puffer
>> geschrieben werden als gesendet werden können, dann kann man in auch
>> gleich auf 100Mbyte erhöhen und hat immer noch nichts gekonnt.
> das ist klar, deshalb sagte ich auch:
>>> und erhöhe die Übertragungsrate
>
> Er soll das aber erst mal probieren, dann sieht er dass es daran lag und
> ist glücklich.
> Wenn er weiß woran es liegt kann er an der Stelle ansetzen und seinen
> Code weiter optimieren. Also Puffer verkleinern, Übertragungsrate so
> weit senken wie möglich.

Und vor allen Dingen: überlegen in wie weit ein hohes Volumen sinnvoll 
ist.

Wenn die Daten letztendlich nur dazu dienen, einen menschlichen 
Beobachter zu informieren, reicht es völlig aus, wenn sich die Daten nur 
alle halbe Sekunde aktualisieren. Kein Mensch kann die Daten schneller 
mental verarbeiten.
Wenn an der anderen Seite natürlich ein weiterverarbeitendes Programm 
sitzt, kann das anderes aussehen.

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.