Forum: Mikrocontroller und Digitale Elektronik TTL Signal Verarbeitung


von Rafi D. (alexanderw)


Lesenswert?

Guten morgen,
an meinem Atmega2560 hab ich an einem Pin ein TTL-Signal anliegen 
welches in undefinierten Zeitabständen ankommt. Und dieses würde ich 
auch gerne unter c auswerten, eine CRC-Prüfung über das ankommende 
Telegramm bilden und dann per UART weiterleiten.

Wie ist die herangehensweise an diese Problem?

Lese ich das komplette Telegramm (max. 32Byte) komplett in ein array ein 
und verarbeite es dann? Sollte ich das mit einer ISR abfangen? Mit einem 
Timer arbeiten?

Gibt es Link`s wo ich mich dazu reinlesen könnte?

MFG Alex

von Ian (Gast)


Lesenswert?

Meine eindeutige Antwort: JA.

von Rafi D. (alexanderw)


Lesenswert?

Ian schrieb:
> Meine eindeutige Antwort: JA.

Danke für die Info. Jetzt hab ich auch die Welt verstanden. Ohne deine 
Antwort wäre das nicht möglich.

von Peter (Gast)


Lesenswert?

>> Meine eindeutige Antwort: JA.
>
>Danke für die Info. Jetzt hab ich auch die Welt verstanden. Ohne deine
>Antwort wäre das nicht möglich.

Aber recht hat er, der Ian. Was solle deine Frage, bzw. was willst Du? 
Dass ein anderer Dein Problem/Deine Aufgabe löst, nur weil Du zu faul 
bist, eine Suchmaschine zu bedienen zu lesen  nachzudenken?

Stelle eine konkrete Frage zu einem klar beschriebenen konkreten Problem 
und Du wirst konkrete Antworten erhalten

von Rafi D. (alexanderw)


Lesenswert?

Alex W. schrieb:
> Guten morgen,
> an meinem Atmega2560 hab ich an einem Pin ein TTL-Signal anliegen
> welches in undefinierten Zeitabständen ankommt. Und dieses würde ich
> auch gerne unter c auswerten, eine CRC-Prüfung über das ankommende
> Telegramm bilden und dann per UART weiterleiten.
>
Es ist noch zu erwähnen das es ein 2400 Baud Signal ist. Heißt 2400Hz 
logisch 0 und 1200Hz logisch 1.
Sorry, mit TTL-Signal ist TTL-Pegel gemeint.

Dies ist die eigentliche, hoffe 'konkrete' Problem. Falls was fehlt an 
info, dann ergänze ich es gerne.

Alex W. schrieb:
> Gibt es Link`s wo ich mich dazu reinlesen könnte?

Ich bin bereit mich zu informieren und will nicht andere meien Arbeit 
machen lassen. Aber das was ich gefunden habe scheint mir nicht für 
meinen fall zu sein. Ich finde viel zu Drehgebern und dem dahinter 
stehenden Gray-Code, aber das brauch ich nicht.

Alex W. schrieb:
> Lese ich das komplette Telegramm (max. 32Byte) komplett in ein array ein
> und verarbeite es dann? Sollte ich das mit einer ISR abfangen? Mit einem
> Timer arbeiten?

Das waren meine Denkansätze mit welcher Methode man das lösen versuchen 
könnte.

von Rafi D. (alexanderw)


Lesenswert?

Peter schrieb:
> Dass ein anderer Dein Problem/Deine Aufgabe löst, nur weil Du zu faul
> bist, eine Suchmaschine zu bedienen zu lesen  nachzudenken?

Faul bin ich keinster Weise und das ist unverschämt so was zu schreiben 
oder zu behaupten.
Wie gesagt gesucht hab ich. Vllt. hab ich die falschen Suchwörter 
eingegeben, aber ich suche immer bevor ich was schreibe.


Zurück zum Thema.
Eine weitere ergänzung zur Problemstellung. Mein Signal liegt an einem 
PIN mit Interrupt funktion und diese würde ich auch gerne nutzen um 
nicht die ganze Zeit im Hauptprogramm auf ein Signal zu warten.

von Karl H. (kbuchegg)


Lesenswert?

> Es ist noch zu erwähnen das es ein 2400 Baud Signal ist.
> Heißt 2400Hz logisch 0 und 1200Hz logisch 1.

Unter "Baud" versteh ich zwar was anderes.
Auch diese Information reicht noch lange nicht, um eindeutig klar zu 
stellen, wie denn eigentlich das Eingangssignal aussieht und wie es 
auszuwerten ist.

von Hopp Triceratop (Gast)


Lesenswert?

Abhaengig vom Timing koennte man das Signal auch mit einem 
timerinterrupt auswerten.
Ob einlesen oder nicht ... Was soll geschehen, wenn das Signal nicht 
passt ? Wenn der CRC falsch ist, fortwerfen ?

von Weingut P. (weinbauer)


Lesenswert?

es stellen sich halt verschiedene Fragen ...

Wenn Dein Signal eh am Interruptpin liegt, liegt es nahe den auch zu 
verwenden und sei es um nur ein Flag zu setzen und die Verarbeitung in 
der Mainloop vorzunehmen.

Ob Du bei jedem eingehenden Byte die CRC fortschreibst oder am Ende über 
alle Zeichen bleibt sich im Prinzip gleich, die Rechenzeit ist die 
Selbe, kommt halt drauf an was Dein sonstiger Programmablauf noch so 
macht und ob sich n paar Mikrosekunden ab und an oder auf einmal störend 
auswirken.

Die Verwendung eines Timers für ein Timeout der Übertragung ist eine 
mögliche Programmversion ... bei unsicherer Übertragung wie IR auch 
durchaus empfehlenswert. Bei jedem empfangenen Zeichen Timer 
zurücksetzen, bei Timerüberlauf n Timout auslösen, CRC prüfen, 
verarbeiten und Ringpuffer zurücksetzen ist eine Möglichkeit. Wenn das 
Signal 0 und 1200Hz ist kannst Du auch nen Timer verwenden um die 
Impulsbreite zu messen, quasi Störsignale ausfiltern, ist 
programmtechnisch nicht die einfachste Übung aber schon öfter 
angewendet. Dazu evtl. den Interrupt auf Flanken stellen und eben bei 
steigender Flanke Timer auslesen und zurücksetzen ... bei Überlauf ist 
0, bei Wert zwischen x und y ist 1 ...

Du siehst, es gibt viele Möglichkeiten und die im Einzelnen durchzukauen 
sprengt leider die Möglichkeiten eines Forumbeitrages

von Peter D. (peda)


Lesenswert?

Alex W. schrieb:
> Es ist noch zu erwähnen das es ein 2400 Baud Signal ist. Heißt 2400Hz
> logisch 0 und 1200Hz logisch 1.

Aha, es handelt sich also um ein seriell codiertes Protokoll.
"TTL-Signal" ist da ziemlich irreführend.

Ohne eine genaue Code- und Protokollbeschreibung ist da nichts zu 
machen.
Man muß schon wissen, wie es ausgewertet werden soll.


Peter

von Bananen Joe (Gast)


Lesenswert?

http://de.wikipedia.org/wiki/Logikpegel
Soviel zu deiner Frage.
Du erhælst also ein Logik-Signal mit TTl-Pegeln, wie diese Signalfolge 
aussieht kønnen wir nur raten. Interessant wære das Protokoll...

von Rafi D. (alexanderw)


Lesenswert?

Ok

