Forum: Mikrocontroller und Digitale Elektronik Assembler 8051 Programm funktioniert nicht wie gewollt


von Earth S. (earthshaker)


Angehängte Dateien:

Lesenswert?

Guten Tag,
mein Programm(siehe unten) sollte mit einen an Port P2.0 angeschlossenen 
Lautsprecher Töne erzeugen. Allerdings besitzte der "Ton" in allen 
Fällen nur eine niedrige, nicht als Ton definierbare Frequenz. Nach 
ausprobieren müsste der Fehler in der ISR von T0 liegen. Könnt ihr mir 
weiterhelfen?


1
include reg_52.pdf
2
code at 0
3
4
  sjmp  init          
5
        
6
  org 03h          
7
  sjmp  ISR_EX0
8
  org 0bh            
9
  sjmp  ISR_T0
10
  org 13h            
11
  sjmp  ISR_EX1
12
  org 1bh          
13
  sjmp  ISR_T1
14
15
  
16
init:  setb  EA    
17
  setb  EX0          
18
  setb  EX1          
19
  setb  ET0              
20
  setb  ET1          
21
  mov  TMOD,#00010001b  
22
  mov   TCON,#00000101b  
23
  setb  P3.7          
24
  clr  P3.6          
25
  mov  R0,#255        
26
  mov   P2,#0          
27
  mov  R1,#40d        
28
  mov  TH1,#11111111b    
29
  mov  TL1,#11111111b    
30
haupt:   sjmp haupt  
31
32
ISR_T0:  clr  TR0
33
  mov  DPTR,#tcode
34
  mov  A,R0          
35
  movc  A,@A+DPTR      
36
  mov  TL0,A          
37
  dec  R0            
38
  mov  A,R0          
39
  movc  A,@A+DPTR      
40
  mov  TH0,A          
41
  inc  R0            
42
  setb  TR0
43
  cpl  P2.0          
44
  reti        
45
46
AusEX01:mov  DPTR,#seg7code    
47
  mov  A,R0        
48
  movc  A,@A+DPTR      
49
  mov  P2,A          
50
  mov  DPTR,#tcode      
51
  mov  A,R0          
52
  movc  A,@A+DPTR      
53
  mov  TH0,A          
54
  inc  R0            
55
  mov  A,R0          
56
  movc  A,@A+DPTR      
57
  mov  TL0,A          
58
  setb  TR0          
59
  setb  TR1          
60
  ret 
61
62
ISR_EX0:cjne  R0,#15,hoch      
63
  reti              
64
hoch:  inc  R0            
65
  acall AusEX01        
66
  reti
67
68
ISR_EX1:cjne  R0,#1,runter    
69
  reti            
70
runter:  mov  A,R0          
71
  subb  A,#3          
72
  mov  R0,A          
73
  acall AusEX01        
74
  reti             
75
76
ISR_T1:  mov  TL1,#11111111b    
77
  mov  TH1,#11111111b    
78
  djnz  R1,loop0        
79
  clr  TR0          
80
  clr  TR1          
81
  mov  R1,#40d        
82
loop0:  reti
83
84
85
86
seg7code:
87
  DB 01101100b ;C
88
  DB 01111110b ;D
89
  DB 11101100b ;E
90
  DB 11101000b ;F
91
  DB 11101110b ;G
92
  DB 11111010b ;A
93
  DB 11011010b ;H
94
  DB 01101100b ;C
95
96
tcode:
97
  DB 00001110b, 11101000b ;c3
98
  DB 00001101b, 01001001b ;d3
99
  DB 00001011b, 11010110b ;e3
100
  DB 00010110b, 01010010b ;f3
101
  DB 00001001b, 11110111b ;g3
102
  DB 00001000b, 11100000b ;a3
103
  DB 00000111b, 11101000b ;h3
104
  DB 00000111b, 01110100b ;c4

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Earth S. schrieb:
> mein Programm(siehe unten) sollte mit einen an Port P2.0 angeschlossenen
> Lautsprecher Töne erzeugen. Allerdings besitzte der "Ton" in allen
> Fällen nur eine niedrige, nicht als Ton definierbare Frequenz. Nach
> ausprobieren müsste der Fehler in der ISR von T0 liegen. Könnt ihr mir
> weiterhelfen?
1
  mov  DPTR,#tcode
2
  mov  A,R0           ;* R0 ist 255 beim ersten Einsprung
3
  movc  A,@A+DPTR     ;* #tcode + ?? wird geladen (Rate mal)
4
  mov  TL0,A          
5
  dec  R0             ;* Jetzt ist R0 = 254
6
  mov  A,R0          
7
  movc  A,@A+DPTR     ;* #tcode + ?? wird geladen (Rate nochmal)
8
  mov  TH0,A

 Was soll das Ganze ?

von Earth S. (earthshaker)


Lesenswert?

Marc V. schrieb:
> mov  A,R0           ;* R0 ist 255 beim ersten Einsprung

