DHT11 Sensor bringt AtMega8 zum Reset

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • DHT11 Sensor bringt AtMega8 zum Reset

      Hallo,

      ich wollte mir eine Funkuhr mit Temperatur + Luftfeuchtemessung basteln.
      Leider führt mein AtMega8a bei jeder Abfrage des DHT11 einen Reset aus.

      Der Code für die DHT11 abfrage hab ich von irgendeinen Webseite (die ich nicht wiederfinde) kopiert.

      Source Code

      1. '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      2. 'Mikrocontroller Konfigurieren
      3. $regfile = "m8adef.dat"
      4. $crystal = 1000000
      5. $hwstack = 100
      6. $swstack = 40
      7. $framesize = 100
      8. 'Ende Mikrocontroller Konfigurieren
      9. '=============================================================
      10. '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      11. 'Ports Konfigurireren
      12. Config Portb = Output
      13. Gnd_digit_1 Alias Portd.5
      14. Gnd_digit_2 Alias Portd.6
      15. Gnd_digit_3 Alias Portd.7
      16. Gnd_digit_4 Alias Portc.3
      17. Config Gnd_digit_1 = Output
      18. Config Gnd_digit_2 = Output
      19. Config Gnd_digit_3 = Output
      20. Config Gnd_digit_4 = Output
      21. Config Portc.5 = Input
      22. Dht_write Alias Portd.4 'Empfange Daten vom DHT-Sensor
      23. Dht_read Alias Pind.4 'Schreibe Daten zum DHT-Sensor
      24. Dht_io Alias Ddrd.4 'Umschalten der Datenrichtung write/read
      25. 'Config Dht_write = Output
      26. 'Config Dht_read = Input
      27. 'Port für Spannungsmessung
      28. 'Ende Ports Konfigurieren
      29. '=============================================================
      30. '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      31. 'Variablen
      32. Dim Var_ziffern(14) As Byte
      33. Var_ziffern(1) = &B0011_1111 '0
      34. Var_ziffern(2) = &B0000_0110 '1
      35. Var_ziffern(3) = &B0101_1011 '2
      36. Var_ziffern(4) = &B0100_1111
      37. Var_ziffern(5) = &B0110_0110
      38. Var_ziffern(6) = &B0110_1101
      39. Var_ziffern(7) = &B0111_1101
      40. Var_ziffern(8) = &B0000_0111
      41. Var_ziffern(9) = &B0111_1111
      42. Var_ziffern(10) = &B0110_1111 '9
      43. '9
      44. Var_ziffern(11) = &B0011_1001 'C 'C
      45. Var_ziffern(12) = &B0111_0001 'F
      46. Var_ziffern(13) = &B0000_0000 'Clear GND
      47. Var_ziffern(14) = &B0100_0000 '- Minuszeichen
      48. Dim Var_ziffern_dot(14) As Byte
      49. Var_ziffern_dot(1) = &B1011_1111 '0
      50. Var_ziffern_dot(2) = &B1000_0110 '1
      51. Var_ziffern_dot(3) = &B1101_1011 '2
      52. Var_ziffern_dot(4) = &B1100_1111
      53. Var_ziffern_dot(5) = &B1110_0110
      54. Var_ziffern_dot(6) = &B1110_1101
      55. Var_ziffern_dot(7) = &B1111_1101
      56. Var_ziffern_dot(8) = &B1000_0111
      57. Var_ziffern_dot(9) = &B1111_1111
      58. Var_ziffern_dot(10) = &B1110_1111 '9
      59. '9
      60. Var_ziffern_dot(11) = &B1011_1001 'C 'C
      61. Var_ziffern_dot(12) = &B1111_0001 'F
      62. Var_ziffern_dot(13) = &B1000_0000 'Clear GND
      63. Var_ziffern_dot(14) = &B1100_0000 '- Minuszeichen
      64. Dim Dht_daten(5) As Byte 'Array für empfangene Daten
      65. Dim Luftfeuchtigkeit As Byte At Dht_daten(1) Overlay
      66. Dim Temperatur As Byte At Dht_daten(3) Overlay
      67. Dim Crc_ergebniss As Byte At Dht_daten(5) Overlay
      68. Dim Var_old_sec As Byte
      69. Dim Var_sec As Byte
      70. Dim Var_count As Byte
      71. Dim Var_zahl As Byte
      72. Dim Var_digit_array(4) As Word
      73. Dim Var_digit_tmp As Dword
      74. Dim Var_volt As Single
      75. Dim Var_volt_adc As Word
      76. Dim Var_undervoltage As Byte
      77. 'Ende Variablen
      78. '=============================================================
      79. '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      80. 'Konstanten
      81. Const Cons_volt = 0.005
      82. Const Cons_volt_restart = 4.24
      83. Const Cons_shutdown = 3
      84. 'Ende Konstanten
      85. '=============================================================
      86. '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      87. 'Watchdog
      88. Config Watchdog = 2048
      89. 'Start Watchdog
      90. 'Ende Watchdog
      91. '=============================================================
      92. '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      93. 'Funktionen
      94. Declare Function Get_dht11() As Byte
      95. 'Ende Funktionen
      96. '=============================================================
      97. '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      98. 'Spannung Messen Anfang
      99. Config Adc = Single , Prescaler = Auto , Reference = Internal
      100. Start Adc
      101. 'Ende Spannung Messen
      102. '=============================================================
      103. '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      104. 'Funkuhr
      105. Config Pind.2 = Input
      106. Config Dcf77 = Pind.2 , Timer = 1 , Timer1sec = 1 , Debug = 1 , Check = 2 , Update = 0,
      107. Enable Interrupts
      108. Config Date = Dmy , Separator = .
      109. 'Ende Funkuhr
      110. '=============================================================
      111. Do
      112. 'Jede Sekunde eine Messung
      113. If _sec <> Var_old_sec Then
      114. Var_old_sec = _sec
      115. Incr Var_sec
      116. If Var_sec < 11 Then
      117. Var_digit_tmp = _min Mod 10
      118. Var_digit_array(1) = Var_digit_tmp
      119. Var_digit_tmp = _min / 10
      120. Var_digit_array(2) = Var_digit_tmp
      121. Var_digit_tmp = _hour Mod 10
      122. Var_digit_array(3) = Var_digit_tmp
      123. Var_digit_tmp = _hour / 10
      124. Var_digit_array(4) = Var_digit_tmp
      125. Elseif Var_sec = 11 Then
      126. If Get_dht11() = 1 Then 'Daten richtig empfangen
      127. Var_digit_array(1) = 10
      128. Var_digit_tmp = Temperatur Mod 10
      129. Var_digit_array(2) = Var_digit_tmp
      130. Var_digit_tmp = Temperatur / 10
      131. Var_digit_array(3) = Var_digit_tmp
      132. Var_digit_array(4) = 12
      133. Else 'Fehlercod ausgeben
      134. Var_digit_array(1) = 10
      135. Var_digit_array(2) = 13
      136. Var_digit_array(3) = 13
      137. Var_digit_array(4) = 13
      138. End If
      139. 'Ende Code erster Teil zweiter Teil da zulang im nächsten Beitrag!
      Display All
      Grüße & Herzlichsten Dank!
      Alex
    • Source Code

      1. 'Hier geht der Code vom ersten Beitrag weiter
      2. 'da er zulang war.
      3. Elseif Var_sec = 21 Then
      4. If Get_dht11() = 1 Then 'Daten richtig empfangen
      5. Var_digit_array(1) = 11
      6. Var_digit_tmp = Luftfeuchtigkeit Mod 10
      7. Var_digit_array(2) = Var_digit_tmp
      8. Var_digit_tmp = Luftfeuchtigkeit / 10
      9. Var_digit_array(3) = Var_digit_tmp
      10. Var_digit_array(4) = 12
      11. Else 'Fehlercod ausgeben
      12. Var_digit_array(1) = 11
      13. Var_digit_array(2) = 13
      14. Var_digit_array(3) = 13
      15. Var_digit_array(4) = 13
      16. End If
      17. End If
      18. If Var_sec = 30 Then Var_sec = 0
      19. Var_volt_adc = Getadc(5)
      20. Var_volt = Var_volt_adc * Cons_volt
      21. If Var_volt < Cons_shutdown Then
      22. Incr Var_undervoltage
      23. Else
      24. Var_undervoltage = 0
      25. End If
      26. If Var_undervoltage = 30 Then
      27. End If
      28. End If
      29. Incr Var_count
      30. If Var_count = 1 Then
      31. Portb = Var_ziffern(13)
      32. Var_zahl = Var_digit_array(4) + 1
      33. Gnd_digit_1 = 0
      34. Gnd_digit_2 = 1
      35. Gnd_digit_3 = 1
      36. Gnd_digit_4 = 1
      37. Portb = Var_ziffern(var_zahl)
      38. Elseif Var_count = 2 Then
      39. Portb = Var_ziffern(13)
      40. Var_zahl = Var_digit_array(3) + 1
      41. Gnd_digit_1 = 1
      42. Gnd_digit_2 = 0
      43. Gnd_digit_3 = 1
      44. Gnd_digit_4 = 1
      45. If Var_sec > 0 And Var_sec < 11 Then
      46. Portb = Var_ziffern_dot(var_zahl)
      47. Else
      48. Portb = Var_ziffern(var_zahl)
      49. End If
      50. Elseif Var_count = 3 Then
      51. Portb = Var_ziffern(13)
      52. Var_zahl = Var_digit_array(2) + 1
      53. Gnd_digit_1 = 1
      54. Gnd_digit_2 = 1
      55. Gnd_digit_3 = 0
      56. Gnd_digit_4 = 1
      57. Portb = Var_ziffern(var_zahl)
      58. Elseif Var_count = 4 Then
      59. Portb = Var_ziffern(13)
      60. Var_zahl = Var_digit_array(1) + 1
      61. Gnd_digit_1 = 1
      62. Gnd_digit_2 = 1
      63. Gnd_digit_3 = 1
      64. Gnd_digit_4 = 0
      65. Portb = Var_ziffern(var_zahl)
      66. Var_count = 0
      67. End If
      68. Waitms 0.25
      69. Reset Watchdog
      70. Loop
      71. End 'end program
      72. Function Get_dht11() As Byte
      73. Local Array_index As Byte 'Index für Array
      74. Local Bit_position As Byte 'Bit-Position im Byte
      75. Local Crc_check As Byte 'Berechnung CRC
      76. 'Start Übertragung
      77. Set Dht_io 'Daten Senden
      78. Reset Dht_write 'Ausgang auf low
      79. Waitms 18 '18ms auf low
      80. Set Dht_write 'Ausgang auf high
      81. Waitus 30 'Ausgang muss 20-40µs high sein
      82. Reset Dht_io 'Daten Empfangen
      83. Waitus 40 'DHT sendet 80µs low => hier halbe Periode
      84. If Dht_read = 1 Then 'ist der Eingang nach 40µs immer noch high
      85. Get_dht11 = 2 'Fehlercode => 2
      86. Exit Function 'Function verlassen
      87. End If
      88. Waitus 80
      89. 'Eingang muss nach weiteren 80 µs wartzeit eigendlich high sein
      90. If Dht_read = 0 Then 'ist der Eingang low
      91. Get_dht11 = 3 'Fehlercode => 3
      92. Exit Function 'Function verlassen
      93. End If
      94. While Dht_read = 1 : Wend 'warten bis Eingang auf low geht => Startsequenz beendet
      95. '40 Daten-Bit's empfangen und in Daten-Array schreiben
      96. 'Byte 1 => Vorkomma Luftfeuchtigkeit
      97. 'Byte 2 => Nachkomma Luftfeuchtigkeit
      98. 'Byte 3 => Vorkomma Temperatur
      99. 'Byte 4 => Nachkomma Temperatur
      100. 'Byte 5 => CRC
      101. For Array_index = 1 To 5 '5 Byte => Dht_daten(5)
      102. For Bit_position = 7 To 0 Step -1 '8 Bit => höheres Bit zu erst
      103. While Dht_read = 0 : Wend 'warten bis der Eingang auf high geht => dauer 50µs
      104. '26-28us high => entspricht 0
      105. '70us high => entspricht 1
      106. Waitus 30 '30µs warten und schauen wie der Eingang ist
      107. If Dht_read = 1 Then 'bei "1" ist der Eingang nach 30µs immer noch high
      108. Dht_daten(array_index).bit_position = 1 '"1" an Bitposition schreiben
      109. While Dht_read = 1 : Wend 'warten bis Eingang wieder auf low geht
      110. Else 'bei "0" ist der Eingang nach 30µs low
      111. Dht_daten(array_index).bit_position = 0 '"0" an Bitposotion schreiben
      112. End If
      113. Next 'ein Bit empfangen
      114. Next
      115. Set Dht_io 'Daten Senden
      116. Set Dht_write 'Ausgang high
      117. 'Vergleich Summe der ersten 4 Bytes des Array, mit dem 5. Byte des Array
      118. Crc_check = Dht_daten(1) + Dht_daten(2)
      119. Crc_check = Crc_check + Dht_daten(3)
      120. Crc_check = Crc_check + Dht_daten(4)
      121. If Crc_check = Dht_daten(5) Then
      122. Get_dht11 = 1 'Alles in Ordnung
      123. Else
      124. Get_dht11 = 4 'Fehlercode => 4
      125. End If
      126. End Function
      127. Return
      Display All
    • Alex_T wrote:

      Waitms 0.25
      Für Wartezeiten kannst du nur ganze Zahlen benutzen.


      Alex_T wrote:

      Config Watchdog = 2048

      Alex_T wrote:

      While Dht_read = 1 : Wend

      Wenn Dht_read nicht null wird, schlägt der Watchdog zu - Reset

      Ich würde erstmal den Watchdog ausschalten, eine LED zum Debuggen anschließen und diese an strategischen Stellen leuchten lassen.
      Das natürlich Schritt für Schritt im Programm, um zu sehen, wo genau das Programm hängen bleibt.
    • Michael wrote:

      Alex_T wrote:

      Config Watchdog = 2048

      Alex_T wrote:

      While Dht_read = 1 : Wend
      Wenn Dht_read nicht null wird, schlägt der Watchdog zu - Reset

      Ich würde erstmal den Watchdog ausschalten, eine LED zum Debuggen anschließen und diese an strategischen Stellen leuchten lassen.
      Das natürlich Schritt für Schritt im Programm, um zu sehen, wo genau das Programm hängen bleibt.
      Mir bereiten diese While Wend Schleifen die auf ein bestimmtes Ereignis warten generell Kopfzerbrechen.
      Könnte man sowas vielleicht an einen Timer Outsourcen?

      Das zerschisst mir mit sicherheit das ganze Programm.
      Also wenn das Programm 2 Sekunden steht ist das echt übel....

      Ich würde gerne diese while wend schleifen weg kriegen...

      Grüße
      Alex
    • Ich denke das Problem ist einfach das Timing beim Einlesen.
      Der Controller-Takt ist ja nur 1MHz, also pro Takt 1µs.

      Die Datenbits sind nur 50µs (50 Takte), also darf man nicht "schlafen", wenn man da Waits rein macht.
      Jede Instruktion benötigt Zeit, das hast du da vielleicht nicht ausreichend berücksichtigt.

      Vielleicht wäre es bei dem geringen Takt (1MHz) ein besserer Weg einen Timer zu verwenden (Prescale=1) und damit die Zeit zu messen für die Low-Pulse. Das kompensiert zumindest die Code-Laufzeit.

      Alternativ könnte man sich auch mal den Befehl PulseIn genauer anschauen.
    • Mitch64 wrote:

      Vielleicht wäre es bei dem geringen Takt (1MHz) ein besserer Weg einen Timer zu verwenden (Prescale=1) und damit die Zeit zu messen für die Low-Pulse.
      eher nicht, der normale Timereinsprung und das Verlassen dauern zusammen schon über 60 Takte für die Register.
      Und ich fürchte, Alex ist noch nicht so weit, dass er Timerinterrupts entsprechend verwenden kann.

      Es spricht ja nichts dagegen, einen höheren Takt zu verwenden, oder?

      Vielleicht gibt es auch Anregungen in anderen Threads hier im Forum:
      google.com/search?&q=site%3Abascomforum.de+dht11
    • Alex_T wrote:


      Mir bereiten diese While Wend Schleifen die auf ein bestimmtes Ereignis warten generell Kopfzerbrechen.
      Könnte man sowas vielleicht an einen Timer Outsourcen?


      Das zerschisst mir mit sicherheit das ganze Programm.
      Also wenn das Programm 2 Sekunden steht ist das echt übel....

      Ich würde gerne diese while wend schleifen weg kriegen...

      Grüße
      Alex
      Hallo Alex,
      diese Wartestelle steht innerhalb einer Funktion, da wirst du den Ablauf deines gesamten Programm ändern müssen, wenn du dies wegbekommen willst.
      Denn du musst ja mit dem Befehl hinter der While Schleife weitermachen, wenn die Bedingung Dht_read <> 0 eingetroffen ist.
      Evtl. macht es Sinn, die While Schleife selber zu nutzen, um etwas anderes zu machen. Aber solche Nebeneffekte innerhalb einer Funktion sind schon recht schräg.
    • @All Danke!

      Das Problem ließ sich einfacher lösen als gedacht.
      Ein umstellen der Frequenz auf 4 Mhz reichte aus.
      Auch der Watchdog läuft ohne Probleme.

      Das mit dem Timer-Interrupts klingt interessant - da muss ich mich umbedingt mal einlesen.
      Dachte mir schon das die Waitus Anweisung in der Funktion mit 1Mhz nicht funktionieren könnte - hab den gedanken wohl etwas verdängt.
      Schlecht ist für mich die höhere Frequenz wegen des Batteriebetriebs.
      Ich hätte lieber noch weniger als 1 Mhz als mehr.

      Grüße
      Alex
    • Vielleicht läuft das auch noch mit 2 MHz Takt. Das kannst du ja mal ausprobieren.

      Wenn du 1MHz Takt oder sogar weniger, wird es schwierig. Da muss man dann schon entweder Assembler anwenden oder geschickt mit Timer arbeiten. Da zählt dann jeder Takt und das sollte man dann im Simulator prüfen. Da wird ja die Anzahl Takte für jede Anweisung angezeigt.
      Rein in Basic programmiert wird es vielleicht gerade noch bei 1 MHz Takt machbar sein.

      Bei der Verwendung von Interrupts muss man auch so manches beachten.
      Wie Michael schon sagte, verbraucht das nur für den Einsprung in die ISR schon 58 Takte und dann nochmal 57 Takte beim Rücksprung.
      Nach Simulator braucht also eine Leere ISR-Routine bereits 111 Takte. Bei 1 MHz Takt ist das 111 mal 1 µs.
      Man kann sich denken, dass so ein DHT nicht auslesbar ist.

      Aber die Rechnung stimmt eben nur, wenn man auf NoSave beim Konfigurieren der ISR-Routine verzichtet.

      Mit NoSave muss man sich selber um die Sicherung/Wiederherstellung der verwendeten Register kümmern.
      Im Vergleich: Bei einer Leeren ISR (was keinen Sinn macht), muss auch nichts an Registern gesichert werden.
      Daher würde die leere ISR mit NoSave nur 9 Takte brauchen. Das wären dann bei 1 MHz Takt also 9µs.
      Da ist also schon eine deutliche Steugerung möglich, wenn man NoSave einsetzt.

      BASCOM Source Code

      1. ' Vergleich Verbrauch an Takten bei ISR-Aufruf
      2. ' - mit NoSave und: 111 Takte
      3. ' - ohne 'NoSave': 9 Takte
      4. $Regfile = "m8def.dat"
      5. $HWStack = 30
      6. $SWStack = 30
      7. $FrameSize = 30
      8. $Crystal = 1000000 ' int. Oszillator
      9. $SIM
      10. On Timer1 ISR_Test NoSave
      11. Enable Timer1
      12. Enable Interrupts
      13. Do
      14. NOP
      15. Loop
      16. ' Die leere ISR-Routine
      17. ISR_Test:
      18. Return
      Display All

      Wie gesagt. Der Vergleich hinkt etwas, weil man ja Register sichern muss. und die ISR i.d.R. nicht leer ist.
      Zeigt aber doch Eindrucksvoll den Gewinn an Zeit.

      Für solche Fälle ist es immer gut, sich auch mit dem Simulator auszukennen.
      Damit lässt sich auch feststellen, welche Register in der ISR geändert werden.
      Damit kann man diese Register selber sichern und hat auch in Basic schon einen Performance-Gewinn.
      Bascom Sichert eben fast alle Register bis auf wenige Ausnahmen, was zwar bequem ist aber auf Kosten der Zeit geht.
    • Alex_T wrote:

      Schlecht ist für mich die höhere Frequenz wegen des Batteriebetriebs.
      Die Info gehört eigentlich in den ersten Beitrag.

      Es ist imho nicht sinnvoll, den AVR dauerhaft auf niedriger Frequenz laufen zu lassen, um Strom zu sparen.
      Der Spareffekt wird aufgefressen durch die lange Rechenzeit und Beschränkungen durch die niedrige Frequenz, wie du sie jetzt erlebt hast.

      Besser ist es, den AVR in den Pausen schlafen zu legen und bei Bedarf zu wecken und mit voller Rechenleistung in entsprechend kürzerer Zeit die Aufgabe zu erledigen.

      Allerdings fürchte ich, dass deine Ausgabe mit 7-Segment-LED Anzeigen funktioniert, wenn ich den Code so ansehe.
      Dann ist Stromsparen durch Taktzeitreduzierung (oder schlafen) eh sinnlos.

      P.S.: Wenn der Code zu groß ist für das Posten im Codefenster, dann ist es besser, du hängst ihn als Dateianhang an.