Das Eingangssignal hat einen Vorlauf von 15 Bits(111111000000000). 
Danach 1 Startbit (logisch 1). Jetzt kommen die jeweiligen Bytes mit 
Information(je nach Telegramm mit unterschiedlicher Länge(1-20 Bytes)). 
Getrennt werden Sie mit einem Stopbit (logisch 1). Im Nachhinein wird 
über das Telegramm eine CRC checksum erstellt und hinten angehängt (2 
Byte's). Nach der Auswertung wird das Telgramm über RS232 an den PC 
weitergeleitet.

Meine Idee wäre:

if(Vorlauf == Bitstruktur(wie oben))
{
 while(tu das solange bis 8 bits geschrieben wurden)
{
  if(positive Flanke & Dauer von 1200Hz)
  {
   schreib eine 1 ins Bit Array und shifte um 1 nach rechts
  }
  if(negative Flanke & Dauer von 2400HZ)
  {
   schreibe eine 0 ins Bit Array und shifte um 1 nach rechts
  }
 }
dann verwerfe das StoppBit und führe obiges bis zum ende des Telegramms 
aus
}

Es sieht primitiv aus und es fehlen einige Kontrollstrukturen, aber so 
ungefähr wollte ich das machen.
Fehlen da irgendwelche grundlegenden Strukturen?

von Rafi D. (alexanderw)


Lesenswert?

Autor: Fhutdhb Ufzjjuz (weinbauer)
habs jetzt erst gesehen.

Danke Fhutdhd, das gibt reichlich anreiz zum nachdenken.

von Weingut P. (weinbauer)


Lesenswert?

nach rechts shiften? ich denk eher nach links, oder?

von Weingut P. (weinbauer)


Lesenswert?

ah, ok, erst das MSB setzen ... ja, dann nach rechts shiften.

von Georg G. (df2au)


Lesenswert?

Zwei aufeinander folgende Nullen? Sind eine positive und eine negative 
Flanke.

Warum nicht den Pin-Change-Interrupt und einen freilaufenden Timer (mit 
Ticker im Bereich 100us)? Dann kannst du gleich kleinere Unterschiede im 
Takt zwischen Sender und Empfänger ausgleichen.

Und das Stop Bit nicht verwerfen sondern kontrollieren.

Und noch ne blöde Frage: Warum nicht gleich ein normales asynchrones 
Format, wie es jeder UART kann? Gleichstromfrei wirst du mit deinem 
Verfahren ohne weitere Klimmzüge auch nicht. Dann doch besser einen 
Standard Code (Manchester wäre das Stichwort).

von Rafi D. (alexanderw)


Lesenswert?

Georg G. schrieb:
> Zwei aufeinander folgende Nullen? Sind eine positive und eine negative
> Flanke.

Wie gesagt es fehlen noch einige Kontrollstrukturen.

Georg G. schrieb:
> Und noch ne blöde Frage: Warum nicht gleich ein normales asynchrones
> Format, wie es jeder UART kann? Gleichstromfrei wirst du mit deinem
> Verfahren ohne weitere Klimmzüge auch nicht. Dann doch besser einen
> Standard Code (Manchester wäre das Stichwort).

Weil diese Norm kurz nach Christis geburt verabschiedet wurde und gesagt 
wurde das,dass Telegramm so aussehen muss ;). Und ich muss mich daran 
halten.
Also liegt es nicht in meiner Hand.
Reg mich auch drüber auf, das veraltete System nicht modernisiert 
werden, wie in meinem Beispiel.

von Karl H. (kbuchegg)


Lesenswert?

Alex W. schrieb:



> Es sieht primitiv aus und es fehlen einige Kontrollstrukturen, aber so
> ungefähr wollte ich das machen.
> Fehlen da irgendwelche grundlegenden Strukturen?

Gib doch mal einen Link auf die Originalbeschreibung des Senders. Aus 
deinem Kauderwelsch wird doch kein Mensch schlau.

von Michael S. (rbs_phoenix)


Lesenswert?

Wo kommt denn das Signal her?

Ein Array ist da doch ziemlich unpraktisch oder nicht? Da verbraucht man 
pro bit doch ein Byte, wenn man z.B. char arr[160]; nimmt.

Ich hätte das bit in ein Byte geschrieben (MSB oder LSB, ja nach 
Protokoll) und dann nach links bzw rechts geschiftet. Solange bis die 8 
Bit durch sind und dann eine nächste Variable genommen. Also dann eher 
"char arr[20];" und pro 8 bit den Index um 1 erhöhen.

von Peter D. (peda)


Lesenswert?

Das ist doch irgendein Kassetteninterface von nem uralten Heimcomputer.


Peter

von Rafi D. (alexanderw)


Lesenswert?

Aus dem CMX469 kommt das Signal (Telegramm) raus. Den Telegrammaufbau 
hab ich oben beschrieben.

Michael Skropski schrieb:
> Ein Array ist da doch ziemlich unpraktisch oder nicht?

deswegen steht da ja auch Bit-Array.

Alex W. schrieb:
> if(positive Flanke & Dauer von 1200Hz)
>   {
>    schreib eine 1 ins Bit Array und shifte um 1 nach rechts
>   }

von Georg G. (df2au)


Lesenswert?

@peda: Kann sein, klingt nach Tarbell von 1978.

von Rafi D. (alexanderw)


Lesenswert?

Peter Dannegger schrieb:
> Das ist doch irgendein Kassetteninterface von nem uralten Heimcomputer.

Sowas hör ich zum ersten mal.

von Georg G. (df2au)


Lesenswert?

"CMX469" war ein gutes Stichwort. Peda hat Recht, Steinzeit der 
Elektronik.
Dann mal viel Spass. Zu dem Thema gibt es n+1 Beispiel Codes, meist 
Assembler (C wurde damals gerade erfunden). Google ist dein Freund.

BTW: Welchen CRC nimmst du? Welches Polynom, welchen Startwert?

von Rafi D. (alexanderw)


Lesenswert?

Georg G. schrieb:
> BTW: Welchen CRC nimmst du? Welches Polynom, welchen Startwert?

Das Generatorpolynom ist wie das IC, sehr eigen. Auf jedenfall nichts 
standardmäßiges.
Und Startwert müsst nochmal nachgucken, aber ich glaub der war 0000;

von Karl H. (kbuchegg)


Lesenswert?

Alex W. schrieb:
> Aus dem CMX469 kommt das Signal (Telegramm) raus. Den Telegrammaufbau
> hab ich oben beschrieben.

Da ist noch (auf tiefer Ebene) so viel unklar, dass man damit wenig 
anfangen kann. Und das nicht zuletzt deshalb, weil nicht klar ist, 
inwiefern da überhaupt die Einheit "Herz" reinspielt. "Herz" ist keine 
vernünftige Angabe für Pulslängen.

Also: was kommt da überhaupt daher?
Sind das EInzelpulse mit definierten Längen, ist das ganze vielleicht 
frequenzmoduliert? Oder wie oder was?

Deine Telegrammschicht in allen Ehren. Aber noch ist überhaupt nicht 
klar, wie denn die Bitdarstellung ist und wie man ein 1-Bit von einem 
0-Bit unterscheidet. Und ich denke, damit sollte man erst mal anfangen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Alex W. schrieb:
> Aus dem CMX469 kommt das Signal (Telegramm) raus. Den Telegrammaufbau
> hab ich oben beschrieben.

Du hast gar nichts beschrieben. Es fehlen mindestens folgende Angaben:

1. Wie lange muss das Signal mit 1/2400 bzw. 1/1200 anliegen,
   damit es als eine 0 bzw. 1 erkannt werden muss? Eine tausendstel
   Sekunde? Eine hundertstel Sekunde? Oder gar eine Sekunde?

2. Wie erkennt man zwei/drei/vier Einsen hintereinander? Ist da Pause
   zwischendurch? Oder ist das Signal dann einfach doppelt/dreifach/
   vierfach so lang?

