Hallo,
ich sitze hier vor einem kleinen Problem, das ich nicht in den Griff
bekomme.
Ich will mit einem Atmega644P-20PU einen String auswerten, den ich vom
Rechner über den UART zum µC geschickt habe. Hier bei stellen die ersten
6 Zeichen die Adresse des Boards dar.
Der String sieht z.B. wie folgt aus:
ABCDEF,GHIJKL,010\r
ABCDEF: Adresse des Boards/Empfängers (es sollen einmal mehrere Boards
verwendet werden
GHIJKL: Adresse des Senders
010: 3Bit zur Übertragung von Informationen
\r: Abschlusszeichen
Nachdem ich den String eingelesen habe (Code aus UART-Tutorial,
Interruptbetrieb), extrahiere ich die ersten 6 Zeichen und vergleiche
Sie mit der Boardadresse. Stimmt diese über ein, werte ich die
3-Informationsbits aus. Allerdings kommt es bei gefühlten 50% der
Übertragungen dazu, dass die Informationsbits nicht ausgelesen werden,
obwohl er das eigentlich machen sollte.
Hier der Code aus meiner main.c:
Hi chris (Gast),
Das Problem wird sein das Deine Informationsbits vom UART als ASCII
empfangen werden, und somit Steuerzeichen darstellen koennen die Deinen
String oder Deine Stringverarbeitungsroutine durcheinender bringen
koennen.
Desweiteren koennen auch dieses Informationsbits ein \r oder ein : sein.
Somit verschluckt sich Deine Stringverarbeitungsroutine, weil sie diese
Zeichen als Delimiter interpretiert.
Ju
Dass sich die Routine verschlucken könnte ist mir klar, aber warum soll
sie das tun, wenn ich die Daten korrekt übertrage? Dann sollte die
Routine doch in der Lage sein diese auch korrekt auszuwerten.
Welche Alternativen gibt es noch die Daten zu übertragen?
Mit der ASCII-Version könnte man einfach mit einem einfachen
Terminalprogramm "zuhören".
1) Dein Hauptprogramm ist nicht optimal.
Du kopierst u.U. zu lange an dem String rum. Das Kopieren muss entweder
fixer gehen, damit die ISR(USART0_RX_vect) den Eingangspuffer möglichst
schnell wieder verwenden kann. Nicht Häppchenweise kopieren,
Stringvergleiche machen und dann wieder ein Häppchen... und
währenddessen schmeisst die ISR fröhlich Zeichen weg!
Als Alternative zum Kopieren (rx_adresse <= uart_string) kannst du mit
zwei Puffern arbeiten und jeweils nur umschalten. Das erspart die
Umkopieraktion.
2) Du könntest die Länge des Eingabepuffers haben und nur dann auf die
Bitwerte prüfen, wenn die Länge das auch zu lässt. Im Moment könnte es
passieren, dass du auf veraltete Bitwerte aus vorangehenden Telegrammen
zugreifst. Die werden ja im Eingangspuffer nie ausgenullt.
3) Du bewegst dich in der ISR am Abgrund eines Bufferoverflows falls dir
'\r' verloren gehen...
Ich hab gerade gemerkt, dass die beiden 22pF-Kondensatoren am Quarz
fehlen. Der der das Board aufgebaut hat hat die wohl vergessen.
Nun wollte ich mal schauen, ob die Taktfrequenz in der richtigen
Größenordnung liegt. Mit dem folgenden Code erzeuge ich ein
Rechtecksignal, das ich ausmessen kann.
1
intmain(void)
2
{
3
init();
4
while(1)
5
{
6
PORTA^=_BV(PA0);
7
}
8
return0;
9
};
Mein Quarz hat 18.432MHz. Leider kann ich nicht abschätzen, wieviel
Zyklen benötigt werden, bis dieser Code ausgeführt ist.
Gemessen habe ich aktuell eine Frequenz von rund 1,84MHz. Passt das oder
ist das zu wenig?
Danke
Juergen G. schrieb:> Das Problem wird sein das Deine Informationsbits vom UART als ASCII> empfangen werden, und somit Steuerzeichen darstellen koennen die Deinen> String oder Deine Stringverarbeitungsroutine durcheinender bringen> koennen.
Genau das ja nun gerade nicht!
Denn in ASCII ist sehr gut definiert, dass Ziffern und Zeichen sich
nicht mit Steuercodes (und schon gar nicht mit der 0) überlappen...
chris schrieb:> Gemessen habe ich aktuell eine Frequenz von rund 1,84MHz.
Warum misst du nicht die Quarzfrequenz direkt?
Ich würds so machen, und schauen, ob 1 sec rauskommt:
Und wenn dann feststeht, dass die Taktfrequenz korrket ist, würde ich
eine der nächst wichtigen Regeln bei der Entwicklung von Programmen mit
Dtaenübertragung beherzigen. Die da lautet:
Sieh zu, dass du dir irgendwo den empfangenen String ausgeben lassen
kannst.
Im einfachsten Fall schick den String einfach an den Sender zurück (aber
pass auf, dass der Sender dir den Datenkanal nicht zumüllt). Wenn man
während der Entwicklungszeit eines Programms die Ansteuerung erst mal
nicht von einem anderen Programm aus macht sondern von einem Terminal
aus,dann ist das auch überhaupt kein Problem
1
while(1)
2
{
3
input_lesen();
4
5
6
if(uart_str_complete==1)
7
{
8
send_string(uart_string);
9
10
for(inti=0;i<6;i++)
und schon schreibt einem der µC nach dem Drücken von Return direkt auf
den Bildschirm, was er verstanden hat. Und dann hat dann auch das
Rätselraten ein Ende, ob man ein Problem in der Übertragung oder in der
Auswertung hat.
Hi chris,
1.
in der Interruptroutine prüfst Du nicht, ob der Datenpuffer nicht mit
mehr als UART_MAXSTRLEN - Bytes beschrieben wird.
Wenn - warum auch immer - mehr Datenbytes empfangen werden und kein
Return erkannt wird, dann kannst Du nicht ausschließen, ob andere
Variablen, die für die übrige Programmkontrolle wichtig wären,
überschrieben werden. Hinweis: In die map-datei schauen, ob das sein
kann. Wenn nicht vorhanden, dann mit erzeugen lassen.
2.
Warum kopierst Du die ersten 6 Bytes in einen andere Stringvariable?
Du kannst doch auch die strncmp()-Funktions verwenden. Die überprüft
eben nur n-Bytes.
Versuche doch mal
entfernen-> for(int i=0;i<6;i++)
entfernen-> rx_adresse[i] = uart_string[i];
entfernen-> rx_adresse[6]='\0';
if(strncmp(uart_string[[0],"ABCDEF",6)==0)
Jetzt würde ich strncmp ab der Adresse uart_string[[0] für die Länge von
6 Bytes mit dem String "ABCDEF" vergleichen. Stringterminierung wie \0
spielt da keine Rolle.
Hinweis: Ich weiß nicht wie groß Dein Programm irgendwann einmal wird.
Aber die str-Funktionen kosten doppelt RAM. Ich habe mir angewöhnt die
Konstante Strings in den Flash zu legen und von dort auch zu
vergleichen. Beim AVR ist das leider anders (Programmflash-Lib
inkludieren). Man muß das mit der strncmp_P()-Funktion machen. Mit const
bekommt man nicht das gewünschte Ergebnis. Mag vielleicht jetzt noch
nicht stören...
3.
Mit cli() kannst Du den allgemeinen Interrupt sperren und mit sei()
wieder zulassen. Nur für den Fall das die Kopiererei eine Art double
buffering werden sollte, unterstelle ich hier mal, dass Deine
UART-Geschwindigkeit wohl 115kBaud nicht überschreitet. Wenn als Dein
Stringende erkannt wird, ist Dein mega644 mit seinen möglichen 20 MHz
schneller am überprüfen, als der nächst Buchstabe eintrift.
Ansonsten solltest Du über Semaphoren nachdenken.
Es macht ja keinen Sinn pausenlos mit Nachrichten zugebommt zu werden,
ohne sie gescheit ausgewertet zu haben oder eine Rückmeldung an den PC
zu senden. Oder?
4. Ringspeicher
Vielleicht solltest Du über die Verwendung eines RIngspeichers
nachdenken. Ich meine damit so eine Art Software FiFo. Meist will man ja
mehr. Irgendwann...
Ich hoffe, dass hier etwas für Dich dabei war.
Viel Erfolg