Im Prinzip schon, nur gehen die wenigsten Timer so langsam.
Irgendwie stelle ich mir immer noch die Frage, wie realisiere ich z.B. zwei verschiedene Zeiten/Frequenzen bzw. zwei LEDs sollen unterschiedlich schnell blinken mit nur einem Timer. (Mit wait Zeiten im Programm wäre es ja einfach, hält ja aber alles nur auf.)
Nehmen wir das Beispiel.
LED 1 im 0,5Hz Takt = 2sec Takt
LED 2 im 1 Hz Takt = 1sec Takt
Vom Ansatz würde ich mir nun überlegen. Ich programmiere einen Timer auf 0,5 Hz, lass in der ISR eine Variable X zählen. Von 1 - 2, bei wert 2 fängt er wieder bei 1 an.
In der Hauptschleife frage ich die Variable X mit einem If ab!
Ist der Ansatz so richtig, oder löst man sowas anders ?
Im Prinzip schon, nur gehen die wenigsten Timer so langsam.
Umgekehrt. Timer immer die kleinste Einheit.
Die zählst 1 Sekunde --> LED2
jedes zweite mal ---> LED1
Da 1 Sekunde für einen Timer ganzschön lang ist, ist es besser, z.B. 1mS einzustellen, also bei 1000->LED2 bei 2000 -> LED1 uns dann wieder von vorn.
Durch das Frequenz-Verhältnis von 1:2 gibt es noch mehr Möglichkeiten, aber sei's drum
mfg robert
Wer glaubt zu wissen, muß wissen, er glaubt.
Supi, danke... Also war mein Ansatz ja nicht verkehrt Macht ja auch sinn dann mit 1ms (1khz).. Vielen Dank
etwas langsamere Frequenzen bekommst du mit nem Uhrenquarz, allerdings schwingt der immer noch relativ schnell.
Ich habe nun mal ein Code, der funktioniert. Aber selbst persönlich finde ich die Lösung nicht so gut. Vll habt ihr ja andere bessere Ideen:
z.B man viel nun nicht 0,5sek sondern auf 0,2sec Ein/AUS... Dann müsste man mit meinm Prog alles wieder anpassen.
Code:$eeprom $eepromhex $regfile = "m32def.dat" ' Prozessortyp ATmega32 $crystal = 16000000 ' Taktrate $hwstack = 32 $swstack = 10 $framesize = 40 $baud = 4800 Config Portb.2 = Output Led1 Alias Portb.2 Config Portb.3 = Output Led2 Alias Portb.3 Config Lcd = 20 * 2 Config Lcdpin = Pin , Db4 = Porta.0 , Db5 = Porta.1 , Db6 = Porta.2 , Db7 = Porta.3 , E = Porta.5 , Rs = Porta.4 Cls Cursor Off Config Timer0 = Timer , Prescale = 64 On Timer0 Timer_irq Const Timervorgabe = 6 Enable Timer0 Enable Interrupts Config Adc = Single , Prescaler = Auto , Reference = Avcc Start Adc Dim W As Word Dim Taktzaehler As Integer Dim 05takt As Bit Dim 10takt As Bit Dim 20takt As Bit Dim Merker1 As Bit Dim Merker2 As Bit Do W = Getadc(7) Locate 2 , 15 Lcd W ; " " Waitms 200 If W >= 400 Then Merker1 = 1 Else Merker1 = 0 End If If W <= 400 Then Merker2 = 1 Else Merker2 = 0 End If Loop Timer_irq: Timer0 = Timervorgabe If Taktzaehler >= 4000 Then Taktzaehler = 0 End If Taktzaehler = Taktzaehler + 1 If Taktzaehler >= 0 And Taktzaehler <= 500 Then 05takt = 1 10takt = 1 End If If Taktzaehler >= 500 And Taktzaehler <= 1000 Then 05takt = 0 10takt = 1 End If If Taktzaehler >= 1000 And Taktzaehler <= 1500 Then 05takt = 1 10takt = 0 End If If Taktzaehler >= 1500 And Taktzaehler <= 2000 Then 05takt = 0 10takt = 0 End If If 05takt = 1 And Merker1 = 1 Then Led2 = 0 Else Led2 = 1 End If If 10takt = 1 And Merker2 = 1 Then Led1 = 0 Else Led1 = 1 End If Return End
Zwar führen viele Wege nach Rom, und Schönheit liegt ja bekanntlich im Auge des Betrachters ( ), aber eine grundsätzliche Regel sollte man konsequent befolgen:Aber selbst persönlich finde ich die Lösung nicht so gut.
In Interrupt-Routinen sollte so wenig wie möglich Code stehen, damit die Hauptschleife nicht so lange unterbrochen wird. Während eines Interrupts sind nämlich die anderen Interrupts erstmal blockiert, und daraus können unübersichtliche Verschachtelungen entstehen. Am besten setzt man in der ISR nur ein Flag-Bit, das in der Hauptschleife abgefragt wird. Ist es 1, wird der dazugehörige Code ausgeführt und es anschließend wieder gelöscht - fertig.
In Deinem speziellen Fall würde ich (...) den Timer z.B. alle 0,1 Sekunden überlaufen und in der ISR ein Flag setzen lassen.
In der Hauptschleife wird dann das Flag abgefragt. Wenn es 1 ist, inkrementierst Du 2 Zähl-Variablen. Wenn die eine 2 bzw. die andere 5 erreicht hat (und Deine "Merker" gesetzt sind), wird der Status der dazugehörigen LED einfach getoggelt und die Zählvariable auf 0 zurückgesetzt.
Wenn Du ein paar Zeilen Code brauchst, sag Bescheid. Aber selber schreiben ist viel schöner
Gruß & Co
Hi, danke für die Antwort. Die hat schon viel geholfen Habe das Programm noch nicht testen können, aber ich denke so meinst du das? Meine ISR läuft nur alle 1ms über und somit auch 500ms, 200ms in der Zählervariable.
Aber wenn ich nun z.B. das Display nur alle Sek bzw hier halbe Sekunde aktualisieren möchte, ist das doch in meinem Code falsch, dann würden die LED nicht mehr richtig blinken wg der Wartezeit oder?
Wie um gehe ich nun sowas?
Ich hatte mal gelesen, kontinuerliche LCD Routinen sind nicht vorteilhaft (wg Zykluszeit??)!
Code:$eeprom $eepromhex $regfile = "m32def.dat" ' Prozessortyp ATmega32 $crystal = 16000000 ' Taktrate $hwstack = 32 $swstack = 10 $framesize = 40 $baud = 4800 Config Portb.2 = Output Led1 Alias Portb.2 Config Portb.3 = Output Led2 Alias Portb.3 Config Lcd = 20 * 2 Config Lcdpin = Pin , Db4 = Porta.0 , Db5 = Porta.1 , Db6 = Porta.2 , Db7 = Porta.3 , E = Porta.5 , Rs = Porta.4 Cls Cursor Off Config Timer0 = Timer , Prescale = 64 On Timer0 Timer_irq Const Timervorgabe = 6 Enable Timer0 Enable Interrupts Config Adc = Single , Prescaler = Auto , Reference = Avcc Start Adc Dim W As Word Dim Taktzaehler02 As Integer Dim Taktzaehler05 As Integer Dim Timer0_flag As Bit Timer0_flag = 0 Do W = Getadc(7) Locate 2 , 15 Lcd W ; " " Waitms 500 'Was ist wenn hier die Zeit nun auf 500ms stehen würde? If Timer0_flag = 1 Then Taktzaehler02 = Taktzaehler02 + 1 Taktzaehler05 = Taktzaehler05 + 1 Timer0_flag = 0 End If If Taktzaehler02 = 200 Then Toggle Led1 Taktzaehler02 = 0 End If If Taktzaehler05 = 500 Then Toggle Led2 Taktzaehler05 = 0 End If Loop Timer_irq: Timer0 = Timervorgabe Timer0_flag = 1 Return End
Letztendlich sollte das doch auch so gehen mit der Wartezeit für das LCD ohne die main loop aufzuhalten ?
Code:$eeprom $eepromhex $regfile = "m32def.dat" ' Prozessortyp ATmega32 $crystal = 16000000 ' Taktrate $hwstack = 32 $swstack = 10 $framesize = 40 $baud = 4800 Config Portb.2 = Output Led1 Alias Portb.2 Config Portb.3 = Output Led2 Alias Portb.3 Config Lcd = 20 * 2 Config Lcdpin = Pin , Db4 = Porta.0 , Db5 = Porta.1 , Db6 = Porta.2 , Db7 = Porta.3 , E = Porta.5 , Rs = Porta.4 Cls Cursor Off Config Timer0 = Timer , Prescale = 64 On Timer0 Timer_irq Const Timervorgabe = 6 Enable Timer0 Enable Interrupts Config Adc = Single , Prescaler = Auto , Reference = Avcc Start Adc Dim W As Word Dim Taktzaehler02 As Integer Dim Taktzaehler05 As Integer Dim Taktzaehler1000 As Integer Do If Timer0_flag = 1 Then Taktzaehler02 = Taktzaehler02 + 1 Taktzaehler05 = Taktzaehler05 + 1 Taktzaehler1000 = Taktzaehler1000 + 1 Timer0_flag = 0 End If If Taktzaehler02 = 200 Then Toggle Led1 Taktzaehler02 = 0 End If If Taktzaehler05 = 500 Then Toggle Led2 Taktzaehler05 = 0 End If If Taktzaehler1000 = 1000 Then W = Getadc(7) Locate 2 , 15 Lcd W ; " " Taktzaehler1000 = 0 End If Loop Timer_irq: Timer0 = Timervorgabe Timer0_flag = 1 Return End
Ganz genau! So ist es viel eleganter als mit waitms500, die das Programm halt für diese Zeit total lahmgelegt hätten. Und Du bekommst genauso alle 1 Sek. den aktuellen ADC-Wert angezeigt.Letztendlich sollte das doch auch so gehen mit der Wartezeit für das LCD ohne die main loop aufzuhalten ?
Eigentlich müsste es mit diesem Code super laufen!
Gruß,
Daniel
Lesezeichen