Bascom ATmega soll immer auf Tastendruck warten

Johnny Bravo

Neues Mitglied
31. März 2012
10
0
0
39
Sprachen
Hi,

Ich habe in meinem Projekt ein (hoffentlich) "nur" kleines Problem.

Mein Programm soll immer auf eine Tastereingabe (Pind.7 nach GND) warten und dementsprechend eine Sub ausführen.
Das funktioniert auch soweit, allerdings wird im Programm nebenbei die Softclock mit einem DCF77 Signal synchronisiert, und ein DS1820 Temperatur Sensor wird ausgelesen und alle Daten auf ein Display ausgegeben.

Da der Temperatursensor ja mindestens 750ms zum konvertieren der Temperatur braucht, klappt die Abfrage nicht immer, ob der Pin auf GND liegt oder war.
Das ist etwas problematisch, da dies eine Klingelsteuerung werden soll und natürlich jederzeit geklingelt werden soll/kann ;)

Verzeiht mir bitte die vielleicht blöden Texte oder Bezeichnungen :)

Wie kann ich nun dem Programm sagen, dass er immer auf den Tastendruck warten soll? Würde eine While oder Case Verzweigung in der Hauptschleife eventuell das Problem lösen?


Hier mein Code:
Code:
$regfile = "m8def.dat"
$crystal = 1000000
$hwstack = 40
$swstack = 16
$framesize = 32

Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portd.5 , Rs = Portd.6
Config Lcd = 20 * 4
Config 1wire = Portd.0
Config Dcf77 = Pinb.2 , Timer = 1 , Debug = 1 , Check = 1 , Inverted = 1
Config Pind.7 = Input
Config Pinc.5 = Output
Config Pinc.4 = Output
Config Portb.1 = Output
Config Date = Dmy , Separator = .
Portd.7 = 1

Enable Interrupts

Dim Dcf As Byte
Dim Temp As Byte
Dim Spp(9) As Byte
Dim T_integer As Integer
Dim T_real As Integer
Dim 1w_i As Byte
Dim 1w_t1 As Integer
Dim 1w_t As Integer
Dim T_komma As Integer
Dim T_komma1 As Integer

Declare Sub Anzeige_lcd
Declare Sub Temperatur_lesen
Declare Sub Temperatur_starten
Declare Sub Integer_real
Declare Function Ds1820_get_temp_f10() As Integer



Cursor Off Noblink
Cls
Waitms 100

Do
nop
  If Pind.7 = 0 Then Gosub Dingdong
  Call Temperatur_lesen
  Waitms 800
  Call Temperatur_starten
  If Pind.7 = 0 Then Gosub Dingdong
  Call Integer_real
  Call Anzeige_lcd
Loop

End


Sub Anzeige_lcd

 Locate 1 , 1
  Lcd " Test Zeile 1"
 Locate 2 , 1
  Lcd " Test Zeile 2"
 Locate 4 , 1
  Lcd " " ; Time$ ; "  " ; Date$
  Locate 3 , 9
 Lcd T_real ; "." ; T_komma1 ; Chr(223) ; "C   "

  If Pind.7 = 0 Then Gosub Dingdong
End Sub


Sub Temperatur_starten

   1wreset
   1wwrite &HCC
   1wwrite &H44


End Sub


Sub Temperatur_lesen

   1wreset
   1wwrite &H33
   Temp = 1wread(1)

   1wreset
   1wwrite &HCC                                             'Rom überspringen, nur 1 Sensor
   1wwrite &HBE                                             ' Temperatur auslesen
   Spp(1) = 1wread(9)                                       ' Daten in ein Array lesen


  If Temp = &H10 Then
     T_integer = Ds1820_get_temp_f10()
  End If
  If Pind.7 = 0 Then Gosub Dingdong
End Sub


Sub Integer_real

      T_real = T_integer / 10
      T_komma = T_integer Mod 10

     If T_komma < 5 Then
       T_komma1 = 0
      Else
        T_komma1 = 5
     End If

End Sub

Dingdong:

 Portb.1 = 1                       'Schaltet Optokoppler/Klingel
  Waitms 100
 Portb.1 = 0
  Locate 2 , 1
   Lcd "    Ding!"
  Waitms 1000
  Locate 2,  1
  Lcd "          Dong!"
  Waitms 1000
  Locate 2 , 1
   Lcd "               "
Return



  Function Ds1820_get_temp_f10() As Integer

   'Rechnung für Family Code 10
   1w_i = Spp(1) And 1
   If 1w_i = 1 Then Decr Spp(1)
   1w_t = Makeint(spp(1) , Spp(2))
   1w_t = 1w_t * 50
   1w_t = 1w_t - 25
   1w_t1 = Spp(8) - Spp(7)
   1w_t1 = 1w_t1 * 100
   1w_t1 = 1w_t1 / Spp(8)
   1w_t = 1w_t + 1w_t1
   1w_t = 1w_t / 10
      ' Temperatur in 0,1 Grad Schritten
   1w_t1 = 1w_t / 10
   Ds1820_get_temp_f10 = 1w_t                               '/ 10

End Function

Wie man sehen kann, habe ich fast überall die Abfrage eingebaut, ob die Taste gedrückt wurde, allerdings klappt das ja leider nicht immer. Wenn man im Falschen Zeitfenster drückt, wird das nicht registriert und natürlich nichts gemacht.
 
Hallo Johnny!

