Hallo, ich versuche mich gerade an der Programmierung eines at89s52, mein Ziel ist es eine Uhr zu programmieren, leider funktioniert meine Zeitschleife nicht ganz... :( hier mal mein code: ;####### Programm für AT89S52 #########; org 000h jmp 0100h org 01bh djnz r1, zurueck mov r1, #0a0h 160 000 Hz/ 160 = 100 djnz r2, zurueck mov r2,#64h 100Hz/ 100 = 1s ljmp 0300h zurueck: reti ;####### Initialisierung #########; org 0100h mov IE,#88h für Interrupt T1 enable und EA Interrupts mov PCON,#00h mov SCON,#00h mov TCON,#00h mov TMOD,#60h für Timer1 auto Reload mov TL1,#06h 4 000 000 Hz / 250 = 160 000 mov TH1,#06h setb TR1 mov P0,#00h mov P1,#00h mov P2,#00h mov P3,#00h mov R0,#00h mov R1,#0a0h mov R2,#64h mov R3,#00h mov R4,#00h mov R5,#00h ;####### Hauptprogramm #########; mainloop: ljmp mainloop org 0300h mov a,p1 inc a mov p1,a jmp mainloop das hier soll nur eine Zeitschliefe sein mit der ich den 1s-Takt nutze um den Port1 jede sekunde um eins zu erhöhen ich verwende einen 4Mhz Oszillator. Sieht von euch jemand einen Fehler? Laut Keil ist kein Fehler (also Tippfehler ausgeschlossen) Danke Gruß Christian
Finde den Fehler leider nicht, nach 1s springe ich zu 0300h dort erhöhe ich den port um 1 und anschlißend springe ich zum hauptprogramm zurück. Was meinst du genau was nicht passt?
Du kommst aus der Interrupt Routine zu 300h, gehst aber nie wieder dorthin zurück. Also hängt sich der Kasten nach 1s in die Endlosschleife.
Danke für die schnellen und hilfreichen Antworten habe es nun einmal umgeschrieben, jedoch funktioniert es immer noch nicht, liegt jetzt noch ein fehler im Programm versteckt? ;####### Programm für AT89S52 #########; org 000h jmp 0100h org 01bh ljmp 0300h ;####### Initialisierung #########; org 0100h mov IE,#88h mov PCON,#00h mov SCON,#00h mov TCON,#00h mov TMOD,#60h mov TL1,#06h mov TH1,#06h setb TR1 mov P0,#00h mov P1,#00h mov P2,#00h mov R0,#00h mov R1,#0a0h mov R2,#64h mov R3,#00h mov R4,#00h mov R5,#00h ;####### Hauptprogramm #########; mainloop: setb p2.2 ljmp mainloop ;##### Interrupt Zeitschleife###; org 0300h djnz r1, zurueck mov r1, #0a0h djnz r2, zurueck mov r2,#64h mov a,p1 inc a mov p1,a inc p0 jmp zurueck zurueck: reti
Ich war der Meinung, dein Prozessor sei MCS51 kompatibel.
Dieser Befehl
> inc p0
erscheint mir illegal. Aber ich lasse mich gern belehren. Läuft der
Assembler wirklich ohne Fehler durch?
1. Statt "... jedoch funktioniert es immer noch nicht, ...", schreibe was du erwartest und was nicht funktioniert. 2. Du arbeitest mit Keil: der hat einen Simulator, mit dem du Schritt für Schritt durch dein Programm gehen kannst.
"inc p0" funktioniert. Aber: P0 ist ein wenig tükisch, da der Port keine PullUps hat.
ja danke für die Infos, anscheinend springt mein Mikrocontroller nicht in die Interruptschleife, da dieser mir die Ports in der Sekundenschleife nicht einschaltet. Ich teste es bisher real an meinem MC. Verschaltung sollte passen. Weis einer von euch ob und wenn ja wie ich einen Counter am besten mit 4Mhz in Keil simulieren kann? Habe in Keil soweit es ging auch alles durchgetest dort hat es funktioniert Ich tendiere dazu dass entweder das die Initialisierung des MC falsch ist oder es falsch aufgespielt wird. Das mit den Pull ups schaue ich mir auch mal an Ich werde mal einige tests durchführen^^ Vielen dank für eure gute Hilfe
> hier mal mein code:
Sorry, aber das ist kein Code, das sind Assembler-Instruktion, mehr
nicht. Code ist dokumentiert. Das machst du so gut wie gar nicht.
Ist nicht bös gemeint. Aber mach bitte folgendes, bevor du weiter den
Fehler suchst:
Schreib hinter jede Instruktion einen Kommentar, was du da bezwecken
willst.
Das bedeutet nicht, dass bei einem 'mov x,y' dann 'schreibe y in x'
hinten dran steht, das sieht man anhand der Instruktion.
Viel mehr sollte da dran stehen, was du bezwecken willst. So steht
beispielsweise bei 'org 01bh' dann 'Timer 1 Interrupt Vektor', bei 'mov
TMOD,#60h' steht 'Timer 1 konfiguriert als ...' und bei 'mov TL1,#06h'
steht 'Reloadwert für xxx ns/µs'.
Glaub's mir, das bringt's wirklich, denn danach gehst du Instruktion für
Instruktion durch, und vergleichst, ob sie tatsächlich das macht, was
der Kommentar angibt.
Was deinen Timer-Interrupt betrifft: Ohne Kommentar (da wären wir schon
bei o.g. Thema) sehe ich nicht, in welcher Betriebsart der läuft, und
ich bin jetzt zu faul nachzuschauen.
Ich vermute 8-Bit mit automatischer Rückladung. Keine Ahnung ob das
Interrupt-Flag hierbei automatisch gelöscht wird wenn er in den
Interrupt springt. Falls nicht, musst du manuell löschen, sonst bist du
nach dem RETI + 1 Instruktion wieder im Interrupt.
Zweitens: in einem Interrupt macht man niemals Verzögerungsschleifen,
im Timer-Interrupt schon gar nicht. Das blockt nur den
Nicht-Interrupt-Ablauf - bitte gleich abgewöhnen. Interrupts müssen
immer so lang wie nötig und noch mehr so kurz wie möglich sein.
Lege stattdessen eine Variable an. Diese Variable gehört nur dem
Interrupt. Sie wird vom restlichen Programm nur während der
Initialisierung mit einem Wert vorbelegt.
Diese Variable zählst du in deinem Interrupt runter, nimm dazu die
DJNZ-Instruktion, sie soll auf RETI springen, wenn die Variable nach dem
Dekrementieren ungleich Null ist.
Nach der DJNZ-Instruktion belegst du die Variable wieder mit dem
ursprünglichen Wert, und führst deine restlichen Aktionen mit deinen
Ports aus.
Fertig.
Eine Erweiterung wäre dann, wenn das Programm mal so läuft wie
gewünscht, dass du beispielsweise die Portgeschichte ebenfalls ins
Hauptprogramm auslagerst und der Timer-IRQ wirklich nur solche Sachen
wie Zeitmessungen etc. macht, das zeigen wir dir dann, wenn dein
Programm läuft.
Mach erstmal das von mir vorgeschlagene Kommentieren, damit hast du
nämlich eine 1A-Möglichkeit zu vergleichen was du meinst zu tun und
was tatsächlich passiert.
Ralf
Da du den MC anscheinend mit 4 Mhz taktest, läuft der Timer doch mit 4.000.000/12 = 333.333,333 Hz. Mir ist nicht klar, wie du da auf eine genaue Sekunde kommen willst. Bedenke, ein Maschinenzyklus beim AT89C52 und AT89S52 ist 1/12 Fosc. Besser ist es, den MC mit z.B. 12 oder 24 MHz zu takten.
Wenn ich mich nicht täusche, hast du TMOD unsinnig gesetzt. (Counter-Mode statt Timer). Den Hinweis von Ralf zur Nutzung von Kommentaren würde ich unterstützen... Ralf schrieb: > beispielsweise bei 'org 01bh' dann 'Timer 1 Interrupt Vektor', bei 'mov > TMOD,#60h' steht 'Timer 1 konfiguriert als ...' und bei 'mov TL1,#06h' > steht 'Reloadwert für xxx ns/µs'.
Bei meinem ersten Post habe ich versucht es ein wenig zu erkären, war aber anscheinend nich ausführlich genug, hier etwas ausführlicher, das reicht erstmal für heute. Wie gefällt euch dieser Aufbau des Programmes? Und danke für den Hinweis des Maschinenzyklus 12/osz hatte ich nicht gewusst. ;####### Programm für AT89S52 #########; org 000h jmp 0100h ;Sprung zu Haupt; org 01bh ljmp 0300h ;Sprung zu Interrupt Zeitschleife ;####### Initialisierung #########; org 0100h mov IE,#88h ;1xEA bit7 und 1x ET1 bit3 (Freigabe Timer 1-interrupt); mov PCON,#00h ;nicht benötigt; mov SCON,#00h mov TCON,#00h mov TMOD,#60h ;1xC/T bit6 und Mode 8-bit-Timer/Counter Reload M1 bit5; mov TL1,#06h ;Reloadwert für ein 12MHz Oszi, Berechnung: 12M / 12 = 1M= Maschinenzyklus, 1M / 250 = 4 000 Bitwert: 256-250 = 6; mov TH1,#06h setb TR1 ;start Timer 1; mov P0,#00h ;Nullsetzen; mov P1,#00h mov P2,#00h mov R0,#00h mov R1,#0a0h ;R1 für Zeitberechnung 4 000 / 160 = 25 deshalb Register Vorladen mit 160 = 64hex; mov R2,#19h ;R2 für Zeitberechnung 25 / 25 =1 deshalb Register vorladen mit 25 (19hex) ; mov R3,#00h mov R4,#00h mov R5,#00h ;####### Hauptprogramm #########; mainloop: mov a,r1 ; Abfrage ob erster Register 0 wenn ja Abfrage des 2. Registers auf 0; jz wert1 jmp mainloop jmp mainloop wert1: mov r1,#0a0h ;Reloadwert für Register 1 ( 4 000 Hz / 160); dec r2 mov a,r2 jz wert2 jmp mainloop jmp mainloop wert2: mov r2,#64 ;Reloadwert für Register 2 (25Hz /25); mov a,p1 ;Ausgabe des Sekundentaktes an P1; inc a mov p1,a jmp mainloop ;##### Interrupt Zeitschleife###; org 0300h dec r1 ;Register 1 erhöhen bei jeden Interrupt; reti
stimmt, ganz oben war der Kommentar in der entscheidenden Zeile ja schon
drin. Aber
> mov TMOD,#60h ;1xC/T bit6 und Mode 8-bit-Timer/Counter Reload M1
ist meiner Ansicht nach immer noch die falsche Initialisierung. Damit
zählst du nicht Maschinenzyklen, sondern Flanken am Pin T1. Und weil
dort nicht viele Flanken ankommen, wird der Counter-Überlauf nicht
erreicht.
Versuchs mal mit
mov TMOD,#20h ;Timer 1 im Mode 8-bit-Timer mit Auto-Reload
Achim S. schrieb: > stimmt, ganz oben war der Kommentar in der entscheidenden Zeile ja schon > drin. Aber > >> mov TMOD,#60h ;1xC/T bit6 und Mode 8-bit-Timer/Counter Reload M1 > > ist meiner Ansicht nach immer noch die falsche Initialisierung. Damit > zählst du nicht Maschinenzyklen, sondern Flanken am Pin T1. Und weil > dort nicht viele Flanken ankommen, wird der Counter-Überlauf nicht > erreicht. > > Versuchs mal mit > > mov TMOD,#20h ;Timer 1 im Mode 8-bit-Timer mit Auto-Reload Okay, danke für den Hinweis, ich dachte das ich Counter auswählen muss wenn ich einen externen Quarz verwende bei XTAL1/XTAL2, und Timer wäre der interne Takt gewesen. Erkennt der MC automatisch das ein Quarz angesteckt ist?
Christian schrieb: > Wie gefällt euch dieser Aufbau des Programmes? Noch nicht gut - du gibst z.B. die Interrupts frei, bevor überhaupt etwas initialisiert ist. Programmierst du in HEX? Warum benutzt du keine Sprunglabel? z.B.:
1 | org 01bh |
2 | ljmp TIMER_OVF |
3 | ; und dann später im Programm |
4 | TIMER_OVF: |
5 | dec r1 |
6 | reti
|
Code markierst du in diesem Forum mit einen 'c' Tag in eckigen Klammern und ohne die Anführungsstriche. Beenden tust du den Codeschnipsel mit '/c' in eckigen Klammern. Die nächste rätselhafte Stelle ist für mich diese hier:
1 | mov R1,#0a0h ;R1 für Zeitberechnung 4 000 / 160 = 25 deshalb |
2 | Register Vorladen mit 160 = 64hex; |
Wie jetzt? Du sagst, das du mit 64hex lädst, tust aber 0a0h ins Register? Definiere dir lieber Konstanten oder schreibe die Werte in Dezimal. Das stört den Assembler normalerweise gar nicht und du sparst dir das Umrechnen. Christian schrieb: > Erkennt der MC automatisch das ein Quarz angesteckt ist? Ohne Quarz startet ein AT89S52 gar nicht, da er keinerlei internen Oszillator besitzt. Du musst einen Quarz oder Resonator an XTAL1 und XTAL2 lt.Datenblatt beschalten.
Danke für die Info, mein Problem ist erstmal glöst der Sekundentakt läuft! dafür besten dank an Achim und den danderen fleißigen Ratgebern. Die anderen Ratschläge werde ich mir auch zu Herzen nehmen. Gruß Christian
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.