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.