Ich habe mir dein Programm jetzt gar nicht angesehen, sondern schreibe nur mal etwas zu deinem Beitrag. :wink:

Eigentlich gilt ja der Grundsatz, dass man einen Taster nicht am externen Interrupt betreiben soll.
Wenn aber dein Tastendruck soooo wichtig ist, dann würde ich das vielleicht mal in Erwägung ziehen.

Was du allerdings optimieren könntest, ist die Wartezeit beim DS1820.
Da der Sensor recht lange braucht, könntest du die Routine in zwei Abschnitte aufteilen.
Die Softclock hast du ja wegen DCF77 sowieso in Betrieb. Aktiviere doch die SECTIC-Subroutine.
In der Routine toggelst du dann ein Flag (Bit).
Bei Systemstart wird NUR die Temperaturkonvertierung im Sensort gestartet!
Nach einer Sekunde ist das Flag dann high (1) und dann werden als erstes NUR die neuen Werte abgeholt UND danach NUR die neue Konvertierung gestartet.
Anschließend kannst du die Werte berechnen und auf dem LCD ausgeben.

Mit dieser Vorgehensweise hast du zwar nur jede Sekunde einen neuen Temperaturwert.... aber für die meisten Verwedungszwecke sollte das wohl reichen. :wink:
Obendrein hast du damit genug Zeit, um auf den Tastendruck zu reagieren.


Grüße,
Cassio
 
Hi Cassio,
danke für deine Antwort.

Die Temperatur ist sogar schon in mehrere Subs aufgeteilt, Temperatur starten, Temperatur lesen/konvertieren und die Temperatur in einen Integer umwandeln. ;)

Die Wartezeit (800ms) ist in der Hauptschleife untergebracht. Wahrscheinlich ist das ja kontraproduktiv.

Wie oft die Temperatur aktualisiert wird ist mir eigentlich relativ egal, die kann meinetwegen sogar 5 Sekunden betragen - falls es sinnvoll ist.
Meinst du also du die sectic Routine in der Hauptschleife unterbringen, ebenfalls alle anderen Instruktionen?
Die Konvertierungszeit brauche ich ja dann auch nicht mehr, oder ?

Code:
Dim flag As Bit

Code:
Do
nop
 flag = 0 
 Gosub Sectic
  Call Anzeige_lcd
Loop

End

Code:
Sectic:
  flag = 1 
  Call Temperatur_lesen
  Call Temperatur_starten   
  Call Integer_real
Return

Ich hoffe ich habe es richtig verstanden, ich bin gerade am Laptop und habe es nur Quick and Dirty gemacht, ohne Bacom zur Hand zu haben ;)

Danke.
 
Hallo !

Nee.... so nicht....
na ja, fast. :wink:


Du kannst die SECTIC direkt in der Config-Zeile für das DCF77 aktivieren.
Beispiel:
Code:
Config Dcf77 = Pina.7 , Timer = 1 , Timer1sec = 1 , Debug = 1 , Update = 0 , Check = 0 , Inverted = 1 ,[B] Gosub = Sectic[/B]

Dann erstellst du eine Subroutine mit dem Namen: Sectic!
Code:
Sectic:

Return


Mit der Anwiesung in der DCF-Config wird nun die Subroutine SECTIC dann automatisch jede Sekunde aufgerufen.


In der Sectic-Sub kannst du nun ein Flag togglen.
Code:
Sectic:
Ds1820_flag = 1

Return

Dieses Flag kannst du dann in deiner Hauptarbeitsschleife verwenden.
Wenn es HIGH ist, dann springst du in deine Sub für den DS1820-Sensor.

In dieser Sub werden zu Beginn die Werte der letzten Temperaturkonvertrierung abgerufen.....
und DANACH eine neue Konvertierung gestartet.

Zum Schluss wird das Flag in der Sub noch wieder resetet.
Code:
DS1820:

'Datenbytes abrufen

'Neue Konvertierung starten

Ds1820_flag = 0

Return


Grüße,
Cassio
 
Hi Cassio,

ich habe deine Antwort in meinen Code portiert, allerdings läuft die Softclock nun ewig und wird nicht mehr synchronisiert. Außerdem wird keine Temperatur mehr angezeigt :fie:
Die Abfrage, ob der Taster gedrückt wurde, muss doch trotzdem in die Hauptschleife?


Hier mal der relevante Code in "Kurzfassung":
Code:
$regfile = "m8def.dat"
$crystal = 1000000
$hwstack = 40
$swstack = 16
$framesize = 32

Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portd.5 , Rs = Portd.6
Config Lcd = 20 * 4
Config 1wire = Portd.0
Config Dcf77 = Pinb.2 , Timer = 1 , Debug = 1 , Check = 1 , Inverted = 1 , Gosub = Sectic
Config Pind.7 = Input
Config Pinc.5 = Output
Config Pinc.4 = Output
Config Portb.1 = Output
Config Date = Dmy , Separator = .
Portd.7 = 1

Enable Interrupts

Dim Dcf As Byte
Dim Temp As Byte
Dim Spp(9) As Byte
Dim T_integer As Integer
Dim T_real As Integer
Dim 1w_i As Byte
Dim 1w_t1 As Integer
Dim 1w_t As Integer
Dim T_komma As Integer
Dim T_komma1 As Integer                                                      
Dim Ds18s20_flag As Bit                                                     

Declare Sub Anzeige_lcd
Declare Sub Temperatur_lesen
Declare Sub Temperatur_starten
Declare Sub Integer_real
Declare Function Ds1820_get_temp_f10() As Integer



