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
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.
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:
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
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.
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
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.