Forum: Mikrocontroller und Digitale Elektronik 1-Wire und non-blocking code (state machine)


von Martin (blauepille)


Lesenswert?

Guten Tag,

ich beschäftige mich aktuell mit 1-Wire auf STM32 (C, CubeIDE) und habe 
mir auch schon einige Beiträge hier im Forum durchgelesen. Mir wäre 
jedoch wichtig, dass der Code nicht blockierend aufgebaut ist und damit 
scheint die Angelegenheit dann etwas komplizierter zu werden. Bevor ich 
da jetzt mit Tests sinnlos Zeit verschwende...

Lässt sich das 1-Wire Protokoll gut mit einer state machine abbilden 
oder würdet ihr diese Aufgabe rein vom Konzept her anders angehen?

Vielen Dank und schöne Grüße,

Martin

von c-hater (Gast)


Lesenswert?

Martin schrieb:

> Mir wäre
> jedoch wichtig, dass der Code nicht blockierend aufgebaut ist und damit
> scheint die Angelegenheit dann etwas komplizierter zu werden.

Das liegt in der Natur der Sache. Asynchroner Code ist immer 
komplizierter strukturiert.

> Lässt sich das 1-Wire Protokoll gut mit einer state machine abbilden

Natürlich.

von Andras H. (kyrk)


Lesenswert?

Ja lässt sich. Ist halt die Frage welche HW Elemente du zu beschleunigen 
nehmen kannst. Und wie schnell dein Kontroller ist.

Nen Reset Pulse mit 480ns möchtest du ja nicht blockierend abwarten. Da 
kann man mit Interrupt etwas machen. Rest könnte kann man ja blockierend 
abwarten. Bei so langsameren Kontrollers wird das vielleicht so gemacht. 
Wenn du aber schnellere Kontrollers hast, mit 100MHz oder mehr, da 
willst du ja auch die kleineren Zeiten nicht blockierend abwarten. Da 
kommt ein UART ins spiel, und das ganze könnte man dann 
Interruptgetrieben machen. Oder wenn du DMA hast, kannst versuchen mit 
DMA die Musters zu generieren. Je nach Kontrollertype kann das 
funktionieren oder nicht.

Also ja, lässt sich. Man muss nur erstmal wissen wie schnell dein 
Kontroller ist, welche HW Bausteine du dafür opfern möchstest. Wie lange 
darf man blockierend laufen.

von Uwe Bonnes (Gast)


Lesenswert?

Generiere die Pulse via UART -> Maxim AN126

von (prx) A. K. (prx)


Lesenswert?

Ich hatte einen 16 MHz AVR mit einem globalen 10 kHz Timer Tick 
betrieben, und auch die Bits von 1-Wire darüber abgewickelt. Nur das 
Timing innerhalb der Bits lief per Delayloop.

Dieser Tick produzierte natürlich spürbar Grundlast, aber das war egal. 
Obendrein war das keine State Machine, sondern ein schneller RTOS 
Kernel, weshalb der Code kaum anders aussah als sonst.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Martin schrieb:
> ich beschäftige mich aktuell mit 1-Wire auf STM32 (C, CubeIDE) und habe
> mir auch schon einige Beiträge hier im Forum durchgelesen. Mir wäre
> jedoch wichtig, dass der Code nicht blockierend aufgebaut ist

Was heißt das GENAU? Jeder Code "blockiert", fragt sich nur, wie lange. 
Bei meiner Implementierung sind die Interrupts für jedes Bit ca. 100us 
gesperrt, zwischen den Bits werden sie wieder freigegeben. Die 
Funktionsaufrufe "blockieren" halt für die jeweilige Byte-Sequenz.

Beitrag "Re: Onewire + DS18x20 Library"

von c-hater (Gast)


Lesenswert?

(prx) A. K. schrieb:

> Obendrein war das keine State Machine, sondern ein schneller RTOS
> Kernel, weshalb der Code kaum anders aussah als sonst.

Ja, für solche Leute sind RTOSe wohl gedacht...

Bis das böse Erwachen kommt, weil halt der ineffiziente Code aus der 
Echtzeit fällt...

von neuer PIC Freund (Gast)


Lesenswert?

> Lässt sich das 1-Wire Protokoll gut mit einer state machine abbilden

Auf einem Tiny10 tat ich genau dies. Fährt automatisch 
SkipRom-ConvertT-SkipRom-ReadScratchpad bitbangend durch. Granuliert als 
Nibble (4 bit-slots) konnte ich die Interrupts aus lassen und das 
Timerbit ohne Verlust pollen. Dient nur als Interface OW2UART.

