Assembler 8051 Programm funktioniert nicht wie gewollt

OP #4602047
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
Angehängte Dateien:
(Firma: Vescomp) #4602115
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 ?
(Firma: Vescomp) #4602207
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.
Gast #4602217
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?
OP #4602252
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?
Gast #4602258
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.
Gast #4602359
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
(Firma: matzetronics) #4602385
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.
#4602417
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 
:)
Gast #4602419
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren