Interrupt benutzen ?

#4005026
Lesenswert?

Hallo

Mein Name ist Max und ich mache gerade Abitur mit dem Schwerpunkt 
Elektrotechnik. in Informatik arbeiten wir deswegen auch mit 
µControllern.
zurzeit arbeiten wir (und warscheinlich auch bis zum ende der 13) mit 
einem Phillips 80c552. unsere jetzige aufgabe besteht darin ein Programm 
zu schreiben mit denen wir Töne erzeugen können. momentan bin ich soweit 
dass ich eine Funktion ( beep(int frequenz, int länge) ) aufrufen kann 
bei der mann die Parameter für die Frequenz (Tonhöhe) und Dauer (in ms) 
angeben kann.

soweit so gut... leider ist mir beim Testen mit verschiedenen frequenzen 
aber der selben tondauer aufgefallen dass umso höher die Frequenz ist 
umso kürzer ist auch die Dauer. Natürlich liegt das am Aufbau meines 
Programms und ich könnte mir vorstellen wie man das Problem besser lösen 
könnte allerdings haben wir Interrupts noch nicht besprochen :(

Hier habt ihr erstmal meinen Programmcode
1
#include <REG552.H>
2

3
int TonAn=0;
4
void Beep(int f,int l);
5

6
void main (void)               
7
{  
8
  TMOD = 0x11;
9
  while(1) 
10
  {
11
   Beep(100,1000);
12
   Beep(200,1000);  
13
   Beep(300,1000);
14
   Beep(400,1000);
15
   Beep(500,1000);  
16
   Beep(600,1000);
17
   Beep(700,1000);
18
   Beep(800,1000);  
19
   Beep(900,1000);
20
   Beep(1000,1000);
21
   Beep(1100,1000);
22
   Beep(1200,1000);
23
   }
24
}
25

26
void Beep(int f,int l) 
27
{  
28
int x;
29

30
   for(x=0;x<l;x++)
31
   {
32
     TR1=0;  
33
      TH1=0xFC; 
34
  TL1=0x18; 
35
      TF1=0;    
36
      TR1=1;
37

38
  do
39
  {
40
        TR0=0;  
41
        TH0=(65536 - (1000000/(f*2)))>>8;
42
    TL0=(65536 - (1000000/(f*2))) & 0x00FF;
43
        TF0=0;    
44
        TR0=1;
45
        while (TF0 == 0);
46

47
        if (TonAn == 0) 
48
    {
49
           TonAn=1;
50
           P4=0xFF;
51
        }
52
    else 
53
    {
54
          TonAn=0;
55
          P4=0x00;
56
        }
57

58
  }while(TF1==0);
59
   }
60
}
Meine vermutung ist dass das Überlauf Flag TF1 schon auf 1 gesetzt wird 
bevor mein Programmcode überhaupt ans ende der "do-schleife" kommt. 
dadurch
sind niedrigere Frequenzen etwas länger und höhere genauer.

Am liebsten würde ich ja die do-schleifen bedingung (x<l) setzen und 
sobald das überlauf Flag von Timer1 auf 1 gesetzt ist ein x++ machen.

ich hoffe ihr versteht was ich meine.... ansonsten bin ich natürlich für 
alle vorschläge und jede Hilfe sehr dankbar
#4005043
Lesenswert?

Max Dirkschneider schrieb:

> soweit so gut... leider ist mir beim Testen mit verschiedenen frequenzen
> aber der selben tondauer aufgefallen dass umso höher die Frequenz ist
> umso kürzer ist auch die Dauer. Natürlich liegt das am Aufbau meines
> Programms

Nicht wirklich. D.h. Ja, es liegt schon am Aufbau des Programms. Aber 
wenn wir den mal als so gegeben hinnehmen, ist das Problem leicht 
einzusehen.

Hz bedeutet Schwingungen pro Sekunde.
Wenn du also eine Schwingung mit 440Hz erzeugst, dann macht die in 1 
Sekunde 440 Schwingungen. Logisch?
Gut. Wenn du aber eine Schwingung mit 880Hz erzeugst, dann jast du 
logischerweise in 1 Sekunde 880 Schwingungen. Machst du hier ebenfalls 
nur 440 Schwingungen, dann ist der Ton nur eine halbe Sekunde lang.

Auf einen Nenner gebracht: Wenn du deine Funktion die 'Zeit' in der Form 
angibst, dass du der Funktion mitgibst wieviele Schwingungen sie 
erzeugen soll, dann musst du in dieser Anzahl auch die Frequenz 
einrechnen, damit du auf Zeiten kommst. Einfach immer nur 1000 
hinschreiben ist zu wenig.



Edit: Ich zieh den Einwand zurück.
Ein genauerer Blick zeigt, dass da 2 Timer im Spiel sind, von denen 
einer als echter Zeitzähler benutzt wird.
#4005062
Lesenswert?

Max Dirkschneider schrieb:
> Karl Heinz
>
>
> vielen vielen Dank für diese elegante Lösung

Ich habs zurück gezogen.

Du benutzt offenbar 2 Timer, wobei einer die echte Zeit abzählt.
Im Moment denke ich, deine Analyse des Problems ist korrekt.
Was ich ändern würde: den Timer 1 10 mal so weit zählen lassen und dafür 
die Zeiten durch 10 dividieren.

Dann läufst du nicht so schnell Gefahr, dass dir der Timer 1 von 0xFC18 
bis zum Überlauf hochzählt, während der andere Schwingungen erzeugt, die 
du jeweils abwartest.

Du kannst natürlich auch einfach Schwingungen zählen. Geht auch.

Man könnte natürlich auch die beiden Schleifen ineinander schachteln und 
somit nur 1 Schleife haben, die sich an der Spieldauer orientiert und 
den 2-ten Timer nach dem Portumschalten jeweils wieder neu startet.
#4005613
Lesenswert?

Hallo nochmal
Dank Karl Heinz habe ich mich dafür entschieden einen Timer wegzulassen
um dann einfach die Tondauer durch die Zyklenanzahl festzulegen.
Leider habe ich jetzt ein genau umgekehrtes Problem.
Aus irgendeinem Grund der mir verborgen bleibt sind jetzt höhere 
Frequenzen
wesentlich länger als tiefe. Dabei hatte ich zu Beginn genau das 
gegenteilige Problem.

Hatt jemand ne Ahnung was ich da wieder falsch gemacht habe ?


1
#include <REG552.H>
2

3
int TonAn=0;
4
void Beep(int f,int l);
5

6
void main (void)               
7
{  
8

9
  TMOD = 0x11;
10
  while(1) 
11
   {
12
    Beep(50,1000);
13
    Beep(200,1000);  
14
    Beep(600,1000);
15
    Beep(1200,1000);
16
   }
17
}
18

19
void Beep(int f,int l) 
20

21
{  
22
int x;
23
x = f*(l/1000);
24

25
  do
26
  {
27
      TR0=0;  
28
      TH0=((65536 - (1000000/(f*2))) & 0xFF00 ) >> 8;
29
      TL0=(65536 - (1000000/(f*2))) & 0x00FF;
30
      TF0=0;    
31
      TR0=1;
32
      while (TF0 == 0);
33

34
      if (TonAn == 0) 
35
      {
36
        TonAn=1;
37
        P4=0xFF;    
38
      }
39
     
40
      else 
41
      {
42
        TonAn=0;
43
        P4=0x00;
44
        x--;
45
      }
46

47
  
48
    
49
  }while(x != 0);
50
  
51
 }
Gast #4006120
Lesenswert?

Hallo Max,

der Mikrocontroller braucht für jede Verarbeitung eines Befehls eine 
gewisse Anzahl von Zyklen. Deine Berechnung der Timer-Vorbelegung ist 
relativ rechenintensiv. Je höher die Frequenz wird, desto häufiger muss 
deine Schleife durchlaufen werden, um auf die theoretisch gleiche 
Ton-Dauer bei unterschiedlichen Frequenzen zu kommen. Durch die ständige 
Neuberechnung wird die Dauer der Schleifen also proportional länger. 
Daher werden die hohen Töne auch länger abgespielt. Darüber hinaus hören 
sich dich Töne auch nicht mehr korrekt an.
Pro Ton/Frequenz musst du die Timerbelegung nur einmal berechnen und 
zwar außerhalb der Schleife. Dann hören sich die Töne auch korrekt an.
Ich habe noch ein paar zusätzliche Optimierungen eingefügt, damit die 
Anzahl der Befehle innerhalb der Schleife möglichst gering ist (Weil 
jeder Befehl eine zusätzliche ungewollte Verzögerung bewirkt).

MfG
Andreas Wolff
1
#include <REG552.H>
2

3
void Beep(int f,int l);
4

5
void main (void)               
6
{  
7
  TMOD = 0x01;
8
  TR0=1;
9
  while(1) 
10
   {
11
    Beep(50,1000);
12
    Beep(200,1000);  
13
    Beep(600,1000);
14
    Beep(1200,1000);
15
   }
16
}
17

18
void Beep(int f,int l) 
19
{  
20
  int x=f/5*(l/100);  // Divisor 5, da 100ms als Basis gewählt wurde. l in ms
21
  unsigned char TimerHigh = ((65536 - (1000000/(f*2))) & 0xFF00 ) >> 8;
22
  unsigned char TimerLow  = (65536 - (1000000/(f*2))) & 0x00FF;
23
  do
24
  {
25
      TH0=TimerHigh;
26
      TL0=TimerLow;
27
      TF0=0;    
28
      while (TF0 == 0);
29
    P4=~P4;
30
    x--;    
31
  }while(x >0);  
32
 }

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