DS18B20 1-Wire Implementierung - Timing-Probleme

#6360244
Lesenswert?

Ich hab die letzten Stunden versucht, das 1-Wire Protokoll anhand des 
DS18B20-Datenblatts auf einem STM32F103C8 zu implementieren.

Dafür hab ich C mit IAR bzw. Keil µVision verwendet (Test-Versionen). 
Zum finden von Fehlern hab ich den Debugger mit einem ST-Link V2 sowie 
einem Logik-Analyzer verwendet.

Ich bin nun an einem recht frustrierten Punkt: Ich kann zwar den 
internen 64-bit ROM-Code auslesen (bzw. das was mir der Logic-Analyzer 
anzeigt sieht gut aus) - allerdings werden einzelne Bits falsch 
eingelesen (obwohl im Logic Analyzer alle 1er Bits bzw. 0er Bits 
identisch aussehen), deswegen stimmt auch die CRC-Summe am Ende des 
ROM-Codes nicht mit der im Programm berechneten überein (meine 
CRC-Implementierung ist nach einem Vergleich mit der AppNote von Maxim 
korrekt).

Ich hab für das Testen extra Compiler-Optimierungen ausgestellt da sowas 
natürlich gerne Timing-Probleme verursacht. Als es dann gar nicht 
klappen wollte, hab ich bei IAR die Optimierungen auf "Niedrig" 
eingestellt - dann wurde der ROM-Code korrekt ausgelesen.

Interessanterweise kommen Keil und IAR bei Optimierungsstufe "0" zu 
unterschiedlichen Werten beim ROM-Code. Mit Keil klappt das korrekte 
Auslesen gar nicht. Und meiner Ansicht nach bin ich innerhalb der 
Spezifikation und relativ weit vom kritischen Bereich entfernt (aus 
64-Bit werden ja 63 oder 62 korrekt gelesen).

Daher meine Frage: Macht es überhaupt Sinn, so etwas wie 1-Wire in C zu 
implementieren? Oder sollte man es in Assembler machen? Wobei ich auf 
ARM-Assembler nicht wirklich groß Lust habe.

Ich hatte beruflich schonmal mit 1-Wire zu tun und weiß nicht, wer sich 
dieses Teufelszeug hat einfallen lassen.
#6360263
Lesenswert?

Max M. schrieb:
> Macht man sowas lieber mit Timer-Interrupts?

Innerhalb eines Bits nicht. Darüber hinaus kann man, muss man nicht.

> Wobei es dann je nach Zustand unterschiedlich lange dauert bis man sich
> durch die State-Machine durchgehangelt hat.

Es klingt ein wenig danach, als ob du dir das Leben schwerer machst als 
nötig. Das einzig wirklich interessante Timing ist das eines einzelnen 
Bits.
#6360302
Lesenswert?

Schlaumaier schrieb:
> Auf einen Arduino-nano (mit 1-Wire-Lib) funktioniert das prima. Man muss
> für ein brauchbares Ergebnis nur den Mittelwert aus 10 Abfragen nehmen.

Wenn die Werte einzelner Messungen derart differieren, dass man mitteln 
muss, ist irgendwas falsch. Jene DS18B20, mit denen ich bisher zu tun 
hatte, differieren bei aufeinanderfolgenden Messungen praktisch nicht.
#6360339
Lesenswert?

Max M. schrieb:
> A. K. schrieb:
>> differieren bei aufeinanderfolgenden Messungen praktisch nicht.
>
> Außer es gibt Übertragungsprobleme und man überprüft die CRC-Summe
> nicht: http://www.blog.pyoung.net/2015/01/28/ds18b20-crc-check-codes/

Dann ist, wie ich schrieb
> irgendwas falsch.
denn erst die CRC weglassen und dann deshalb mitteln ist eindeutig der 
falsche Weg. Wobei die Leitung nicht sonderlich anspruchvoll ist. Ich 
habe zig Meter quer durchs ganze Haus liegen, extrem simple 
Drillingsleitung, und CRC-Fehler sind trotzdem selten.
#6360515
Lesenswert?

