habe folgendes problem. habe für den uart ein protokoll geschrieben das kommandos entgegennimmt und dann wieder zurücksendet. dieses tut auch soweit. nun bin ich auf folgendes problem gestoßen: wenn ich versorgungsspannung wegnehme und nach ner zeit wieder anlege, kommt es manchmal vor, dass der tiny erst nach drücken von reset auf eine anfrage reagiert. soweit ich weiß, sollte aber der tiny nach dem einschalten von haus aus einen reset durchführen. tiny deffekt ? braucht das init() eine mindestwartezeit bevor dieser benutzt werden kann ? hat jemand eine erklärung dafür ?
:
Bearbeitet durch User
Warum hältst du dich nicht an die Netiquette und beachtest z. B. die Groß-/Kleinschreibung?
Hi Wie sehen die Einstellungen für Takt und SUT (Fuses) aus? MfG Spess
getaktet wird er mit einem externen Quatz mit 16MHz F_CPU = 16000000 die fuses sehen im makefile so aus: AVRDUDE_WRITE_LFUSE = -U lfuse:w:0xef:m AVRDUDE_WRITE_HFUSE = -U hfuse:w:0xdf:m AVRDUDE_WRITE_EFUSE = -U efuse:w:0xff:m
Roland Höck schrieb: > hat jemand eine erklärung dafür ? Zeig mal dein Programm. Du musst immer bedenken, dass eine UART Übertragung eine Abfolge von Zuständen auf diversen Leitungen ist. Diese Leitungen haben aber nach dem Anlegen der Spannung aber schon Pegel, noch ehe die entsprechende Hardware dafür konfiguriert wurde. D.h. nach dem Einschalten kann es schon mal sein, dass irgendeine Hardware zb einen Fehlerzustand meldet, der nur daraus resultiert, dass die Hardware schon auf die Pegel an den Leitungen angesprochen hat obwohl du das noch gar nicht wolltest. Bei Interruptpins ist das zb genau dasselbe. Wenn dein Programm sich jetzt aber nicht mehr von alleine aus einem derartigen Fehlerzustand rausmanövrieren kann, dann sieht es so aus, als ob alles hängt. Daher: wie sieht das Programm aus.
Woher kommen die Kommandos? Sendet der Sender bereits, wenn du den Tiny einschaltest? Das hier
1 | int8_t befehl_speichern(uint8_t *Data_Array) |
2 | {
|
3 | uint8_t Zaehler = 0; |
4 | uint8_t UART_block = 0; |
5 | uint8_t buffer = 0; |
6 | Data_Array[2]=0; |
7 | |
8 | for(int i = 0;i<=9;i++) |
9 | {
|
10 | Data_Array[i]=0; |
11 | }
|
12 | |
13 | while((Zaehler < (Data_Array[2])+4)) // solange noch nicht letzter Block |
14 | {
|
15 | UART_block = rx_block(); // rx_block -> UART_Block holen |
16 | if(UART_block & FS) // wenn FS == 1 |
17 | {
|
18 | Zaehler = 1; |
19 | Data_Array[Zaehler-1] = UART_block; // Ziel ID in Data_Array[Zähler-1] speichern |
20 | }
|
21 | else // wenn FS == 0 |
22 | {
|
23 | if(Zaehler == 2) |
24 | {
|
25 | buffer = UART_block; // Type in Data_Array[Zähler-1] speichern |
26 | buffer >>= 3; // um 3 nach rechts schieben -> type steht jetzt ganz rechts |
27 | Data_Array[Zaehler-1]= buffer; |
28 | Zaehler++; |
29 | UART_block &= 0x07; // length in Data_Array[Zähler-1] speichern |
30 | Data_Array[Zaehler-1] = UART_block; |
31 | }
|
32 | else
|
33 | {
|
34 | Data_Array[Zaehler-1] = UART_block; // Data(Z-3) in Data_Array[Zähler-1] speichern |
35 | }
|
36 | }
|
37 | Zaehler++; |
38 | }
|
39 | |
40 | Zaehler = 0; // while Ende |
41 | return 0; |
42 | }
|
ist potentiell gefährlich. Nachdem ich die Einrückungen korrigiert habe, sieht man recht gut, dass es für den Fall, dass der Sender bereits fleissig am Senden ist, durchaus den Fall gibt, dass das erste empfangene Zeichen eben kein gesetztes FS haben kann und dass du dann Gefahr läufst, ober den Weg
1 | if(UART_block & FS) // wenn FS == 1 |
2 | {
|
3 | }
|
4 | else // wenn FS == 0 |
5 | {
|
6 | if(Zaehler == 2) |
7 | {
|
8 | }
|
9 | else
|
10 | {
|
11 | Data_Array[Zaehler-1] = UART_block; // Data(Z-3) in Data_Array[Zähler-1] speichern |
12 | }
|
13 | }
|
14 | Zaehler++; |
ganz einfach dein Array zu überlaufen. Wie ist das Protokoll aufgebaut? IMHO ist das nicht so gut implementiert. Wenn es eine dezidierte Start-Kennung gibt, die auch sicher erkannt werden kann, dann fängt eine Auswertung besser damit an, dass man erst mal genau auf diese Startkennung wartet und alle anderen Bytes verwirft. Erst dann, nachdem die Startkennung erhalten wurde, beginnt man damit diverse Buffer mit den Zeichen zu füllen.
1 | .....
|
2 | |
3 | // auf die Startkennung warten
|
4 | do
|
5 | {
|
6 | c = rx_block(); |
7 | } while( !( c & FS ) ); |
8 | Data_Array[0] = c; |
9 | |
10 | // das erste Byte ist da, das nächste Byte ist die Länge
|
11 | Len = rx_block(); |
12 | Data_Array[1] = Len; |
13 | |
14 | if( Len > 8 ) |
15 | return Fehler; |
16 | |
17 | // jetzt diese Anzahl an Bytes einlesen
|
18 | for( i = 0; i < Len; i++ ) |
19 | Data_Array[i+2] = rx_block(); |
20 | ...
|
Voraussetzung ist, dass das hier
1 | .... c & FS .... |
absolut eindeutig ist, und in den Daten nicht vorkommen kann. Denn dann kann man den Anfang eines Datensatzes nicht mehr eindeutig erkennen und dann ist man in solchen Fällen sowieso in der Breduille. Mit etwas Glück kann einen vielleicht die dann mglw. fehlerhafte Länge aus dem Schlamassel rausholen, aber garantiert ist das nicht, und es lassen sich immer Fälle konstruieren, in der die ganze Übertragung hängt und auch nicht mehr von alleine auf die Füsse fällt.
:
Bearbeitet durch User
im prinzip soll ja wenn ein FS kommt das array neu befüllt werden. wo ist das nicht gut implementiert ? das protokoll ist folgendermaßen aufgebaut bit: 7 6 - 0 7 6 -3 2 - 0 7 6 - 0 FS | ID FS | Type | length FS | Data0 .... für den fall, dass die nachricht nicht komplett empfangen wird, wartet der tiny einfach. nach einer gewissen zeit, sendet dann der master die nachricht erneut, und es kommt wieder ein FS -> Zähler = 1 -> Array wird neu befüllt theoretisch wird zuerst der tiny eingeschaltet und dann gesendet. FS soll den Framestart signalisieren und nur im Block ID "1" ansonsten "0" sein
Roland Höck schrieb: > im prinzip soll ja wenn ein FS kommt das array neu befüllt werden. > wo ist das nicht gut implementiert ? Wenn dir eine Startkennung, aus welchem Grund auch immer, verloren geht, kann es dir passieren, dass du dir das Array und den nachfolgenden Speicher mit Bytes flutest. Siehe den Alternativcode, der dieses Problem nicht hat. Wenn dort eine Startkennung verloren geht, dann wird alles weitere was reinkommt bis zur nächsten korrekt erkannten Startkennung verworfen.
:
Bearbeitet durch User
Roland Höck schrieb: > FS soll den Framestart signalisieren und nur im Block ID "1" ansonsten > "0" sein Das war nicht die Frage. Die Frage lautet: kann diese Bitkombination auch in den Datenbytes vorkommen? Denn wenn es das kann, dann kannst du dir das FS-Bit auch gleich in die Haare schmieren. Es ist zu nichts nütze.
ah ok jetz versteh ich schon was du meinst. natürlich soll es auch von mir aus so sein, das er bis zum nächsten FS alles verwirft und dann erst anfängt. hab jetz die Zeile UART_block = rx_block() durch do { UART_block = rx_block(); while( !( UART_block & FS ) ); ersetzt und werde das nachher testen und hoffen das es damit erledigt ist und das Protokoll ist so gebaut, dass das vorderste bit immer für FS da ist. und wird auch für nichts anderes benutzt. also stehen mir für daten,... jeweils 7 bit zur verfügung. FS = 1 taucht wirklich nur am anfang der Nachricht auf
:
Bearbeitet durch User
Im Zweifelsfall: Wenn möglich, sieh zu, dass du den Rückkanal der UART dazu benutzen kannst, da Statusmeldungen auszugeben. Dann kannst du die Empfangsroutine soweit pimpen, dass du über die Rückmeldungen nachvollziehen kannst, was der Tiny eigentlich kriegt und wie er es auswertet.
Roland Höck schrieb: > ist. und wird auch für nichts anderes benutzt. also stehen mir für > daten,... jeweils 7 bit zur verfügung. FS = 1 taucht wirklich nur am > anfang der Nachricht auf Sehr gut! Da hast du den Fuss in der Tür, wie du empfangene Bytes auf jeden Fall auf den Recordanfang synchronisieren kannst (solange es keinen Übertragungsfehler gibt, aber lass uns jetzt mal nicht den Teufel an die Wand malen).
:
Bearbeitet durch User
genau den sinn hatte ja FS (Framestart) ja am anfang. habs soweit vorher ja schon getestet, er hat die nachrichten auch immer zuverlässig interpretiert und geantwortet.
:
Bearbeitet durch User
Vergiss auch nicht auf eine Plausibilitätsprüfung für die Länge. Geh immer vom schlimmsten Fall aus: Irgendwas ist grauslich schief gegangen und deine Empfangsroutine fängt an, Bytes die eigentlich Datenbytes sind mit den Steuerinfortmationen zu verwechseln. Was auf keinen Fall passieren darf: das dein Programm der Meinung ist, da müssten jetztz 58 Bytes daher kommen, weil es durch den Fehler ein Byte mit dem Wert 58 kriegt, wenn es eigentlich die Länge erwartet. Denn in dem Fall bügelst du dir dann dein Array, bzw. den dahinterliegenden Speicher über den Haufen. Und ab da werden dann keine Wetten mehr angenommen, was da alles passiert. Eine robuste Empfangsroutine (bzw. Protokoll) überlebt es auch, wenn man mitten im Betrieb das Kabel rauszieht und wieder einsteckt. D.h. eine robuste Empfangsroutine kann sich auch mitten in eine bereits laufende Übertragung einklinken und kommt nicht durcheinander.
:
Bearbeitet durch User
das protokoll war vorher eigentlich sauber geplant, und es wurden auch gewisse fehlersituationen berücksichtigt. habe genau das gleich protokoll wie in meinem pap geplant jetzt auf der neuen grundlage gebaut also mit warten auf FS und siehe da. es is auch noch ein effizienterer code raus gekommen ohne viele if abfragen und soweit ich das bisher sagen kann scheint der gut zu funktionieren. parität wird ja übrigends in der folgeroutine überprüft und aussortiert die länge ist ja eigentlich bei mir immer plausibel, da ich vom 2. block die letzten 3 bit dafür her nehme, als maximal 7 sein kann
1 | do // warten bis FS |
2 | {
|
3 | UART_block = rx_block(); |
4 | }while( !( UART_block & FS ) ); |
5 | Zaehler = 1; |
6 | Data_Array[Zaehler-1] = UART_block; |
7 | Zaehler++; |
8 | UART_block = rx_block(); |
9 | buffer = UART_block; // Type in Data_Array[Zähler-1] speichern |
10 | buffer >>= 3; // um 3 nach rechts schieben |
11 | Data_Array[Zaehler-1]= buffer; |
12 | Zaehler++; |
13 | UART_block &= 0x07; // length in Data_Array[Zähler-1] speichern |
14 | Data_Array[Zaehler-1] = UART_block; |
15 | Zaehler++; |
16 | while((Zaehler < (Data_Array[2])+4)) |
17 | {
|
18 | UART_block = rx_block(); |
19 | Data_Array[Zaehler-1] = UART_block; |
20 | Zaehler++; |
21 | }
|
:
Bearbeitet durch User
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.