von EAF (Gast)


Lesenswert?

Martin schrieb:
> Mir wäre
> jedoch wichtig, dass der Code nicht blockierend aufgebaut ist und damit
> scheint die Angelegenheit dann etwas komplizierter zu werden.

Ja!
Selbst wenn es "nicht blockierend" geschrieben ist, können einem 
irgendwelche ISRs derbe ins Timing spucken.

Drum:
Mit einem 2 Kerne µC mag das günstiger sein.
Auch ein 2ter µC(Tiny?), welcher als Koppler zwischen z.B. I2C und 
OnWire dient, bekommt man das hin.

Provokation
Was ist mehr Wert, die Arbeit(Lebenswerk?) eines verbissenen ASMlers, 
dessen Karre bei der nächsten asynchronen Anforderung umfällt, oder ein 
mini Häuflein Euronen.

von Martin (blauepille)


Lesenswert?

c-hater schrieb:
> Das liegt in der Natur der Sache. Asynchroner Code ist immer
> komplizierter strukturiert.

Gut zu wissen. Ich nehme mal an, man darf die streng asynchrone Struktur 
an geeigneten Stellen auch etwas entschärfen bzw. man muss es nicht mit 
der Verschachtelungs-Tiefe übertreiben, wenn es aufgrund zu vieler 
Bedingungen und Verzweigungen zu unübersichtlich wird und das Timing es 
erlaubt?

Andras H. schrieb:
> Also ja, lässt sich. Man muss nur erstmal wissen wie schnell dein
> Kontroller ist, welche HW Bausteine du dafür opfern möchstest. Wie lange
> darf man blockierend laufen.

Der µC läuft aktuell mit 25 MHz (incl. APB1 Timer Clock). Einen UART 
könnte ich aber sicherlich für 1-Wire spendieren, das scheint das Timing 
ja zu entschärfen.

Uwe Bonnes schrieb:
> Generiere die Pulse via UART -> Maxim AN126

Ich werde das mit dem UART in Erwägung ziehen. Wie würde man denn bei 
1-Wire über UART den 1-Wire-Slave anschließen? In einem Schema von Maxim 
sieht es so aus, als würde man den UART-TX via PullUp gleichzeitig mit 
UART-RX + DQ verbinden. Ist das der Trick, damit man das Gesendete 
entweder 1:1 empfängt (weil der Slave den Bus nicht auf Low zieht) oder 
eben etwas anderes, was durch die Bitzeiten in der jeweiligen Baudrate 
erzeugt wird?

Falk B. schrieb:
> Was heißt das GENAU? Jeder Code "blockiert", fragt sich nur, wie lange.

Hmm, das ist eine gute Frage. Es geht mir wohl auch darum, das jetzt 
nicht völlig falsch anzugehen. Vermutlich wird bei mir aber auch Deine 
Lösung mit dem vertretbaren Blockieren funktionieren. Ich reize den µC 
nicht bis zum letzen Takt aus und habe auch (noch) keine superkritischen 
Timing-Sachen, daher sehe ich mir das nochmal an.

neuer PIC Freund schrieb im Beitrag #7234626:
> Auf einem Tiny10 tat ich genau dies. Fährt automatisch
> SkipRom-ConvertT-SkipRom-ReadScratchpad bitbangend durch.

Auch nicht schlecht. :) Ich vermute aber, dass eine state machine bei 
vollständiger 1-Wire-Protokoll-Implementierung etwas unübersichtlich 
wird.

EAF schrieb:
> Was ist mehr Wert, die Arbeit(Lebenswerk?) eines verbissenen ASMlers,
> dessen Karre bei der nächsten asynchronen Anforderung umfällt, oder ein
> mini Häuflein Euronen.

Hast schon recht. Ich verstehe nur nicht, warum Maxim das Timing so 
kritisch designt hat? Bei den vergleichsweise gigantischen Wartezeiten, 
die man für eine Temperatur-Messung ertragen muss, wäre ein entschärftes 
Timing doch nicht so schlimm gewesen?!?

Vielen Dank euch allen!

von c-hater (Gast)


Lesenswert?

EAF schrieb:

> Selbst wenn es "nicht blockierend" geschrieben ist, können einem
> irgendwelche ISRs derbe ins Timing spucken.

Natürlich nur dann, wenn diese inkompetent und ohne deterministisches 
Timing geschrieben sind. Also gerade nicht in Asm, sondern in 
irgendeiner verschissenen Hochsprache. Denn genau das können 
Hochsprachen nicht: ein deterministisches Timing garantieren. Alles was 
die garantieren, ist: "so schnell wie möglich". Wobei das eigentlich in 
Wahrheit bedeutet: "so schnell mir (also dem Compiler) möglich", was 
auch nochmal ein durchaus signifikanten Unterschied bedeuten kann...

