Forum: Mikrocontroller und Digitale Elektronik Abgeschlossenen Regelvorgang an PC melden


von Marvin N. (marvin_n804)


Angehängte Dateien:

Lesenswert?

Hallo,

für eine Positionierungsaufgabe habe ich den Code im Angang geschrieben 
(mit Hilfe von vorherigen Threads hier).

Was funktioniert:
Über UART können Kommandos an den AVR gesendet werden, welcher dann den 
Motor entsprechend positioniert:
a1000: fährt Position 1000 an
r500:  fährt +500 zur aktuellen Position
s10: setzt den Schwellenwert für die Zweipunktregelung
f50: setzt das OSC Register

Was nicht funktioniert:
Am angeschlossenen PC muss ich wissen, ob der Motor noch fährt, um zu 
bestimmen, ob bereits eine neue Position angefahren werden kann.
Dazu soll nach erfolgreicher Positionierung ein 'ACK' oder ähnliches 
gesendet werden.
Die Hauptschleife in der main kann ich nicht verwenden, da diese auf 
eingehende UART-Zeichen wartet.
Würde noch die Timer-ISR der Regelung bleiben. Bisher scheiterten alle 
Versuche daran, dass die Regelung versagte, oder keine eingehenden 
Zeichen mehr angenommen wurden.
1
ISR(TIMER0_COMP_vect)
2
{
3
    diff=soll-count;
4
    if(flag==1 && diff>s)
5
    {
6
      motorRight();
7
    }
8
    else if (flag==1 && diff<(-s))
9
    {
10
      motorLeft();
11
    }
12
    else if(flag==1)
13
    {
14
      motorBreak();
15
///////////
16
      uart_puts("+\n\r");
17
//////////
18
    }
19
    else
20
    {
21
      count=0;
22
      soll=0;
23
    }
24
}
Dies war zum Beispiel nicht erfolgreich.

UART-Bibliothek ist von Peter Fleury.

Ich wäre für Ideen dankbar.

mfg
Marvin

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Eines deiner Problem ist das blockende Lesen von der UART. Die meiste 
Zeit hängt der MC ja in der Zeile, in der auf eingehende Zeichen 
gewartet wird und tut sonst nichts.
Mein Vorschlag wäre, zuerst mal die UART Routine darauf umzuschreiben, 
das sie zurückkehrt, wenn eben kein Zeichen da ist. Das Zusammenbasteln 
des Commandstrings kannst du ja trotzdem so lassen, wenn du z.B. ein CR 
als Zeichen dafür nimmst, das eine Eingabe komplett ist.

Zusätzlich kannst du dir ein paar Flags definieren, die den Zustand des 
Antriebes reflektieren und in der Timer ISR aktualisieren. Wenn das Ziel 
erreicht ist, wird ein Flag gesetzt, um dem PC das + zu schicken, sobald 
das geschehen ist, wird das Flag gelöscht.
Die Abfrage dieses Flags kannst du z.B. in main() machen.

von Marvin N. (marvin_n804)


Lesenswert?

Danke für die hilfreiche Antwort.

Ich habe jetzt ein Flag, welches anzeigt, ob der Motor in Bewegung ist. 
Dieses kann ich auch problemlos mittels uart ABFRAGEN.
1
case 'h':
2
        if(done==1)uart_puts("+\n\r");
3
        else uart_puts("*\n\r");
4
        break;

Es aktiv an den PC ohne vorherige Anforderung zu senden funktioniert 
noch nicht. Das Problem ist, wie schon festgestellt, die blockierende 
UART-Übertragung.

Ich hab (erfolglos) versucht, durch Abbrechen der Warteschleife das 
Problem zu lösen:
1
uint8_t uart_getc_wait()
2
{
3
  unsigned int c;
4
        uint8_t counter=0;
5
  do {
6
    c = uart_getc();
7
                counter++;
8
  } while( c == UART_NO_DATA && counter<100);
9
10
  return (uint8_t)c;
11
}
Ist das der richtige Ansatz?

von Konzeptvorschlag (Gast)


Lesenswert?

Konzept-Vorschlag:

UART-Interrupt -> setzt Flag das Commando empfangen wurde

main()    1) prüft Empfangs-Flag und führt entsprechendes Commando
             in einer Extra-Funktion aus
          2) Extra-Funktion setzt Flag (oder über Rückgabewert)
             dass sie fertig ist
          3) ACK senden

von Marvin N. (marvin_n804)


Lesenswert?