Ist das eine gute Idee, das so zu machen?

Timer2-Initialisierung:
1
  /* Enable Clock for Timer 2 */
2
  RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
3

4
  /* Set Timer 2 Prescaler Value */
5
  TIM2->PSC = 0;
6

7
  /* Set Timer 2 Auto Reload Value */
8
  TIM2->ARR = 0xFFFF;
9

10
  /* Disable Update */
11
  TIM2->CR1 |= TIM_CR1_UDIS;

Bei 72MHz mit Prescaler '1' kann man sich dann die nötigen Delays 
ausrechnen.

Beim Starten der Kommunikation funktioniert das noch:
1
  /* Enable Timer 2 */
2
  TIM2->CR1 |= TIM_CR1_CEN;
3

4
  setWriteMode();
5

6
  /* Begin Master Tx Reset Pulse By Pulling 1-Wire Line Low */
7
  GPIOC->ODR &= ~GPIO_ODR_ODR14;
8
  
9
  /* Wait 480µs */
10
  TIM2->CNT = 0;
11
  while( TIM2->CNT < 34560 ) { ; }
12
  TIM2->CNT = 0;
13
  
14
  /* End Master Tx Reset Pulse By Releasing 1-Wire Line */
15
  GPIOC->ODR |= GPIO_ODR_ODR14;
16

17
  setReadMode();
18

19
  /* Let DS18B20 Delay Time Elapse */
20
  while( TIM2->CNT < 4320 ) { ; }
21
  TIM2->CNT = 0;
22

23
  /* 1-Wire Should Definitely Be Low Now */
24
  const bool is_low = !( ( GPIOC->IDR & GPIO_IDR_IDR14 ) >> 14 );
25

26
  /* Rx Pulse Of DS18B20 Needs To Be At Least 480µs long */
27
  while( TIM2->CNT < 30240 ) { ; }
28
  
29
  /* Disable Timer 2 */
30
  TIM2->CR1 &= ~TIM_CR1_CEN;

Beim Schreiben einer '0' bekomme ich anstatt des erwarteten 60µs Delays 
jedoch 150µs:
1
  /* Begin Write 0 Slot By Pulling 1-Wire Line Low */
2
  GPIOC->ODR &= ~GPIO_ODR_ODR14;
3

4
  /* Wait 60µs */
5
  TIM2->CNT = 0;
6
  while( TIM2->CNT < 4320 ) { ; }
7

8
  /* Release 1-Wire Line */
9
  GPIOC->ODR |= GPIO_ODR_ODR14;

Irgendwas über den Timer schein ich übersehen zu haben. Eventuell kann 
man das CNT-Register nicht einfach so on-the-fly setzen?
#6360657
Lesenswert?

Versuche mal den Prescaler auf 72 zu setzen. Dann wird der Timer jede 
1µs aufgerufen. So bleiben wenigstens ein paar Takte für das Programm 
übrig.

Bei einem Prescaler von 1 bleiben für das Hauptprogramm keine Takte 
übrig.  Man muss Timerinterups auslassen. Das erklärt die starke 
Abweichung zum errechneten Wert. Fast jeder zweite Timerinterupt muss 
ausgelassen werden.

Ein paar Grundlagen in die Arbeitsweise von Mikroprozessoren würden dir 
sicher gut tun. Wozu so ein Takt wohl gut ist?  Kann es sein, dass ein 
Prozessor Befehl ein oder mehrere Takte benötigt um abgeschlossen zu 
werden? Und was mag wohl passieren, wenn ich zu jedem Takt ein Interrupt 
auslöse um das Hauptprogramm zu unterbrechen?
#6360745
Lesenswert?

Max M. schrieb:
> Ich hab für das Testen extra Compiler-Optimierungen ausgestellt da sowas
> natürlich gerne Timing-Probleme verursacht.