Selbst in Asm fällt es auf vielen Architekturen schwer, ein 
determistisches Timing zu garantieren. Aber nicht auf AVR8. Da geht das 
recht einfach. Und weil das da geht, kann man ganz hervorragend alles 
ausrechnen, insbesondere natürlich auch den worst case.

Man muss es einfach nur können und tun...

von EAF (Gast)


Lesenswert?

Martin schrieb:
> wäre ein entschärftes
> Timing doch nicht so schlimm gewesen?!?

Wenn man sich kein Kabel für einen Takt leisten kann/will, kann man es 
nur über das Timing regeln. Und das muss dann eben recht exakt sein.

von EAF (Gast)


Lesenswert?

c-hater schrieb:
> Man muss es einfach nur können und tun...

Du kannst gar nichts!

von c-hater (Gast)


Lesenswert?

EAF schrieb:
> c-hater schrieb:
>> Man muss es einfach nur können und tun...
>
> Du kannst gar nichts!

Nun, das sagst du. Allerdings kann ich kein Werk von dir sehen, was 
deine Kompetenz in irgendeiner Form belegen könnte.

Ich hingegen habe wenigstens ein paar Sachen öffentlich zur Verfügung 
gestellt, die definitiv funktionieren und insbesondere auch den Vorteil 
der Asm-Programmierung für AVR8-Targets zeigen. Weil sie halt Sachen 
umsetzen, die mit dem üblichen Compilern nicht gehen, weil der Code halt 
schlicht zu beschissen ist, den diese produzieren.

Also steht hier leeres Blafasel eines Blinden Wichsers ohne jeden Beleg 
gegen öffentlich verfügbare und nachweislich funktionierende Lösungen.

Nicht schwer, hier die Wahl zu treffen, wem man glaubt...

von c-hater (Gast)


Lesenswert?

EAF schrieb:
> c-hater schrieb:
>> Man muss es einfach nur können und tun...
>
> Du kannst gar nichts!

Nun, das sagst du. Allerdings kann ich kein Werk von dir sehen, was 
deine Kompetenz in irgendeiner Form belegen könnte...

Ich hingegen habe wenigstens ein paar Sachen öffentlich zur Verfügung 
gestellt, die definitiv funktionieren und insbesondere auch den Vorteil 
der Asm-Programmierung für AVR8-Targets zeigen. Weil sie halt Sachen 
umsetzen, die mit dem üblichen Compilern nicht gehen, weil der Code halt 
schlicht zu beschissen ist, den diese produzieren.

Also steht hier leeres Blafasel eines Blinden Wichsers ohne jeden Beleg 
gegen öffentlich verfügbare und nachweislich funktionierende Lösungen.

Nicht schwer, hier die Wahl zu treffen, wem man glaubt...

von (prx) A. K. (prx)


Lesenswert?

c-hater schrieb:
> (prx) A. K. schrieb:
> Bis das böse Erwachen kommt, weil halt der ineffiziente Code aus der
> Echtzeit fällt...

Bin ich du? ;-)

Die Steuerung lief 2 Jahrzehnte und flog erst nach dem Verkauf des 
Hauses raus.

Das war aber nicht als Empfehlung gemeint.

Was dir bestimmt gefallen wird: Der Kernel "AvrX" war in Assembler 
implementiert. Weniger: mein Programm jedoch in C/C++.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Ich hab das mal auf dem AVR gemacht:

Beitrag "DS18B20 mit Interrupt, AVR-GCC"

von c-hater (Gast)


Lesenswert?

(prx) A. K. schrieb:

> Bin ich du? ;-)

Sicher nicht. Du kannst halt nicht alles haben.

> Die Steuerung lief 2 Jahrzehnte und flog erst nach dem Verkauf des
> Hauses raus.

Naja, wenn die Zeit reicht für den Task (und alle konkurrierenden), dann 
ändert natürlich auch eine Laufzeit der unveränderten Anwendung von 20 
Jahren nichts an diesem Sachverhalt. Ist doch logisch.

Wenn allerdings Tasks hinzukommen oder bestehende Task nach Änderungen 
mehr Rechenzeit benötigen, ist irgendwann Schluss. Sollte auch logisch 
sein.