Cursor Off Noblink
Cls
Waitms 100

Do
nop
  If Pind.7 = 0 Then Gosub Dingdong
  Call Anzeige_lcd
  If Ds18s20_flag = 1 Then Gosub Sectic
Loop

End

Sub Anzeige_lcd

[...]'LCD Texte
End Sub


Sub Temperatur_starten

   1wreset
   1wwrite &HCC
   1wwrite &H44
   Waitms 800

End Sub


Sub Temperatur_lesen

   1wreset
   1wwrite &H33
   Temp = 1wread(1)

   1wreset
   1wwrite &HCC                                             'Rom überspringen, nur 1 Sensor
   1wwrite &HBE                                             ' Temperatur auslesen
   Spp(1) = 1wread(9)                                       ' Daten in ein Array lesen


  If Temp = &H10 Then
     T_integer = Ds1820_get_temp_f10()
  End If
End Sub


Sub Integer_real
[...] ' Temperatur in Integer umwandeln

End Sub

Dingdong:
[...] ' LCD Text
Return

Sectic:
Ds18s20_flag = 1
Call Temperatur_lesen
Call Temperatur_starten
Call Integer_real
If Pind.7 = 0 Then Gosub Dingdong
Return



  Function Ds1820_get_temp_f10() As Integer
[...]  ' Temperatur auslesen
   Ds18s20_flag = 0
End Function

Danke für deine Hilfe.
 
Hallo Johnny!

Scheinbar hast du meine Hinweise nicht richtig gelesen.......
und teilweise sogar falsch verstanden. :hmmmm:


Was ich dir geschrieben habe waren einfach nur ein paar Denkanstöße und keine fertige Lösung!

In meinem Beitrag habe ich z.B. geschrieben (incl. Tippfehler :wink: ):
Mit der Anwiesung in der DCF-Config wird nun die Subroutine SECTIC dann automatisch jede Sekunde aufgerufen.


Wenn die SECTIC jede Sekunde automatisch aufgerufen wird, warum schreibst du dann soetwas:
Code:
If Ds18s20_flag = 1 Then Gosub Sectic

Was soll das bringen? :hmmmm:


Ich würde sagen, du liest dir meinen Beitrag noch mal in Ruhe durch und versuchst dass dann noch mal. :wink:
Oder hier noch mal die Kurzform:
  • SECTIC toggelt ein Flag
  • In der Hauptroutine (DO-LOOP) wird das Flag abgefragt und darauf reagiert
  • Je nach Flag und Reaktion wird die SUB für die Temperatur ausgeführt
  • Anschließend geht es mit der Hauptschleife (DO-LOOP) weiter


Also.... auf ein Neues und gutes Gelingen! :)


Bis später dann..... :ciao:
Cassio
 
Hi Cassio,

man möge mir verzeihen, es war gestern schon Spät und heute habe ich es trotzdem nicht verstanden :D
Ich habe auch gemerkt, dass die If Abfrage ziemlich Sinn frei ist. :cool:

Neuer Versuch:

Hauptschleife:
Code:
Do                                         
 If Ds18s20_flag = 1 Then                  
   gosub Temperatur_lesen                                   
   gosub Temperatur_starten
   gosub Integer_real                             
  End If
If Pind.7 = 0 Then gosub Dingdong
Loop

Sectic:
Code:
Sectic:
 Ds18s20_flag = 1
Return

Temperatur in Integer umwandeln:
Code:
Temperatur_lesen:

   1wreset
   1wwrite &H33
   Temp = 1wread(1)

   1wreset
   1wwrite &HCC                                            
   1wwrite &HBE                                             
   Spp(1) = 1wread(9)                                       


  If Temp = &H10 Then
     T_integer = Ds1820_get_temp_f10()
  End If
 Ds18s20_flag = 0                                     'Hier den Flag auf  0 setzen, oder doch in der anderen Sub wo die Temp nach Integer umgewandelt wird?
Return

Ich glaube dass ich es jetzt (hoffentlich) verstanden habe. Meine Frage ist jetzt noch, sollen die Subs (Temp auslesen, Temp konvertieren, Temp als Integer) bei einem Flag = 1 gestartet werden, oder nur der eigentlich relevante Teil wo die Temperatur als Integer umgewandelt wird (und die anderen beiden Subs in die Hauptschleife packen als Sub)?
Und wo es am sinnvollsten ist den Flag wieder auf 0 zu setzen? In der Sub Temp auslesen oder doch beim Integer?

Sorry für die vielleicht blöden Fragen, ich möchte ja das wie und warum verstehen, aber ich bin noch ziemlicher Anfänger :)
 
Hallo Johnny!

Na, das sieht doch schon besser aus. :wink:

Generell müsstest du für den DS1820 gar nicht so viele einzelne Subroutinen verwenden.
Dies würde auch nur Sinn machen, wenn du die Inhalte zu verschiedenen Zeiten (oder Aktionen) erledigen möchtest.

Da aber alles nacheinander passiert, kannst du es auch in eine einzige Sub packen.
Allerdings solltest du dann aber die Reihenfolge beachten:
-erst die Werte abholen
-dann neue Konvertierung starten
-danach Temp.-Wert berechnen

Das Rücksetzen des Flags wird dann kurz vor dem Verlassen der Subroutine erledigt.


Mit dieser Variante solltest du nun auch keine größeren Probleme mehr mit deinem Klingeltaster haben.

