Forum: Mikrocontroller und Digitale Elektronik Sinustabelle wird nicht richtig ausgelesen!


von J. T. (chaoskind)


Lesenswert?

Hallo liebe Leute,

ich bin gerade dabei, neu in das Hobby uC einzusteigen. Nun bin ich 
dabei, ein kleines Stück Code zu schreiben, das über den PortC vom 
Mega32 bytes ausgibt, die ein DAC0808 dann als Sinus, Dreieck usw 
ausgeben soll. Für das Rechteck und Sägezähn klappt das ganze auch 
wunderbar. Nun wollte ich selbiges auch für den Sinus machen, habe mir 
ne Tabelle mit den entsprechenden 8bit-Werten besorgt. Diese habe ich im 
EEPROM abgelegt, der DAC funktioniert, wie bei den anderen Wellenformen 
gesehen, er gibt von 0V-5V aus. Aber auf dem Oszi sehe ich keine 
Sinuskurve, sondern ein Gebilde, das von 0-2,5V wie eine Sinuskurve 
steigt(1/4pi), dann aber auf 0V zurückspringt,weiterläuft wie ein Sinus 
aber quasi die 2,5V nach unten versetzt. Wenn dann bei (3/4pi) wieder 
null erreicht ist, wird auf 2,5 volt zurückgesprungen, das letzte 
Viertel der oberen Sinushälfte wird normal durchlaufen. Nach unten ist 
es das selbe. Quasi so ähnlich




   +          +   +       +
  +        +         +     +
 +      +              +    +
+     +                  +   +   +                     +   +
                              +    +                 +    +
                               +       +           +     +
                                +          +    +       +

Ich programmiere im AVR Studio, Programmer ist nen mysmart usb mk2, uC 
ist ein Atmega32 16pu

Hier noch der Code,den teil fürs Rechteck usw hab ich mal weggelassen.
Vielen Dank im vorraus schonmal,
mit gespannten Grüßen, Jendrik

P.S.
Da die anderen Wellenformen richtig ausgeben werden, denke ich das man 
sowas wie MSB am DAC vertauscht auschließen kann, obwohl das Fehlerbild 
schon darauf schließen lässt..
1
.include "m32def.inc"
2
3
.def   zaehler    = r0
4
.def  frq1    = r1
5
.def  frq2    = r2
6
.def  irqcount  = r3
7
.def   a1      = r16
8
.def   a2      = r17
9
.def  a3      = r18
10
.def  interrupt = r19
11
.def  a4      = r20
12
13
;codesegmentbeginn und startadresse
14
.cseg
15
.org  0x0000
16
17
rjmp   anfang
18
19
;Interruptvektoren
20
rjmp taster          ;interrupt0?
21
rjmp taster      ;interrupt0
22
23
24
25
26
27
anfang:
28
29
;eeprom
30
ldi    a1,0b00010000
31
out    eecr,a1
32
33
;interrupts
34
ldi    a1,0b01000000
35
out    gicr,a1
36
37
;stackpointer initialisieren
38
ldi   a1,low(ramend)
39
out    spl,a1
40
ldi    a1,high(ramend)
41
out    sph,a1
42
43
;Datenrichtung
44
ldi    a1,255
45
out    ddrc,a1
46
out    ddrb,a1
47
48
;Initialisieren
49
ldi    a1,0
50
mov    zaehler,a1
51
mov    irqcount,a1
52
out    ddrd,a1
53
ldi    a1,40
54
mov    frq1,a1
55
ldi    a1,255
56
mov    frq2,a1
57
;sei  ;globale interrupts aktivieren
58
59
rjmp sinus
60
;--------------------------------------------------------  
61
62
;----------------------------------------------------------
63
;sinus 2
64
  
65
Sinus:  
66
  
67
    ;eeprompointer setzen
68
    ldi    zh,high(2*sinustab)
69
    out    eearh,zh
70
    ldi    zl,low(2*sinustab)