Der Punkt ist halt: Ineffiziente Tasks (und auch das RTOS selber) sorgen 
dafür, dass diese Situation eintritt, lange bevor sie tatsächlich 
eintreten müsste, wenn die Fähigkeiten der Hardware des Targets optimal 
genutzt würden...

von (prx) A. K. (prx)


Lesenswert?

MaW: man sollte wissen, was man tut. ;-)

von Falk B. (falk)


Lesenswert?

Martin schrieb:
> Ich werde das mit dem UART in Erwägung ziehen. Wie würde man denn bei
> 1-Wire über UART den 1-Wire-Slave anschließen? In einem Schema von Maxim
> sieht es so aus, als würde man den UART-TX via PullUp gleichzeitig mit
> UART-RX + DQ verbinden. Ist das der Trick, damit man das Gesendete
> entweder 1:1 empfängt (weil der Slave den Bus nicht auf Low zieht)

Ja.

> oder
> eben etwas anderes, was durch die Bitzeiten in der jeweiligen Baudrate
> erzeugt wird?

Das auch.

> Falk B. schrieb:
>> Was heißt das GENAU? Jeder Code "blockiert", fragt sich nur, wie lange.
>
> Hmm, das ist eine gute Frage. Es geht mir wohl auch darum, das jetzt
> nicht völlig falsch anzugehen. Vermutlich wird bei mir aber auch Deine
> Lösung mit dem vertretbaren Blockieren funktionieren. Ich reize den µC
> nicht bis zum letzen Takt aus und habe auch (noch) keine superkritischen
> Timing-Sachen, daher sehe ich mir das nochmal an.

Gute Idee. Man kann alles übertreiben. Ein Code muss nur so "nicht 
blockierend" sein, wie es für die Anwendung ausreichend ist.

> neuer PIC Freund schrieb im Beitrag #7234626:
>> Auf einem Tiny10 tat ich genau dies. Fährt automatisch
>> SkipRom-ConvertT-SkipRom-ReadScratchpad bitbangend durch.
>
> Auch nicht schlecht. :) Ich vermute aber, dass eine state machine bei
> vollständiger 1-Wire-Protokoll-Implementierung etwas unübersichtlich
> wird.

Nö. ALles eine Frage der Umsetzung. Außerdem, wenn es einmal läuft, ist 
der inhalt egal, man muss es nur noch nutzen.

> EAF schrieb:
>> Was ist mehr Wert, die Arbeit(Lebenswerk?) eines verbissenen ASMlers,
>> dessen Karre bei der nächsten asynchronen Anforderung umfällt, oder ein
>> mini Häuflein Euronen.
>
> Hast schon recht. Ich verstehe nur nicht, warum Maxim das Timing so
> kritisch designt hat?

Was heißt denn kritisch? Die haben schon ziemlich großzügige Toleranzen 
drin.

> Bei den vergleichsweise gigantischen Wartezeiten,
> die man für eine Temperatur-Messung ertragen muss, wäre ein entschärftes
> Timing doch nicht so schlimm gewesen?!?

Unsinn. Das sind zwei vollkommen verschiedene Schuhe! Das eine ist die 
unterste Bitübertragungsschicht, OSI Layer 1. Das Andere die 
Anwerdschicht, OSI-Layer 4 oder höher.

von Falk B. (falk)


Lesenswert?

c-hater schrieb:
> Natürlich nur dann, wenn diese inkompetent und ohne deterministisches
> Timing geschrieben sind. Also gerade nicht in Asm, sondern in
> irgendeiner verschissenen Hochsprache. Denn genau das können
> Hochsprachen nicht: ein deterministisches Timing garantieren.

Abwer sicher, mein Hochverehrter. Auch ein C-Programm ist 
deterministisch, wenn gleich nicht auf den Takt genau wie ein 
ASM-Progamm.

> Selbst in Asm fällt es auf vielen Architekturen schwer, ein
> determistisches Timing zu garantieren.

Unfug. Deterministisch != taktgenau.

> Aber nicht auf AVR8. Da geht das
> recht einfach. Und weil das da geht, kann man ganz hervorragend alles
> ausrechnen, insbesondere natürlich auch den worst case.

Jo, und darauf hat auch jeder Bock und das ist auch voll nötig, in jeder 
Lebenslage . . .

> Man muss es einfach nur können und tun...

Man muss es vor allem nur dann tun, wenn es WIRKLICH nötig ist. Parkst 
du dein Auto auch auf dem Millimeter genau? Du vermutlich schon . . .

von Sebastian (Gast)


Lesenswert?