Es kann allerdings vorkommen dass jemand klingelt, wenn gerade die Temperatur berechnet wird..... sich dein Programm also in der Sub befindet. :wink:
Dieser Tastendruck geht dir dann immer noch durch die Lappen.

Wenn du ganz sicher gehen möchtest keinen Tastendruck zu verpassen, dann musst mit dem externen Interrupt (INT0 oder INT1) arbeiten.

Probiere es aber erst mal so aus.

Grüße,
Cassio
 
Hi,
ok, dann packe ich alles was mit der Temperatur zu tun hat in eine Sub:

Code:
Temperatur_starten:

   1wreset
   1wwrite &HCC
   1wwrite &H44
   Waitms 800

   1wreset
   1wwrite &H33
   Temp = 1wread(1)

   1wreset
   1wwrite &HCC                                             'Rom überspringen, nur 1 Sensor
   1wwrite &HBE                                             ' Temperatur auslesen
   Spp(1) = 1wread(9)                                       ' Daten in ein Array lesen


  If Temp = &H10 Then
     T_integer = Ds1820_get_temp_f10()
  End If

    T_real = T_integer / 10
      T_komma = T_integer Mod 10

     If T_komma < 5 Then
        T_komma = 0
       End If
     If T_komma > 5 Then
        T_komma = 5
     End If

     Ds18s20_flag = 0
Return

Die Temperatur wird jetzt korrekt ausgelesen, allerdings bekomme ich nach 2 mal klingeln lauter komische Zeichen auf dem LCD angezeigt. Nichts ist mehr lesbar oder erkennbar.
Könnte das mit dem SW und HW Stack zu tun haben?

Code:
$hwstack = 40
$swstack = 16
$framesize = 32

Am klingelverhalten hat sich leider nicht viel getan, es reagiert leider immer noch nicht immer.

EDIT:
Die komischen Zeichen sind weg, es lag an einer If Verzweigung in der Hauptschleife, die Testweise etwas an einem bestimmtem Datum machen sollte - machte sie aber anscheinend nicht und hat alles durcheinander gebracht.
 
Hallo Johnny!

Also deine Frame/Stack-Werte sind definitv zu gering!
Setz doch bitte alles mal auf 128!


Dann hast du leider meine Anweisung zum DS1820 immer noch nicht so umgesetzt, wie ich das schon zweimal geschrieben habe!
Du sollst erst die Daten auslesen und dann eine Konvertierung starten.


Ob der Rest vom Programm schlüssig ist und funktioniert habe ich nicht geschrieben.
Ich bin der Meinung, dass du da an einigen Stellen bestimmt noch mal nachbessern musst. :wink:


Grüße,
Cassio
 
Hi,

ok, die Stackwerte habe ich alle auf 128 erhöht.
Du konntest natürlich nicht wissen dass ich Testweise eine andere Abfrage in der Haupschleife eingebaut hatte, welche die Grafikfehler ausgelöst hatte. Die habe ich entfernt und nun geht es wieder halbwegs.

Das mit dem Taster hat mich doch gestört, und nun greife ich auf INT0 konfiguriert als Low Level zurück.
Das funktioniert soweit auch ganz gut, ich konnte bislang keine Aussetzer, also verpasste Betätigungen feststellen.

Jedoch schaltet der Interrupt komischerweise sporadisch in die ISR (Dingdong), obwohl der Taster an INT0 nicht gedrückt wurde.
Ich habe Testweise eine Led an PortB.1 gesteckt, diese leuchtet auch bei Low Level jedesmal wenn ich den Taster drücke.
Bei Falling und Rising leuchtet die Led beim ersten mal einmal und beim 2ten Tastendruck 2 mal kurz hintereinander.

Code:
Config Pind.2 = Input                                       'Taster Test
Portd.2 = 1                                 

On Int0 Dingdong
Config Int0 = Low Level

Enable Int0
Enable Interrupts

Code:
Dingdong:
PortB.1 = 1
Waitms 100
PortB.0 = 0
[Diverse anweisungen, Texte auf das LCD zu schreiben]
Return

Ich habe gelesen dass die ISR so kurz wie möglich sein soll - also vermute ich dass es eventuell an den LCD Texten in der ISR und den insgesamt 2s Wartezeit liegen könnte.
Wie kann ich jetzt also in der ISR eine andere Sub aufrufen, sobald INT0 auf die Veränderung reagiert und diese verlassen wurde? Ein einfaches Gosub in der ISR würde vermutlich nichts bringen, da diese Subroutine vorher abgearbeitet werden muss, bevor die ISR wieder in die Hauptschleife springt, oder liege ich falsch?

Es kann doch nicht so schwer sein auf einen blöden Tastendruck zu warten :/
 