von Ian (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Also: was kommt da überhaupt daher?

Es ist ein einziges, elendes Gestammel.
Anstatt dem TO alles aus der Nase zu ziehen, sollte man ihm an der Nase 
ziehen oder sonstwohin treten. Wenn ich dann noch 'Firma: FH' lese, dann 
ist das doch eine erschreckende Vorstellung.

von Stefan W. (dl6dx)


Lesenswert?

Alex W. schrieb:
> Das Eingangssignal hat einen Vorlauf von 15 Bits(111111000000000).
> Danach 1 Startbit (logisch 1). Jetzt kommen die jeweiligen Bytes mit
> Information(je nach Telegramm mit unterschiedlicher Länge(1-20 Bytes)).
> Getrennt werden Sie mit einem Stopbit (logisch 1). Im Nachhinein wird
> über das Telegramm eine CRC checksum erstellt und hinten angehängt (2
> Byte's).

Könnte glatt ein POCSAG-Telegramm sein... Dazu passt auch der antike 
KCS.

Grüße

Stefan

von Weingut P. (weinbauer)


Lesenswert?

hmmm ... wenn ich mir das Datenblatt anschau:

http://www.datasheetarchive.com/dataframe.php?file=DSA-138162.pdf&dir=Datasheets-7&part=CMX469A#

schaut das für mich nach FM-Übertragung aus, sprich die 0 ist nich "kein 
Signal", sondern hohe Frequenz, 1 ist niedrige Frequenz ... ne Kippstufe 
als Eingang und Impulslänge mit Timer messen, wird nicht anders gehen 
aus meiner Sicht.

Welcher Interrupt ob Pin Change oder Flanke kommt auf die 
Eingangsschaltung an.

von Karl H. (kbuchegg)


Lesenswert?

> Aus dem CMX469 kommt das Signal (Telegramm) raus.

Ach, da ist ein Frequenzdemodulator im Spiel.
Na super. Schön das man diese Information dann auch nach 3 Seiten 
Postings auch schon bekommt.

Damit wird dann Franks Nachfrage
Beitrag "Re: TTL Signal Verarbeitung"
zur relevanten.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ich habe mir ausgehend von

   http://dtusat1.dtusat.dtu.dk/group.php?c_gid=7

das Datenblatt

  http://dtusat1.dtusat.dtu.dk/files/filedl.php?fileid=1289

mal angeschaut.

Das, was ich da sehe, sind schöne Sinussignale am TX. Das ganze ist also 
ein analoges Modem. Einfach das als TTL-Pegel bezeichnen würde ich das 
nicht.

Wenn ich mir darin die "Interface Timing Diagrams" anschaue, wird eine 1 
mit einer einzigen(!) Halbwelle bzw. 0 mit einer Vollwelle der doppelten 
Frequenz ausgegeben. Das passt natürlich zu den Angaben des TO, dass die 
Baudrate 2400Bd beträgt, aber eine "1" durch lediglich 1200Bd 
repräsentiert wird.

Wenn der TO wirklich da ein TTL-Rechtecksignal "sieht" (durch 
irgendeinen Sinus-nach-Rechteck-Wandler), dann wird eine "1" durch eine 
Pegellänge von 833µs, eine "0" durch zwei Pegellängen von je 417µs 
ausgegeben.

Wie man diesen Wellensalat nun z.B. auf Bytegrenzen synchronisiert, habe 
ich jetzt aber nicht mehr aus dem Datenblatt herauslesen wollen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Wie man diesen Wellensalat nun z.B. auf Bytegrenzen synchronisiert, habe
> ich jetzt aber nicht mehr aus dem Datenblatt herauslesen wollen.

Ich antworte mir mal selbst:
Das steht auch gar nicht drin, für das Protokoll ist das Modem gar nicht 
zuständig. Vermutlich gibt es da ein Startbit, 8 Bit Daten und ein 
Stopbit.

Das könnte man mit einer einfachen Anpassung im IRMP erschlagen, 
indem man die Puls-/Pausenverhältnisse als neues 
Pulse-Distance-Protokoll parametrisiert - mit der Besonderheit, dass die 
"0" zwei Pegellängen besitzt statt einer. Ich halte aber die ganze 
Anwendung für zu exotisch, um mir das antun zu wollen ;-)

von Erich (Gast)


Lesenswert?

Hallo Leute,

seht euch das hier mal an:

http://en.wikipedia.org/wiki/Kansas_City_standard
http://en.wikipedia.org/wiki/Audio_frequency-shift_keying


Die Fragen und Beiträge des Autors sind allerdings wirklich unter aller 
Kajüte.
Möge dieser Thread schnell zu seiner Fortbildung beitragen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jetzt, wo die Signalform klar ist, zur ursprünglichen Frage:

Alex W. schrieb:
> Lese ich das komplette Telegramm (max. 32Byte) komplett in ein array ein
> und verarbeite es dann? Sollte ich das mit einer ISR abfangen? Mit einem
> Timer arbeiten?

Setze einen Timer auf, wo Du in der ISR die Pulslängen misst. Fülle in 
der ISR Dein 32-Byte-Array auf und setze ein Flag, sobald die 32 Byte 
eingelesen sind.

Werte dann Dein Array im Hauptprogramm aus, sobald das Ready-Flag 
gesetzt ist. So macht das IRMP auch.

Viel Glück,

Frank

von Rafi D. (alexanderw)


Angehängte Dateien:

Lesenswert?

Jetzt hab ich endlich das Oszi, hier noch einmal das Signal bzw. 
Telegramm. blau geht als NF-Signal in den CMX und türkis kommt als 
serielles Telegramm raus.
In diesem Fall trifft es den Nagel auf den Kopf. Bilder sagen mehr als 
tausend Worte.

von XXX (Gast)


Lesenswert?

Hallo

Das sieht doch wunderbar aus.
Startbit, 9 Datenbits, Stopbit.

Geschwindigkeit ausrechnen.
Pegel anpassen
An UART anschließen
UART richtig einstellen
Daten empfangen

Gruß
Joachim

von Stefan W. (dl6dx)


Lesenswert?

Ach ja, hast du eigentlich das Datenblatt vom CMX469 (kein CMX469A?) 
gelesen?

Am Ausgang RxSync hast du den zurückgewonnen Bittakt. Du musst nur auf 
der fallenden Flanke sampeln.

Der Anschluss des Modems sieht also so aus:

Ein Portbit als Dateneingang (braucht nicht interruptfähig sein).
RxSync auf einen externen IRQ legen und auf der fallenden Flanke 
auslösen lassen. In der Interruptroutine liest du dann das aktuelle Bit 
vom anderen Port ein.

Wie du die Bits zusammensetzen und ob du Füllbits entfernen musst, sagt 
dir die (immer noch nicht benannte) Protokollspezifikation.

Grüße

Stefan

von Stefan W. (dl6dx)


Lesenswert?

XXX schrieb:
> Das sieht doch wunderbar aus.
> Startbit, 9 Datenbits, Stopbit.

Vorsicht! Der CMX469 wurde gern für POCSAG-Anwendungen und 
vergleichbares verwendet. Das sind in der Regel bitsynchrone Protokolle, 
nichts asynchrones.

Grüße

Stefan

von Stefan W. (dl6dx)


Lesenswert?

Stefan Wagner schrieb:
> Ach ja, hast du eigentlich das Datenblatt vom CMX469 (kein CMX469A?)
> gelesen?

Um Missverständnisse zu vermeiden: Die Frage ging an den OP.

Grüße

Stefan

von Rafi D. (alexanderw)


Lesenswert?

Danke Stefan.
Ja ich hatte mir nur CMX469A durchgelesen. Die Idee mit dem RxSync ist 
super und wenn mich nicht alles täuscht auch nicht schwer zu 
implementieren.

Mache mich mal auf die Socken und versuche das zu implementieren.

XXX schrieb:
> Startbit, 9 Datenbits, Stopbit.

Das sind 8 bits + Stopbit.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Alex W. schrieb:
> In diesem Fall trifft es den Nagel auf den Kopf. Bilder sagen mehr als
> tausend Worte.

Ach, Du hängst auf der digitalen Seite und nicht auf der analogen Seite 
des CMX? Sag das doch gleich, dann hätte man sich die Rätselei mit 
"1=1200Bd" und "0=2400Bd" absolut sparen können.

Suboptimal, dass hier die Informationen nur tröpfchenweise geflossen 
sind.

von Rafi D. (alexanderw)


Lesenswert?

Ich wollte hier keinen in die Irre führen.
Demnächst werde ich meine Fragen sorgfältiger und genauer beschreiben.

von Stefan W. (dl6dx)


Lesenswert?

Alex W. schrieb:
> Mache mich mal auf die Socken und versuche das zu implementieren.

Das Einlesen des einzelnen Bits ist nur ein Teil des Ganzen.

> Das sind 8 bits + Stopbit.

Ich halte es für sehr unwahrscheinlich, dass auf einen bereits 
bitsynchronisierten Bitstrom noch ein asynchrones Framing draufgepackt 
wurde. Das wäre schlicht überflüssig.

Anhand des bis jetzt bekannten Hintergrunds erscheint mir viel 
wahrscheinlicher, dass über eine Flag-Sequenz auf den Telegrammstart 
synchronisiert wird und dann entweder eine fixe Telegrammlänge erwartet 
wird oder aber die jeweils zu erwartenden Telegrammlänge über einen 
vordefinierten Header codiert ist. Das bedeutet, du liest so viele Bits 
ein, wie vordefiniert bzw. im Header angegeben, dann die Bits der FCS 
(Frame Check Sequence, meist ein CRC). Dann ist das Telegramm komplett 
und das Programm wartet wieder auf die Flagsequenz.

Typische Beispiele für solche Protokolle sind FMS und POCSAG.

Aber welches Protokoll ist es denn nun in deinem Fall? Ohne die Info 
kommt man nicht weiter.

Grüße

Stefan

von Erich (Gast)


Lesenswert?

Habe hier nochwas gefunden.
Etwas unklar ob's zum Thema passt, aber den Link wollte ich weitergeben.

http://www.codeforge.com/article/141947

von Rafi D. (alexanderw)


Lesenswert?

So gestern hat es mit em Starten nicht geklappt. Aber heute und ich 
komme gerade nicht weiter. Habe auch die Register so gesetzt wie im 
DAtenblatt steht aber der Interrupt will bei mir nicht. Hab ich 
eventuell ein Register oder iwas anderes vergessen zu setzten oder kann 
der Code aus anderen Gründen nicht funktionieren?
Hier ist ein Ausschnit aus dem Code. Es handelt sich nur um eine 
Testfunktion, ob der Int0 überhaupt was tut.

steht in Telegramm.h und wird in main.c eingebunden.
1
volatile uint8_t getBit;
2
ISR(INT0_vect)
3
{
4
  getBit = 1;
5
}
main.c
1
// Initialisierungen externen Interrupt des dig. Signals
2
EIMSK |= (1<<INT0);     // Maske für den Int0
3
EICRA |= (1<<ISC01);  // INT0 auslösen bei fallender Flanke
4
sei();
5
while(1)
6
if (getBit == 1)
7
{
8
  uart2_putc("1");
9
  _delay_ms(300);
10
11
}
12
if (getBit == 0)
13
{
14
  uart2_putc("0");
15
  _delay_ms(300);
16
    
17
}
P.S.: Genutzt wird ein Atmega 2560

von Karl H. (kbuchegg)


Lesenswert?

Alex W. schrieb:

> Hier ist ein Ausschnit aus dem Code. Es handelt sich nur um eine
> Testfunktion, ob der Int0 überhaupt was tut.

Punkt 1:
Testprogramme können nicht einfach genug sein.
Welchen Sinn hat es die 15 Zeilen eines Testprogramms auf möglichst 
viele Files aufzuteilen? Das führt doch nur dazu, dass man überhaupt 
nichts mehr sieht

Punkt 2:
Auch wenn das nur ein Testprogramm ist, ist eine ordentliche 
Codestrukturierung ein absolutes MUSS. Immer! Dazu gehören auch 
vernünftige Einrückungen. Die sind nicht Selbstzweck oder dienen dazu 
damit der Boss happy ist, sondern die sind dein Werkzeug um dir optisch 
die Struktur eines Codes klar zu machen. Und die muss man konsequent 
einsetzen.
Dann fällt dir zb auch auf, dass in deiner Hauptschleife nur das erste 
if enthalten ist, weil du die { } Blockklammern beim while vergessen 
hast

Punkt 3:
Poste immer vollständigen Code! Dadurch gibst du uns auf der anderen 
Seite des Bildschirms die Möglichkeit, deinen Code auch mal 
auszuprobieren. Und: Es kommt gar nicht so selten vor, dass das 
eigentliche Problem im Code gar nicht dort ist, wo du denkst, das es 
wäre, sondern ganz woanders. Da du aber die Reste deines Codes nicht 
zeigst, kann das hier auch keiner sehen. Speziell bei einfachen 
Testprogrammen ist der Code nicht umfangreich. Den kompletten Code 
posten ist also auch für dich weniger Aufwand und auf dieser Seite des 
Bildschirms sieht man alles, was man sehen muss und wir brauchen nicht 
blöd nachfragen. Ein BWL-er würde sagen: eine Win-Win Situation.

von Rafi D. (alexanderw)


Angehängte Dateien:

Lesenswert?

Ich dachte ich tue einen gefallen und poste nicht alles, damit das nicht 
zu viel wird und von der Hauptsache ablenkt. Eine Codestrukturierung 
versuche ich immer einzuhalten. In diesem Fall hab ich sie nur ausser 
acht gelassen, da es sich um einen Test handelt und keine fertige bzw. 
endgültige Version.

Ansonsten ist im Anhang der komplette Code.
Ratschlag mit KomplettCodeAnhängung wargenommen  und akzeptiert.

von Karl H. (kbuchegg)


Lesenswert?

Schmeiss doch erst mal den ganzen restlichen Schwachsinn raus, ok?
Ein Testprogramm hat eine Aufgabe. Dein Testprogramm soll feststellen ob 
dein INT0 funktioniert. Nicht mehr und nicht weniger. Also mach das auch 
- nicht mehr und nicht weniger. Kein Mensch braucht dabei Kommandos, die 
zu einem Gerät geschickt werden (oder auch nicht), Kommandos die von 
einem PC kommen (oder auch nicht), Taster die dafür sorgen das Kommandos 
geschickt werden (oder auch nicht). Und im Regelfall wird auch die UART 
Kommunikation reibungslos funktionieren, wenn sie erst mal funktionirt, 
d.h. Frame Errors kann man in einem Testprogramm erst mal ignorieren.


Und plötzlich ist dein Testprogramm ganz kurz und konzentriert sich auf 
das was du testen willst. Dass deine UART funktioniert glaub ich dir 
auch so. Das brauchst du nicht testen. (zumindest jetzt nicht mehr, wenn 
sie gestern funktioniert hat, funktioniert sie auch heute)

von Karl H. (kbuchegg)


Lesenswert?

An welchen Pin hast du deinen Eingang angeschlossen?

INT0 ist am Pin PD0.
Dort liegt auch SCL. Ist an dem Pin sonst noch was angeschlossen? (zb 
ein ISP Programmer?)

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:
> An welchen Pin hast du deinen Eingang angeschlossen?

Hast du überhaupt dein Gerät angeschlossen?

Wenn es nur darum geht, den Interrupt zu testen würde ich das gar nicht 
tun.
Taster an den Interupt Eingang, der nach Masse schaltet. Pullup 
Widerstand dazuschalten und passt schon. Jede Komponente mehr bringt nur 
mehr zusätzliche mögliche Fehlerquellen.

1
#define F_CPU 4000000UL
2
#define BAUD_RATE 9600
3
4
#include <stdlib.h>
5
#include <avr/io.h>
6
#include <avr/interrupt.h>
7
8
#include "uart.h"   
9
10
volatile uint8_t getBit;
11
12
ISR(INT0_vect)
13
{
14
  getBit = 1;
15
}
16
17
int main(void)
18
{
19
  DDRD  = 0x00;  // Port D als Eingang setzen
20
  PORTD = 0x01;  // INT0 liegt an PD0
21
  
22
  uart2_init(UBRR_BERECHNUNG(BAUD_RATE,F_CPU));
23
24
  EIMSK |= (1<<INT0);    // Maske für den Int0
25
  EICRA |= (1<<ISC01);  // INT0 auslösen bei fallender Flanke
26
  
27
  sei();
28
29
  uart2_puts( "Und scharf!\n" );
30
    
31
  while (1)
32
  {
33
    if (getBit)
34
      uart2_putc('1');
35
    else
36
      uart2_putc('0');
37
  }
38
}

reicht schon. Damit kann man schon testen. Die UART ist zwar eine 
mögliche zusätzliche Fehlerquelle aber durch die Ausgabe des Textes vor 
dem eigentlichen arbeiten hat man eine Kontrolle, ob die UART 
funktioniert. Programm laufen lassen und auf den Taster latschen und 
nachsehen ob sich die Dauerausgabe von 0 auf 1 ändert. Wenn ja - 
Gratulation: der INT0 funktioniert erst mal.

von Rafi D. (alexanderw)


Lesenswert?

Hab ihn.

Hatte den ISP net an im AS. Dachte mir auch gerade warum er mir auf die 
Pinabfragen antwortet wobei die gar net verwendet werden.
Aufmerksamkeitsfehler höchsten Grades.
Aber an sich funktioniert jetzt alles einwandfrei, INT0 löst aus und 
uart sendet dann auch as Zeichen.

Danke für die Erkenntnis wie man Fehler einkreist und eliminiert.

von Karl H. (kbuchegg)


Lesenswert?

Alex W. schrieb:
> Hab ihn.
>
> Hatte den ISP net an im AS. Dachte mir auch gerade warum er mir auf die
> Pinabfragen antwortet wobei die gar net verwendet werden.
> Aufmerksamkeitsfehler höchsten Grades.

Siehst du.
Und genau deshalb ist es SO wichtig, dass Testprogramme einfach sind. Je 
weniger Fehlermöglichkeiten du einbaust, desto weniger Fehler kannst du 
auch tatsächlich machen.

von Rafi D. (alexanderw)


Angehängte Dateien:

Lesenswert?

So ich hab nach einer privaten Pause mal damit angefangen meine 
ankommenden Daten auszuwerten.
Doch leider macht das mein Code nicht so wie ich will. ;)
Kurz zum Code: An meinem INT0 kommt das digitale Sync Signal an(2400 
baud). Mit der fallenden Flanke am INT0 frage ich den Pin D2 ab, wo mein 
digitales Signal(1200/2400 Baud) ankommt. Um die Bits in ein Byte zu 
schreiben frage ich nach dem Interrupt Flag ab und schreibe dann die 
entsprechenden Bits per shift in eine 16 Bit variable.
Angefügt, als Bild, hab ich noch die ankommenden Daten am PC die mir der 
µC ausgibt und den Code.

