Forum: Mikrocontroller und Digitale Elektronik Pausen-Problem


von Tommy (Gast)


Lesenswert?

Hallo zusammen,
habe folgendes Problem!
Ich möchte eine 1 Wire Kommunikation zwischen einem Maxim-Baustein und 
einem uc herstellen. Meinen Takt erhalte ich durch einen 4MHz Quarz. Ich 
brauche eine genaue Pause von einer us. Jedoch scheinen die delay 
Funktionnen nicht genau genug zu sein. Kann mir jemand einen Tipp geben, 
wie ich eine us Sekundenpause in C realsieren kann?
Vielen Dank im voraus

von Tom (Gast)


Lesenswert?

Wie wärs mit einem Timer ?

von Mat (Gast)


Lesenswert?

4 "Nops" machen ...

von Tommy (Gast)


Lesenswert?

Was ist denn ein nop? Bin noch Anfänger!

von Random .. (thorstendb) Benutzerseite


Lesenswert?

__asm("nop"); (genaue gcc syntax hab ich gerad nicht im kopf) macht 
einen Prozessortakt lang rein gar nix.

Muss man in C als inline-assembler oder asm func. einbinden. Einige 
Compiler haben auch intrinsics dafür (z.B. __nop(); ).


VG,
/th.

von Mat (Gast)


Lesenswert?

ein No-Operation Befehl, d.h. dass dein uC genau ein Takt lang nichts 
macht (sofern du ein AVR verwendest), wenn du bei 4MHz 4 Takte lang 
nichts machst, hast du genau eine usec gewartet.
Befehl: _NOP()

von Schwupps (Gast)


Lesenswert?