c-hater schrieb:
> EAF schrieb:
>
>> Selbst wenn es "nicht blockierend" geschrieben ist, können einem
>> irgendwelche ISRs derbe ins Timing spucken.
>
> Natürlich nur dann, wenn diese inkompetent und ohne deterministisches
> Timing geschrieben sind. Also gerade nicht in Asm, sondern in
> irgendeiner verschissenen Hochsprache.

Das ist doch Unsinn. Eine ISR spuckt einem auch in Assembler in die 
Timing-Suppe wenn man sie lässt.

LG, Sebastian

von EAF (Gast)


Lesenswert?

Ach komm!
Jetzt lass doch bitte mal den C Hasser in Ruhe.
Ihm ist doch gar nicht in der Lage einen Irrtum 
einzusehen/einzugestehen.
bzw. ist seine Lösungsmenge begrenzt, beleidigen, oder den Schwanz 
einkneifen.

von Peter D. (peda)


Lesenswert?

Martin schrieb:
> Der µC läuft aktuell mit 25 MHz (incl. APB1 Timer Clock). Einen UART
> könnte ich aber sicherlich für 1-Wire spendieren, das scheint das Timing
> ja zu entschärfen.

Der AVR schafft es bequem bei 8MHz, da sollten 25MHz überhaupt kein 
Problem sein. Und wenn man dann noch einen MC mit Interruptlevel hat, 
dann brauchen andere Tasks auch keinerlei Rücksicht zu nehmen. Der 
1-Wire Timerinterrupt läuft einfach still und leise im Hintergrund.
Auch irgendwelche Assembler-Hacks sind vollkommen unnötig.

Hier nochmal der Link:
Beitrag "DS18B20 mit Interrupt, AVR-GCC"

Und nochmal die Statemaschine:
1
ISR(TIMER0_OVF_vect)
2
{
3
  if (ONWI_oe && !ONWI_out)             // if low
4
  {
5
    ONWI_oe = 0;                        // pin = tristate
6
    _delay_us(5);                       // min high time
7
  }
8
  uint8_t* pbuf = onwi.pbuf;            // for faster access
9
  switch (++onwi.state)
10
  {
11
    case OW_RES_LO:                     // 480us low
12
      if (onwi.delay--)                 // n * 100ms
13
        onwi.state = OW_DELAY;
14
      else
15
      {
16
        ONWI_out = 0;
17
        ONWI_oe = 1;                    // pin = low
18
      }
19
    case OW_RES_HI:                     // 480us high
20
    default:                            // n * 480µs
21
      TCNT0 = 256 - OW_RESET_SLOT;
22
      return;
23
    case OW_WR_DONE:                    // 1. command byte finished
24
      pbuf++;
25
      onwi.state = OW_WR_BIT0;
26
    case OW_WR_BIT0:                    // write bit 0
27
      if (onwi.wr_cnt--)
28
      {
29
    case OW_WR_BIT1:                    // write bit 1
30
    case OW_WR_BIT2:
31
    case OW_WR_BIT3:
32
    case OW_WR_BIT4:
33
    case OW_WR_BIT5:
34
    case OW_WR_BIT6:
35
    case OW_WR_BIT7:                    // write bit 7
36
        ONWI_oe = 1;                    // pin = low
37
        _delay_us(1);
38
        if (*pbuf & 1)
39
          ONWI_oe = 0;                  // pin = tristate
40
        *pbuf >>= 1;
41
        break;
42
      }
43
      ONWI_out = 1;                     // parasite power on
44
      ONWI_oe = 1;
45
      pbuf = onwi.buf - 1;
46
    case OW_RD_DONE:
47
      pbuf++;
48
      onwi.state = OW_RD_BIT0;
49
      if (onwi.rd_cnt--)
50
      {
51
        ONWI_oe = 0;                    // parasite power off
52
        ONWI_out = 0;
53
    case OW_RD_BIT1:                    // read bit 1
54
    case OW_RD_BIT2:
55
    case OW_RD_BIT3:
56
    case OW_RD_BIT4:
57
    case OW_RD_BIT5:
58
    case OW_RD_BIT6:
59
    case OW_RD_BIT7:                    // read bit 7
60
        ONWI_oe = 1;                    // pin = low
61
        _delay_us(1);
62
        ONWI_oe = 0;                    // pin = tristate
63
        _delay_us(5);
64
        *pbuf >>= 1;
65
        if (ONWI_in)
66
          *pbuf |= 0x80;
67
        break;
68
      }
69
      TCCR0B = 0;                       // stop T0
70
      return;
71
  }
72
  onwi.pbuf = pbuf;
73
  TCNT0 = 256 - OW_BIT_SLOT;
74
}