Das Gegenteil ist der Fall, ohne Optimierung kann die Codelaufzeit 
deutliche Timingfehler verursachen.
Also bei kritischen Timings immer mit Speedoptimierung compilieren.
Ein Timer ist außerdem keine schlechte Idee. Bei kleinem CPU-Takt kann 
es trotzdem notwendig sein, eine Delaylib zu verwenden.
Hier mal ein Beispiel für den AVR:
Beitrag "DS18B20 mit Interrupt, AVR-GCC"
#6360853
Lesenswert?

Uwe K. schrieb:
> Bei einem Prescaler von 1 bleiben für das Hauptprogramm keine Takte
> übrig.

Warum? Der Timer läuft unabhängig von der CPU.

Uwe K. schrieb:
> Das erklärt die starke
> Abweichung zum errechneten Wert. Fast jeder zweite Timerinterupt muss
> ausgelassen werden.

Interrupts sind nicht aktiviert.

Uwe K. schrieb:
> Kann es sein, dass ein
> Prozessor Befehl ein oder mehrere Takte benötigt um abgeschlossen zu
> werden?

Ja, natürlich. Eine Abweichung von ~5µs hätte ich noch verstanden da die 
CPU ggf. den exakten Timerwert verpasst und danach natürlich noch den 
Pin up bzw. low schalten muss.

Uwe K. schrieb:
> und was mag wohl passieren, wenn ich zu jedem Takt ein Interrupt
> auslöse um das Hauptprogramm zu unterbrechen?

Mach ich nicht (oder ich hab grob was übersehen)?
Moderator (Firma: Titel) Persönliche Seite #6360929
Lesenswert?

Max M. schrieb:
> Daher meine Frage: Macht es überhaupt Sinn, so etwas wie 1-Wire in C zu
> implementieren?
OneWire ist eigentlich ziemlich simpel, weil der Start eines Bits vom µC 
festgelegt wird und dann nur noch die Dauer des nachfolgenden Low-Pegels 
gemessen werden muss.
Und C ist ziemlich deterministich: das Programm macht "eigentlich" bei 
jedem Durchlauf jedesmal das Selbe. So ist es auch beim Assembler (man 
kann sich ja ohne Probleme mal den Assemblercode des C-Compilers 
ansehen). Insofern macht er prinzipiell keinen Unterschied ob C oder 
Assembler.
Und wenn man einen grundlegenden Fehler im Design hat, dann hat der 
nichts mit der Programmiersprache zu tun...

Max M. schrieb:
> Mach ich nicht (oder ich hab grob was übersehen)?
Setzt mal direkt vor dem Einlesen des OneWire-Signals einen Portpin und 
gleich danach wieder zurück. Sieh dir diesen Einlesezeitpunkt im Bezug 
zum OneWire-Signal an. "Triffst" du beim Einlesen immer den richtigen 
Punkt?
Gast #6360930
Lesenswert?

Max M. schrieb:
> Daher meine Frage: Macht es überhaupt Sinn, so etwas wie 1-Wire in C zu
> implementieren?

Eigentlich unproblematisch. Das haben nämlich schon Leute vor dir 
geschafft. Es gibt die STM32 tauglichen Arduino-Libs für OneWire und 
DS1820.
Du musst halt nur noch etwas programmieren lernen, dann kriegst du das 
auch hin. Optimierungen entfernen manchmal code, den man zu 
timing-Zwecken hingeschrieben hat, oder sortieren code um, wenn man die 
Reihenfolge nicht erzwingt.
Beim STM stört die lose Kopplung des Timings von I/O vs. CPU abe das 
versuchst du ja durch Timerabfragen zu kompensieren. Interessant wird 
OneWire, wenn Interrupts reinhauen und dein Timing zerstören oder gar 
die I/O manipulieren.
Andererseits hat man nicht immer die Zeit, die 3ms die Interrupts zu 
sperren, die das Auslesen des DS1820 dauert.
#6361014
Lesenswert?