71
    out    eearl,zl
72
  
73
  Sin1:
74
75
    ;rega3 255, da 255 werte in der tabelle. a2,wie lange jedes byte ausgeben wird
76
    ldi    a3,255
77
    ldi    a2,8
78
    
79
    sin2:
80
      out    eearl,zl      ;tabellenposition
81
      sbi    eecr,eere     ;eeprom lesen
82
      in    a1,eedr        ;wert aus eeprom in a1
83
      out    portc,a1
84
      out    portb,a1
85
      inc    zl            ;tabellenposition ein weiter
86
      call  sin_time       ;schleife für byteausgabedauer aufrufen
87
88
      dec    a3            ;zähler für ausgabe eins runter
89
      brne  sin2           ;nächstes byte ausgeben wenn nicht null
90
      jmp    sin1          ;sonst wieder von vorn
91
92
        sin_time:
93
          
94
          dec    a2
95
          brne   sin_time
96
          ret                      
97
98
;----------------------------------------------------------
99
;interrupts
100
101
taster:
102
103
    inc    irqcount
104
    mov    interrupt,irqcount
105
    cpi    interrupt,2
106
    breq  tr
107
    reti
108
  
109
    tr:
110
    clr    irqcount
111
    reti
112
113
114
115
116
117
.eseg
118
119
sinustab:
120
121
    .db 127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124

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


Lesenswert?

jendrik t. schrieb:
> der DAC funktioniert ...  er gibt von 0V-5V aus.
Was gibt er bei 0x00 aus, was bei 0x7f, was bei 0x80, was bei 0xff?

> der DAC funktioniert, wie bei den anderen Wellenformen gesehen
Woher hattest du die Werte für diese Wellenformen?

> out    eearl,zl
Ist diese Tabelle wirklich an einer Page-Grenze abgelegt? Reicht es aus, 
wenn du das Low-Byte manipulierst?

> Aber auf dem Oszi sehe ich keine
> Sinuskurve, sondern ein Gebilde, das von 0-2,5V wie eine Sinuskurve
> steigt(1/4pi), dann aber auf 0V zurückspringt,weiterläuft wie ein Sinus
> aber quasi die 2,5V nach unten versetzt. Wenn dann bei (3/4pi) wieder
> null erreicht ist, wird auf 2,5 volt zurückgesprungen, das letzte
> Viertel der oberen Sinushälfte wird normal durchlaufen.
> Nach unten ist es das selbe. Quasi so ähnlich
Aber nur Quasi?
Nehmen wir mal das Bild hier und tragen die Spannungen nach deiner 
Beschreibung ein, dann habe ich ein Problem:
     0   pi/4    pi/2    3pi/4
>2.5V   +        +   +       +
>      +      +         +     +
>     +     +             +    +
> 0V +    +                 +   +   +                 +    +
>                                 +   +              +    +
>                                  +    +          +     +
> ???V                              +      +    +       +
Was müsste denn bei ???V stehen?


1
    sin1:
2
3
    ldi    a2,8
4
    
5
    sin2:
6
      ...
7
      call  sin_time       ;schleife für byteausgabedauer aufrufen
8
      ...
9
      brne  sin2           ;nächstes byte ausgeben
10
      ...
11
12
   sin_time:
13
          dec    a2
14
          brne   sin_time
15
          ret
Dir ist klar, dass a2 nicht so richtig wirken kann?
Das der Wert 8 nur einmal ganz am Anfang des sinus gilt?

1
  Sin1:
2
3
    ldi    a3,255
4
    
5
    sin2:
6
      ...
7
      dec    a3            ;zähler für ausgabe eins runter
8
      brne  sin2           ;nächstes byte ausgeben wenn nicht null
9
      jmp    sin1          ;sonst wieder von vorn
Du könntest einfach ohne Vergleich mit a3 weitermachen, denn 0-1 ist -1 
und das ist 0xFF und das ist 255...