NOP = No OPeration (http://de.wikipedia.org/wiki/NOP)

NOP ist ein Assembler Befehl, der genau einen Takt lang nichts macht.
Bei deinem Takt musst du 4 NOPs machen.

von Tommy (Gast)


Lesenswert?

okay, dann würde ja dann folgendes bedeuten:
1
#define nop() asm volatile("nop")
2
3
DDRA|=(1<<PA0);
4
while(1)
5
{
6
PORTA|=(1<<PA0);
7
nop();
8
nop();
9
nop();
10
nop();
11
PORTA&=~(1<<PA0);
12
nop();
13
nop();
14
nop();
15
nop();
16
}

Jetzt müsste doch eigentlich abwechselnd der PIN A0 eine us high und 
dann low gehen oder?

von Mat (Gast)


Lesenswert?

das setzen und löschen braucht auch noch seine Zeit ...

von Peter (Gast)


Lesenswert?

> das setzen und löschen braucht auch noch seine Zeit ...
und das while auch, wenn du es ganz genau machen willst/muss wirst musst 
du dir den erzeugen asm-code anschauen und bei jedem Befehl die Takte 
ermitteln.

ich denke erst 3 nops und dann 2 nops  sind näher dran.

von Peter D. (peda)


Lesenswert?

Tommy schrieb:
> Jetzt müsste doch eigentlich abwechselnd der PIN A0 eine us high und
> dann low gehen oder?

Du hast das Prinzip des 1w nicht verstanden.
Der Pin darf nur zwischen low und tristate wechseln.
High ist verboten!

Nimm die Delayfunktion, die ist sehr genau.
Aber Genauigkeit brauchst Du nicht bei 1w.
Hauptsache es stören keine Interrupts.


Peter

von Tommy (Gast)


Lesenswert?

ja, so muss es sein, da die Zeit nicht bei mir stimmt! Wie soll man denn 
dann das Timing genau hinbekommen?

von Hannes L. (hannes)


Lesenswert?

Ganz ohne ASM-Verständnis wird's nicht gehen.

...

von Karl H. (kbuchegg)


Lesenswert?

Die Frage ist: Wie genau muss es denn sein?

Die wenigsten Bausteine sind so heikel, dass 1µs ganz exakt stimmen 
muss. Normalerweise hat man da einen großen Spielraum. Gerade bei so 
kleinen Zeiten.

von Mat (Gast)


Lesenswert?

Port setzen alleine braucht ja z.b. schon 3 Takte ...
- Port einlesen
- Bit(s) ändern
- Port schreiben

von Tommy (Gast)


Lesenswert?

Achso heisst das dann, dass ich den PORTA auf low setze und dann nur 
noch mit dem Datenregister schalte? DDRA|=(1<<PA0) ist gleich setzen und 
DDRA&=~(1<<PA0) ist gleich empfangen? Stimmt das dann?

von Peter D. (peda)


Lesenswert?

Tommy schrieb:
> ja, so muss es sein, da die Zeit nicht bei mir stimmt! Wie soll man denn
> dann das Timing genau hinbekommen?

Wie schon gesagt, das ist unnötig.
Schau Dir mal die Timings genau an, Du hast immer einen Spielraum von 
1:4.


Peter

von Peter (Gast)


Lesenswert?

@Mat
> Port setzen alleine braucht ja z.b. schon 3 Takte ...
> - Port einlesen
> - Bit(s) ändern
> - Port schreiben

zum Glück gibt es ein ASM-Befehl der das Setzen eines Bits direkt 
übernimmt.
Dafür muss nichts gelesen werden.

von Mat (Gast)


Lesenswert?

>@Mat
>> Port setzen alleine braucht ja z.b. schon 3 Takte ...
>> - Port einlesen
>> - Bit(s) ändern
>> - Port schreiben

>zum Glück gibt es ein ASM-Befehl der das Setzen eines Bits direkt
>übernimmt.
>Dafür muss nichts gelesen werden.

hmm, kenn ich gar nicht, dachte immer es kann nur Byteweise gearbeitet 
werden.

von Stefan M. (celmascant)


Lesenswert?

Wenn du einen schnelleren Quarz nimmst, kannst du die Zeiten genauer 
einhalten. Bei 4 Takten Pause für 1µs Wartezeit hast du bei einem Takt 
zu früh oder zu spät schon +/-25% Abweichung des Timings!
Bei einem doppelt so schnellen Quarz sind es immernoch 12,5%.

Befasse dich mal damit wie eine Warteschleife in Assembler aufgebaut ist 
und schau dir an wie lange die Befehle brauchen.
Du wirst schnell feststellen, das mit 4 Befehlen Pause eine 
Warteschleife schlecht ist. Da musst du dann wirklich den Code an der 
Stelle optimieren, damit du das Timing einhalten kannst.

Also mein Tip: auf ASM-Basis optimieren und/oder schnellerer Quarz für 
mehr Spielraum.

@ Karl heinz Buchegger:
Ja, gute Frage. Wie genau muss denn typischerweise das Timing beim 1wire 
eingehalten werden? Ich könnte mir vorstellen, das 25% Abweichung schon 
zu viel sind.

Gruss Stefan

von Tommy (Gast)


Lesenswert?

Also laut den Timings habe ich genug Zeit jedoch habe ich es noch nicht 
ganz mit dem Richtungsregister verstanden.
Ich habe den Maximbaustein mit einem Pull up Widerstand am Pin PA0 
angeschlossen. Jetzt will ich einfach erstmal nur ein Reset auslösen.
Das heisst, die Leitung muss 480 us auf low und dann 120 us auf high 
gezogen werden. Danch liest man den PIN aus! Und wenn ich das jetzt 
richitg verstanden habe muss das mit dem Richtungsregister gemacht 
werden und nicht mit dem Portregister, ist das richtig?

von Peter D. (peda)


Lesenswert?

Tommy schrieb:
> Achso heisst das dann, dass ich den PORTA auf low setze und dann nur
> noch mit dem Datenregister schalte? DDRA|=(1<<PA0) ist gleich setzen und
> DDRA&=~(1<<PA0) ist gleich empfangen? Stimmt das dann?

Ja.

Schau einfach mal hier:

Beitrag "DS1820, DS18B20 in C"

Da hatte ich die Delayfunktion selber geschrieben, da damals der AVR-GCC 
noch nicht so weit war.

Die 15µs sollte man nicht so ausreizen (10µs ist besser).


Peter

von Stefan M. (celmascant)


Lesenswert?

Ja, du darfst eben nicht High-Low umschalten, sondern nur TriState-Low.
Das heisst du musst den Pin auf Eingang ohne Pull-up schalten für 
Tri-State.
Low sollte ja klar sein^^

@ Mat: Bei den meisten MC's gibts im Datenblatt ein paar Seiten die mit 
Instruction-Set betitelt sind^^ Da sind alle Befehle aufgelistet...

von Tommy (Gast)


Lesenswert?

vielen Dank! schaue es mir gleich mal an!

von Karl H. (kbuchegg)


Lesenswert?

Mat schrieb:
>>@Mat
>>> Port setzen alleine braucht ja z.b. schon 3 Takte ...
>>> - Port einlesen
>>> - Bit(s) ändern
>>> - Port schreiben
>
>>zum Glück gibt es ein ASM-Befehl der das Setzen eines Bits direkt
>>übernimmt.
>>Dafür muss nichts gelesen werden.
>
> hmm, kenn ich gar nicht, dachte immer es kann nur Byteweise gearbeitet
> werden.

Aber dein Compiler kennt die Befehle zum Glück.

von Tommy (Gast)


Lesenswert?

Peter kannst du mir noch eine Frage beantworten?
Ich verstehe es immer noch nicht mit dem Reset! Ich bin jetzt soweit, 
dass ich glaube, das es Hardwaremäßig funktioniert. Ich sehe auf meinem 
Oszi mein low setzen, dann wieder high setzen und danach das Antworten 
des Bausteins.
Aber was ich nicht verstehe ist folgendes. Um eine Bestätigung zu 
erhalten, das der Baustein bereit ist, müsste der PIN doch low sein, da 
ja der Baustein die Leitung runterzieht! Oder wartet man die 
Resetprozedur komplett ab und wenn dann am ausgelesenen PIN high anliegt 
ist alles in Ordnung? Aber dann würde man doch auch ein OKAY kriegen, 
wenn überhaupt kein Baustein dran ist, da die Leitung ja high aktiv ist!

von Karl H. (kbuchegg)


Lesenswert?

Tommy schrieb:

> Aber was ich nicht verstehe ist folgendes. Um eine Bestätigung zu
> erhalten, das der Baustein bereit ist, müsste der PIN doch low sein, da
> ja der Baustein die Leitung runterzieht! Oder wartet man die
> Resetprozedur komplett ab und wenn dann am ausgelesenen PIN high anliegt
> ist alles in Ordnung?

Das Datenblatt sagt dir, wie lange es dauert bis der Baustein anfängt 
den Pin auf Low zu ziehen. Und es sagt dir auch, wie lange der Baustein 
die Leitung auf Low ziehen wird, ehe er wieder loslässt. Du nimmst dir 
jetzt einen Zeitpunkt irgendwo in der Mitte und siehst nach, ob die 
Leitung tatsächlich Low ist.
Dann wartest du die Restzeit ab und siehst nach ob die Leitung wieder 
High ist (nur zur Sicherheit, ob auch der Pullup Widerstand tatsächlich 
drann ist :-)

> Aber dann würde man doch auch ein OKAY kriegen,
> wenn überhaupt kein Baustein dran ist, da die Leitung ja high aktiv ist!

Nicht wenn du forderst, dass dein erstes Nachsehen, mitten im 
Zeitfenster des Bausteins, ein Low ergeben muss und die Leitung nach 
Ablauf der Zeit wieder High sein muss.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Ich sehe auf meinem Oszi mein low setzen, dann wieder high setzen
Immer noch nicht verstanden :-/
Zitat:
>> Peter Dannegger schrieb:
>>> Du hast das Prinzip des 1w nicht verstanden.
>>> Der Pin darf nur zwischen low und tristate wechseln.
>>> High ist verboten!

1) du schreibst in das Port-Register für den 1-Wire eine 0.
2) du schaltest nur noch mit dem Richtungsregister
   zwischen Ein- und Ausgang um.
   Eingang = Hochohmig
   Ausgang = Aktive 0