von augenkrebs (Gast)


Lesenswert?

Peter D. schrieb:
> Und nochmal die Statemaschine:

Also die Einrückungen gefallen mir gar nicht, das hätte ich
von einem (Profi-?) PeDa anders erwartet .....

von Falk B. (falk)


Lesenswert?

augenkrebs schrieb:
> Also die Einrückungen gefallen mir gar nicht, das hätte ich
> von einem (Profi-?) PeDa anders erwartet .....

Naja, es ist einer der häßlichen C-Tricks, mit verschachtelten 
switch/case und if. Würde ich auch nicht so machen wollen. Bringt keinen 
funktionalen und leistungsmäßigen Gewinn, dafür umso mehr Spaghetticode.

von Bauform B. (bauformb)


Lesenswert?

Martin schrieb:
> Lässt sich das 1-Wire Protokoll gut mit einer state machine abbilden
> oder würdet ihr diese Aufgabe rein vom Konzept her anders angehen?

So pauschal gefragt: ja, ganz anders, und zwar wegen der Hardware.
 * Der 1-Wire Bus ist eigentlich für 5V ausgelegt.
 * 1-Wire EEPROMs z.B. funktionieren mit 3.3V nur "gerade noch"
 * manche Chips brauchen viel Strom, also einen umschaltbaren Pull-Up
 * STM32-Pins erzeugen unnötig steile Flanken
 * STM32-Pins sind relativ empfindlich, man möchte kein Kabel ohne 
ESD-Schutz anschließen. Mehr als wenige Dutzend Ohm Serienwiderstand 
sind aber nicht erlaubt und Kapazitäten stören sowieso.

Man braucht also meistens ein paar externe Bauteile. Ein DS2484 erledigt 
das alles in einem 6-Pin SOT-23, inklusive Level Shifter und 8kV ESD 
Schutz. Nebenbei sorgt er selbständig für das korrekte Timing, auch mit 
Overdrive Speed. Und dank I2C braucht er ggf. keinen einzigen uC-Pin 
extra.

Es gibt auch noch andere 1-Wire Master, z.B. den DS2480 für UART zu 
1-Wire, jeder mit eigenen Vor- und Nachteilen:

https://www.maximintegrated.com/en/products/parametric/search.html?fam=1wire&node=4868

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Falk B. schrieb:
> dafür umso mehr Spaghetticode.

State machines sind von Natur aus Spaghetticode. Übersichtlichen 
sequentiellen Code gibt es nur mit mindestens Coroutinen.

von (prx) A. K. (prx)


Lesenswert?

Bauform B. schrieb:
> Der 1-Wire Bus ist eigentlich für 5V ausgelegt

Die gerne genutzten 1820er haben auch mit 3,0V kein Problem.

von Falk B. (falk)


Lesenswert?

(prx) A. K. schrieb:
> State machines sind von Natur aus Spaghetticode.

Nö! Du weißt genau was ich meine, denn ich habe es EXPLIZIT beschrieben! 
Was soll die Besserwisserei?

von (prx) A. K. (prx)


Lesenswert?

Falk B. schrieb:
> Was soll die Besserwisserei?

Du Besserwisser kritisierst ihn, ich Besserwisser dich. Wirst du 
verkraften müssen. Ich finde seinen Code überdies recht geschickt so 
gestaltet, dass die Abfolge in etwa erhalten bleibt.

: Bearbeitet durch User
von 900ss (900ss)


Lesenswert?

(prx) A. K. schrieb:
> Ich finde seinen Code überdies recht geschickt so gestaltet, dass die
> Abfolge in etwa erhalten bleibt.

Magst du deine Statemachine mit RTOS auch zur Verfügung stellen? Ist nur 
Neugierde, wie du das mittels RTOS gelöst hast.

von Uwe Bonnes (Gast)


Lesenswert?

Martin schrieb:
>> Generiere die Pulse via UART -> Maxim AN126
>
> Ich werde das mit dem UART in Erwägung ziehen. Wie würde man denn bei
> 1-Wire über UART den 1-Wire-Slave anschließen? In einem Schema von Maxim
> sieht es so aus, als würde man den UART-TX via PullUp gleichzeitig mit
> UART-RX + DQ verbinden. Ist das der Trick, damit man das Gesendete
> entweder 1:1 empfängt (weil der Slave den Bus nicht auf Low zieht) oder
> eben etwas anderes, was durch die Bitzeiten in der jeweiligen Baudrate
> erzeugt wird?


https://www.maximintegrated.com/en/design/technical-documents/tutorials/2/214.html

von J. S. (jojos)


