Hallo,
ich will eine Variablenfolge die z.B so aussieht 99|33|01|01 über die
serielle Schnittstelle zum Mikrocontroller schicken und im Mikro dann
das Empfangene auf Gleichheit vergleichen.
Im Moment mache ich das so:
1
charReceiveSerial[40];
2
charLr99110101[]="99|11|01|01";
3
4
// Zeichen Empfangen wenn was anliegt
5
if((UCSR0A&(1<<RXC0)))
6
{
7
8
uart_gets(ReceiveSerial,sizeof(ReceiveSerial));
9
10
USART_Transmit();// Kontrolle zum Terminalprogramm
11
12
13
if(!strcmp(ReceiveSerial,Lr99110101))
14
{
15
16
stopbit=false;
17
}
18
19
}
Das ist das uart_gets()
1
/*String empfangen*/
2
voiduart_gets(char*Buffer,uint8_tMaxLen)
3
{
4
uint8_tNextChar;
5
uint8_tStringLen=0;
6
7
NextChar=uart_getc();// Warte auf und empfange das nächste Zeichen
8
9
// Sammle solange Zeichen, bis:
10
// * entweder das String Ende Zeichen '\0'kam
11
// * oder das aufnehmende Array voll ist
12
while(NextChar!='\r'&&StringLen<MaxLen-1){
13
*Buffer++=NextChar;
14
StringLen++;
15
NextChar=uart_getc();
16
}
17
// Noch ein '\0' anhängen um einen Standard
18
// C-String daraus zu machen
19
*Buffer='\0';
20
}
Funktionieren tut das, doch merke ich das die uart_gets() unglaublich
viel Zeit beansprucht, da andere Funktionen ins stocken geraten.
Wie könnte ich denn auch eleganter dieses char Array auf Gleichheit
abfragen ohne eine Funktion zu benutzen die das mit eine Stringfunktion
macht?
Vielen Dank für die Tips....
1.) UART Receive Interrupt verwenden
ODER
2.) while-schleife abbrechen, wenn z.B. 10ms kein Zeichen gekommen ist.
Wenn allerdings ein Zeichen kommt, dann alle einlesen, bis '\r'. Sonst
wartest du bis auf den St.Nimmerleinstag auf deinen String
Hallo Markus,
Deine Empfangsfunktion bringt wahrscheinlich deshalb den Rest ins
Stocken, weil es je nach Baudrate, Sendegeschwindigkeit/-frequenz der
Gegenseite und Länge der Nachricht ein paar Millisekunden oder länger
dauern kann, bis die Nachricht gelesen wurde.
Die Abhilfe geht in die Richtung, die Daniel geschrieben hat. Falls das
nicht möglich ist, müßtest Du während des Empfangens hin und wieder eine
Funktion aufrufen, die die anderen gewünschten Funktionen ausführt, so
eine Art Miniatur-Scheduler.
Zum Stringvergleich:
In diesem Fall ist der in Ordnung, anders geht es auch nicht schneller.
Wenn Du mit mehreren anderen Strings vergleichen willst, dann solltest
Du Dir einen Zustandsautomaten schreiben, der mit jedem Zeichen
weitergesetzt wird oder Dich mal mit String-Matching-Algorithmen
beschäftigen
(http://en.wikipedia.org/wiki/Category:Algorithms_on_strings,
http://de.wikipedia.org/wiki/String-Matching-Algorithmus).
Danke schonmal.
Kann mir vielleicht einer ein Tipp geben und zwar will ich diese
Variable:
1
charCodetest2[]={'29','34','41','52'};
per RS232 ohne eine String Funktion übertragen. Also einfach nur per
Zahl. Wie ist da der beste Weg? Ich habe folgende Funktionen zur
Verfügung (s. Unten), gerne nehme ich dann auch noch Beispiele entgegen.
DAs Problem welches ich einfach habe ist das ein char nur 1 Zeichen sein
darf, also bei der erste Ziffer mit 29 würde mit der usart_write_char
Funktion nur eine 9 übertragen.
Wie stelle ich das am besten an das nachher "29344152" auf meinem
Terminal steht?
Vielen Dank.
Matthias H. schrieb:> Hallo Markus,>> Deine Empfangsfunktion bringt wahrscheinlich deshalb den Rest ins> Stocken, weil es je nach Baudrate, Sendegeschwindigkeit/-frequenz der> Gegenseite und Länge der Nachricht ein paar Millisekunden oder länger> dauern kann, bis die Nachricht gelesen wurde.> Die Abhilfe geht in die Richtung, die Daniel geschrieben hat. Falls das> nicht möglich ist, müßtest Du während des Empfangens hin und wieder eine> Funktion aufrufen, die die anderen gewünschten Funktionen ausführt, so> eine Art Miniatur-Scheduler.>
Ich merke es auch beim Empfangen, also da passiert auch irgendetwas
zeitkritisches...
Hallo Markus,
> Ich merke es auch beim Empfangen, also da passiert auch irgendetwas> zeitkritisches...
Das kannst Du ausrechnen. Nehmen wir an, Du benutzt eine Baudrate von
9600 und die Einstellungen 8N1 (8 Bits, keine Parität, 1 Stoppbit). Dann
werden pro Zeichen 9 Bits plus Startbit übertragen, also max. 960
Zeichen pro Sekunde. Deine Nachricht ist anscheinend 12 Zeichen lang.
Also dauert die Übertragung mindestens 1/80 Sekunde, also 12,5 ms. Falls
Dein Sender langsamer sendet, mit Pausen zwischen den Zeichen, oder
Deine Empfangsfunktion aus irgendeinem Grund noch viel Rechenleistung
verbrät, dann dauert es entsprechend länger.
Markus P. schrieb:> Danke schonmal.>> Kann mir vielleicht einer ein Tipp geben und zwar will ich diese> Variable:>>
1
>charCodetest2[]={'29','34','41','52'};
2
>
>>> per RS232 ohne eine String Funktion übertragen. Also einfach nur per> Zahl. Wie ist da der beste Weg? Ich habe folgende Funktionen zur> Verfügung (s. Unten), gerne nehme ich dann auch noch Beispiele entgegen.> DAs Problem welches ich einfach habe ist das ein char nur 1 Zeichen sein> darf, also bei der erste Ziffer mit 29 würde mit der usart_write_char> Funktion nur eine 9 übertragen.> Wie stelle ich das am besten an das nachher "29344152" auf meinem> Terminal steht?
Indem du damit anfängst erst mal das Array richtig zu definieren und zu
initialisieren.
1
uint8_tCodetest2[]={29,34,41,52};
Du willst Zahlen speichern. Also ist schon mal char kein geeigneter
Datentyp dafür. Gewöhn dir an, char ausschliesslich für echte Zeichen
(also 'A', 'B', 'C'...) bzw. in Arrayform für Strings ("Hallo") zu
benutzen.
und dann schreibst du dir eine Funktion, die eine Zahl ausgeben kann.
1
voidusart_write_uint8(uint8_tnr)
2
{
3
charbuffer[6];
4
5
itoa(nr,buffer,10);
6
usart_write_str(buffer);
7
}
mit dieser Hilfsfunktion schreibst du dir eine weitere Funktion, die ein
Array von Zahlen ausgeben kann
Das Geheimnis beim Programmieren besteht nicht darin, sich für jeden
Pfurz immer wieder möglichst komplizierte neue Funktionen einfallen zu
lassen. Das Geheimnis besteht darin, sich mit Basisfunktionen und darauf
aufbauenden Hilfsfunktionen letztendlich bis zu der Ebene
hochzuarbeiten, mit der man sein Problem lösen kann.
> char Codetest2[] = {'29','34','41','52'};
Das funktioniert so natürlich nicht, falls es überhaupt durch den
Compiler geht.
Du hast im wesentlichen folgende Möglichkeiten, falls Du nicht was
völlig eigenes basteln möchtest:
- Du überträgst zeichenweise (+ Nullbyte o. ä. als Endemarkierung). Da
braucht man dann nichts umzucodieren.
1
charCodetest2[]="29344152";
- Du überträgst zeichenweise binär. Dann mußt Du irgendein Zeichen außer
der 0 als Endezeichen festlegen. Ist aber ineffizient.
- Du überträgst in BCD-Codierung
(http://de.wikipedia.org/wiki/BCD-Code) binär. Dabei werden 2 Ziffern in
ein Byte gepackt, was effizienter ist als zeichenweiser Versand.
BCD geht ungefähr so (mit ungültiger Ziffer als Endemarkierung):
1
charCodetest2[]={0x29,0x34,0x41,0x52,0xf0};
- Du überträgst binär. Dann mußt Du festlegen, welchen Datentyp Du
verwenden möchtest, z. B. 4-Byte-Integer mit Vorzeichen, und mußt auf
die Byte Order achten, also in welcher Reihenfolge der Prozessor die
einzelnen Datenbytes, die die Variable bilden, im Speicher anordnet. Es
ist Network Byte Order = "Big Endian" empfehlenswert. Siehe Funktionen
htonl()/ntohl() usw. der Standardbibliothek, soweit vorhanden.
- Wenn Du kompliziertere Datenstrukturen übertragen möchtest, so wäre es
eine Überlegung wert, sich mal Google Protocol Buffers oder andere
Standardverfahren anzusehen (wobei Protocol Buffers wahrscheinlich zu
groß für Deinen Mikrocontroller ist...).
Vielen Dank Karl-Heinz du hast mir sehr weiter geholfen!!!!
Mein Problem wird nur auch noch das sein was der Matthias mir schon sehr
gut vorgerechnet hat. Ich betreibe auf den gleichen yc auch noch einen
Phasenanschnitt und da muss ich alle paar ms einen Triac ansteuern, da
kann ich mir keinen Zeitverlust gönnen. Jetzt weiß ich garnicht wie ich
das machen kann ohne den Phasenanschnitt zu beeinflussen ? Hättest du
(ihr) da auch vielleicht eine Idee ?
Vielen super dank schonmal ...
Hallo Markus,
Markus P. schrieb:> Mein Problem wird nur auch noch das sein was der Matthias mir schon sehr> gut vorgerechnet hat. Ich betreibe auf den gleichen yc auch noch einen> Phasenanschnitt und da muss ich alle paar ms einen Triac ansteuern, da> kann ich mir keinen Zeitverlust gönnen. Jetzt weiß ich garnicht wie ich> das machen kann ohne den Phasenanschnitt zu beeinflussen ? Hättest du> (ihr) da auch vielleicht eine Idee ?
Du mußt Dir überlegen, in welchem Zeitraster Du den Triac bedienen mußt,
damit er funktioniert, wie Du willst und wieviel Zeit Dir zum Lesen der
Nachricht übrig bleibt.
Falls die Funktion uart_getc() blockierend liest, mußt Du eine andere
Möglichkeit finden.
Daniel V. hat ja dazu schon Anregungen geschrieben.
Interruptbetrieb heißt, daß der Schnittstellenbaustein einen
Hardware-Interrupt auslöst, sobald ein Zeichen ankommt und dann eine
Funktion aufgerufen wird, die das Zeichen z. B. in einen Buffer (am
besten eine globale Variable) liest. Die Interruptfunktion sollte so
wenig wie möglich machen, das heißt, das Prüfen, ob eine Nachricht
vollständig gelesen wurde und die Verarbeitung sollten außerhalb des
Interrupthandlers in der Hauptschleife gemacht werden. Es könnte noch
weitere Nebenbedingungen geben, z. B. daß Funktionen der
Standardbibliothek nicht aufgerufen werden dürfen oder so. Ob das von
Deinem Mikrocontroller unterstützt wird und wie es geht, sollte in der
Dokumentation stehen. Dazu sind noch ein paar Kleinigkeiten zu beachten,
z. B. sollten die Interrupts abgeschaltet werden, während der Puffer in
der Hauptschleife geleert wird, sonst gibt es undefiniertes Verhalten
und Fehler.
Beim Lesen mit Timeout brauchst Du eine nichtblockierende Lesefunktion
für die Schnittstelle und liest so lange, bis ein Timer zuende ist, z.
B. 10 ms, oder die Nachricht komplett ist.
>> Hey, dein Kommentar und dein Code passen nicht zusammen.> Das ist kein oder_ sondern ein _und.
Aber es ist eine while-Abfrage. Er soll solange drin bleiben, wie BEIDE
(also UND) Bedingungen erfüllt sind. Ist die eine ODER die andere
Bedingung nicht mehr erfüllt, dann wird die Schleife beendet.