Hallo Leute ich hoffe ihr könnt mir helfen, stehe richtig auf dem schlauch. Aufgabestellung siehe Anhang. Ich habe allerdings ein Problem mit dem Timer Hier ist der Code: stack_seg SEGMENT IDATA ; Deklaration Stack Segment code_seg SEGMENT CODE ; Deklaration Code Segment RSEG stack_seg ; Anfang des Stack Segmentes Stack_data: DS 5 ; Für stack_data werden 5 Byte reserviert CSEG AT 0 ; Programmbeginn bei Adresse NULL wird LJMP init ORG 0x0B JMP ISR_tim0 timer_high EQU 0x3C timer_low EQU 0xAF // Springt zu unserer Main, wo der Code gestartet wird // Startadresse der siebenSegmentAnzeige_Tabelle, wo die Segmentsteuerung gespeichert ist. Tabelle: // Tabellenlabel db 0x3F; // Ansteuerung für 0 db 0x06; // Ansteuerung für 1 db 0x5B; // Ansteuerung für 2 db 0x4F; // Ansteuerung für 3 db 0x66; // Ansteuerung für 4 db 0x6D; // Ansteuerung für 5 db 0x7D; // Ansteuerung für 6 db 0x07; // Ansteuerung für 7 db 0x7F; // Ansteuerung für 8 db 0x6F; // Ansteuerung für 9 db 0x3F; // Ansteuerung für A db 0x3F; // Ansteuerung für B db 0x3F; // Ansteuerung für C db 0x3F; // Ansteuerung für D db 0x3F; // Ansteuerung für E db 0x3F; // Ansteuerung für F RSEG code_seg init: MOV DPTR, #Tabelle MOV SP, #Stack_data MOV TH0, #timer_high MOV TL0, #timer_low MOV TMOD, #0x01 SETB PT0 SETB ET0 SETB EA MOV P1, #0x00 MOV P0, #0x00 MOV P2, #0xFF MOV P3, #0x00 MOV P2, #0x13 MOV R3, #0x02 MOV R4, #0x04 Read: MOV A, P2 // Einlesen von Port 2 8 bit-Wert // Für Überprüfung MOV R1, A // Wert von A Sichern in R1 ANL A, #0FH // Low-Teil (Bits: 0-3) ausmaskiert MOV R2, A // LOw-Teil sichern MOV A, R1 // Originalwert nach A schreiben RRC A // Der High-Teil (rotierbefehl, 4xMal zum maskieren) RRC A RRC A RRC A ANL A, #0FH // von A wird ausmaskiert sjmp CHECK Label: MOV R1,A MOV A, R2 // Der Low-Teil wird nach A geschrieben CHECK: CJNE A, #9h, CHECK_LESS LJMP Berechnung CHECK_LESS: JC Berechnung EXCEPTION: MOV A, #0H Berechnung: MOV DPTR, #Tabelle MOVC A, @A+DPTR DJNZ R3,Label Ausgabe: SETB TR0 MOV P1, #02H MOV P0, R1 MOV P1, #01H MOV P0, A CLR TR0 JMP Ausgabe ISR_tim0: ; Interrupt Routine PUSH ACC ; Sichere Accu auf Stack PUSH PSW ; Sichere ProgramStatusWord auf Stack DEC R4 ; R1 dekrementieren MOV TH0,#timer_high ; Timer0 Register laden MOV TL0,#timer_low ; Timer0 Register laden POP PSW ; ProgramStatusWord wird wiederhergestellt POP ACC ; Accu wird wiederhergestellt RETI end
Hi, also ohne genauen Einblick in den Intel-Assambler zu haben, sehe ich keinen Sinn in deinem Timer-Interrupt. Was macht er? Zählt den anfänglichen Wert von R4=0x04 bis Null und anschließend durch Überlauf von 255 wieder nach Null. Des Weiteren liest du nur einmal die Werte vom Port ein, deine Ausgabeschleife wird nie wieder verlassen. Ist das so gewollt? Vom Prinzip würde ich den Timer es so machen: ISR_tim0: ; Interrupt Routine PUSH ACC ; Sichere Accu auf Stack PUSH PSW ; Sichere ProgramStatusWord auf Stack [Wenn aktuell Segment 1 dann springe zu Segment 2] MOV P1, #01H MOV P0, A [Springe zu Ende_Segment:] Segment2: MOV P1, #02H MOV P0, R1 Ende_Segment: MOV TH0,#timer_high ; Timer0 Register laden MOV TL0,#timer_low ; Timer0 Register laden POP PSW ; ProgramStatusWord wird wiederhergestellt POP ACC ; Accu wird wiederhergestellt RETI Jetzt hast du schon mal eine feste Frequenz für das Multiplexen. Jetzt musst du nur noch zyklisch den Eingang prüfen und deine Berechnung starten. Entweder machst du dies in einer Endlosschleife im Hauptprogramm oder im Timer-ISR. Ich hoffe es hilft dir weiter.
erst mal danke für deine antwort. die ausgabe schleife ist so gewollt. der teimer soll eigentlich das flimmern der anzeige beseitigen. Leider habe ich mit timer keine erfahrung. bin neu. Danke für die hilfe.
Der Timer Interrupt muß etwas anderes machen: Er dient als Zeitbasis für die Umschaltung zwischen den beiden Ziffern. Wenn die Anzeige zweistellig ist, steuert man entweder die Ziffer Nummer eins oder die Ziffer Nummer zwei an, möglichst abwechselnd und so, daß auf beide eine gleichlange Zeit entfällt. Dafür ist der Timer gut. Man könnte im Timer-Interrupt eine Variable umschalten, die angibt, ob Ziffer 1 oder Ziffer 2 angesteuert ist. Im Hauptprogramm muß diese Variable kontinuierlich ausgewertet werden und entsprechend die Daten für Ziffer 1 oder Ziffer 2 auf dem Port ausgegeben. Wie immer gilt: Es leuchten nicht beide Ziffern gleichzeitig. Durch schnelles Umschalten zwischen beiden erzeugt die Trägheit des Auges diesen Eindruck.
Ehe man programmiert, schreibt man sich erstmal den PAP (Programmablaufplan) in Worten auf, z.B.:
1 | Init:
|
2 | starte T0 |
3 | while( 1 ){ // Main-Loop forever |
4 | call wait |
5 | Abfrage der 1. 4 Pins |
6 | umwandeln in 7-Segment |
7 | anzeigen Digit 1 |
8 | |
9 | call wait |
10 | Abfrage der 2. 4 Pins |
11 | umwandeln in 7-Segment |
12 | anzeigen Digit 2 |
13 | }
|
14 | |
15 | wait: |
16 | while( TF0 == 0 ){} // warte, bis Bit gesetzt |
17 | TF0 = 0 // Bit löschen |
18 | T0 = Reload-Wert // laden für 100Hz |
19 | return
|
Peter
opteronfx schrieb: > MOV A, P2 // Einlesen von Port 2 8 bit-Wert > // Für Überprüfung > MOV R1, A // Wert von A Sichern in R1 > ANL A, #0FH // Low-Teil (Bits: 0-3) ausmaskiert > MOV R2, A // LOw-Teil sichern > MOV A, R1 // Originalwert nach A schreiben > RRC A // Der High-Teil (rotierbefehl, 4xMal zum maskieren) > RRC A > RRC A > RRC A > ANL A, #0FH // von A wird ausmaskiert Geht einfacher so:
1 | mov a, P2 |
2 | mov b, #16 |
3 | div ab ; A = high nibble, B = low nibble |
Peter
Das ist ein guter tip. Danke. Also jungs ich komme mit meinem timer nicht weiter. wie würdet ihr das dann technisch machen? Danke.
opteronfx schrieb: > Also jungs ich komme mit meinem timer > nicht weiter. Was am Timer ist denn das Problem? Du mußt schon sagen, wo es klemmt. Peter
opteronfx schrieb: > Das ist ein guter tip. Danke. Also jungs ich komme mit meinem timer > nicht weiter. wie würdet ihr das dann technisch machen? Bau dir im Timer-Interrupt eine State-Machine, die je Interrupt die Segmente nacheinander anspricht. Mit einer Variablen bzw. RAM-Byte extra dafür, was man für Verzweigungen dann dort im Interrupt benutzt. Du zählst sie in jedem Interrupt um 1 hoch, und verzweigst dann je nach Wert dorthin, wo du was machen möchtest. So ein Unterscheidungsblock mit Verzweigungen, geht gut mit bedingten Sprungbefehlen (z.B. JZ, JNZ, CJNE).
Danke nochmals. Also folgendes, ich versuche zwei bcd-werte auszugeben. Damit das flimmerfrei passiert sollte ein timer programmiert werden. Das ist genau das wo ich nicht mehr weiter komme. Von Timer habe ich einfach keine Ahnung. Es wäre einfach nett, wenn ihr mal einen fertigen vorschlag zeigen würdet. Ich bedanke mich für eure Mühe. stack_seg SEGMENT IDATA ; Deklaration Stack Segment code_seg SEGMENT CODE ; Deklaration Code Segment RSEG stack_seg ; Anfang des Stack Segmentes Stack_data: DS 5 ; Für stack_data werden 5 Byte reserviert CSEG AT 0 ; Programmbeginn bei Adresse NULL wird LJMP init Tabelle: // Tabellenlabel db 0x3F; // Ansteuerung für 0 db 0x06; // Ansteuerung für 1 db 0x5B; // Ansteuerung für 2 db 0x4F; // Ansteuerung für 3 db 0x66; // Ansteuerung für 4 db 0x6D; // Ansteuerung für 5 db 0x7D; // Ansteuerung für 6 db 0x07; // Ansteuerung für 7 db 0x7F; // Ansteuerung für 8 db 0x6F; // Ansteuerung für 9 db 0x3F; // Ansteuerung für A db 0x3F; // Ansteuerung für B db 0x3F; // Ansteuerung für C db 0x3F; // Ansteuerung für D db 0x3F; // Ansteuerung für E db 0x3F; // Ansteuerung für F RSEG code_seg MOV DPTR, #Tabelle MOV SP, #Stack_data MOV P1, #0x00 MOV P0, #0x00 MOV P2, #0xFF MOV P3, #0x00 MOV P2, #0x43 MOV R3, #0x02 Read: mov a, P2 // wert einlesen mov b, #16 div ab // A high und B lowbyte sjmp CHECK Label: MOV R1,A MOV A, B CHECK: CJNE A, #9h, CHECK_LESS LJMP Berechnung CHECK_LESS: JC Berechnung EXCEPTION: MOV A, #0H Berechnung: MOV DPTR, #Tabelle MOVC A, @A+DPTR DJNZ R3,Label Ausgabe: MOV P1, #02H MOV P0, R1 MOV P1, #01H MOV P0, A JMP Ausgabe end Soweit bin ich gekommen, aber die anzeige muss mindestens 100 mal in die sekunde dargestellt werden, damits flimmerfrei ist. Und das ist genau mein problem. Ich weiss einfach nicht wie man eine timer_isr schreibt und wo man das im programm einsetzen soll.
ich habe versucht hier etwas zu basteln, bin am verzweifeln stack_seg SEGMENT IDATA ; Deklaration Stack Segment code_seg SEGMENT CODE ; Deklaration Code Segment RSEG stack_seg ; Anfang des Stack Segmentes Stack_data: DS 5 ; Für stack_data werden 5 Byte reserviert CSEG AT 0 ; Programmbeginn bei Adresse NULL wird LJMP init ORG 0x0B JMP ISR_tim0 timer_high EQU 0x3C timer_low EQU 0xAF // Springt zu unserer Main, wo der Code gestartet wird // Startadresse der siebenSegmentAnzeige_Tabelle, wo die Segmentsteuerung gespeichert ist. Tabelle: // Tabellenlabel db 0x3F; // Ansteuerung für 0 db 0x06; // Ansteuerung für 1 db 0x5B; // Ansteuerung für 2 db 0x4F; // Ansteuerung für 3 db 0x66; // Ansteuerung für 4 db 0x6D; // Ansteuerung für 5 db 0x7D; // Ansteuerung für 6 db 0x07; // Ansteuerung für 7 db 0x7F; // Ansteuerung für 8 db 0x6F; // Ansteuerung für 9 db 0x3F; // Ansteuerung für A db 0x3F; // Ansteuerung für B db 0x3F; // Ansteuerung für C db 0x3F; // Ansteuerung für D db 0x3F; // Ansteuerung für E db 0x3F; // Ansteuerung für F RSEG code_seg init: MOV DPTR, #Tabelle MOV SP, #Stack_data MOV TH0, #timer_high MOV TL0, #timer_low MOV TMOD, #0x01 SETB PT0 SETB ET0 SETB EA MOV P1, #0x00 MOV P0, #0x00 MOV P2, #0xFF MOV P3, #0x00 MOV P2, #0x43 MOV R3, #0x02 MOV R2, #0x02 Read: mov a, P2 mov b, #16 div ab sjmp CHECK CHECK: CJNE A, #9h, CHECK_LESS LJMP Berechnung CHECK_LESS: JC Berechnung EXCEPTION: MOV A, #0H Berechnung: MOV DPTR, #Tabelle MOVC a, @a+DPTR MOV R3, a mov a, b movc a, @a+dptr mov b, a // b low mov a, r3 // a high main_loop: setb tr0 segment_1: call warte100ml MOV P1, #02H MOV P0, a segment_2: call warte100ml MOV P1, #01H MOV P0, b jmp main_loop warte100ml: MOV A,R2 ; Lade R2 in den Accu JZ label ; Springe wenn Accu==0 zum Segment: JMP warte100ml ; Warte so lange bis ca. 200msec gewartet wurden. label: CLR TR0 MOV R2,#0x02 mov a, r3 // a high-wert wiederherstellen reti ISR_tim0: ; Interrupt Routine PUSH ACC ; Sichere Accu auf Stack PUSH PSW ; Sichere ProgramStatusWord auf Stack DEC R2 ; R4 dekrementieren MOV TH0,#timer_high ; Timer0 Register laden MOV TL0,#timer_low ; Timer0 Register laden POP PSW ; ProgramStatusWord wird wiederhergestellt POP ACC ; Accu wird wiederhergestellt reti end
Mach im Timerinterrupt mal sowas: Definiere vorher mal ein Zählbyte SEGMENTZAEHLER irgendwo im Datenspeichersegment. Es ist nur eine grobe Idee, da ich schon mal in Assembler mit dem 8051 arbeitete. cjne SEGMENTZAEHLER, #0, T0_INT_LABEL1 sjmp Segment_Multiplex_1 T0_INT_LABEL1 cjne SEGMENTZAEHLER, #1, T0_INT_LABEL2 sjmp Segment_Multiplex_2 T0_INT_LABEL2 cjne SEGMENTZAEHLER, #2, T0_INT_LABEL3 sjmp Segment_Multiplex_3 T0_INT_LABEL3 sjmp Segment_Multiplex_4 Segment_Multiplex_1 ... Verarbeitung Segment 1 sjmp TO_RETI Segment_Multiplex_2 ... Verarbeitung Segment 2 sjmp TO_RETI Segment_Multiplex_3 ... Verarbeitung Segment 3 sjmp TO_RETI Segment_Multiplex_4 ... Verarbeitung Segment 4 sjmp TO_RETI TO_RETI INC SEGMENTZAEHLER ; State Variable ANL SEGMENTZAEHLER, #3 ; nur 4 Segmente RETI Jedesmal, wenn ein Interrupt erfolgt, geht die Sache (SEGMENTZAEHLER) einen Schritt weiter. Nach der höchsten Stelle muß wieder bei Null begonnen werden. Vielleicht führt es gedanklich in die richtige Richtung...
War mein PAP wirklich so unverständlich?
1 | init: |
2 | mov tmod, #01h ; T0 = 16bit |
3 | setb tr0 ; run T0 |
4 | main: |
5 | mov a, p2 |
6 | mov b, #16 |
7 | div ab ; quotient = high nibble |
8 | call bcd_to_7s |
9 | call wait |
10 | setb p1.0 ; digit 0 off |
11 | mov p0, a ; high digit |
12 | clr p1.0 ; digit 1 on |
13 | |
14 | mov a, b ; remainder = low nibble |
15 | call bcd_to_7s |
16 | call wait |
17 | setb p1.0 ; digit 1 off |
18 | mov p0, a ; low digit |
19 | clr p1.1 ; digit 0 on |
20 | jmp main |
21 | |
22 | wait: |
23 | jbc tf0, _wait1 ; wait until overflow |
24 | jmp wait |
25 | _wait1: |
26 | mov th0, #high(-5000) ; 1MHz / 200Hz = 5000 |
27 | mov tl0, #low(-5000) |
28 | ret |
29 | |
30 | bcd_to_7s: |
31 | inc a ; skip 'ret' |
32 | movc a, @a+pc |
33 | ret |
34 | db 3fh, 06h, 5bh, 4fh, 66h, 6dh, 7dh, 07h, 7fh, 6fh |
35 | db 10h, 10h, 10h, 10h, 10h, 10h ; non valid digits = '_' |
36 | end |
Peter
Hallo Peter erst mal danke. ich wollte nur mal fragen was an meinem program falsch ist. nochmals vielen dank und einen schönen tag noch. lg, aus liederbach
opteronfx schrieb: > ich wollte nur mal fragen was an meinem > program falsch ist. Du hältst den Timer an, startest ihn aber nicht wieder. Und 2 * 200ms = 2,5Hz, das ist etwas langsam. Du liest nur einmal den P2 ein, ist das so gewünscht? Benutze für Quelltext die Formatierungen des Forums, dann ist das deutlich übersichtlicher. 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.