Idee ist für mich soweit nachvollziehbar.
Problem ist ja, dass ich die fertige Fleury-UART-Bibliothek verwende.
Es wäre also gut, wenn ich mit der vorhandenen Funktion uart_getc() 
auskommen würde. Ich würde gerne nur uart_getc_wait(), uart_gets() und 
meine main() modifizieren.

Ich hätte eigentlich gerne in die Hauptschleife eine Funktion, wie 
uart_dataAvailable(), die prüft, ob ein Zeichen da ist. Wenn ja, wird 
dies an den aktuellen Puffer angehangen, wenn der voll ist, oder der 
String zuende ist, soll das entsprechende Kommando ausgeführt werden. 
Dann würde die Hauptschleife nicht blockieren und ich könnte abhängig 
von dem Regelungs-Flag ein '+' senden.

von oldmax (Gast)


Lesenswert?

Hi

Marvin N. schrieb:
> Die Hauptschleife in der main kann ich nicht verwenden, da diese auf
> eingehende UART-Zeichen wartet.

Ich denke, das ist prinzipiell ein falscher Ansatz. Da du ( der µC) den 
Zeitpunkt eingehender Zeichen nicht kennst, musst du pollen oder noch 
besser einen Interrupt anwenden. Pollen geht, wenn der Programmzyklus 
klein genug ist, so das ein eingetroffenes Zeichen erfasst ist, bevor es 
durch nachfolgende überschrieben wird. Allerdings ist diese 
Vorgehensweise nicht 100%tig. Besser ist es, einen Ringpuffer zu bauen. 
Ein ankommendes Zeichen wird in der Interruptroutine (ISR) in den 
Ringpuffer geschrieben. Wohin sagt ein Schreibzeiger der dann 
weitergestellt wird. Im Programm prüfst du bei jedem Zyklus, ob 
Schreibzeiger und ein Lesezeiger, der auch auf den Ringpuffer zeigt, 
gleich sind. Ist dies nicht der Fall, ist ein neues Zeichen eingetroffen 
und du übergibst dieses einem Arbeitspuffer. Anschließend führst du den 
Schreibzeiger nach. Dabei kannst du kontrolieren, ob alle Zeichen 
eingetroffen sind und dann deine Aktion einleiten. Dieses Vorgehen 
belastet den Zyklus so gut wie nicht und du nutzt einfach die Zeit 
zwischen den einzelnen Bytes für weitere kleine Aufgaben. Da ich in 
Assembler programmiere und mit Hochsprachen auf den µC nicht viel am Hut 
hab, kann ich dir halt nur diese Vorgehensweise vorstellen und 
beschreiben. Umsetzen musst du sie selber. Nun ist es völlig egal, wann 
du ein "Ack" zurückschickst. Ein Zeichen verpassen ist Vergangenheit.
Ringpuffer: Ca. 10 - 20 Byte
Schreibzeiger: Basisadresse Ringpuffer + Schreibzeiger, beginnend mit 0
Lesezeiger:  Basisadresse Ringpuffer + Lesezeiger, beginnend mit 0
Beide Zeiger werden bei Überschreitung des Pufferbereiches wieder auf 0 
gesetzt und beginnen den Bereich von vorn zu adressieren.
Also Schreibvorgang:
Adresse = Basis + Schreibzeiger
Zeichen nach adressierter Speicherzelle
Schreibzeiger +1
Schreibzeiger > Puffer dann Schreibzeiger =0
fertig
Lsesvorgang:
Schreibzeiger = Lesezeiger dann fertig
Adresse = Basis + Lesezeiger
Inhalt adressierter Speicherzelle nach Arbeitspuffer
Lesezeiger + 1
Lesezeiger > puffer dann Lesezeiger =0
fertig
Arbeitspuffer:
alle Zeichen eingetroffen dann Auswertung
sonst fertig

Das beschreibt so grob die Funktionen einer Kommunikation über ser. 
Schnittstelle.
Gruß oldmax

von Marvin N. (marvin_n804)


Lesenswert?

oldmax schrieb:
> Besser ist es, einen Ringpuffer zu bauen.

Wenn ich richtig informiert bin, verwendet die Fleury-Bibliothek bereits 
einen Ringpuffer und mit Interrupts arbeitet sie sowieso.

Was ich erreichen möchte, sollte also unter Verwendung dieser möglich 
sein.

von Marvin N. (marvin_n804)


Angehängte Dateien:

Lesenswert?

Ich habe jetzt eine Lösung gefunden.
Ist die Idee soweit vernünftig, oder gibt es Verbesserungsvorschläge?

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.