Ich empfange unterschiedliche Anzahlen von eingelesenen Bit's, ich gebe 
doch mit meiner for-Schleife vor das es nur 8 Bits sein sollen?
Erst dachte ich das pro for-Schleifen Durchlauf die Zeit ein Rolle 
spielt, dann hab ich jedoch gerechnet und 1 Takt dauert bei 4Mhz ca. 
0,25µs wobei die Daten jede 0,42ms ankommen. D.h. das zwischen den 
jeweiligen eingelesenen Bits 1680 Takte liegen. Braucht mein 
For-Schleife denn soviel Takte? Sollte ich eine Abbruchbedingung für 8 
eingelese bits einfügen wie z.B. if (n==8){break;}?

Ist das richtig das ich nur 2Byte shiften kann, also ein int? D.h. das 
ich dann z.B. die 16 bit variable so ausgeben muss
tmpcheck = (byte[0] << 8) + byte[1]; ?

von Stefan W. (dl6dx)


Lesenswert?

Alex W. schrieb:
> Doch leider macht das mein Code nicht so wie ich will.

Offen gesagt: Das wundert mich nicht. Du scheinst immer noch vieles nur 
halb oder gar nicht verstanden zu haben.

> Kurz zum Code: An meinem INT0 kommt das digitale Sync Signal an 2400
> baud). Mit der fallenden Flanke am INT0 frage ich den Pin D2 ab, wo
> mein digitales Signal(1200/2400 Baud) ankommt.