Du gibst aber niemals eine aktive 1 aus.

von Karl H. (kbuchegg)


Lesenswert?

Lothar Miller schrieb:
>> Ich sehe auf meinem Oszi mein low setzen, dann wieder high setzen
> Immer noch nicht verstanden :-/
> Zitat:
>>> Peter Dannegger schrieb:
>>>> Du hast das Prinzip des 1w nicht verstanden.
>>>> Der Pin darf nur zwischen low und tristate wechseln.
>>>> High ist verboten!
>
> 1) du schreibst in das Port-Register für den 1-Wire eine 0.
> 2) du schaltest nur noch mit dem Richtungsregister
>    zwischen Ein- und Ausgang um.
>    Eingang = Hochohmig
>    Ausgang = Aktive 0
>
> Du gibst aber niemals eine aktive 1 aus.

Oder um es noch deutlicher zu sagen:
Eine 1 auf der Leitung entsteht dadurch, dass der Pullup Widerstand die 
Leitung auf High zieht. Er und nur er alleine sorgt für die 1. Sind alle 
Teilnehmer am Bus auf Eingang geschaltet (=Tristate), dann hat die 
Leitung 1 Pegel. Will ein Teilnehmer die Leitung auf 0 ziehen, dann 
schaltet er seinen Pin auf Ausgang und zieht die Leitung runter. Will er 
die Leitung wieder zurück auf 1, dann geht er wieder auf Eingang und der 
Pullup zieht die Leitung wieder hoch. Auf die Art kann es nie passieren, 
dass 2 Ausgänge gegeneinander arbeiten.