Du rufst erst zweimal den inc Befehl im Ext. Interrupt auf, bevor du den 
Timer startest dann ist dieser beim Einsprung 1

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Earth S. schrieb:
> Du rufst erst zweimal den inc Befehl im Ext. Interrupt auf, bevor du den
> Timer startest dann ist dieser beim Einsprung 1

 Sorry, übersehen, dachte Timer startet von alleine.
 Du weisst aber, dass die Werte als Big Endian gelesen werden und
 erster Wert nur 0xFF ist ?

von Earth S. (earthshaker)


Lesenswert?

Marc V. schrieb:
>  Sorry, übersehen, dachte Timer startet von alleine.
>  Du weisst aber, dass die Werte als Big Endian gelesen werden und
>  erster Wert nur 0xFF ist ?

Und jetzt bitte noch für einen dummen Schüler erklärt?

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Earth S. schrieb:
> Und jetzt bitte noch für einen dummen Schüler erklärt?

 Wo habe ich das behauptet ?
 Egal, ich bin raus.

von Earth S. (earthshaker)


Lesenswert?

Marc V. schrieb:
>  Wo habe ich das behauptet ?
>  Egal, ich bin raus.

ich bin ein Schüler, ich hab mich selbst als dumm bezeichnet.

Was wolltest du mit deiner Aussage erklären? Ich verstehe das nämlich 
nicht so ganz

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Earth S. schrieb:
> ich bin ein Schüler, ich hab mich selbst als dumm bezeichnet.
>
> Was wolltest du mit deiner Aussage erklären? Ich verstehe das nämlich
> nicht so ganz

 Hab es aber anders verstanden, deswegen.

 Big Endian in deinem Fall heisst, dass zuerst Wert für TH steht und
 dann der Wert für TL.
 Little Endian heisst, es steht zuerst der Wert für TL und erst dann
 der Wert für TH.

 Da du zuerst TH lädst, wird der mit 0 geladen und TL dann mit 255.

: Bearbeitet durch User
von Achim S. (Gast)


Lesenswert?

ein paar Kommentare hätten der Lesbarkeit deines Codes nicht geschadet.

Was machst du mit Timer 1? Du lädst ihn vor auf seinen Maximalwert, so 
dass er sofort überläuft und in seine ISR springt. Das passiert 40 mal, 
und danach hältst du in der ISR_T1 deinen Timer 0 an, so dass beide 
Timer stoppen und damit auch der Lautsprecher nicht mehr angeseteuert 
wird (bis zum nächsten Tastendruck).

Ist das Absicht oder lese ich den Code falsch?

von Earth S. (earthshaker)


Lesenswert?

Achim S. schrieb:
> ein paar Kommentare hätten der Lesbarkeit deines Codes nicht geschadet.
>
> Was machst du mit Timer 1? Du lädst ihn vor auf seinen Maximalwert, so
> dass er sofort überläuft und in seine ISR springt. Das passiert 40 mal,
> und danach hältst du in der ISR_T1 deinen Timer 0 an, so dass beide
> Timer stoppen und damit auch der Lautsprecher nicht mehr angeseteuert
> wird (bis zum nächsten Tastendruck).
>
> Ist das Absicht oder lese ich den Code falsch?

Eigentlich war genau das Gegenteil Erwünscht, Dankeschön


Jetzt habe ich das geändert, die Ausgabezeit stimmt jetzt.
aber das, was ausgegeben wird ist mehr oder weniger ein knacken;
Hilft es wenn ich die Timer(0)reloadwerte in 2 register schiebe und 
diese dann immer daraus lade?

von nemesis... (Gast)


Lesenswert?

Earth S. schrieb:
> Guten Tag,
> mein Programm(siehe unten) sollte mit einen an Port P2.0 angeschlossenen
> Lautsprecher Töne erzeugen.

Was für ein Lautsprecher? Gewöhnlich kann so ein Port keinen 
Lautsprecher
treiben.

Earth S. schrieb:
> Ich verstehe das nämlich
> nicht so ganz

Du hättest dich schon in deinem Eingangsthread als Schüler outen sollen.
Einem Schüler erklärt man einen Sachverhalt ganz anders, als einem,
sagen wir mal, Erfahrenen.

von Achim S. (Gast)


Lesenswert?

Earth S. schrieb:
> Hilft es wenn ich die Timer(0)reloadwerte in 2 register schiebe und
> diese dann immer daraus lade?

ob du die Reloadwerte aus 2 Registern lädst oder ob du sie vom dptr 
liest ist egal. Wenn dein 8051 einen Timer 2 besitzt, kannst du den auch 
im Auto-Reload laufen lassen.

Interessanter ist, ob die Reload-Werte richtig sind. Auch der Kommentar 
von nemesis ist wichtig: ein normaler Portpin kann keinen Lautsprecher 
treiben, und beim 8051 ist das erst recht der Fall, weil der 
Higshside-Treiber (bis auf ein paar µs bei der Schaltflanke) hochohmig 
ist. Also: wie sieht deine Hardware aus?

Zur Wahl deiner Reload-Werte: die ergeben alle recht seltsame 
Frequenzen. Beispiel:

Earth S. schrieb:
> DB 00001110b, 11101000b ;c3