Ist es normal, dass
1
  /* Begin Write 0 Slot By Pulling 1-Wire Line Low */
2
  GPIOC->ODR &= ~GPIO_ODR_ODR14;
3

4
  /* Release 1-Wire Line */
5
  GPIOC->ODR |= GPIO_ODR_ODR14;

5.5µs benötigt? Liegt vermutlich am Open-Drain Ausgang, aber dass das so 
lange dauert? Damit könnte man kein I²C mit 400kHz implementieren.
Beitrag #6361040 wurde von einem Moderator gelöscht.
#6361046
Lesenswert?

Max M. schrieb:
> 5.5µs benötigt? Liegt vermutlich am Open-Drain Ausgang, aber dass das so
> lange dauert? Damit könnte man kein I²C mit 400kHz implementieren.

Man kann bei den STM32 den Pin direkt als Open Drain definieren. Dann 
ist keine solche Umschaltung nötig.

Pinsteuerung mit read-modify-write ist bei ARMs mitunter langsam, aber 
das ist bei leidlich erst zu nehmenden Takten trotzdem zu lang. Wobei 
auch der Peripherietakt mitmischt. Aber um das genauer unter die Lupe zu 
nehmen, müsste der Asm-Code inspiziert werden, Messmethode inklusive.
#6361095
Lesenswert?

Max M. schrieb:
> Ist es normal, dass
>   /* Begin Write 0 Slot By Pulling 1-Wire Line Low */
>   GPIOC->ODR &= ~GPIO_ODR_ODR14;
>
>   /* Release 1-Wire Line */
>   GPIOC->ODR |= GPIO_ODR_ODR14;
>
> 5.5µs benötigt? Liegt vermutlich am Open-Drain Ausgang, aber dass das so
> lange dauert? Damit könnte man kein I²C mit 400kHz implementieren.

Man korrigiere mich wenn ich mich irre, aber haben nicht die meisten 
ARMs extra Set/Clear Register, damit man eben NICHT Read-Modifiy-Write 
für die IOs braucht? Die sollte man nutzen!
Gast #6361377
Lesenswert?

Falk B. schrieb:
> Kann man machen, hat in einigen Situationen auch Vorteile. ABER! Man
> sollte das auf einem ARM-Controlller auch rein in Software hinkriegen!

Wozu? Um sich etwas zu beweisen? Blödsinn! Man nutzt die 
Hardwareschnittstelle, die einem soviel Arbeit wie möglich abnimmt. Und 
das ist in diesem Fall die UART!
#6361422
Lesenswert?

Verzweifelter Minderleister schrieb:
> Wozu? Um sich etwas zu beweisen? Blödsinn! Man nutzt die
> Hardwareschnittstelle, die einem soviel Arbeit wie möglich abnimmt. Und
> das ist in diesem Fall die UART!

Selber Blödsinn.

Der einzige Vorteil ist, daß andere Interrupts das Timing nicht stören 
können.
Ansonsten ist das so ziemlich von hinten durch die Brust ins Auge.
Die Timings lassen sich nur sehr grob einstellen, da alles in 9 Bit 
passen muß. Auf den meisten 8Bittern kann man die Baudrate gar nicht so 
fein einstellen oder man kann nur bestimmte Quarzfrequenzen benutzen. 
Auch braucht man 2 Portpins und Zusatzbeschaltung für den open-Drain 
Ausgang.

Die meisten Implementierungen sind daher in SW oder mit dem DS2482.
#6361433
Lesenswert?

Das Sampling des Pins stimmt ziemlich genau. Dafür hab ich einen zweiten 
Pin verwendet den ich toggle wenn das Sampling stattfindet (siehe 
Anhang).

Anstatt den gezeigten Nullern werden allerdings Einsen gelesen. Die 
ersten 4 Bytes des ROM-Codes stimmen jedoch (und da kommen auch Nuller 
vor, die korrekt gelesen werden).