von Tommy (Gast)


Lesenswert?

Verstehe!
Kann es sein das manche Application Notes manch mal für den A.... sind?
Für mein Baustein gibt es folgende App Note (für Reset z.B.)
1
int Reset(void)
2
{
3
    int result;
4
    
5
    outp(PORTADDRESS,0x00); //Drives DQ low
6
    Waitx(480);  //480us
7
    outp(PORTADDRESS,0x01); //Releases the bus
8
    Waitx/(120);
9
10
    //Sample and return the Presence Detect
11
    result = inp(PORTADRRESS) & 0x01;
12
    Waitx(360);
13
14
    return result;
15
}

Doch wenn ich das so Programmiere ist result immer bei mir 1, da dort 
die Leitung gerade wieder hoch gegangen ist!

von Karl H. (kbuchegg)


Lesenswert?

Tommy schrieb:
> Doch wenn ich das so Programmiere ist result immer bei mir 1, da dort
> die Leitung gerade wieder hoch gegangen ist!

Dann sind wahrscheinlich die 120 ein klein wenig zu lang. Geh auf 100 
und dafür die 360 auf 380 (weil 100+380 gleich 480) Was sagt denn das 
Datenblatt über das Timing?

von Tommy (Gast)


Lesenswert?

Ich verstehe nicht, warum sie das dann so knapp kalkuliert haben! Würde 
man nur 100 us warten, würde es dicke reichen. Oder hat das einen 
anderen Grund?

von Karl H. (kbuchegg)


Lesenswert?

Tommy schrieb:
> Ich verstehe nicht, warum sie das dann so knapp kalkuliert haben! Würde
> man nur 100 us warten, würde es dicke reichen. Oder hat das einen
> anderen Grund?

Keine Ahnung.
PeDa wartet in seinem Beispiel (DS1820) nur 66µs (für die krummen 66 
gibt es sicherlich einen guten Grund). Also noch kürzer.
Und er sieht nach Ablauf der Zeit auch noch nach, ob die Leitung wieder 
auf High gegangen ist :-)

Im Zweifel würde ich eher PeDa trauen als einem Datenblatt :-)

von Tommy (Gast)


