Forum: Mikrocontroller und Digitale Elektronik Interrupt benutzen ?


von Max D. (maximax)


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

von Mitleser (Gast)


Lesenswert?

Max Dirkschneider schrieb:
> 09.02.2015 12:00:
>     Bearbeitet durch Moderator

(Ist nicht an den Mod gerichtet)

Bitte keine Tabs in Sourcecode verwenden.
Einrückungen konsistent machen damit es lesbar(er) wird.

von Karl H. (kbuchegg)


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.

von Max D. (maximax)


Lesenswert?

Karl Heinz


vielen vielen Dank für diese elegante Lösung dadurch brauche ich ja 
nicht einmal einen zweiten Timer.(wenn ich das richtig verstanden habe)

Ich versuche mich mal daran und melde mich wenn ich es geschaft habe 
oder noch am verzweifeln bin.

:)

Edit: wieso wurde jetzt die Antwort von Karl Heinz gelöscht !?

von Karl H. (kbuchegg)


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.

von Ulrich F. (Gast)


Lesenswert?

> Edit: wieso wurde jetzt die Antwort von Karl Heinz gelöscht !?
Wer kann das wissen, warum er seine Antwort löscht....
Vielleicht war sie falsch, vielleicht hat er aus Versehen 
Urheberrechtlich geschützten Code publiziert, wer weiß .......
Er wird schon seinen Grund haben.

Edit: Zu spät....

von Karl H. (kbuchegg)


Lesenswert?

Ulrich F. schrieb:
>> Edit: wieso wurde jetzt die Antwort von Karl Heinz gelöscht !?
> Wer kann das wissen, warum er seine Antwort löscht....
> Vielleicht war sie falsch

Sie war nicht angemessen. Aber ich war zu langsam und die Antwort wurde 
schon gelesen.

von Max D. (maximax)


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
 }

von Andy (Gast)


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
 }

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.