Sehr seltsam. Vielleicht ist der Eingangspin defekt?
Angehängte Dateien:
Gast #6361447
Lesenswert?

Peter D. schrieb:
> Auf den meisten 8Bittern kann man die Baudrate gar nicht so
> fein einstellen oder man kann nur bestimmte Quarzfrequenzen benutzen.
> Auch braucht man 2 Portpins und Zusatzbeschaltung für den open-Drain
> Ausgang.

Ich suche keinen Streit, fakt ist aber dass es eine Steinzeitmthode ist 
OneWire mit Software zu machen und fehleranfällig, wie man hier sehen 
kann. Wir reden aber über STM32. Aber auch auf einem Atmega würde ich 
niemals in Software arbeiten. RX und TX Pins verbinden, einen Pullup 
nach VCC und beide Pins als Opendrain definieren.

Ich habe genau 3 Klassen:
a) USART: 38 Zeilen
b) OneWire: 149 Zeilen
c) DS18B20: 230 Zeilen

Eventuell schafft ihr eine OneWire auch komplett in 5 Zeilen, aber wo 
ist der Vorteil? Direkter Hardwarezugriff, gekapselt in C++ Klassen - 
das kann man auch auf AVR und macht das ganze super portierbar, wartbar 
und fehlerfreier, als sowas in Software zu frickeln.

Max M. schrieb:
> Sehr seltsam. Vielleicht ist der Eingangspin defekt?

Es ist so gut wie nie ein Hardwarefehler.
#6361454
Lesenswert?

Verzweifelter Minderleister schrieb:
> Es ist so gut wie nie ein Hardwarefehler.

Der Verdacht war nicht ganz unbegründet. Ich hab mir vor 2 Jahren 
schonmal einen DS18B20 für 1€ aus China kommen lassen. Ich hab mir den 
damals nicht genauer angeschaut da wieder etwas anderes wichtiger war. 
Gestern wollte ich meine Software dann damit testen. Allerdings ist das 
Teil innerhalb weniger Sekunden derart heiß geworden, dass es sich 
vermutlich um einen einfach BJT gehandelt hat.

Dann musste der Reichelt 10€ Express herhalten.

Verzweifelter Minderleister schrieb:
> Ich suche keinen Streit, fakt ist aber dass es eine Steinzeitmthode ist
> OneWire mit Software zu machen und fehleranfällig, wie man hier sehen
> kann.

Ich wäre bei dir mit dem UART wenn ich dafür jetzt nicht einen diskreten 
Open-Drain Eingang aufbauen bzw. mir einen zusätzlichen IC besorgen 
müsste.
Moderator (Firma: Titel) Persönliche Seite #6361455
Lesenswert?

Max M. schrieb:
> Anstatt den gezeigten Nullern werden allerdings Einsen gelesen.
Gib mal das, was du an dieser Stelle einliest gleich wieder an einem 
anderen Pin aus und leg das auch auf den LA. Also einfach mal dem 
Signalpfad folgen. Nicht, dass bei der nachfolgenden Bearbeitung der 
Bits und Bytes was schiefgeht.

Und miss mal mit einem Oszi das pyhsikalische Signal. Also ob da ein 
brauchbarer 0-Pegel ist, oder ob nur dein LA eine 0 sieht, der µC wegen 
einer Buskollision aber eine 1.
Moderator Persönliche Seite #6361465
Lesenswert?

Verzweifelter Minderleister schrieb:
> Ich habe genau 3 Klassen: a) USART: 38 Zeilen
> b) OneWire: 149 Zeilen
> c) DS18B20: 230 Zeilen

Wo kann man sich Deine SW herunterladen?

Berücksichtige bitte, dass es auch Projekte gibt, wo schon alle USARTs 
mit anderen Aufgaben belegt sind. Hatte ich zum Beispiel mit einem 
STM32F407VET6 - trotz 6 vorhandener USARTs.
Gast #6361468
Lesenswert?