Lesenswert?

Ja wenn ich es so mache dann klappt es ohne Probleme!

von Tommy (Gast)


Lesenswert?

Verstehe!!
Gut werde mich jetzt mal ans Write und Read begeben!
Mal gucken ob ich es jetzt hin bekomme

von Peter D. (peda)


Lesenswert?

Karl heinz Buchegger schrieb:
> PeDa wartet in seinem Beispiel (DS1820) nur 66µs (für die krummen 66
> gibt es sicherlich einen guten Grund).

Der Presence-Puls beginnt nach 15-60µs und dauert 60-240µs
(DS18B20, S.15, Figure 13. Initialization Timing).

D.h. er beginnt spätestens nach 60µs und endet frühestens nach 75µs.
Die Mitte ist 67µs, noch 1µs für Programmlaufzeiten abgezogen = 66µs.


Peter

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Kann es sein das manche Application Notes manch mal für den A.... sind?
> Für mein Baustein gibt es folgende App Note (für Reset z.B.) ...
Ja, aber für welchen Prozessor? Ist das u.U. ein 8051-Derivat?
Die können gar keine aktive '1' ausgeben   :-o
Bei denen gilt: entwder Low oder Pullup (30k).

> Im Zweifel würde ich eher PeDa trauen als einem Datenblatt :-)
Es ist gar nicht das DB, das diesen Pseudo-Fehler enthält.
Es ist eine AppNote   ;-)

von Tommy (Gast)


Lesenswert?

Hallo zusammen,
habe es jetzt soweit, das die  64 bit Net Adresse vom Maxim Baustein 
ausgegeben wird. Wie wäre es jetzt am besten die Zahl zu speichern? Im 
Moment bekomme ich nur die Bitfolge. Oder ist es am besten die Zahl in 
einem array abzulegen?

von Karl H. (kbuchegg)


Lesenswert?

Tommy schrieb:
> Hallo zusammen,
> habe es jetzt soweit, das die  64 bit Net Adresse vom Maxim Baustein
> ausgegeben wird. Wie wäre es jetzt am besten die Zahl zu speichern? Im
> Moment bekomme ich nur die Bitfolge. Oder ist es am besten die Zahl in
> einem array abzulegen?

Ich kann nur wieder die Empfehlung von weiter oben wiederholen: Sieh dir 
das DS1820 Beispiel vom PeDa an. Da findest du so mancherlei, was dir 
deine Fragen beantwortet.

von Tommy (Gast)


Lesenswert?

Peter Danneggers Beispiel hat mir sehr fürs Verständnis geholfen. 
Dadurch habe ich das Reset & Write verstanden, auch die einzelnen Bis 
auslesen habe ich verstanden, aber dann hörts mit dem Verständnis auf! 
Seine read Funktion verstehe ich nicht!

von Karl H. (kbuchegg)


Lesenswert?

Du kannst dir ja bei ihm zb. einmal ansehen, was er mit der Id vom 
Baustein macht. Wie er sie speichert, wie er sie weiterbenutzt etc.

von Tommy (Gast)


Lesenswert?

Aber genau darin besteht das Problem! Ich kann das nicht ganz ersehen! 
So wie ich das verstehe, würde ich jetzt einen array von uint8_t 
anlegen, und dort die Oktetts ablegen.
Bei mir würde das bedeuten:
Ich würde die 64 Bitfolge in 8 Oketetts wandeln und diese in einem Array 
ablegen. Dann würde ich bei Bedarf z.B. CRC check die dementsprechene 
Bitefolge rausnehmen und weiterverarbeiten. Jedoch bin ich mir nciht 
sicher, ob er das so gemacht hat!

von Karl H. (kbuchegg)


Lesenswert?

Tommy schrieb:
> Aber genau darin besteht das Problem! Ich kann das nicht ganz ersehen!
> So wie ich das verstehe, würde ich jetzt einen array von uint8_t
> anlegen, und dort die Oktetts ablegen.
> Bei mir würde das bedeuten:
> Ich würde die 64 Bitfolge in 8 Oketetts wandeln

