Hallo zusammen, ich versuche mich gerade am ASM 8051 programmieren und über gerade eine einzelne Note(z.B. ein Viertel mit 440Hz) auszugeben, jedoch gibts da ein paar Probleme. Also einen Dauerton habe ich auf jedenfall schon geschafft, dies funktioniert einwandfrei. Hier das bis jetzige Programm: http://pastebin.com/jiZP43uc Ich soll wie gesagt einen Ton mit 440Hz 600ms lang spielen(entspricht einer Viertelnote). Der verwendete 8051er hat 24MHz/12=2MHz Taktfrequenz Mit dem Timer1 will ich zählen bis 600ms vorbei sind und mit Timer0 wird der Takt des Tones erzeugt. Timer1 wird im Mode 1 betrieben, also 16-Bit-Timer. Es gibt 2 Register TH1 und TL1. Wenn TL1 Overflow, dann wird TH1 inkrementiert, d.h. man kommt am ende auf 256*256 verschiedene Werte. Wenn TH1 Overflow ist dann springt der auf die Interruptadresse(flash: 001BH und beim Monitor: 801BH). Timer0 soll gestoppt werden wenn Timer1 zur Interruptadresse springt. Hier die Formel zur Berechnung des Start-Values von Timer1: f(x) = 65536 - (x*10^3*2); x=600ms; 256*256=65536; --> f(x)=startwert = negativer wert Im T1_ISR stoppe ich den Timer0. Mehr brauche ich eigentlich hier nicht oder? Mein Problem ist es, das ich nicht ganz weiß wie ich das umsetzen soll. Ich haben wir aufgeschrieben: PlayTone(R0) --> PlayTone aufrufen und R0 übergeben T0_INIT Reload --> T0 auf autoreload Mode 2 setzen T0 starten --> SETB TR0 RET --> zurück zum Main PlayNote(R0,R1) --> PlayNote aufrufen und R0,R1 überegeben Timer1 laden/starten CALL PlayTone --> wieder aufrufen? ich glaube das gehört weg, oder seht ihr einen Sinn darin? R1mal warten auf TF=1(Überlauf) --> das erklärt das 4*150 - R1=4 in dem Fall T0 stoppen --> das mach ich ja im T1_ISR(CLR TR0) Wenn ich mir jetzt die Reihenfolge der Befehle hir so ansehe, dann heißst das das ich im PlayTone das INIT_T0 aufrufen soll, aber das wie ich es jetzt gemachdt habe passt auch oder? ___ Zum PlayNote: Warum bitte ins PlayNote auch R0 übergeben? (In R0 steht der Wert, von dem Timer0 zu zählen starten muss, also muss er 142mal inkrementieren, bis er einen Zustand(0 oder 1) "gezeichnet" hat / Berechnung: Ton hat 440Hz --> T = 2272,72us --> T/2/16=72us(/16, weil es sonst nicht mit dem zählen ausgeht) --> 256-(71us/0,5us)=114 --> R0=114 ) Ich komme nicht darauf was im PlayNote stehn sollte? Vielleicht das selbe wie im PayTone, also das Timer1 starten und so? Zum Timer1 laden/starten: Ich bekomme ja mit der Formel oben einen negativen Wert? Wie kann ich das denn umgehen? Ich hoffe ich habe alles plausibel erklärt und ihr kennt euch sofort aus :D. Wenn ihr mehr Infos braucht, dann sagt es bitte. mfg Thomas :)
Auf einem 8051 programmierte ich schon mal Melodien, aber ganz einfach, wie in Spielautomaten der 1980-er Jahre. Im Grunde hat man im Hauptprogramm eine Liste mit aneinander gereihten Parametersätzen wie Zeitdauer und Frequenz, und ruft dann damit den Timer auf. Ein Flag signalisiert für das Hauptprogramm immer das Ende, wo es wieder weiter geht. Kann sein, daß ich beide Timer benutzte, das weiß ich nicht mehr so genau. Einen für die Zeit, den anderen für den Ton.
Das macht nur mit 2 Timern Sinn. Einer für die Tonhöhe, einer für die Dauer. Wenn Du da perioden zählen wolltes, wird das nie was. Ich hatte das in C so erledigt: /* Melodieerzeugung mit 2 Timern Timer 0 erzeugt einen Grundtakt von 25ms für die Notendauer Timer 1 erzeugt die Ausgabefrequenz Im Array Noten[] steht die gewünschte Melodie Im Array Dauer[] steht die Notendauer (1, 2, 4, 8, 16 möglich) Steht für ganze, halbe, viertel, achtel und sechzehntel Note. (punktiertes Viertel mit 3 und Punktierte Achtel mit 6 geht auch) Timer 1 erzeugt die Frequenz aus dem Wert Noten[aNote] Reload-Wert für Timer: halbe Periodendauer in us 1000000[us/s]/(2*Frequenz) = 500000/Frequenz ==> bei 24MHz dann 2000000[us/s] Timer 0 erzeugt die Tondauer aus dem Wert Dauer[aNote] Notendauer: 120 Viertel/Minute => Viertel Note dauert 0,5s Halbe Note dauert 1s, ganze Note dauert 2s, achtel Note dauert 0,25s Grundzeit ist 25ms, für ein Achtel muss dann 80/8 mal gewartet werden zwischen 2 Noten ist 25ms Pause => Timer 1 wird dabei ausgeschaltet! */ Statt den Arrays definierst Du halt Const-Listen in Assembler.
Nachtrag: zwischen 2 Noten füge ich noch eine Pause von 25ms (ein Überlauf Timer 0) ein, damit wiederholte Noten auch getrennt wiedergegeben werden.
Danke für die Antworten! Aber leider kann ich weder mit const-Listen noch mit der C-Theorie was anfangen :(. Sorry Leute. Ich bin voll der Anfänger im Asm programmieren. Da ist das erste mal aufm PC mit Timer/Counter. Und darum will/muss/soll ich es so machen wie ich oben beschrieben habe, vielleicht kleine Verbesserungen/Abänderungen. Ich hoffe jemand kann mir trotzdem helfen.
Na ja, meine Beschreibung enthält keinen einzigen Befehl. Weder C noch Assembler. Die Listen für die Melodie definierst Du in ASM mit db. Zum Beispiel eine Tonleiter - die Tonzuordnungen zu Zählerständen erfolgen an anderer Stelle, bei Dir in notesdefine.h (was aber eher nach C aussieht und funktionell eher unvollständig ist) Also die Notwendigen Byte-Werte noch definieren C4 equ 42 ; was auch immer A4 equ 114 ; einziger nutzbarer Wert aus der .h-Datei... Tonleiter: db C4, D4, E4, F4, G4, A4, H4, C5 Der Zugriff auf die Tabelle erfolgt in ASM über movec und den Data-Pointer mov DPTR, #Tonleiter ; Datapointer auf Tabellenanfang mov A, #0 ; ersten Wert lesen movc A, @A+DPTR ; jetzt steht der Wert von C4 im Akku Wenn Du Tabellen mit 16-Bit Werten machen willst, dann dw als Kürzel. Wird in ASM aber ziemlich trickreich.
Danke dir, ich habe mir jetzt das ganze durchdacht und soweit gekommen: http://pastebin.com/LRzNeCfv Mein Problem: Das Main-Programm wartet nicht bis die note fertiggespielt wurde, sondern geht immer weiter durch. Ich hab mir das überlegt mit einer zweiten schleife vielleicht, aber ich kanns net umsetzen irgendwie^^. Mein 2tes Problem: Im ISR verwenden ich ja den Akku, aber das darf man ja im Interrupt nicht, wenn ich da R2 bzw. R3 verwende kann ich das cjne nicht verwenden, da #t0count bzw. #t1count nicht funktionieren. Könnt ihr mir bitte auf die Sprünge helfen bzw. wie kann ich das machen, dass es passt. Es gibt sicher leichtere Möglichkeit das zu programmieren, aber ich muss das so machen, also bitte so fortsetzen, außer es geht überhaupt nicht, was ich da fabriziere^^.
Du solltest halt am Ende der Note ein Flag setzen, das dem Hauptprogramm sagt, das es nun die nächste Note spielen darf (also die Werte in die Timer schreibt) und das Flag löscht. Solange das Flag nicht gesetzt ist, muss das Hauptprogramm Däumchen drehen, oder sich mit Tastaturabfrage, Lämpchen, UART oder sonst was beschäftigen. Flags sind gut aufgehoben im B Register oder in der 'bit addressable area' thomas schrieb: > Im ISR verwenden ich ja den Akku, aber das darf man ja im Interrupt > nicht, wenn ich da R2 bzw. R3 verwende kann ich das cjne nicht > verwenden, da #t0count bzw. #t1count nicht funktionieren. Doch, du musst lediglich den Akku pushen am Anfang der ISR und poppen am Ende. Es ist gute Praxis, ISRs immer in einer anderen Registerbank laufen zu lassen und diejenigen anderen Register am Anfang der ISR zu retten und am Ende zu restaurieren, die sonst noch benutzt werden.
Danke! Also soll ich in Register B irgendnen Wert hineinschreiben? Ja und wie stoppe ich dann das main. Das verstehe ich überhaupt nicht. Das mit dem ISR ist mir jedoch klar.
Mh ich glaube ich habs ich setze einfach ein Bit vor Call Playtone und mache dann zwischen zeile 308 und 309 "JB bit,$". Das bit resette ich dann in der Zeile 430(statt SETB TR0, TR1 gehört da CLR). So müsst es eigentlich funktionieren? Und welches bit sollte ich nehmen? im PSW das Flag 0?
Bernhard Spitzer schrieb: > Ich hatte das in C so erledigt: > /* Melodieerzeugung mit 2 Timern > Timer 0 erzeugt einen Grundtakt von 25ms für die Notendauer > Timer 1 erzeugt die Ausgabefrequenz > [...] > Halbe Note dauert 1s, ganze Note dauert 2s, achtel Note dauert 0,25s > Grundzeit ist 25ms, für ein Achtel muss dann 80/8 mal gewartet werden > zwischen 2 Noten ist 25ms Pause => Timer 1 wird dabei ausgeschaltet! > */ Und das hat dann funktioniert? Ich hab es kompiliert und der Code hat garnichts gemacht muahaha :D SCNR^^
thomas schrieb: > Und welches bit sollte ich nehmen? > im PSW das Flag 0? Kannst du machen. Der Bitbereich im internen RAM hat aber auch 128 Flaggen, im Adreßbereich zwischen 0x20 und 0x2F. Versuchs mal so, und gestalte die Hauptprogrammschleife aus einer Aneinanderreihung von Tönen, zwischen denen immer wieder ein Abspielprogramm aufgerufen wird. Z.B.: Lade Timer 0 mit dem Ton Lade Timer 1 mit der Tondauer Rufe das Abspielprogramm Lade Timer 0 mit dem Ton Lade Timer 1 mit der Tondauer Rufe das Abspielprogramm Lade Timer 0 mit dem Ton Lade Timer 1 mit der Tondauer Rufe das Abspielprogramm Lade Timer 0 mit dem Ton Lade Timer 1 mit der Tondauer Rufe das Abspielprogramm usw. usf. Im Abspielprogramm werden beide Timer gestartet, und nach abgelaufener Zeit gestoppt, Rückkehr ins Hauptprogramm. Der Teufel steckt natürlich noch im Detail: Die Programmierarbeit. Das ist schon noch etwas mehr, als nur die 2 Parameter laden. Z.B. auch Timerüberläufe berücksichtigen. Wie man die Töne ausrechnet, weißt du sicher. Sonst kannst du danach auch noch mal fragen. Ob der µC noch was anderes macht, sonstige Aufgaben, solltest du erst mal ganz außer acht lassen. Das kann man später überlegen, wenn mal was funktioniert.
/* */... > Und das hat dann funktioniert? > > Ich hab es kompiliert und der Code hat garnichts gemacht muahaha :D > Beinahe lustig... Wieso meldest Du dich nicht ordentlich an, dann kann ich Deine Beiträge leichter ignorieren. Der Fragende wollte halt Assembler und kein C-Code. Statt PAP oder Struktogramm zu zeichnen habe ich halt meinen Kommentar aus dem Programm rauskopiert. Wilhelm schrieb: > Kannst du machen. Der Bitbereich im internen RAM hat aber auch 128 > Flaggen, im Adreßbereich zwischen 0x20 und 0x2F. Das sind dann die Bitadressen 00h bis 7Fh. Festlegung z.B. mit Merker bit 00h Wenn der Stack durch viele Unterprogramm-Aufrufe und push größer werden kann, sollte man die Bits liebe an den oberen Rand des Bitadressierbaren Speichers legen, z.B. Merker bit 7Fh Wenn der Speicher knapp werden sollte, gibt es häufig noch die internen Ports P4 und P5, die zwar auf dem Chip, aber an vielen Gehäusen nicht vorhanden sind. setb und clr funktioniert damit auch problemlos (aber aufpassen, wenn mal jemand das Programm auf einem 80535 laufen lässt.)
Ok gut danke^^. Aber das mit den Pausen verstehe ich nicht ganz, was soll ich da machen genau? Hat wer eventuell Tipps etc. bitte? hier der code: bissl habe ich schon was zwecks pausen gemacht, also das er timer nicht gesetzt werden, aber wie mache ich weiter dann im main? http://pastebin.com/aCZTaGZg
Pause = kein Ton, also Bit nicht toggeln sondern nur warten (in meinem Beispiel ist jan immer 25ms Pause zwischen 2 Noten, weil sonst 2 Viertel wie eine hlabe Note klingen würden). Ob jetzt 0 oder 1 ausgegeben wird ist dem Lautsprecher da ziemlich egal (bei größeren Verstärkern schaltet man halt einen Elko dazwischen, damit kein Gleichstrom durch den Lautsprecher fleißt).
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.