Hi
Ich hab jetzt nicht alles verfolgt, da BASCOM nicht meine Welt ist, aber ich erkenne einen grundsätzlichen Denkfehler:
"Wartezeiten" Warum? Auch in Bascom gilt wie in allen Programmiersprachen: Einlesen, Verarbeiten und Ausgeben. Damit dein Programm jederzeit einen Input mitbekommt, gibt es zwei Möglichkeiten: Polling und Interrupt. Ersteres ist für Kontakt- und Signalabfragen geeignet, deren Signaldauer länger der Zykluszeit deines Programmes ist. Interrupt kommt immer dann zum Einsatz, wenn die Zykluszeit länger wie die Signaldauer ist. Und da ist dein Problem: du verlängerst mit "Wartezeiten" den Zyklus. Dadurch bist du gezwungen, nicht nur die Eingaben per Interrupt zu erfassen, sondern auch die Ausgaben im Interrupt zu bearbeiten und zuzuweisen, wenn's denn irgendwie funktionieren soll. Das ist äußerst ungeschickt, denn genau umgekehrt wird ein Schuh draus. Die Zykluszeit darf nur vom Programm beeinflußt werden. Also, ein Befehl hat x Taktzyklen. Somit ist die Programmzykluszeit abhängig von der Taktfrequenz und der Anzahl der Befehle.
Nun zu deinem Problem:
So wie ich es verstanden habe, liefert ein Bauteil seine Information erst nach einer Zeit. Das löst du, in dem du die Wartezeit ablaufen läßt. Nun ist der Controller damit beschäftigt, unnützn Kram abzuarbeiten und die Peripherie wird ignoriert. Das geht anders.
Der Controller hat einen Timer, der dir die Möglichkeit gibt, in einem Zeitintervall eine ISR, also eine Interrupt-Service-Routine aufzurufen. Nix mit GOSUB, sondern eine ISR wird vom Controller beim Interrupt aufgerufen.
Sagen wir, du bekommst jede mSek diesen Aufruf der ISR.
Zuerst zählst du mal bis hundert, dann hast du bei jedem Überlauf schon mal eine Zehntelsekunde für irgendwelche Zeitereignisse. Ein weiterer Zähler bis 10 liefert nun einen Sekundenimpuls.
Etwa so:
Code:
Timer_ISR
     Inc mSek
     If mSek<100 then return
    msek=0
    Zehntel_Bit = "1"
    Inc zehntel
    if zehntel<9 then Return
    Sekunde_Bit="1"
    Return
Das ist jetzt mal einfach so dahin geschmierter Pseudocode. Aber mit ein paar Änderungen sicherlich in BASCOM lauffähig.
Deine Programmschleife hat nun folgende Aufgabe:
die Eingänge abfragen
die Verarbeitung der IO und der Bits aus der ISR
die Ausgabe zu setzen

Das läuft in der Schleife und wird durch keine Wartezeit gebremst.
Soll nun eine Funktion mit einer Wartezeit belegt werden, so kann das ganz einfach mit einem Zähler erfüllt werden. Angenommen, du setzt ein Ausgangsbit und möchtest nach 5 Sekunden wieder ausschalten. Natürlich wird in dem Bereich "Verarbeitung" die Ausgabe vorbereitet, in dem ein Byte- ich nenn es mal "Out_Port_B" die Bits zugewiesen bekommt. Bei den Eingängen ist dies ählich, da steht die Information in einer Variablen namens "In_Port_C". Auch hier ein kleiner Pseudocode:
Code:
If In_Port_C and "00010000" then
   Out_Port_B= Out_Port_B or "00000010"
   Ein_Zeit=70
end if

If Zehntel_Bit="1" then
   If Ein_Zeit > 0 then
      Dec  Ein_Zeit 
      If Ein_Zeit =0 then Out_Port_B=Out_Port_B And "11111101"
   end If
   Zehntel_Bit="0" 
end If

Du kannst auch Sekunden benutzen, dann setzt du den Zähler halt auf 5. Wenn du diesen Ablauf verfolgst, dann stellst du fest, die ISR ist kurz. Ob das "Zehntel_Bit" 2 oder 3 msek. später bearbeitet wird ist doch völlig egal. Dies ist die einzige Ungenauigkeit, da die ISR genau nach der Bitabfrage aufgerufen werden kann als auch direkt davor. Der Programmcode dazwischen entspricht der Verschiebung. Deiner Anwendung ist das aber völlig egal, selbst bei einer Uhr würde es keinerlei Auswirkung auf die Genauigkeit haben, denn in der Bearbeitung liegst du immer im Bereich eines Interruptes. Ein weiterer Effekt ist, das du Eingänge nicht mehr über Interrupt erfassen musst, da eine Einlesefunktion aufgrund der rel. kurzen Programmzykluszeit ein Signal von einem Kontakt immer mitbekommt. So schnell kannst du gar nicht tippen. Es werden sogar die Prellsignale vom Kontakt erkannt und du die Eingänge zeitlich verzögern mußt, bevor ein Signal sauber steht. Bei dem Beispiel ist das egal, aber willst du Tastendrücke zählen, dann ist Entprellen Pflicht.
Nun noch eine kurze Erklärung zu den "And" und "Or"
Möchtest du ein einzelnes Bit in einem Byte abschalten, gilt AND
A: "00111010"
Konst: "11101111"
Erg.: "00101010" Bit 4 ist aus
Möchtest du ein einzelnes Bit setzen, gilt OR
A: "00111010"
Konst: "01000000"
Erg: "01111010" Bit 6 ist an

Es ist immer nur ein Bit verändert, der Rest bleibt unberührt.
Um ein Bit auf seinen Zustand abzufragen ist auch eine UND Verknüpfung anwendbar:
A: "00111010"
Konst: "00100000"
Erg: "00100000" ist >0 also Bit 5 ist "1"

A: "00111010"
Konst: "01000000"
Erg: "00000000" ist =0 also Bit 6 ist "0"

So, damit solltest du erst einmal von deiner Wartezeit wegkommen.
Gruß oldmax
 
Hi,