Soll damit 0x0E in TH0 und 0XE8 in TL0 geladen werden? Falls ja, dann 
erzeugt das den Timerüberlauf nach 61,7ms (sofern dein 8051 mit 12MHz 
getaktet ist). Wenn du in den Zeitabständen den Portpin invertierst gibt 
es einen Ton von ~8Hz - also nichts hörbares.

Wahrscheinlich wolltest du eher 260Hz treffen. Dann musst du den 
Reloadwert aber auf 0x10000 - 0x0EE8 setzen, nicht auf 0x0EE8 (der Timer 
zählt aufwärts, nicht abwärts).

Außerdem behandelst du den Index auf deine Notentabelle nicht richtig. 
Warum initialisiert du R0 auf 255? Lass es bei 0 loslaufen, mit 255 
zeigt es auf einen Speicher, der nicht definiert ist.

Auch das das dec R0 und inc R0 erscheinen mir falsch. Wenn du R0 als 
Index verwenden willst, dann muss es entweder in Zweierschritten hoch- 
und runterzählen. (weil jede Note zwei Byte belegt).

Oder du zählst R0 in Einserschritten und machst die Verdopplung des 
Zeigerst beim Auslesen.

Also ungefähr so:

  ;index der Note (0..7) steht in R0
  mov  DPTR,#tcode
  mov  A,R0
  rl   A  ;Offset für High-Byte ist 2*Index
  movc  A,@A+DPTR
  mov  TH0,A
  mov  A,R0
  rl   A
  inc  A  ;Offset für Low-Byte ist 2*Index+1
  movc  A,@A+DPTR
  mov  TL0,A

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Das nächste Problem ist, das der Timer ja genau nur eine Periode 
durchläuft und dann schon der nächste Wert kommt. Das gibt aber keinen 
Ton, selbst wenn die Reloadwerte richtig wären, denn dazu muss man mehr 
als eine halbe Periode eines Tons spielen.

Bei einem z.B. 60er Beat ist die Tonlänge ohne Pause ja 1 Sekunde lang. 
Du musst also für einen Ton mit 250 Hz den Timer 250 mal durchlaufen 
lassen, um einen Ton von einer Sekunde Länge zu bekommen.

von Reinhard D. (decimalreinhard)


Lesenswert?

Achim S. schrieb:
> Soll damit 0x0E in TH0 und 0XE8 in TL0 geladen werden? Falls ja, dann
> erzeugt das den Timerüberlauf nach 61,7ms (sofern dein 8051 mit 12MHz
> getaktet ist). Wenn du in den Zeitabständen den Portpin invertierst gibt
> es einen Ton von ~8Hz - also nichts hörbares.
>
> Wahrscheinlich wolltest du eher 260Hz treffen. Dann musst du den
> Reloadwert aber auf 0x10000 - 0x0EE8 setzen, nicht auf 0x0EE8 (der Timer
> zählt aufwärts, nicht abwärts).

Das könnte das bereits erwähnte "knacken" erklären.
Danke dafür

ich probiere es morgen früh mal aus und kann mich ja dann nochmal melden 
:)

von Achim S. (Gast)


Lesenswert?

Matthias S. schrieb:
> Das nächste Problem ist, das der Timer ja genau nur eine Periode
> durchläuft und dann schon der nächste Wert kommt.

ich glaube nicht: R0 (der Ton) wird zwar in der ISR_T0 decrementiert, 
danach aber auch wieder incrementiert, so dass weiter der selbe Ton 
kommt. Die Tonlänge soll wohl über Timer1 eingestellt werden, wobei sich 
oben schon gezeigt hat, dass das falsch gelöst war.

Ein neuer Ton kommt imho nur als Reaktion auf einen externen Interrupt 
zustande (also wohl bei Tastendruck). Dann wird sowohl in der Ext-ISR 
als auch in der daraus aufgerufenen Routine zur Siebensegmentanzeige der 
Wert von R0 (also die Note) verändert - was allerdings ebenfalls eine 
ziemlich unübersichtliche Geschichte ist.

Reinhard D. schrieb:
> ich probiere es morgen früh mal aus und kann mich ja dann nochmal melden

Bist du der Thread-Opener und jetzt unter anderem Namen unterwegs? Danke 
für die Verwirrung.

Wie schauts mit der Frage nach der Hardware aus?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Achim S. schrieb:
> Bist du der Thread-Opener und jetzt unter anderem Namen unterwegs?
Korrekt.

@Reinhard D.
Bitte nur 1 Name pro Thread!
Siehe die Nutzungsbedingungen:
https://www.mikrocontroller.net/articles/Hilfe:Forum_Nutzungsbedingungen

von Earth S. (earthshaker)


Lesenswert?

Reinhard D. muss wohl mein Projektpartner gewesen sein.
Entschuldigung für die Verwirrung

Aber durch setzen von Timer 1 auf 0 und umkehren der Frequenzen läuft 
jetzt alles wie gewünscht.
Danke an meine Helfer Achim S., Matthias Sch.

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
Noch kein Account? Hier anmelden.