Und das Beste zuletzt: du bräuchtest a3 gar nicht, weil zl schon den 
index beinhaltet und kostenlos überläuft. Und weil du fürderhin zh 
ignorierst.
1
Sinus:  
2
    ldi    zh,high(2*sinustab)
3
    out    eearh,zh
4
    ldi    zl,low(2*sinustab)
5
    out    eearl,zl
6
    ldi    a2,8
7
sin2:
8
    out    eearl,zl      ;tabellenposition NUR LOW-BYTE !!!
9
    sbi    eecr,eere     ;eeprom lesen
10
    in     a1,eedr       ;wert aus eeprom in a1
11
    out    portc,a1      
12
    inc    zl            ;eins weiter --> läuft automatisch von 255 auf 0 über
13
    call   sin_time      ;schleife für byteausgabedauer aufrufen
14
    jmp    sin2          ;--> the never ending story
15
16
sin_time:
17
    dec    a2
18
    brne   sin_time
19
    ldi    a2,8          ;Zeit wieder laden
20
    ret



BTW: dir ist schon klar, dass ein viertel vom ganzen Sinus ausreichen 
würde? Der Rest kann mit Offset, Invertierung und einer Subtraktion 
erledigt werden...


BTW2: Warum legst du die Tabelle in EEPROM? Im ROM wäre so eine 
statische Tabelle doch viel besser aufgehoben...

von Rainer U. (r-u)


Lesenswert?

Kann das sein, dass der Compiler "2xsinustab" als Byte rechnet? (fixed 
overflow)?

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


Lesenswert?

Rainer Unsinn schrieb:
> "2xsinustab"
Warum eigentlich 2*sinustab? Die Tabelle liegt doch im EEPROM...

Siehe auch den Beitrag "Re: [AVR] m8535-EEPROM wird falsch gelesen"

von spess53 (Gast)


Lesenswert?

Hi

>Kann das sein, dass der Compiler "2xsinustab" als Byte rechnet? (fixed
>overflow)?

Nein. Wobei '2*sinustab' für den EEprom sowieso falsch ist. Führt hier 
nur nicht zu einem Fehler, weil die Adresse von sinustab Null ist.

MfG Spess

von J. T. (chaoskind)


Lesenswert?

Hi, danke erstmal für die Antworten.

Also die Geschichte mit der multiplikation der Adresse mit 2 hab ich aus 
sonnem kleinen Anfängerbuch. Hab da auch nicht ganz verstanden was das 
soll. Evtl könnte mir das auch jdm erklären. Ich hatte es aber auch mit 
ldi zh,high(sinustab) versucht, mit dem selben Ergebnis.

@ Lothar Miller

>Was gibt er bei 0x00 aus, was bei 0x7f, was bei 0x80, was bei 0xff?

das müsst ich mal nachmessen..

tadaa

Messen ist doch ne feine Sache, vor allem, wenn mans richtig macht. *gg

die "schicke" Sinuskurve ging von 0v bis ca 3,65v, womit dann doch klar 
war, das ein Bit nicht richtig geschaltet wird.... Das Breadboard war 
schuld. Also vielen danke für eure Hilfsversuche, und über eine 
Erklärung was das mit dieser ominösen (2*Sinustab) auf sich hat, wann 
man das macht, wäre ich immernoch dankbar.

>Was müsste denn bei ???V stehen?
da müsste die 0V stehen, hatte das nur schnell ausm kopf gezeichnet *g


>Dir ist klar, dass a2 nicht so richtig wirken kann?
>Das der Wert 8 nur einmal ganz am Anfang des sinus gilt?
Nein ist es mir nicht... Aber nachdem ich es nun nochmal durchgegangen 
bin, leuchtet es mir ein! Danke für den Hinweis, das erklärt schonmal 
warum er beim sinus quasi überhaupt nicht auf änderungen vom a2 wert 
reagiert hat, bei den anderen wellenformen hat sich das nämlich in 
durchaus wahrnehmbaren Tonhöhenänderungen geäussert *g.