Lesenswert?

900ss D. schrieb:
> Ist nur
> Neugierde, wie du das mittels RTOS gelöst hast.

ich bin nicht Falk, habe es aber auch gerade mit RTOS und RP2040 
gemacht. D.h., eine fertige Komponente genommen und die funktioniert, 
arbeitet mit wait_us() und afaik vertrödelt das Zeit mit auf Timer 
warten. Habe noch nicht nachgemessen wie gut das Timing (unter Last) 
ist, werde ich nachholen.

Das RTOS macht es jedenfalls einfach etwas parallel laufen zu lassen, 
nur wenn der DS in einem Thread mit höherer Prio läuft, dann blockiert 
das trödeln andere trotzdem. Bei niedriger Prio stören andere das 
Timing, da ist die Frage wie Tolerant der DS ist. Temperaturen liest man 
ja zyklisch und wenige Ausfälle (wenn sie von der CRC erkannt werden) 
sind je nach Anwendung tolerierbar, micht würde das nicht stören. Die 
CRC wird Dallas doch sicher eingebaut haben weil OneWire nicht so sicher 
ist? Eine Statistik für fails einzubauen wäre interessant.
Beim RP2040 lässt sich die Kommunikation sicher vom PIO unterstüzen?

Hatte die DS bisher lange Zeit rumliegen, möchte aber jetzt wie wohl 
viele andere auch die Heizungsanlage besser überwachen. Ich hatte die DS 
mit Edelstahlgehäuse und andere Teile bei AZ bestellt, die DS konnten 
innerhalb 24 h ohne Aufpreis geliefert werden, die anderen Teile kamen 
einen Werktag später. Interessant, das scheint ja aus Lagern zu kommen 
die Bedarfsgesteuert gefüllt werden.

von Peter D. (peda)


Lesenswert?

Falk B. schrieb:
> Naja, es ist einer der häßlichen C-Tricks, mit verschachtelten
> switch/case und if.

Vom Prinzip her ist switch/case nur eine andere Schreibweise von goto.
Das Durchfallen erlaubt aber, Codesequenzen nicht ausufernd für jeden 
Case duplizieren zu müssen und macht es daher übersichtlicher.
Auch ist es während der Entwicklung deutlich einfacher, den Code nur an 
einer Stelle korrigieren zu müssen und nicht auch in haufenweise 
Duplikaten.
Das Durchfallen ist quasi das Prinzip der optimalen Reihenfolge, kommt 
also dem (faulen) Menschen entgegen.

Mich stört jede gleiche Codesequenz, die ich an 2 Stellen hinschreiben 
müßte, weil man sie dann auch an 2 Stellen lesen und verstehen müßte und 
an 2 Stellen Fehler machen kann. Wenn es aber nicht anders geht, mache 
ich daraus eine Unterfunktion, die ich an n Stellen aufrufe.

: Bearbeitet durch User
von J. S. (jojos)


Lesenswert?

Peter D. schrieb:
> Mich stört jede gleiche Codesequenz, die ich an 2 Stellen hinschreiben
> müßte,

ja, nur das man in den if Block reinspringen darf hatte ich noch nicht 
gesehen, das sieht nicht schön aus.
Die neueren gcc meckern beim Fallthru auch mehr, wenn man das möchte 
soll man das im Code als Kommentar hinschreiben.

von Alt G. (altgr)


Lesenswert?

Martin schrieb:
> Guten Tag,
>
> ich beschäftige mich aktuell mit 1-Wire auf STM32
> dass der Code nicht blockierend

Mit so einem popeligen schnarchprozessor wird das schwierig.

von EAF (Gast)


Lesenswert?

J. S. schrieb:
> ja, nur das man in den if Block reinspringen darf hatte ich noch nicht
> gesehen, das sieht nicht schön aus.

Die Protothreads des Adam Dunkels basieren auf dem gleichen Prinzip.

von Peter D. (peda)


Lesenswert?

Alt G. schrieb:
> Mit so einem popeligen schnarchprozessor wird das schwierig.

Das läuft sogar auf einem standard 8051 (mit Keil C51 Compiler 
getestet). Und der teilt durch 12, hat also wahnsinnige 1MIPS an einem 
12MHz Quarz.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

900ss D. schrieb:
> Magst du deine Statemachine mit RTOS auch zur Verfügung stellen? Ist nur
> Neugierde, wie du das mittels RTOS gelöst hast.