Frank M. schrieb:
> Wo kann man sich Deine SW herunterladen?
>
> Berücksichtige bitte, dass es auch Projekte gibt, wo schon alle USARTs
> mit anderen Aufgaben belegt sind. Hatte ich zum Beispiel mit einem
> STM32F407VET6 - trotz 6 vorhandener USARTs.

Müsste ich unter Projekte & Code posten. Wenn alle Usarts belegt sind 
und man dennoch eine mehr benötigt ist das ein grundsätzlicher 
Designfehler.
Moderator Persönliche Seite #6361484
Lesenswert?

Verzweifelter Minderleister schrieb:
> Müsste ich unter Projekte & Code posten.

Sehr gern, wäre wirklich nett.

> Wenn alle Usarts belegt sind und man dennoch eine mehr benötigt ist das
> ein grundsätzlicher Designfehler.

Ich benötige aber gar keine weitere USARTs, von daher ist Deine Aussage 
über den Designfehler nichtig :-)

One-Wire geht auch mit Pin-Wackeln. Zwingend muss man dem STM32 also 
keinen weiteren USART aus der Nase popeln.

Die Verwendung eines USARTs für One-Wire ist nett, aber keine Religion.
Gast #6361487
Lesenswert?

Frank M. schrieb:
> Die Verwendung eines USARTs für One-Wire ist nett, aber keine Religion.

Wobei die Belegung von allen 6 verfügbaren U(S)ARTs natürlich die 
Ausnahme ist. Gaz eventuell würde ich da eventuell auch auf eine 
Software zurückgreifen - ist aber mehr als hässlich.
Gast #6361491
Lesenswert?

Frank M. schrieb:

> Die Verwendung eines USARTs für One-Wire ist nett, aber keine Religion.

Sicher nicht. Man kann auch andere serielle Peripherie dafür 
"zweckentfremden".

Die mit Abstand dümmste (weil empfindlichste) Lösung auf 
Single-Core-Maschinen ist jedenfalls definitiv Bit-Banging mit Delays...

Bei Architekturen wie etwa dem Propeller hingegen ist das vollkommen OK.
#6361495
Lesenswert?

Verzweifelter Minderleister schrieb:
> Wieso solltest du das müssen? Du benutzt einenSTM32F103C8 ...

Steht in dem von dir verlinkten Dokument.

c-hater schrieb:
> Man kann auch andere serielle Peripherie dafür
> "zweckentfremden".

Macht halt imho keinen Sinn wenn damit der wesentliche Faktor von 1-Wire 
wegfällt - nämlich, dass man nur einen Daten-Pin benötigt. Dann lieber 
einen Sensor, der I2C oder SPI unterstützt.
Gast #6361501
Lesenswert?

Max M. schrieb:
> Steht in dem von dir verlinkten Dokument.

Ne. Du verbindest den TX und RX Pin miteinander, definierst beide als 
Opendrain und verpasst denen noch einen externen Pullup. Also benötigst 
du genau einen Widerstand und du hast einen Hardware OneWire.

Eine diskreten Opendrain Eingang benötigst du nicht, denn der STM32 hat 
einen eingebaut.
Gast #6361503
Lesenswert?

Max M. schrieb:

> Macht halt imho keinen Sinn wenn damit der wesentliche Faktor von 1-Wire
> wegfällt - nämlich, dass man nur einen Daten-Pin benötigt.

Nein, dass man nur einen Pin benötigt ist nicht der wesentliche Faktor. 
Wäre es so, würde das Protokoll OnePin heißen. Es heißt aber OneWire. 
DAS ist der wesentliche Faktor...
Moderator Persönliche Seite #6361504
Lesenswert?

c-hater schrieb:
> Man kann auch andere serielle Peripherie dafür "zweckentfremden".

