Ist das denn nicht eine sehr umständliche Methode, wie man eine Uhr realisieren kann? Ich meine, da benötigt man ja einen Timer, den man sonst für nichts verwenden kann. Meine Idee wäre da, meiner Meinung nach, eleganter: Man hat eine relativ breite Zahl im Speicher. Bei jedem Taktzyklus erhöht man sie um einen bestimmten Wert. Ist diese Zahl größer als ein Schwellenwert, so ist eine Sekunde abgelaufen und die Zahl wird um den Schwellenwert reduziert. Wenn man den Schwellenwert geschickt wählt, so kann man einfach das Carry-Flag abfragen. Was passiert nun da: Man kann sich das so vorstellen wie ein Zeiger, der in einem Kreis rotiert. Bei jedem Taktzyklus geht der Zeiger um einen bestimmten Winkel weiter. Wenn man den Winkel jedes Schrittes einstellt, so kann man einstellen, wie oft der Zeiger pro Zeiteinheit rumläuft. Nehmen wir mal ein Beispiel. Die ISR wird mit hypothetischen 100 kHz aufgerufen. Die Zählervariable hat 32 Bit und der Schwellenwert ist somit 2^32. Wenn man nun bei jedem ISR nur um 1 weiterzählt so ergibt sich der Überlauf mit einer Frequenz von 100 kHz/(2^32)=.000023283064365386962890625Hz auf. Zählt man um n weiter, so kann man n mal diese Frequenz erzielen. Man kann somit seine 1Hz in 23uHz-Schritten einstellen, das sind sehr kleine Schritte. Natürlich kann man die Schrittweite in einer weiteren Variable speichern und sie somit anpassen. Stellt euch vor, Ihr habt gelegentlich DCF77-Empfang. Man muss sich dann nur die Zeit seit dem letzten Update merken und die neue Zeitdifferenz berechnen. Daraus kann man den Fehler der Frequenz berechnen und korrigieren. Beim nächsten Verbindungsabbruch sollte die Uhr dann kalibriert laufen. So kann man noch viel genauere Uhren bauen. Wie man mit der selben Technik Töne beliebiger Frequenz erzeugen kann, kann sich ja jeder denken. Servus Casandro
>Ich meine, da benötigt man ja einen Timer, den man sonst für nichts >verwenden kann. Ich habe mir das Tutorium nicht angeguckt, aber die Uhr ist bei meinen Timeranwendungen eher ein Nebenprodukt. >Was passiert nun da: Man kann sich das so vorstellen wie ein Zeiger, der >in einem Kreis rotiert. Bei jedem Taktzyklus geht der Zeiger um einen >bestimmten Winkel weiter. Wenn man den Winkel jedes Schrittes >einstellt, so kann man einstellen, wie oft der Zeiger pro Zeiteinheit >rumläuft. Dafür benutzt man doch den CTC-Modus: Man stellt den "Winkel" so ein, dass man ihn auch noch für andere Sachen wie Tastenentprellung, PWM oder Multiplexing benutzt. >Die Zählervariable hat 32 Bit und der Schwellenwert ist somit 2^32. Welch Speicherverschwendung. >das sind sehr kleine Schritte. Wer's braucht... Ich rechne in der Regel eher in Sekunden (und Teilen davon) bei Controllern. Das macht einfach mehr sinn für mich, da ich dann nicht alles 1/x rechnen muß. µHz sind 10^6 Sekunden... Wie wäre es, wenn du sowas mal programmieren würdest?
Rahul Der trollige wrote: > Wie wäre es, wenn du sowas mal programmieren würdest? Hier, realtime_s gibt an wie groß der Schritt ist, und realtime_t gibt an, wie viele Schritte eine Sekunde braucht. Damit kann count_realtime_clock_50Hz mit einer fast beliebigen Frequenz aufgerufen werden, durch die beiden Konstanten kann man das immer ausgleichen. Das geht alles nebenbei, ohne, dass man einen Timer speziell dafür abrichten muss. Mein Timer läuft beispielsweise mit 62,5 KHz über und irgendwo im Programm habe ich etwa 50 Hz. Diese 50 Hz kann ich ausnutzen. Leider sind das jedoch 50,08 Hz, was man jedoch durch die beiden Konstanten ausgleichen könnte. Der Algorithmuss hat aber noch weitere Vorteile. Stell Dir vor, Du möchtest einige LEDs mit unterschiedlicher Geschwindigkeit blinken lassen. Du nimmst einfach für jede LED etwas Speicher und zählst den bei jedem IRQ um x hoch. Die LED steuerst Du einfach mit dem hochwertigsten Bit an. Sie wird dann mit einer Frequenz blinken, die genau proportional zu X ist. Das macht auch die Erzeugung von Tönen deutlich einfacher. .dseg realtime_hsek: .byte 1 realtime_sek: .byte 1 realtime_min: .byte 1 realtime_std: .byte 1 .cseg .equ realtime_s=-1 .equ realtime_t=50 count_realtime_clock_50Hz: PUSH r17 LDS r17,realtime_hsek SUBI r17,realtime_s STS realtime_hsek,r17 CPI r17,realtime_t BRGE count_realtime_clock_50Hz_1s count_realtime_clock_50Hz_1s_return: POP r17 ret count_realtime_clock_50Hz_1s: SUBI r17,realtime_t STS realtime_hsek,r17 LDS r17,realtime_sek ;Sekunden SUBI r17,-1 STS realtime_sek,r17 CPI r17,60 BRGE count_realtime_clock_50Hz_1m rjmp count_realtime_clock_50Hz_1s_return count_realtime_clock_50Hz_1m: LDI r17,0 STS realtime_sek,r17 LDS r17,realtime_min ;Minuten SUBI r17,-1 STS realtime_min,r17 CPI r17,60 BRGE count_realtime_clock_50Hz_1h rjmp count_realtime_clock_50Hz_1s_return count_realtime_clock_50Hz_1h: LDI r17,0 STS realtime_min,r17 LDS r17,realtime_std ;Stunden SUBI r17,-1 STS realtime_std,r17 CPI r17,24 BRGE count_realtime_clock_50Hz_1d rjmp count_realtime_clock_50Hz_1s_return count_realtime_clock_50Hz_1d: LDI r17,0 STS realtime_std,r17 rjmp count_realtime_clock_50Hz_1s_return init_realtime_clock: ;Falls die Uhr eine seltsame Zeit hat, einfach mit 00:00:00 belegen LDS r17,realtime_std CPI r17,24 BRGE init_realtime_clock_init_needed LDS r17,realtime_min CPI r17,60 BRGE init_realtime_clock_init_needed LDS r17,realtime_sek CPI r17,60 BRGE init_realtime_clock_init_needed ret init_realtime_clock_init_needed: LDI r17,0 STS realtime_std,r17 STS realtime_min,r17 STS realtime_sek,r17 ret ====8<=======8<========= Tonerzeugung, Phase Distortion Synthesis (fast gleiches Prinzip) .dseg .cseg .def omega_1rl=r2 .def omega_1rh=r3 .def phi_1rl=r4 .def phi_1rh=r5 .def volume_1r=r6 .def modf_1r=r7 .def modg_1r=r8 .def t1=r17 .def mul_h=r1 .def mul_l=r0 ;In der ISR habe ich keine Zeit fuer Speicherzugriffe .macro audio_isr_prepare PUSH omega_1rl LDS omega_1rl,omega_1 PUSH omega_1rh LDS omega_1rh,omega_1+1 PUSH phi_1rl LDS phi_1rl,phi_1 PUSH phi_1rh LDS phi_1rh,phi_1+1 PUSH volume_1r LDS volume_1r,volume_1 PUSH modf_1r LDS modf_1r,modf_1 PUSH modg_1r LDS modg_1r,modg_1 PUSH r1 PUSH r0 .endmacro .macro audio_isr_finish POP r0 POP r1 POP modg_1r POP modf_1r POP volume_1r STS phi_1,phi_1rl POP phi_1rl STS phi_1+1,phi_1rh POP phi_1rh POP omega_1rl POP omega_1rh .endmacro ;Wird ziemlich genau mit 15625 Hz aufgerufen, braucht genau 19TZ .macro audio_pm_15625Hz LDI zh,high(sintab*2) ;1 ADD phi_1rl,omega_1rl ;1 ADC phi_1rh,omega_1rh ;1 MUL phi_1rh,modf_1r ;2 MOV zl,mul_l ;1 LPM t1,Z ;3 MUL t1,modg_1r ;2 MOV zl,phi_1rh ;1 ADD zl,mul_h ;1 LPM t1,Z ;3 MUL t1,volume_1r ;2 OUT OCR0,mul_h ;1 ; ========== ; 19 TZ .endmacro sound_init: LDI r17,0 STS volume_1,r17 ret sound_playsound: ; r17 ton; r18 dauer; r19 Decay; r20 Klangfarbe ;r17 Bits 4-7 Oktave ; Bits 0-3 Ton ;r18 Dauer in 20ms Schritten ;r19 Nachhall in 20 ms Schritten PUSH r21 PUSH r22 PUSH zl PUSH zh ;Klangfarbe MOV r21,r20 ANDI r21,$f0 ;Modulationsfrequenz SWAP r21 STS modf_1,r21 MOV r21,r20 ANDI r21,$0f ;Modulationsgrad SWAP r21 ; damit grad staerker wird STS modg_1,r21 ;Tonhoehe LDI zh,high(sound_scale*2) LDI zl,low(sound_scale*2) MOV r21,r17 ;Ton holen ANDI r21,$0f ;maskieren ;SWAP r21 ;verschieben ADD zl,r21 ADD zl,r21 LPM r21,Z+ ;low Byte LPM r22,Z ;high Byte MOV zh,r17 ;Register recyclen SWAP zh ANDI zh,$0f sound_playsound_octave_loop: LSR r22 ROR r21 INC zh CPI zh,$0f BRLT sound_playsound_octave_loop ;frequenz steht in r21:r20 drin ;LDI r21,0 ;LDI r22,20 STS omega_1,r21 STS omega_1+1,r22 ;wenn Ton kuerzer als 4*20=80 ms, dann nicht anschwingen CPI r18,4 BRLT sound_playsound_hold ;Anschwingen 80 ms LDI r21,7 LDI r22,0 sound_playsound_attack_loop: SUBI r22,-63 STS volume_1,r22 call sleep_frame DEC r21 BRNE sound_playsound_attack_loop SUBI r18,4 sound_playsound_hold: ;Ton halten LDI r22,255 STS volume_1,r22 call sleep_frame DEC r18 BRNE sound_playsound_hold sound_playsound_decay: ;abklingen max 1s LDI r18,255 sound_playsound_decay_loop: call sleep_frame SUBI r18,5 BREQ sound_end STS volume_1,r18 DEC r19 BRNE sound_playsound_decay_loop sound_end: ;Ton aus LDI r18,0 STS volume_1,r18 POP zh POP zl POP r22 POP r21 ret sound_demo: sound_demo2: LDI r22,0 sound_demo2_start: LDI zh,high(sound_freude_schoener_goetterfunken*2) LDI zl,low(sound_freude_schoener_goetterfunken*2); sound_demo2_loop: LPM r23,Z+ LDI r17,'-' call out_char_r17 CPI r23,0 BREQ sound_demo2_start MOV r24,r23 ANDI r24,$7f LDI r17,$A0 ADD r17,r24 LDI r18,10 LDI r19,12 SBRC r23,7 LDI r19,22 MOV r20,r22 call sound_playsound call get_key_r17 CPI r17,27 BREQ sound_demo2_ende CPI r17,'0' BRLT sound_demo2_loop CPI r17,'9'+1 BRGE sound_demo2_loop MOV r22,r17 call out_char_r17 SUBI r22,'0' SWAP r22 ORI r22,$06 rjmp sound_demo2_loop sound_demo2_ende: ret nop nop nop nop .cseg sound_scale: ;wird in Intel-Richtung abgespeichert .dw 17557,18601,19708,20879,22121,23436,24830,26306,27871,29528,31283,33144 sound_freude_schoener_goetterfunken: .db $14,$14,$15,$17,$17,$15,$14,$12,$10,$10,$12,$14,$14,$12,$12+$80, $14 .db $14,$15,$17,$17,$15,$14,$12,$10,$10,$12,$14,$12,$10,$10+$80 .db $12+$80,$14,$10,$12,$14,$15,$14,$10,$14,$15,$14,$12,$10,$12 .db $7,$14,$15,$17,$17,$15,$14,$12,$10,$10,$12,$14,$12,$10,$90,0 =8<==========8<============8<========= Das sind natürlich nur Fragmente aus einem größeren Projekt.
Du hast schonmal in die Codesammlung geguckt ? Beitrag "Die genaue Sekunde / RTC" Du weißt schon, daß es unhöflich ist, die Leute sich totscrollen zu lassen ? Wozu ist denn wohl der Dateianhang da ? Peter
Peter Dannegger wrote: > Du hast schonmal in die Codesammlung geguckt ? > > Beitrag "Die genaue Sekunde / RTC" Da steht nichts über die Funktion, da ist nur Code in irgendeinem seltsamen Packerformat dabei. Ich vermute jedoch, dass das ähnlich funktioniert. So etwas ist jedoch, meiner Meinung nach, so grundlegend, dass es sich in das Tutorium gehört. > Du weißt schon, daß es unhöflich ist, die Leute sich totscrollen zu > lassen ? Das mag sein, aber wer ließt denn sonst den Code? > Wozu ist denn wohl der Dateianhang da ? Für ein komplettes Projekt würde ich den auch hernehmen, aber für kurze Fragmente ist das nicht sinnvoll. Wie schon gesagt, den Anhang ließt kein Mensch. > Peter Servus Casandro
Christian Berger wrote: > Da steht nichts über die Funktion, da ist nur Code in irgendeinem > seltsamen Packerformat dabei. Oooch is der aber drollig. > Das mag sein, aber wer ließt denn sonst den Code? Falsch ! Umgekehrt wird ein Schuh draus. Man öffnet den Anhang in einem neuen Fenster und schon kann man den Code lesen und den Beitrag. > Für ein komplettes Projekt würde ich den auch hernehmen, aber für kurze > Fragmente ist das nicht sinnvoll. Kurze Fragmente sind etwa 20 Zeilen, aber kein 318-Zeilen-Monster. Warscheinlich isses nichmal assemblierbar. > Wie schon gesagt, den Anhang ließt > kein Mensch. Wie schon gesagt, ich habs nicht ansehen können, da mein Scrollfinger schmerzt. Ich konnte nur die "Ende"-Taste drücken und schon wars vorbei. Peter
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.