Ich habe gelesen dass die ISR so kurz wie möglich sein soll - also vermute ich dass es eventuell an den LCD Texten in der ISR und den insgesamt 2s Wartezeit liegen könnte.
Wenn du einen Programmbereich richtig langsam bekommen willst, dann ba an der Stelle LCD-Ausgaben rein :p :rolleyes:
Die sind in der ISR ein absolutes No-Go.

Gruß
Dino
 
Du konntest natürlich nicht wissen dass ich Testweise eine andere Abfrage in der Haupschleife eingebaut hatte, welche die Grafikfehler ausgelöst hatte. Die habe ich entfernt und nun geht es wieder halbwegs.


Hallo!

Ganz ehrlich.....
Was ich (und alle helfenden Anderen hier auch) überhaupt nicht mögen ist der Umstand,
dass hier ein anderer Programmcode eingestellt, als zu Hause ausprobiert wird! :mad:

Wenn wir dir hier helfen können (und wir machen das alle freiwillig), dann müssen wir auch über das selbe Programm sprechen!


Ich weiß momentan überhaupt nicht mehr, welches Programm du nun verwendest und was das alles beinhaltet.
Aus dem Grunde kann ich nur sagen:
Stell dein derzeitig VOLLSTÄNDIGES Programm hier ein.......
und wenn ich heute noch mal Zeit und Lust habe, dann schaue ich mir das ggf. noch mal an.

Tatsache ist bis jetzt.....
- dass du nicht alle Hinweise von mir umgesetzt hast,
- teilweise noch alte Fragmente im Programmcode auftauchen die dir das Leben schwer machen
- und du von Fehlern berichtest die ich hier mangels fehlenden Programmcode nicht nachvollziehen kann.


Sorry, aber so wird das hier nichts.
Da kann ich meine Freizeit auch für andere Dinge nutzen.

Es kann doch nicht so schwer sein auf einen blöden Tastendruck zu warten :/

Wer hat denn behauptet dass es eine einfache Sache ist? :hmmmm:
So ein "blöder Tastendruck" kann ganz schön knifflig werden, wenn er eine bestimmte Priorität im Gesamtprogramm besitzen soll.


Gruß,
Cassio
 
Erstmal danke für eure Antworten.
Ja, das mit der Zeile die ich testen wollte habe ich vergessen zu erwähnen und auch vergessen herauszunehmen. Ich wollte nur schauen ob die DCF Monatsabfrage so funktioniert wie ich sie mir vorgestellt habe.
Ich weiß auch dass ihr das in eurer Freizeit macht und weiß das auch zu schätzen, aber wie gesagt ich bin noch ziemlicher Anfänger und wenn mir hier etwas erklärt wird versuche ich das anhand von Beispielen im Netz zu verstehen.

Das ich noch nicht alles abgearbeit habe, liegt nur daran dass für mich im Moment der Taster oberste Priorität besitzt. Der Temperatur kann ich mich hinterher noch widmen, das Problem fiel mir nur ein da es zwar funktioniert, aber noch nicht zu 100%.

Ich habe es mittlerweile etwas anders gelöst: In der ISR wird ein Flag auf 1 gesetzt. In der Hauptschleife wird nun dieses Flag abgefragt und bei 1 wird eine Sub ausgeführt welches den Optokoppler schaltet.
Das funktioniert auch so wie ich es mir vorgestellt habe. Allerdings habe ich halt immer noch das Problem dass der Interrupt immer beim Spannungsverlust auf 1 ausgeführt wird, und sporadisch im Programm selber (manchmal erst nach einigen Stunden)
Also jedesmal wird dann logischweise geklingelt obwohl niemand den Taster gedrückt hat.

Hier der gesamt Code, ich habe mal Kommentare hinzugefügt.:
Code:
$regfile = "m8def.dat"
$crystal = 1000000
$hwstack = 128
$swstack = 128
$framesize = 128

Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portd.5 , Rs = Portd.6
Config Lcd = 20 * 4
Config 1wire = Portd.0
Config Dcf77 = Pinb.2 , Timer = 1 , Debug = 1 , Check = 1 , Inverted = 1 , Gosub = Sectic
Config Portb.1 = Output                                          'Optokoppler/Klingel
Config Date = Dmy , Separator = .
Config Pind.2 = Input                                       'Klingeltaster, wird nach GND gezogen
Portd.2 = 1                                                    

On Int0 Dingdong
Config Int0 = Falling

Enable Int0
Enable Interrupts


Dim Dcf As Byte
Dim Temp As Byte
Dim Spp(9) As Byte
Dim T_integer As Integer
Dim T_real As Integer
Dim 1w_i As Byte
Dim 1w_t1 As Integer
Dim 1w_t As Integer
Dim T_komma As Integer
Dim Ds18s20_flag As Bit
Dim Dingdong_flag As Bit

Declare Sub Anzeige_lcd
Declare Function Ds1820_get_temp_f10() As Integer



Cursor Off Noblink
Cls
Waitms 100

Do

  Call Anzeige_lcd                                             'LCD Text darstellen
  If Dingdong_flag = 1 Then Gosub Dinglcd               
  If Ds18s20_flag = 1 Then Gosub Temperatur_starten
Loop

End


Sub Anzeige_lcd

 Locate 1 , 1
  Lcd "Zeile 1"
 Locate 2 , 1
  Lcd " Zeile 2"
 Locate 4 , 1
  Lcd " " ; Time$ ; "  " ; Date$                                   'DCF77 Datum und Zeit
  Locate 3 , 9
 Lcd T_real ; "." ; T_komma ; Chr(223) ; "C"                'DS18S20 Temperatur