Du solltest die richtigen Begriffe verwenden: Der Ausgang RxSync des 
Modem-IC ist der Bittakt, auf dessen fallender Flanke das demodulierte 
Empfangssignal gültig ist. INT0 wird also durch die fallende Flanke des 
Bittakts getriggert. Zu diesem Zeitpunkt liest du das an PD2 anliegende 
Bit ein.
Der Bittakt hat übrigens eine fixe Frequenz von 2400 Hz. Die Einheit 
"Baud" ist hier falsch! Das Empfangssignal hat eine Bitrate von 2400 
bit/s (auch hier ist "Baud" nicht richtig). Ansonsten: 
http://de.wikipedia.org/wiki/Baud

> Um die Bits in ein Byte zu schreiben frage ich nach dem Interrupt
> Flag ab und schreibe dann die entsprechenden Bits per shift in eine
> 16 Bit variable.

Das ist extrem umständlich und unnötig. Diese Bitschieberei gehört in 
die ISR. Dorthin gehört sinnvollerweise auch die Byte- bzw. 
Telegrammsynchronisation (Vergleich mit dem Startwort bzw. Flag).

Hier ein Beispiel, bei dem das MSB zuerst übertragen wird und die 
Bytesynchronisation über ein 8 Bit breites Flag erfolgt.
1
/*
2
 Bitweises Einlesen der synchronen Daten vom Modem.
3
 INT0 wird auf der fallenden Flanke des Bittakts getriggert,
4
 das Datenbit an PD2 ist zu diesem Zeitpunkt gültig.
5
6
 Die empfangenen Bits werden in den Empfangspuffer bitbuf geschoben.
7
 Die byteweise Synchronisation wird über den Vergleich mit dem Flag
8
 ermittelt. Sobald bitbuf == FLAG ist, ist das nächste Bit das erste
9
 des folgenden Bytes.
10
11
 Das Flag bytesync gibt an, ob die Byte-Synchronität erreicht ist.
12
 bitcnt ist der Zähler für die jeweils empfangenen Bits je Byte.
13
/*
14
15
#define DATA_IN     (1<<PD2)
16
#define BITBUF_BITS 8        // Größe von bitbuf in Bits
17
#define BB_MSB_1    0x80     // Maske für 1 am MSB von bitbuf
18
#define FLAG        0x7e     // vom Protokoll vorgegeben
19
20
ISR(INT0_vect)
21
    {
22
    static uint8_t bitbuf = 0;
23
    static uint8_t bitcnt;
24
    static bool    bytesync = FALSE;
25
26
    bitbuf >>= 1;  // Platz für das neue Bit schaffen
27
    if (PIND & DATA_IN)   // und in das MSB schreiben
28
       {
29
       bitbuf |= BB_MSB_1; 
30
       }
31
32
    if (bytesync)
33
       {
34
       if (--bitcnt == 0) // 8 Bit eingelesen
35
            {
36
            // bitbuf weiterreichen, z.B. in einen Ringpuffer
37
38
            bitcnt = BITBUF_BITS;
39
            }
40
       }
41
    else if (bitbuf == FLAG)
42
       {
43
       bytesync = TRUE;
44
       bitcnt = BITBUF_BITS;
45
       }
46
    }

Der Code ist rein als Beispiel gedacht und ungetestet.

Was fehlt, ist das Erkennen des Verlusts der Bytesynchronisation, weil 
das sehr protokollabhängig ist. Ebenso fehlen Mechanismen für ein 
eventuelles Bit- oder Bytestuffing.

Erfolgt die Synchronisation mit einem 16 Bit oder 32 Bit breiten Wort, 
musst du bitbuf auf uint16_t bzw. uint32_t ändern und natürlich 
BITBUF_BITS und BB_MSB_1 anpassen.

Ansonsten, wie gesagt: Eigne dir die Grundlagen an! Du wirst sonst 
weiter massive Probleme haben.

Grüße

Stefan

PS: Separat kompilierte C-Quelltextdateien mit Daten- und/oder 
Funktionsdeklarationen erhalten üblicherweise die Extension ".c". Die 
Extension ".h" ist für Dateien vorgesehen, die ausschließlich 
Definitionen oder Präprozessor-Makros enthalten und über #include 
eingebunden werden.

von Karl H. (kbuchegg)


Lesenswert?

Alex W. schrieb:

Abgesehen von dem was Stefan schon gesagt hat


> digitales Signal(1200/2400 Baud) ankommt. Um die Bits in ein Byte zu
> schreiben frage ich nach dem Interrupt Flag ab

Aber sicher nicht so
1
    if (INTF0 == 0)

Wie fragt man denn ein Bit in einem Register ab?

Ausserdem: Das Interrupt Flag wird automatisch gelöscht, sobald die ISR 
betreten wird. D.h selbst wenn du die ABfrage hier richtig stellst wird 
das nicht funktionieren (zumindest nicht in 95% aller Fälle), weil du 
das Interrupt Flag gar nicht gesetzt erwischt (weil es längst durch den 
Aufruf der ISR wieder gelöscht wurde)

von Karl H. (kbuchegg)


Lesenswert?

Stefan Wagner schrieb:

>> Kurz zum Code: An meinem INT0 kommt das digitale Sync Signal an 2400
>> baud). Mit der fallenden Flanke am INT0 frage ich den Pin D2 ab, wo
>> mein digitales Signal(1200/2400 Baud) ankommt.
>
> Du solltest die richtigen Begriffe verwenden: Der Ausgang RxSync des
> Modem-IC ist der Bittakt, auf dessen fallender Flanke das demodulierte
> Empfangssignal gültig ist. INT0 wird also durch die fallende Flanke des
> Bittakts getriggert. Zu diesem Zeitpunkt liest du das an PD2 anliegende
> Bit ein.
> Der Bittakt hat übrigens eine fixe Frequenz von 2400 Hz. Die Einheit
> "Baud" ist hier falsch! Das Empfangssignal hat eine Bitrate von 2400
> bit/s (auch hier ist "Baud" nicht richtig). Ansonsten:
> http://de.wikipedia.org/wiki/Baud

erstens das und zweitens interessiert das nur insofern, als 
sichergestellt sein muss, dass die Interrupts nicht zu schnell kommen 
und den AVR überfordern. Mit 2400Hz ist man aber weit weg von jeglicher 
Gefahr. So gesehen interessiert diese Zahlenangabe keinen.

Die Flanke kommt - der Dateneingang wird ausgewertet, nach 8 Flanken hat 
man ein Byte beisammen. Mehr braucht man nicht. Einzig das Herstellen 
der Bytesynchronisierung ist eine knifflige Sache. Aber auch dafür hast 
du ja schon was vorgesehen (obwohl ich mir nicht sicher bin ob das so in 
seinem konkreten Fall funktioniert)

von Rafi D. (alexanderw)


Lesenswert?

Ich hab mir die Grundlagen angeignet, nur viele (meisten) Sachen lernt 
mit der Zeit und an Beispielen.
z.B. hab ich gelesen das die Interrupts so kurz wie möglich gehalten 
werden sollen, ergo hab ich das gemacht.
Und die Daten extern in einer Funktion verareitet.

Vielen Dank, für das Beispiel. Merke daran das ich gewisse Sachen anders 
realisiseren müsste.

Stefan Wagner schrieb:
> static bool    bytesync = FALSE;

Wird das nicht nach jedem Interrupt FALSE gesetzt, sodass dies

if (bytesync) nie eintreffen kann?

von Karl H. (kbuchegg)


Lesenswert?

Alex W. schrieb:
> Ich hab mir die Grundlagen angeignet, nur viele (meisten) Sachen lernt
> mit der Zeit und an Beispielen.
> z.B. hab ich gelesen das die Interrupts so kurz wie möglich gehalten
> werden sollen, ergo hab ich das gemacht.

so kurz wie möglich heißt nicht, das man gar nichts machen darf.
Wenn sich dadurch der restliche Code extrem verkompliziert oder 
fehleranfällig wird, dann ist man übers Ziel hinausgeschossen.
Du bist es. Ein paar Bits zurecht zu schieben, ein paar Variablen zu 
inkrementieren und abzufragen, ist noch lange nicht am Limit von 'so 
kurz wie möglich'. Das sind in Summe vielleicht 10 oder 20 
Prozessortakte, die da verbraucht werden. Bei ein paar Mhz Taktfrequenz 
ist das ein verschwindend geringer Anteil an der Gesamtzeit.

Quadratische Gleichungen lösen, die Bibel per serieller Schnittstelle zu 
verschicken, auf Tasterbetätigung durch den Benutzer warten, _delay_ms 
verwenden, .... das wären Beispiele davon, wo gegen 'so kurz wie 
möglich' verstossen wird.

Du hast ja auch das umgekehrte Problem:
Was nützt es dir, wenn deine ISR mit Volldampf Bits generieren kann, 
wenn die Hauptschleife dann gar nicht mehr nachkommt?

von Karl H. (kbuchegg)


Lesenswert?

Alex W. schrieb:

>> static bool    bytesync = FALSE;
>
> Wird das nicht nach jedem Interrupt FALSE gesetzt, sodass dies
>
> if (bytesync) nie eintreffen kann?


Soviel zu
> Ich hab mir die Grundlagen angeignet

Was macht denn das static an dieser Stelle?

von Rafi D. (alexanderw)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Was macht denn das static an dieser Stelle?

ich hatte das static in diesem Fall als Gültigkeitsbereichdefiniton im 
Kopf. Wird natürlich nicht immer wieder neu erzeugt. Sorry, mein Fehler.

von Rafi D. (alexanderw)


Lesenswert?

Stefan Wagner schrieb:
> Was fehlt, ist das Erkennen des Verlusts der Bytesynchronisation, weil
> das sehr protokollabhängig ist. Ebenso fehlen Mechanismen für ein
> eventuelles Bit- oder Bytestuffing.

Was ist mit Verlust der Bytesynchronisation gemeint?

von Stefan W. (dl6dx)


Lesenswert?

Alex W. schrieb:
> Was ist mit Verlust der Bytesynchronisation gemeint?

Bei einem bitseriellen Datenstrom hast du keine "eingebaute" Erkennung 
der Grenzen des Datenworts (in der Regel sind das Oktette, also Bytes). 
Irgendwie muss also auch eine Information über die Wortgrenze mit 
übertragen werden. Gleiches gilt für Beginn und Ende eines Datenblocks 
(Telegramm, Frame).

In der Regel nimmt man dafür eine spezielle Bitsequenz (Flag), die 
ausschließlich zum Kennzeichnen eines Blockanfangs verwendet wird. Damit 
es zu keiner Fehlerkennung kommt, müssen Datenwerte, die dem Flag 
gleichen, über ein definiertes Verfahren "maskiert" werden. (Dazu weiter 
unten mehr.)

Bei kurzen Datenblöcken, die immer gleich aufgebaut und gleichlang sind 
(z.B. Funkruf-Telegramme) reicht in vielen Fällen das Flag-Wort am 
Beginn. Das Ende des Datenblocks kann durch simples Abzählen der seit 
dem Flag empfangenen erkannt werden.

Bei Protokollen, die variable Blocklängen und beliebige Inhalte 
zulassen, wird entweder ein kurzer, definierter Kopf, der einen 
Längenzähler enthält, verwendet, oder man kennzeichnet das Ende 
ebenfalls durch ein Flag. (Beispiel: HDLC)

Sender und Empfänger können nach Aufbau der Bit- und Bytesynchronität 
durch Störungen "aus dem Tritt kommen" und ein einzelnes Bit geht 
verloren. Danach ist die Bytesynchronität ebenfalls weg.
(Siehe z.B. http://de.wikipedia.org/wiki/Bitslip )

Man muss also regelmäßige "Synchronpunkte" einbauen.

Jetzt noch zur "Maskierung" von Datenwerten, die gleich dem Flag sind.

Es gibt zwei grundsätzliche Verfahren, die Bitstuffing bzw. Bytestuffing 
genannt werden.

Bitstuffing wird z.B. bei HDLC verwendet. Das Flagbyte bei HDLC hat den 
Wert 0b01111110 (0x7e), also 6 '1'-Bits umrahmt von je einem '0'-Bit. 
Damit es zu keiner Verwechselung kommt, wird vom Sender bei den Daten 
nach fünf aufeinander folgenden '1'-Bits immer ein '0'-Bit eingefügt 
("dazwischengestopft", daher auch der Name "Bitstuffing". Der Empfänger 
entfernt entsprechend immer ein nach 5 '1'-Bits in Folge auftretendes 
'0'-Bit.

Bytestuffing ist das Äquivalent auf Byteebene. Tritt ein Datenbyte auf, 
dass gleich einem reservierten Wert ist, wird ein spezielles 
Markierungsbyte in den Datenstrom eingefügt, das Datenbyte nach einer 
vordefinierten Regel (reversibel) umgewandelt und hinter das 
Maskierungsbyte gehängt. (Verwendet z.B. bei PPP.)

Grüße

Stefan

von Rafi D. (alexanderw)


Lesenswert?

Danke Stefan,
werde mich mal ransetzen und gucken wie ich das anwenden bzw. lösen 
kann.

von Stefan W. (dl6dx)


Lesenswert?

Stefan Wagner schrieb:
> Das Ende des Datenblocks kann durch simples Abzählen der seit
> dem Flag empfangenen erkannt werden.

Das muss heißen: "der seit dem Flag empfangenen Bits"

Grüße

Stefan

von Rafi D. (alexanderw)


Lesenswert?

Protokoll-Aufbau:
2 Bytes Vorlauf (weiter unten), die Infobytes 1-3 und 2 Bytes für die
CRC Prüfung. Zusatzbytes werden entsprechende des verwendeten
Telegramms, diese werden nach den Infobytes eingefügt. Die Anzahl der zu
ergänzenden Zusatzbytes steht im 2. Infobyte in den Bits 0-3.
Zur Synchronisation dient ein 15 Bit langer Flag. Dieser hat führend
sechs Bits logisch 1 zur Bitsynchronisation und folgend neun Bits
logisch 0 für die Rahmensynchronisierung. Der Vorlauf wird mit einem
Startbit abgeschlossen und der Anfang der Informationswörter
eingeleitet.
Gesendet werden die Info- bzw. Zusatzbytes gedreht(Als Sender wird hier
der CMX bezwichnet, der den Bitstrom bzw. Bytestrom an den µC 
sendet)d.h. LSB-First.
Zwischen jedem gesendeten Byte wird ein Sperrbit eingeschoben um die
Informationswörter von einander zu trennen.

Bitstuffing wäre in diesem Fall nicht nötig, wohl eher "Bitdestuffing"
um die jeweiligen Sperrbits zu entfernen.Das Telegram später per RS232 
weitergeschickt.

/*
 Bitweises Einlesen der synchronen Daten vom Modem.
 INT0 wird auf der fallenden Flanke des Bittakts getriggert,
 das Datenbit an PD2 ist zu diesem Zeitpunkt gültig.

 Die empfangenen Bits werden in den Empfangspuffer bitbuf geschoben.
 Die byteweise Synchronisation wird über den Vergleich mit dem Flag
 ermittelt. Sobald bitbuf == FLAG ist, ist das nächste Bit das erste
 des folgenden Bytes.

 Das Flag bytesync gibt an, ob die Byte-Synchronität erreicht ist.
 bitcnt ist der Zähler für die jeweils empfangenen Bits je Byte.
/*

#define DATA_IN     (1<<PD2)
#define BITBUF_BITS 8        // Größe von bitbuf in Bits
#define BB_MSB_1    0x80     // Maske für 1 am MSB von bitbuf
#define FLAG        0x7e     // vom Protokoll vorgegeben

ISR(INT0_vect)
    {
    static uint8_t bitbuf = 0;
    static uint8_t bitcnt;
    static bool    bytesync = FALSE;

    bitbuf >>= 1;  // Platz für das neue Bit schaffen
    if (PIND & DATA_IN)   // und in das MSB schreiben
       {
       bitbuf |= BB_MSB_1;
       }

    if (bytesync)
       {
       if (--bitcnt == 0) // 8 Bit eingelesen
            {
            // bitbuf weiterreichen, z.B. in einen Ringpuffer

            bitcnt = BITBUF_BITS;
            }
       }
    else if (bitbuf == FLAG)
       {
       bytesync = TRUE;
       bitcnt = BITBUF_BITS;
       }
    }

Deinen obigen Quellcode habe ich versucht Stefan. Da ist mir was
aufgefallen, manchmal bzw. öfters passiert es das er anstatt 8, nur 7,6
oder gar 5 Bits einließt. Das ist ja dieser sogenannte Bit-Slip. Wie
kann man diesem entgegenwirken bzw. hier müssen ja jetzt die erwähnten
Synchronpunkte eingebracht werden.

MFG Alex

von Stefan W. (dl6dx)


Lesenswert?

Rafi Dafi schrieb:
> Protokoll-Aufbau:
> 2 Bytes Vorlauf (weiter unten), die Infobytes 1-3 und 2 Bytes für die
> CRC Prüfung. Zusatzbytes werden entsprechende des verwendeten
> Telegramms, diese werden nach den Infobytes eingefügt. Die Anzahl der zu
> ergänzenden Zusatzbytes steht im 2. Infobyte in den Bits 0-3.
> Zur Synchronisation dient ein 15 Bit langer Flag. Dieser hat führend
> sechs Bits logisch 1 zur Bitsynchronisation und folgend neun Bits
> logisch 0 für die Rahmensynchronisierung. Der Vorlauf wird mit einem
> Startbit abgeschlossen und der Anfang der Informationswörter
> eingeleitet.

Also

- ein Startwort mit 16 Bit,
- 3 Bytes Telegrammkopf
- n Bytes Zusatzdaten (n <= 0 <= 15)
- 2 Bytes CRC

Zum CRC: Welches Generatorpolynom und welcher Startwert?

> Gesendet werden die Info- bzw. Zusatzbytes gedreht(Als Sender wird hier
> der CMX bezeichnet, der den Bitstrom bzw. Bytestrom an den µC
> sendet)d.h. LSB-First.

Ok. LSB first ist recht häufig, das würde ich nicht als "gedreht" 
bezeichnen.

> Zwischen jedem gesendeten Byte wird ein Sperrbit eingeschoben um die
> Informationswörter von einander zu trennen.

Das ist technisch eigentlich unnötig. Steht das in der 
Protokollbeschreibung wirklich explizit so drin?

Was ist das denn nun eigentlich für ein Protokoll? Es wäre wirklich 
hilfreich, wenn du entweder den Namen nennen würdest oder die 
Protokollbeschreibung im Wortlaut zitieren könntest.

> Bitstuffing wäre in diesem Fall nicht nötig, wohl eher "Bitdestuffing"
> um die jeweiligen Sperrbits zu entfernen.

Das muss dann eben in der Schieberoutine (in der ISR) berücksichtigt 
werden.

> Das Telegramm wird später per RS232 weitergeschickt.

Gibt es da ein vorgegebenes Datenformat?

Noch mal zum Telegrammkopf: Sind das (wie ich vermute) gepackte Felder, 
d.h. ein Byte enthält mehrere Informationen? Das müsstest du noch 
angeben.

> Deinen obigen Quellcode habe ich versucht Stefan. Da ist mir was
> aufgefallen, manchmal bzw. öfters passiert es das er anstatt 8, nur 7,6
> oder gar 5 Bits einließt. Das ist ja dieser sogenannte Bit-Slip. Wie
> kann man diesem entgegenwirken bzw. hier müssen ja jetzt die erwähnten
> Synchronpunkte eingebracht werden.

Der muss sowieso erst mal umgebaut werden. Um dir eine "Anschubhilfe" zu 
geben, mach ich mal einen Modulrumpf, den du dann vervollständigen 
kannst.

Lies dir zwischenzeitlich mal die UART-FIFO-Routinen von Peter Danegger 
oder Norbert Fleury durch, insbesondere wie die FIFOs funktionieren. Die 
brauchst du nämlich für die Schnittstelle zum Hauptprogramm.

Grüße

Stefan

von Stefan W. (dl6dx)


Lesenswert?

Rafi Dafi schrieb:
> Der Vorlauf wird mit einem Startbit abgeschlossen und der Anfang der
> Informationswörter eingeleitet.

> Zwischen jedem gesendeten Byte wird ein Sperrbit eingeschoben um die
> Informationswörter von einander zu trennen.

Das fällt mir erst beim zweiten Lesen so richtig auf. Dieses Protokoll 
sieht in der Tat so aus, als ob ein asynchrones Zeichenframing einfach 
auf einen synchron übertragenen Bitstrom "aufgestülpt" worden wäre.

Was um Himmels willen ist das?

Grüße

Stefan

von Rafi D. (alexanderw)


Lesenswert?

Stefan Wagner schrieb:
> Das ist technisch eigentlich unnötig. Steht das in der
> Protokollbeschreibung wirklich explizit so drin?

ja steht es. kann man auch auf dem oszi bild sehen.
Beitrag "Re: TTL Signal Verarbeitung"
schau auf den letzteren teil. da werden 8bit NULLEN gesendet und 
zwischen ihnen das Stop-bit 1.

Stefan Wagner schrieb:
> Was ist das denn nun eigentlich für ein Protokoll? Es wäre wirklich
> hilfreich, wenn du entweder den Namen nennen würdest oder die
> Protokollbeschreibung im Wortlaut zitieren könntest.

Es handelt sich um den Nahverkehr und die Übertragung zwischen Bus und 
Ampel für eine schnellere Grünschaltung.

Gesendet wird mit dem Datenformat 8N1.
Und ja es sind gepackte Felder. Aber die kann man ja anschließend nach 
dem Empfang des Telegramms analysieren und die entsprechende Infos zu 
extrahiern, es geht ja auch darum die Daten erst fehlerfrei einzulesen.

Du hattest ja auch bei dir den Vergleich

Rafi Dafi schrieb:
> else if (bitbuf == FLAG)
>        {

verwendet. Würde es dann so gehen das er bei dem ersten eingelesenen Bit 
dieses auch mit dem ersten des Flags vergleicht. Beim zweiten 
eingelesenen mit dem 2. des Falgs usw.
Müsste ich nicht hier eine Abfrage machen, die jedes Bit auf 
Synchronität prüft?

wenn bitbuffer(1.Bit) == Flag(1.bit), dann Flag>>= 1, dann das nächste 
eingelesene Bit auf gleichheit prüfen usw.
und wenn das bitpuffer == Flag ist dann die nächsten Bytes einfach 
einlesen.

von Stefan W. (dl6dx)


Angehängte Dateien:

Lesenswert?

Rafi Dafi schrieb:
> Es handelt sich um den Nahverkehr und die Übertragung zwischen Bus und
> Ampel für eine schnellere Grünschaltung.

Ich hab mal eben Google angeworfen. Ist das eine VDV-Norm?

> Gesendet wird mit dem Datenformat 8N1.

Damit hätten wir tatsächlich die bizarre Situation, dass auf einen 
bereits bitsynchronen Datenstrom noch ein Framing einer asynchronen 
Übertragung draufgepackt wurde.

 Bei einem echten Framing wie für eine asynchrone Übertragung "8N1" 
müsste ein Startbit (immer 0) vor dem Byte und ein Stopbit (immer 1) 
danach kommen, also 10 Bits. Deine Beschreibung sagt aber nur was von 
einem Stopbit (Trennbit), also müsstest du das noch mal anhand deiner 
beispieldaten (siehe das Oszillogramm) prüfen.

Wenn das klar ist un auch klar ist, ob das Framing im ganzen Telegramm 
so aussieht, muss die Verarbeitung etwas anders aussehen.

Das angehängte Beispiel für einen bitsynchron übertragenen Datenstrom 
ohne zusätzliches Framing müsstest du dann so ändern:

- Das Flag muss eventuell angepasst werden
- In der ISR werden immer 10 (evt nur 9, siehe oben) Bit eingelesen, 
(RX_Bits entsprechend anpassen)
- Die Bits des Framings werden dann einfach "abgeschnitten". Das zuletzt 
empfangene Stopbit wird durch einen Rechtsshift um ein Bit entfernt, das 
Startbit ausmaskiert. ((bitbuf >> 1) & 0xFF)

Grüße

Stefan

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

Rafi Dafi schrieb:
> Es handelt sich um den Nahverkehr und die Übertragung zwischen Bus und
> Ampel für eine schnellere Grünschaltung.

Hm, sowas bräuchte ich manchmal auch ...
wär doch mal eine schöne Bastelei, läßt sich bestimmt auch auf "zwischen 
PKW und Ampel" portieren ;-)

von Rafi D. (alexanderw)


Lesenswert?

Stefan Wagner schrieb:
> Damit hätten wir tatsächlich die bizarre Situation, dass auf einen
> bereits bitsynchronen Datenstrom noch ein Framing einer asynchronen
> Übertragung draufgepackt wurde.

Das versteh ich nicht ganz. Wegen des Sperrbit's wird es zu einer 
asynchronen Übertragung?

von Stefan W. (dl6dx)


Lesenswert?

Stefan Wagner schrieb:
> Damit hätten wir tatsächlich die bizarre Situation, dass auf einen
> bereits bitsynchronen Datenstrom noch ein Framing einer asynchronen
> Übertragung draufgepackt wurde.

Rafi Dafi schrieb:
> Wegen des Sperrbit's wird es zu einer asynchronen Übertragung?

Ja. Eigentlich müsste da auch noch das Startbit herumgeistern.

ich vermute, dass dieses System noch zu Zeiten entworfen wurde, als 
phasenkohärente FSK kein Standard war (kam in D im Datenfunk in den 80er 
Jahren auf). Die damaligen (vergleichsweise einfachen) Modems hatten nur 
einen Eingang bzw. Ausgang für das Datensignal. Man konnte also auch mit 
der Modemstrecke zwei UART verbinden. (Dass das wesentlich schlechter 
funktioniert, als eine phasenkohärente FSK, steht auf einem anderen 
Blatt.)

Zieht man das in Betracht, könnte deine Protokollbeschreibung 
tatsächlich auf dem Output eines UART aufbauen.

Bei der heute verwendeten phasenkohärente FSK gibt das Modem den Bittakt 
vor, man muss also bitsynchron übertragen. Dein Empfänger ist ein 
solches Modem, daher der "seltsame Mischmasch".

Grüße

Stefan

von Rafi D. (alexanderw)


Lesenswert?

Stefan Wagner schrieb:
> Rafi Dafi schrieb:
>> Wegen des Sperrbit's wird es zu einer asynchronen Übertragung?
>
> Ja. Eigentlich müsste da auch noch das Startbit herumgeistern.

Das einzige Startbit ist das LSB-bit des Low-Byte's im Flag. Also die 1 
in 0xFC01.
Das hatte ich nicht erwähnt da es ja sogesagt zum Flag gehört und dann 
wäre es ja noch irreführender.

von Stefan W. (dl6dx)


Lesenswert?

Rafi Dafi schrieb:
> Das einzige Startbit ist das LSB-bit des Low-Byte's im Flag. Also die 1
> in 0xFC01.

Beim asynchronen Framing ist das Startbit aber immer 0, das Stopbit (und 
der Ruhepegel der Strecke) immer 1. Ein 1-Bit kann also kein Startbit 
eines asynchronen Frames (Zeichens) sein. In der Beschreibung passt also 
etwas nicht.

Und es erscheint mir extrem unwahrscheinlich, dass da etwas definiert 
worden ist, das zum Zeitpunkt der Protokolldefinition nur mit extremem 
Aufwand hätte implementiert werden können.

Wenn das Protokoll für eine UART-basierte Hardware entworfen wurde, ist 
als Ruhezustand der Strecke eine kontinuierliche Folge von 1-Bits zu 
erwarten. Die Startbedingung eines Zeichens ist der Wechsel von 1 auf 0 
(das Startbit) und die Endbedingung ist der Rücksprung auf den 1-Pegel 
nach (hier) 8 Datenbits.

Der "Trenner" zwischen zwei Bytes wäre also immer ein 1-Bit gefolgt von 
einem 0-Bit gewesen.

Schau dir die Protokollspezifikation daraufhin noch mal an.

Grüße

Stefan

von Rafi D. (alexanderw)


Lesenswert?

Die Protokollspezifikation ist genauso wie beschrieben.

von Stefan W. (dl6dx)


Lesenswert?

Ok, dann musst du die ungenutzten Trennbits halt "zu Fuß" herausnehmen.

Lies jeweils ein Byte und das nachfolgende Trennbit (also 9 Bit) ein und 
schiebe das Trennbit (das dann LSB in bitbuf ist) nach rechts heraus.

Grüße

Stefan

von Rafi D. (alexanderw)


Angehängte Dateien:

Lesenswert?

Hab einen Code geschrieben, denn ich erst morgen testen kann.
Jedoch wollte ich fragen ob ihn sich jemand angucken könnte um 
eventuelle Fehler aufzudecken.
Vielen Dank.

von Karl H. (kbuchegg)


Lesenswert?

Eine Frage:
Hast du auf dem PC einen C-Compiler zur Verfügung?
(Wenn nicht - warum nicht?)

Denn: Im Grunde sind in deinem Code nur 2 Dinge, die tatsächlich 
AVR-spezifisch sind.
Da ist zum einen die Tatsache, dass die Funktion eine ISR ist, die 
Interrupts also ausgelöst werden müssen.
Und zum anderen fragst du 1 Pin ab.

Das lässt sich aber auch einfach auf dem PC faken. Du gehst ganz einfach 
davon aus, dass die Interrupts ausgelöst werden und ersetzt das durch 
einen Funktionsaufruf aus main. Und den Eingangspin fakest du mit einem 
Array, aus dem das jeweils nächste Bit kommt.
1
...
2
3
unsigned char Bits[] = { 0, 0,
4
                         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5
                         1, 0, 1, 1, 0, 1, 0, 0, 1,
6
                         1, .... };
7
8
int NextBit = 0;
9
10
...
11
12
// ISR(INT0_vect)
13
void Interrupt()
14
{
15
  static uint16_t bitpuffer = 0;
16
  static uint8_t bitzaehler = PUFFERBITS;
17
  static uint8_t InfBytesZaehler = INFBYTES;
18
  static uint8_t tmpBytes = 0;
19
  static bool bytesync = false;
20
  static bool VorlaufFlag = false;
21
  static bool InfBytesFlag = false;
22
23
  bitpuffer <<= 1;
24
25
//  if (PIND & (1<<PD2))    // Bei jeder fallenden Flanke des RxSync wird Pin D2 ausgelesen
26
    if (Bits[NextBit++])
27
      ...
28
29
30
31
32
int main()
33
{
34
  while( 1 ) {
35
    Interrupt();     // simulierter Interrupt Aufruf
36
37
    // FIFO auswerten oder woran du eben sonst erkennst, dass
38
    // ein Byte vorhanden ist und dieses dann ausgeben
39
    ...
40
  }
41
}

D.h. da eine rudimentäre Testumgebung aufzubauen, mit der man diese 
Funktionalität auch ohne reale Hardware testen kann, ist kein 
allzugroßer Aufwand. Dann kannst du das heute noch testen und hast den 
Vorteil, dass die Debug-Umgebung auf einem PC normalerweise wesentlich 
besser ist, als das was du auf dem AVR vorfindest.

Und morgen, wenn du auf die reale Hardware gehst, weißt du dann schon 
mit Sicherheit, dass deine Bitauswertung und Zusammenfassung zu Bytes, 
das Erkennen des Vorlaufs, etc. auf jeden Fall schon mal funktioniert.


Wenns um Algorithmen geht, die eigentlich nicht wirklich von der 
AVR-Hardware abhängen, wie zb hier bei dir das Zusammenfassen von Bits 
zu Bytes, dann mach ich gerne einen Test am PC, eben weil das da 
einfacher zu testen ist und ich leicht eine immer gleichbleibende 
Testumgebung zur Verfügung stellen kann. Inklusive eines 
kontrollierbaren, reproduzierbaren Inputs in den Algorithmus. Denn: 
Reproduzierbarkeit ist das A und O beim Debuggen.

von Erich (Gast)


Lesenswert?

>Das lässt sich aber auch einfach auf dem PC faken.

Eine etwas merkwürdige Bezeichnung.
Üblicherweise nennt sich das "stub".

http://de.wikipedia.org/wiki/Stub_%28Programmierung%29

Das ist Standard in der (professionellen) SW Entwicklung vom embedded 
Systemen.

GOOGLE:   stub "embedded software"
          stub "embedded software" Modultest
ggf. mit Einschränkung <Seiten auf deutsch>

Gruss

von Karl H. (kbuchegg)


Lesenswert?

Erich schrieb:
>>Das lässt sich aber auch einfach auf dem PC faken.
>
> Eine etwas merkwürdige Bezeichnung.
> Üblicherweise nennt sich das "stub".

:-)
Auch recht.

wieder was gelernt.

von Rafi D. (alexanderw)


Lesenswert?

C-Compiler hab ich hier nicht drauf. Noch nicht. Das ändert sich aber 
heute abend und dann werde ich es testen.
Danke für den Vorschlag.
Mir fällt auf Anhieb DevC++ ein. Wenn es etwas besseres bzw. 
Verständlicheres als freeware gibt dann bin ich für diese Info dankbar.

MFG Rafi

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.