Heute Abend. Ist aber unspektakulär. Er basiert auf einem anderen, 
linearen Code von Peter D, bei dem ich die Delayloops jenseits des 
inneren Bit-Timings durch Timer-Waits des RTOS ersetzte. Damit sind die 
Bits zwar aufgrund des 10 kHz RTOS-Ticks mit 100us weiter auseinander 
als möglich, aber das stört nicht.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

(prx) A. K. schrieb:
> 900ss D. schrieb:
>> Magst du deine Statemachine mit RTOS auch zur Verfügung stellen? Ist nur
>> Neugierde, wie du das mittels RTOS gelöst hast.
>
> Heute Abend. Ist aber unspektakulär. Er basiert auf einem anderen,
> linearen Code von Peter D, bei dem ich die Delayloops jenseits des
> inneren Bit-Timings durch Timer-Waits des RTOS ersetzte.
1
#define USE_TIMER (AVRX && TICK<=200) /* use an AvrX timer? */
2
3
#if USE_TIMER
4
  static TimerControlBlock ds_timer;
5
  #define wait_sync() AvrXDelay(&ds_timer, 1); // synchronize to timer tick
6
  #define wait_us(us) AvrXDelay(&ds_timer, TICKS_US(us));
7
  #define wait_ms(ms) AvrXDelay(&ds_timer, TICKS_MS(ms));
8
#else
9
  #define wait_sync()
10
  #define wait_us(us) delay_us(us)
11
  #define wait_ms(ms) delay_ms(ms)
12
#endif

Der Code nutzt wait_xx, wenn das Timing nach oben relativ offen ist, und 
delay_xx, wenn nicht. Das war schon praktisch alles, was als Anpassung 
an das preemptive RTOS erforderlich war.

Unabhängig von RTOS oder nicht gibt es natürlich noch BeginCritical() 
und EndCritical() um Sektionen ohne Interrupt, wie die Übertragung eines 
Bits. Eine einzelne Bitübertragung läuft also am Stück (sowas wie 80µs), 
zwischen den Bits oder im 1W-Reset kann der Code aber unterbrochen 
werden.

Mit RTOS kann es also zwischen den Bits zu einem Taskwechsel kommen, und 
bei wait_xx ohnehin. Das ist der ganze Unterschied zwischen dem Betrieb 
mit RTOS und ohne, was die Ansteuerung von 1-Wire angeht.

Um auf diese Art auch das Timing innerhalb der Bitübertragung ohne 
Delayloops machen können, braucht man mehr als einen Mega32.

> Bits zwar aufgrund des 10 kHz RTOS-Ticks mit 100us weiter auseinander
> als möglich, aber das stört nicht.

Das hatte ich falsch in Erinnerung. Mit Taskwechsel zwischen den Bits 
kann dort eine nicht klar definierte Zeit verstreichen, was aber im 
1-Wire Protokoll nicht relevant ist. Das Timing vom 1W-Reset ist durch 
den Timer-Tick nach oben etwas offen, aber das sind die Devices auch.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

An Tasks gab es:
- Abfrage der lokalen Tastatur
- Benutzerinteraktion mit LCD-Anzeige
- Kommunikation mit Bedienmodul im Wohnbereich
- Die Steuerung, darin wird der 1-Wire-Code aufgerufen
- Überwachung, ob alles mit rechten Dingen zugeht

: Bearbeitet durch User
von Martin (blauepille)


Lesenswert?

Hallo Leute,

nochmal vielen Dank für die Hilfe. Die Übertragung mit Hilfe von UART 
funktioniert inzwischen. Ich habe jetzt beim STM32 den USART_TX als 
Alternate Function Push Pull konfiguriert, den USART_RX als Alternate 
Function Open Drain und einen PullUp mit 1,5K so wie im folgenden Schema 
eingelötet:

https://www.maximintegrated.com/content/dam/images/design/tech-docs/214/214fig01.png

Der 1-Wire Slave ist über 3 Adern angeschlossen und wird über die dritte 
Leitung mit den 3,3 Volt für den µC mitversorgt. Ich hoffe, dass ist so 
in Ordnung.

LG,
Martin

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Martin schrieb:
> Ich habe jetzt beim STM32 den USART_TX als
> Alternate Function Push Pull konfiguriert, den USART_RX als Alternate
> Function Open Drain und einen PullUp mit 1,5K so wie im folgenden Schema
> eingelötet:

Das ist aber arg hochohmig bei Low-Pegel.
Ich würde TXD auf Open Drain setzen und den Pullup gegen VCC. Zum 
Bedämpfen von Reflexionen noch ein 47..220Ω in Reihe zu TXD.
Wie kann man einen Eingang (RXD) auf Open Drain setzen?

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.