End Sub


Temperatur_starten:                                              'Auslesevorgang starten/konvertieren/in Integerwert umwandeln

   1wreset
   1wwrite &HCC
   1wwrite &H44
   Waitms 850

   1wreset
   1wwrite &H33
   Temp = 1wread(1)

   1wreset
   1wwrite &HCC                                             'Rom überspringen, nur 1 Sensor
   1wwrite &HBE                                             ' Temperatur auslesen
   Spp(1) = 1wread(9)                                       ' Daten in ein Array lesen


  If Temp = &H10 Then
     T_integer = Ds1820_get_temp_f10()
  End If

      T_real = T_integer / 10
      T_komma = T_integer Mod 10

     If T_komma < 5 Then
        T_komma = 0
       End If
     If T_komma > 5 Then
        T_komma = 5
     End If

     Ds18s20_flag = 0
Return

Dingdong:                                                                            'ISR von INT0
 Dingdong_flag = 1
Return

Dinglcd:                                                                               'Wird bei DingDong_Flag = 1 ausgeführt, schaltet den Optokoppler / Klingel
   Portb.1 = 1
   Waitms 100
   Portb.1 = 0
   Dingdong_flag = 0    
Return

Sectic:
  Ds18s20_flag = 1
Return



  Function Ds1820_get_temp_f10() As Integer

   'Rechnung für Family Code 10
   1w_i = Spp(1) And 1
   If 1w_i = 1 Then Decr Spp(1)
   1w_t = Makeint(spp(1) , Spp(2))
   1w_t = 1w_t * 50
   1w_t = 1w_t - 25
   1w_t1 = Spp(8) - Spp(7)
   1w_t1 = 1w_t1 * 100
   1w_t1 = 1w_t1 / Spp(8)
   1w_t = 1w_t + 1w_t1
   1w_t = 1w_t / 10
      ' Temperatur in 0,1 Grad Schritten
   1w_t1 = 1w_t / 10
   Ds1820_get_temp_f10 = 1w_t                               '/ 10
End Function

Wer hat denn behauptet dass es eine einfache Sache ist?
So ein "böder Tastendruck" kann ganz schön knifflig werden, wenn er eine bestimmte Priorität im Gesamtprogramm besitzen soll.

Ja, aber in meiner Leichtgläubigkeit dachte ich: Da ein Interrupt (so wie ich es verstanden habe) immer abgefragt wird, dürfte es ja eigentlich nicht so schwer sein, darauf zu reagieren. Deswegen verstehe ich nicht warum der Int0 beim Spannungsverlust und irgendwann sporadisch auftritt.
 
Hi
Wie ich sehe, bist du immer noch dabei, einen Klingeltaster per Interrupt abzufragen. Scheinbar ist es dir egal, was wir so von uns geben. :hahaha:
Nun, ja, dann mach weiter. Ist zwar meines Erachtens nicht der Weg, aber bitte. Wenn es dir Spaß macht sich zu verlaufen... :wavey:
Gruß oldmax
 
Hallo Johnny!

Lass mir mal bitte etwas Zeit.

Ich ändere dein Programm mal ein wenig, um dich mit den Beispielen auf einen möglichen richtigen Weg zu bringen. :wink:


Spiel also in der Zwischenzeit nicht so viel an deinem jetzigen Programm herum. :cool:


Grüße,
Cassio
 
Hi Johnny,

lassen wir Cassio erstmal in Ruhe am Quellcode arbeiten.

Ich habe es mittlerweile etwas anders gelöst: In der ISR wird ein Flag auf 1 gesetzt. In der Hauptschleife wird nun dieses Flag abgefragt und bei 1 wird eine Sub ausgeführt welches den Optokoppler schaltet.
Das funktioniert auch so wie ich es mir vorgestellt habe. Allerdings habe ich halt immer noch das Problem dass der Interrupt immer beim Spannungsverlust auf 1 ausgeführt wird, und sporadisch im Programm selber (manchmal erst nach einigen Stunden)
Also jedesmal wird dann logischweise geklingelt obwohl niemand den Taster gedrückt hat.

...

Ja, aber in meiner Leichtgläubigkeit dachte ich: Da ein Interrupt (so wie ich es verstanden habe) immer abgefragt wird, dürfte es ja eigentlich nicht so schwer sein, darauf zu reagieren. Deswegen verstehe ich nicht warum der Int0 beim Spannungsverlust und irgendwann sporadisch auftritt.

Ich hab da aber auch noch nen Tip. Du ziehst ja über den PullUp den Eingang nach Vcc und mit dem Taster nach GND. Der PullUp hat etwa 50kOhm. Eine Klingelleitung kann recht lang sein und eine Menge Schmutzsignale einfangen (Danebenliegende Stromkabel induzieren zB Störsignale, ...). Es muß also nicht unbedingt an der Software liegen das nach mehreren Stunden sporadisch auf einmal ein Interrupt ausgelöst wird. Sieh dir mal im Datenblatt an wie der Interrupt erkannt wird (die Filterschaltung am INT-Eingang). Bei entsprechend hohem Systemtakt können schon Spikes von wenigen Mikrosekunden zu einem Interrupt führen. Um eingestreute Störungen vom Eingang abzuhalten kann man eine ähnliche Beschaltungwie beim Reset-Pin machen. Man schaltet also vom Eingangspin zu GND einen Keramikkondensator von etwa 1nF. Dieser kleine Kondensator schließt dir kurze eingestreute Spikes kurz und verhindert eine Fehlauslösung.

