Forum: Mikrocontroller und Digitale Elektronik tiny4313 uart sendet erst nach reset


von Roland H. (blacksmoke85)


Lesenswert?

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
von Brat (Gast)


Lesenswert?

Warum hältst du dich nicht an die Netiquette und beachtest z. B. die 
Groß-/Kleinschreibung?

von spess53 (Gast)


Lesenswert?

Hi

Wie sehen die Einstellungen für Takt und SUT (Fuses) aus?

MfG Spess

von Roland H. (blacksmoke85)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Roland H. (blacksmoke85)


Angehängte Dateien:

Lesenswert?

hier der relevante code

von Karl H. (kbuchegg)


Lesenswert?

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
von Roland H. (blacksmoke85)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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
von Karl H. (kbuchegg)


Lesenswert?

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.

von Roland H. (blacksmoke85)


Lesenswert?

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
von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
von Roland H. (blacksmoke85)


Lesenswert?

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
von Karl H. (kbuchegg)


Lesenswert?

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
von Roland H. (blacksmoke85)


Lesenswert?

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
Noch kein Account? Hier anmelden.