Genau das macht eine der Routinen auf unterster Ebene.
8 Bits empfangen, in ein Byte (aka uint8_t) zusammenschieben und 
zurückgeben.
Darüberliegende Softwareschichten arbeiten nur noch mit Bytes und nicht 
mit einzelnen Bits.

Da gibt es die Funktion w1_bit_io. Die bringt 1 Bit auf den Weg, bzw. 
empfängt eines. Benutzt wird sie in w1_byte_wr (was werden wohl die 
ganzen 8-er in dieser Funktion sein?). Alles ausserhalb 1wire.c benutzt 
nur noch die w1_byte_wr.
Einzige Ausnahme ist die rom_search Funktion. Die arbeitet noch auf 
Bitebene. Aber das auch nur, weil sie bei mehreren Geräten die 
Buskollisionen auseinanderklamüsern muss und das geht auf Bytebene nicht 
mehr. Aber sobald die Ids aller Geräte feststehen, arbeitet alles nur 
noch auf Bytebene.

von Tommy (Gast)


Lesenswert?

Ah, okay!
Ich hätte da noch ne wahrscheinlich blöde Frage! Ist es eigentlich nötig 
den CRC check zu machen, wenn eh nur ein Baustein dran ist? So wie es 
bei mir aussieht kippt da kein Bit zufällig um! Oder ist es Standart, 
dass man immer den CRC nachprüft!

von Karl H. (kbuchegg)


Lesenswert?

Die Frage ist:
Wieviel Laufzeit kostet dir die CRC Prüfung (im Vergleich zum restlichen 
Program, hast du die Zeit)?
Was passiert, wenn sich ungültige Daten durchmogeln?
(Wenn eine Thermometer-Anzeige deswegen falsch anzeigt ist das eine 
Sache. Wenn dadurch aber der Ölbrenner die ganze Nacht lang durchfeuert, 
ist das eine ganz andere Sache)

Letztenendes kann dir niemand vorschreiben, ob du die Prüfung machst 
oder nicht. Aber Programmierer fürchten nichts so sehr, wie falsche 
Eingangsdaten in ihre Algorithmen. Denn die haben sie nicht unter 
Kontrolle.

von Tommy (Gast)


Lesenswert?

Hab's verstanden,
dann werde ich mir mal anschauen wie man so einen CRC check macht!

von Peter D. (peda)


Lesenswert?

Tommy schrieb:
> dann werde ich mir mal anschauen wie man so einen CRC check macht!

Im einfachsten Fall nimm _crc_ibutton_update aus der crc16.h.


Peter

von Tommy (Gast)


Lesenswert?

Ich brauch den 8 bit CRC check! Den du meinst ist doch ein 16 Bit CRC 
check, oder?

von Tommy (Gast)


Lesenswert?

Ich würde gerne den CRC check richtig verstehen, aber iregendwie werde 
ich aus der App Note 27 nicht richtig schlau!
Wenn ich das richtig verstanden habe, ist das Generatorplynom 
x^8+x^5+x4+1, sprich: 10011001. Hoffe das ist soweit schon mal richtig.
Jetzt mache ich mit den empfangenen Daten und dem Generatorpolynom eine 
XOR Verknüpfung und wenn am Ende (alle empfangenen Daten inklusive der 
Pruefsumme) kein Rest bleibt, dann ist kein Fehler aufgetreten.
Ist das so richtig?

von Tommy (Gast)


Lesenswert?

Ich hätte da noch eine Frage,
Wenn die Net Addresse z.B. 8C00001221749830 lautet
Dann ist doch 8C die Prüfsumme und 30 der Family Code.
Wenn ich jetzt den CRC check machen will, muß ich dann die Inputdaten 
umdrehen?
In diesem Fall beginnend mit 4 Nullen die würden dann wegfallen!
Bei der ersten 1 würde ich dann anfangen zu rechnen!
Kann mir da jemand helfen?

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.