Aber lassen wir Cassio erstmal in Ruhe drüberschauen.

Gruß
Dino
 
Hallo zusammen!

So...... nun habe ich das Programm mal etwas umgebaut und ich habe die Hoffnung,
dass Johnny daraus etwas lernen wird. :wink:


Es gibt nun einige Änderungen....
  • Die DS18s20 Routinen wurden geteilt
  • Temperaturberechnung auf Single-Wert geändert
  • Das LCD wird jetzt nur noch einmal pro Sekunde aktualisiert
  • Wochentagstabelle (und Abfrage) wurde integriert
  • Der INT0 wurde wieder "entfernt"


Auf diese Weise sollte nun genug "Luft" bleiben, dass der Klingeltaster immer erkannt wird......
und das unnötig häufige sowie zeitintensive Beschreiben des LCD gehört nun auch der Vergangenheit an. :wink:


Bleibt mir nur zu sagen.....
Lern und mach etwas draus. :cool:

Gruß,
Cassio



Hier der Programmcode:
Code:
$regfile = "m8def.dat"
$crystal = 1000000
$hwstack = 128
$swstack = 128
$framesize = 128


Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portd.5 , Rs = Portd.6
Config Lcd = 20 * 4

Config 1wire = Portd.0

Config Dcf77 = Pinb.2 , Timer = 1 , Debug = 1 , Check = 1 , Inverted = 1 , Gosub = Sectic
Config Date = Dmy , Separator = .

Config Portb.1 = Output                                          'Optokoppler/Klingel

Config Pind.2 = Input                                       'Klingeltaster, wird nach GND gezogen
Dingdong Alias Pind.2



Dim Ds18s20_flag As Bit
Dim Lcd_flag As Bit


Config Single = Scientific , Digits = 1
Dim Ist_temp As Single                                      ' Ist-Temperatur
Dim Temp As Word                                            '
Dim Temp1 As Integer                                        '
Dim Scratch(9) As Byte                                      '
Dim I1w As Byte

Dim Dtag As Byte
Dim Wtag As String * 2


Cursor Off Noblink
Cls
Waitms 10


'Erster Systemstart------------------------------------

Gosub Ds1820_start
Do
   Temp = 1wread()                                          ' Ende der Temperaturmessung abwarten
Loop Until Temp = &HFF

Gosub Ds1820_temp
Ds18s20_flag = 0

Lcd_flag = 1


'Hauptschleife-----------------------------------------
Do

If Dingdong = 0 Then
   Gosub Klingel
End If



If Ds18s20_flag = 1 Then
   Gosub Ds1820_temp
End If



If Lcd_flag = 1 Then
   Dtag = Dayofweek()
   Wtag = Lookupstr(dtag , Wochentage)
   Gosub Anzeige_lcd                                        'LCD Text darstellen
End If


Loop


End                                                         'end program


'######################################################
Anzeige_lcd:
Locate 1 , 1
   Lcd "Zeile 1"
Locate 2 , 1
   Lcd " Zeile 2"
Locate 4 , 1
   Lcd Time$ ; " " ; Wtag ; " " ; Date$                     'DCF77 Datum und Zeit

Locate 3 , 9
   Lcd Ist_temp ; Chr(223) ; "C"                            'DS18S20 Temperatur

Lcd_flag = 0

Return


'######################################################
Ds1820_start:

1wreset
1wwrite &HCC
1wwrite &H44

Return



'######################################################
Ds1820_temp:

1wreset
1wwrite &HCC                                                'Skip_Rom Anweisung (sonst &h55 + DS_ID() )
1wwrite &HBE                                                'Scratchpad_auslesen Anweisung

For I1w = 1 To 9                                            'Scratchpad einzeln auslesen und speichern
   Scratch(i1w) = 1wread()
Next I1w

Temp = Scratch(2)                                           'Byte 1 = Temperatur-MSB in WORD-Variable
Shift Temp , Left , 8                                       'Wert im WORD ganz nach oben schieben
Temp = Temp + Scratch(1)                                    'Byte 2 = Temperatur-LSB zum WORD hinzu

Temp1 = Temp                                                'WORD-Variable in INTEGER-Variable übertragen
Temp1 = Temp1 / 2                                           'Temperatur durch 2 wegen der 0,5 Grad Schritte

Ist_temp = Scratch(8) - Scratch(7)                          'Count_per_C minus Count_Remain
Ist_temp = Ist_temp / Scratch(8)                            'Ergebniss durch Count_per_C
Ist_temp = Ist_temp + Temp1                                 'Counts + Temperaturwert
Ist_temp = Ist_temp - 0.25                                  'Ergebnis - 0,25 = IST-TEMPERATUR in 0,1 Grad Schritten

Gosub Ds1820_start                                          'Neue Temp-Konvertierung starten

Ds18s20_flag = 0

Return



'######################################################
Klingel:

Locate 1 , 1
Lcd "Klingeltaster wurde "
Locate 2 , 1
Lcd "   gedrueckt !!!    "

Wait 1

Return



'######################################################
Sectic:

Ds18s20_flag = 1
Lcd_flag = 1

Return


'######################################################
Wochentage:
Data "Mo" , "Di" , "Mi" , "Do" , "Fr" , "Sa" , "So"
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)