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 ;)
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.
> 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.
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.
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.
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
1 | *
|
2 | * Sendet eine PC-Frame an die Windows Bedienoberfläche |
3 | *
|
4 | * Param: FC = Funktionscode für Geräteindex in Hex , siehe Protokoll Beschreibung |
5 | * value = Float Wert, der Gesendet werden soll |
6 | *
|
7 | */
|
8 | void KOM_sendInfo(unsigned char FC,float value) |
9 | {
|
10 | |
11 | fToSend.fDato = value; |
12 | |
13 | // Startbyte
|
14 | uart_putc(0x02); |
15 | // Funktionscode
|
16 | uart_putc(FC); |
17 | // Daten
|
18 | uart_putc(fToSend.byte.Drei); // Höchstes Byte |
19 | uart_putc(fToSend.byte.Zwei); |
20 | uart_putc(fToSend.byte.Eins); |
21 | uart_putc(fToSend.byte.Null); //Niedrigstes Byte |
22 | // Checksumme
|
23 | uart_putc(0xFF); |
24 | // Endbyte 1
|
25 | uart_putc(0x03); |
26 | // Endbyte 2
|
27 | uart_putc(0x00); |
28 | |
29 | // Kleine Pause, damit Windows zeit für die Datenauswertung hat, bevor
|
30 | // die Nächsten Daten geschickt werden. Ansonsten droht ein Empfangspuffer
|
31 | // Überlauf im Windows bei zu kleiner Wartezeit!
|
32 | |
33 | //zeit(WAITFORWINDOWS); // <------------ DER ÜBELTÄTER
|
34 | |
35 | |
36 | }
|
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
> 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.
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...
1 | /*************************************************************************
|
2 | Function: uart_putc()
|
3 | Purpose: write byte to ringbuffer for transmitting via UART
|
4 | Input: byte to be transmitted
|
5 | Returns: none
|
6 | **************************************************************************/
|
7 | void uart_putc(unsigned char data) |
8 | {
|
9 | unsigned char tmphead; |
10 | |
11 | |
12 | tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK; |
13 | |
14 | while ( tmphead == UART_TxTail ){ |
15 | ;/* wait for free space in buffer */ |
16 | }
|
17 | |
18 | UART_TxBuf[tmphead] = data; |
19 | UART_TxHead = tmphead; |
20 | |
21 | /* enable UDRE interrupt */
|
22 | UART0_CONTROL |= _BV(UART0_UDRIE); |
23 | |
24 | }/* uart_putc */ |
25 | |
26 | |
27 | |
28 | SIGNAL(UART0_TRANSMIT_INTERRUPT) |
29 | /*************************************************************************
|
30 | Function: UART Data Register Empty interrupt
|
31 | Purpose: called when the UART is ready to transmit the next byte
|
32 | **************************************************************************/
|
33 | {
|
34 | unsigned char tmptail; |
35 | |
36 | |
37 | if ( UART_TxHead != UART_TxTail) { |
38 | /* calculate and store new buffer index */
|
39 | tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK; |
40 | UART_TxTail = tmptail; |
41 | /* get one byte from buffer and write it to UART */
|
42 | UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */ |
43 | }else{ |
44 | /* tx buffer empty, disable UDRE interrupt */
|
45 | UART0_CONTROL &= ~_BV(UART0_UDRIE); |
46 | }
|
47 | }
|
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 ?
ja stimmt, wird schon so gemacht. Ich kannte den code von Peter Fleury nicht.
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.
@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.
> 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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.