>Du könntest einfach ohne Vergleich mit a3 weitermachen, denn 0-1 ist -1
>und das ist 0xFF und das ist 255...

>Und das Beste zuletzt: du bräuchtest a3 gar nicht, weil zl schon den
>index beinhaltet und kostenlos überläuft. Und weil du fürderhin zh
>ignorierst.
*g, den Vergleich hab ich gemacht, damit er dann eigl nach jedem Zeichen 
den a2 wert aus sin1 wieder laden kann.. aber das war mein Denkfehler in 
der vorherigen Frage

>BTW: dir ist schon klar, dass ein viertel vom ganzen Sinus ausreichen
>würde? Der Rest kann mit Offset, Invertierung und einer Subtraktion
>erledigt werden...

Diese Möglichkeit ist mir bekannt, aber da ich ne Sinustabelle für nen 
kompletten Sinus gefunden habe, und mir noch nicht richtig im klaren 
darüber bin, wie ich die Tabelle dann rückwärts auslese und invertiere, 
dachte ich, erstmal die leichtere Variante, daran werd ich mich dann mal 
machen, falls der Speicherplatz im Mega32 doch mal eng wird. Wobei das 
ja ganicht so kompliziert sein kann, man muss ja nur die Adresse 
andersrum laufen lassen, und in der 2ten Hälfte den jeweiligen Wert 
invertieren...oder nicht? aber dann muss doch in dem Teil ohne 
Invertierung darauf achten, das er gleich viele Steps bis zur
Ausgabe am Port braucht, damit der sinus nicht in der ersten Hälfte 
schneller läuft?
>BTW2: Warum legst du die Tabelle in EEPROM? Im ROM wäre so eine
>statische Tabelle doch viel besser aufgehoben...

Das hab ich auch aus diesem wahnsinnig schlauen Buch, das sagt dass man 
die Adresse mit 2 multiplizieren soll... Wie greife ich denn auf das ROM 
zu? Ich wusste bisher nur vom Flashspeicher und vom EEPROM


P.S. Die Werte für die anderen Wellenformen hab ich nicht aus einer 
Tabelle. Für den Sägezahn lass ich einfach n Zähler hochlaufen und 
ausgeben. Geht gleichmäßig rauf und springt auf null zurück, so wie es 
sein soll. Für das Rechteck lass ich einfach 0X00 und 0Xff ausgeben und 
dazwischen zählt ein Timer für die Frequenz

von Spess53 (Gast)


Lesenswert?

Hi

>Das hab ich auch aus diesem wahnsinnig schlauen Buch, das sagt dass man
>die Adresse mit 2 multiplizieren soll... Wie greife ich denn auf das ROM
>zu? Ich wusste bisher nur vom Flashspeicher und vom EEPROM

Mit ROM ist der Flashspeicher gemeint. Der ist aber Wordweise (16 Bit) 
organisiert. Um die Adresse eines Bytes (8 Bit) zu erhalten muss man die 
Wordadresse verdoppeln.

>Wie greife ich denn auf das ROM zu?

Du legst die Tabelle mit z.B.
1
   .org $1000
2
sinustab:
3
    .db 127,130,133,136,139,1...

die Tabelle in den Flash. Wichtig ist, das die beiden Ziffern $00 oder 
$80 sind. Im Programm greifst du mit
1
    ldi    zh,high(2*sinustab)
2
    out    eearh,zh
3
    ldi    zl,low(2*sinustab)
4
    out    eearl,zl
5
6
    ....
7
8
    lpm a1,Z
9
    inc ZL
10
    ....

auf die Werte zu.

MfG Spess

von J. T. (chaoskind)


Lesenswert?

Alles klar, das werd ich direkt mal versuchen =)

Danke schön

MfG des Chaoskind

p.s. doch noch nicht ganz klar, welche beiden ziffern müssen $00 oder 
$80 sein? entspricht $00 0x00?

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.