Sicher. Aber das Wort "zweckentfremden" sagt schon aus, dass die 
Verwendung nicht dem Zweck entspricht. Viel sinnvoller wäre ein 
One-Wire-Pin in HW am µC, der genau für diesen Zweck gedacht ist. Habe 
ich bisher aber noch nirgendwo gesehen. Allerdings muss ich zugeben, 
dass ich bisher auch nicht danach gesucht habe.
Gast #6361510
Lesenswert?

Frank M. schrieb:
> Viel sinnvoller wäre ein
> One-Wire-Pin in HW am µC, der genau für diesen Zweck gedacht ist. Habe
> ich bisher aber noch nirgendwo gesehen.

Eine Usart (RX + TX verbunden mit gemeinsamen Pullup) kommt aber 
Geschwindigkeitstechnisch an die Definition von Onewire heran. Da muss 
man sich um kein Timinggewackel in Software mehr kümmern. Deutlich 
weniger fehleranfällig.
Moderator Persönliche Seite #6361513
Lesenswert?

Verzweifelter Minderleister schrieb:
> Eine Usart (RX + TX verbunden mit gemeinsamen Pullup) kommt aber
> Geschwindigkeitstechnisch an die Definition von Onewire heran. Da muss
> man sich um kein Timinggewackel in Software mehr kümmern. Deutlich
> weniger fehleranfällig.

Dem kann ich nur zustimmen. Umso mehr blicke ich der Veröffentlichung 
Deines Codes unter P&C mit Freude entgegen.
Gast #6361550
Lesenswert?

Da das nicht getestet ist, poste ich das mal eben hier statt in Projekte 
& Code.

Ohne Gewähr auf irgendwas. Da ich kein Profi und Minderleister bin, bin 
ich für Verbesserungsvorschläge offen. Ohne HAL.

So mache ich das.
Angehängte Dateien:
#6361599
Lesenswert?

Weiß jemand, wie man den Prescaler eines laufenden Timers verändert?

Laut Datenblatt geschieht das entweder durch einen Überlauf / Unterlauf 
oder durch ein manuelles Update (TIM_EGR_UG-Bit).

Allerdings funktioniert das bei mir nicht.

So wird der Timer initialisiert:
1
  /* Set Timer 2 Prescaler Value */
2
  TIM2->PSC = 0;
3
  
4
  /* Set Timer 2 Auto Reload Value */
5
  TIM2->ARR = 0xFFFF;
6
  
7
  /* Enable Update Interrupts */
8
  TIM2->DIER |= TIM_DIER_UIE;
9

10
  /* Enable Timer 2 */
11
  TIM2->CR1 |= TIM_CR1_CEN;

Dann arbeite ich eine weile mit Prescaler = 1 und irgendwann setze ich:
1
    /* New Prescaler Value */
2
    TIM2->PSC = 4095;
3
    /* Trigger custom update */
4
    TIM2->EGR = TIM_EGR_UG;
5
    /* Wait until update interrupt occurs */
6
    while( TIM2->SR & TIM_SR_UIF == 0) { ; }
7
    /* Clear update interrupt flag */
8
    TIM2->SR &= ~TIM_SR_UIF;
9
    
10
    /* Reset counter to 0 */
11
    TIM2->CNT = 0;
12
    GPIOC->ODR &= ~GPIO_ODR_ODR15;
13
    while( TIM2->CNT < 17578) { ; }
14
    GPIOC->ODR |= GPIO_ODR_ODR15;

Mit einem CPU-Takt von 72MHz hätte ich jetzt erwartet, dass GPIOC15 1s 
low bleibt, allerdings bleibt er nur 0.243ms low. Warum?
#6361690
Lesenswert?

Verzweifelter Minderleister schrieb:
> Tip: Immer -1, weil die 0 mitzählt.

Deswegen auch 4095 im PSC-Register.

Ich hab gerade gemerkt, selbst wenn ich ganz am Anfang bei der 
Initialisierung 4095 ins PSC-Register schreibe, ändert sich genau gar 
nichts am Verhalten. D.h. der Timer läuft immer mit Prescaler 0 (bzw. 1, 
je nachdem wie man es liest).

Also einen ärgerlicheren Tag hatte ich selten.
Gast #6361713
Lesenswert?

Max M. schrieb:
> Ich hab gerade gemerkt, selbst wenn ich ganz am Anfang bei der
> Initialisierung 4095 ins PSC-Register schreibe, ändert sich genau gar
> nichts am Verhalten. D.h. der Timer läuft immer mit Prescaler 0 (bzw. 1,
> je nachdem wie man es liest).

Ich kann leider von hier nicht debuggen. Aber auch bei der 
Initialisierung musst du erst einen Update erzwingen, z.B. Durch 
TIM2->CNT = 0xffff;
Erst beim Überlauf wird PSC übernommen.

Und hast du generell mal deine Takte überprüft?
Gast #6362156
Lesenswert?

Ich finde auch 1-wire hat einen eklatanten Designfehler, der das Ganze 
so gut wie unbrauchbar macht. Im Gegensatz zu i²c gibt es keine frei 
wählbaren Adressen. Wenn ich 10 Temperaturfühler einlöte, muss ich 
entweder dessen Adressen beim Löten bereits kennen oder die Software 
einlernen etc.

Wie bescheuert ist denn das? Man hätte doch auch Adresspins wie bei i²c 
verwenden können. Dann bräuchte man auch nicht so einen Unsinn wie 
MatchROM etc.

Wenn man nur ein Device pro Typ verwendet - ok. Ansonsten meiner Meinung 
nach unbrauchbar.

Oder gibts auch 1-wire Chips mit Adresspins?
#6362169
Lesenswert?

Verzweifelter Minderleister schrieb:
> Im Gegensatz zu i²c gibt es keine frei
> wählbaren Adressen.

Der DS18B20 hat 2 frei verfügbare Bytes im EEPROM.
Du kannst also einfach jeden Sensor vor dem Einbau konfigurieren und 
dort z.B. eine Adresse + Prüfbyte abspeichern.
Die Auswertesoftware liest dann einfach alle gefundenen Sensoren aus und 
speichert den Meßwert auf der Adresse im EEPROM. Sollten 2 Sensoren die 
gleiche Adresse haben, gibt man eine Fehlermeldung aus.
#6362222
Lesenswert?

Ich sehe hier 1-W in Vorteil gegenüber I2C, wenn man viele Sensoren an 
einem Gerät verwendet. Ein halbes Dutzend hatte ich schon mehrfach.

I2C Devices dieser Klasse haben nur sehr wenige hardwareseitig fest 
definierte Adressen zu Auswahl per Pin, beispielsweise 2. Damit ist die 
maximale Anzahl Devices pro Bus eng limitiert. 1-W Devices haben 
eindeutige Adressen, so dass man so viele davon an einen Bus hängen 
kann, wie man hardwareseitig dran kriegt.

Wenn man etliche Sensoren an einen Bus hängt, wird man die klugerweise 
einzeln trennbar machen. Schon um in Fehlerfall den Schmutzfuss zu 
finden. Damit ergibt sich auch eine einfache Möglichkeit, deren Adressen 
nacheinander ins Gerät einzukonfigurieren, oder alternativ mit einem 
separaten Gerät für den Feldeinsatz eine logische Adresse ins EEPROM vom 
Sensor zu schreiben.

Wen die Adressierung nervt, der kann einen 1-W Bus pro Device verwenden 
und auf die Adressierung verzichten. Das hat auch den Vorteil, dass ein 
defekter Sensor nur sich selbst lahm legt, nicht den ganzen Bus.
#6362771
Lesenswert?

Meine DS18B20 haben alle eine vom Hersteller festgelegte 16stellige 
Hexadezimalseriennummer, die man auslesen kann.
Jetzt nur noch die Fühler kennzeichnen und die Seriennummer in einer 
Tabelle o. ä. zuordnen.
Damit lässt sich die Temperatur von jedem einzelnen Fühler separat 
auslesen.
fertig

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren