Forum: Mikrocontroller und Digitale Elektronik Probleme mit dem richtigen setzten des sei() makros bei externem Interrupt ATmega16


von doca (Gast)


Lesenswert?

Liebes Forum!

Bei unserem Projekt gibt es ein Problem mit dem externen Interrupt Int0.
Wir verwenden einen ATmega16.

Der Interrupt ist ziemlich sicher richtig initialisiert worden und 
funktioniert teilweise auch.

Das Problem: Der Code, welcher nach dem sei() Makro steht wird nicht 
richtig oder garnicht ausgeführt.

Das Programm schaut wie folgt aus:
1
void init(void)
2
{
3
  DDRA = 0x00; //set PORTA as input
4
  PORTA = 0xFF; //pull-widerstände
5
  DDRD = _BV(PD5) | _BV(PD4); // set OC1A/B pin as output, required for output
6
  DDRB = _BV(PB3); // set OC0 pin as output
7
  
8
  TCCR1A = _BV(WGM10) | _BV(COM1A1) | _BV(COM1B1); // clear timer/counter on compareAB match, phase correct pwm
9
  TCCR1B = _BV(CS10); // no prescaler
10
  
11
  TCCR0 = _BV(WGM00) | _BV(COM01) | _BV(CS00);  //no prescaler, set/clear on compare match (OCR0)
12
13
  TIMSK = _BV(OCIE0) | _BV(OCIE1A) | _BV(OCIE1B); //enable interrupt on compare match timer0,1ab
14
  
15
  MCUCR = _BV(ISC01) | _BV(ISC00); //generates interrupt on INT0 on falling edge
16
  GICR = _BV(INT0); //enable interrupt on INT0
17
18
}
19
20
int main(void)
21
{
22
        init();
23
  
24
  int y = 0;
25
  int z = 0;
26
  sei();
27
  
28
  while(1)
29
  { 
30
    for (uint8_t i=0;i<255;i++)
31
    {  
32
      for (uint8_t x = 0;x<1000;x++)
33
      {}
34
      
35
      y++;
36
      OCR0 = y;
37
    }
38
    
39
    for (uint8_t i=0;i<255;i++)
40
    {
41
      y--;
42
      OCR0 = y;
43
      
44
    
45
      for (uint8_t x = 0;x<1000;x++)
46
      {}
47
    }
48
  }
49
}
Wir wären um eure Hilfe sehr dankbar!

lg doca

von Karl H. (kbuchegg)


Lesenswert?

1
      for (uint8_t x = 0;x<1000;x++)
2
      {}

wie kann ein uint8_t jemals den Endwert 1000 erreichen? Der geht doch 
nur bis 255!

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:
>
1
>       for (uint8_t x = 0;x<1000;x++)
2
>       {}
3
>
>
> wie kann ein uint8_t jemals den Endwert 1000 erreichen? Der geht doch
> nur bis 255!

Was soll der Quatsch eigentlich?
Selbst wen du das dann richtig stellst, optimiert es der Compiler wieder 
raus.

Wenn du Wartezeiten willst, dann nimm fürs erste _delay_ms bis du 
gelernt hast, wie man mit einem Timer längere Wartezeiten realisiert.

von g457 (Gast)


Lesenswert?

> Das Problem: Der Code, welcher nach dem sei() Makro steht wird nicht
> richtig oder garnicht ausgeführt.

Interrupts einschalten ohne die passenden ISRs ist.. ähm.. 'ungünstigt'. 
Oder enthältst Du uns reichlich relevanten Code vor? Und was heisst 
'nicht richtig'?

von Kai2 (Gast)


Lesenswert?

doca schrieb:
> Das Problem: Der Code, welcher nach dem sei() Makro steht wird nicht
> richtig oder garnicht ausgeführt.

Und du willst uns testen, ob wir rausfinden, was der Code machen soll 
und was falsch läuft und dir auch noch des Problem nennen?

von Karl H. (kbuchegg)


Lesenswert?

doca schrieb:

> Der Interrupt ist ziemlich sicher richtig initialisiert worden und
> funktioniert teilweise auch.

kann man schlecht sagen. Du zeigst ja die ISR nicht.

von doca (Gast)


Lesenswert?

Danke für die schnelle Antwort.
Leider immer noch der gleiche Fehler.

von Karl H. (kbuchegg)


Lesenswert?

doca schrieb:
> Danke für die schnelle Antwort.
> Leider immer noch der gleiche Fehler.

Zeig alles. Und zwar so, wie es jetzt aussieht.
Und auch nicht uninteressant: was ist eigentlich der Fehler?
"Code wird nicht richtig ausgeführt" ist keine Fehlerbeschreibung. Was 
passiert? Was sollte deiner Meinung nach passieren?

Es ist ja nicht so, dass wir hinter dir sitzen würden und dir über die 
Schulter schauen können. Oder gehst du zum Arzt und sagst "Es tut weh. 
Mach mal."

von (prx) A. K. (prx)


Lesenswert?

doca schrieb:
> Leider immer noch der gleiche Fehler.

Weil immer noch der gleiche teilweise hier unbekannte Code?

von doca (Gast)


Lesenswert?

Die ISR schaut wie folgt aus:

ISR (INT0_vect)
 {
     _delay_ms(2000);
 }

(Kann also eigentlich nicht viel falsch an der ISR sein, oder?)

Der Code soll mit einer PWM eine LED heller und wieder dunkler machen. 
(Das funktioniert auch einwandfrei solang man das sei() Makro nicht 
verwendet.)

von g457 (Gast)


Lesenswert?

Karl Heinz schrieb:
> Was soll der Quatsch eigentlich?
> Selbst wen du das dann richtig stellst, optimiert es der Compiler wieder
> raus.

Nein, das darf er nicht, weil das eine Endlosschleife ist. Gcc macht das 
auch richtig offensichtlich wenn die Optimierungen an sind:
1
$ cat main.c 
2
#include <inttypes.h>
3
4
int main(void)
5
{
6
        for (uint8_t x = 0; x < 1000; x++)
7
        {}
8
9
        return 0;
10
}
11
12
$ gcc -Wall -Wextra -O3 -std=c99 -g -o main main.c 
13
main.c: In function ‘main’:
14
main.c:5:24: warning: comparison is always true due to limited range of data type [-Wtype-limits]
15
  for (uint8_t x = 0; x < 1000; x++)
16
17
$ objdump -S main | grep -e "main(" -C 8
18
  4003b6:       68 01 00 00 00          pushq  $0x1
19
  4003bb:       e9 d0 ff ff ff          jmpq   400390 <_init+0x20>
20
21
Disassembly of section .text:
22
23
00000000004003c0 <main>:
24
#include <inttypes.h>
25
26
int main(void)
27
{
28
        for (uint8_t x = 0; x < 1000; x++)
29
        {}
30
  4003c0:       eb fe                   jmp    4003c0 <main>
31
32
00000000004003c2 <_start>:
33
  4003c2:       31 ed                   xor    %ebp,%ebp
34
  4003c4:       49 89 d1                mov    %rdx,%r9

Nix für ungut

von Kaj G. (Firma: RUB) (bloody)


Lesenswert?

doca schrieb:
> Danke für die schnelle Antwort.
> Leider immer noch der gleiche Fehler.
Poste den gesamten Code oder troll dich woanders.
WAS hast du denn jetzt geandert?
Wir koennen nicht in deinen PC, deinen Code, deine Toolchain, geschweige 
denn in deinen Kopf gucken um zu sehen, was wo falsch laeuft...
Also: Wie bitte sollen wir dir helfen? Erklaer mal...

Sorry, aber sowas kotzt mich echt an... >:[

von doca (Gast)


Lesenswert?

Der gesamte Code schaut wie folgt aus(entschuldigt die lückenhafte 
Auskunft):
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
5
void init(void)
6
{
7
  DDRA = 0x00; //set PORTA as input
8
  PORTA = 0xFF; //pull-widerstände
9
  DDRD = _BV(PD5) | _BV(PD4); // set OC1A/B pin as output, required for output
10
  DDRB = _BV(PB3); // set OC0 pin as output
11
  
12
  TCCR1A = _BV(WGM10) | _BV(COM1A1) | _BV(COM1B1); // clear timer/counter on compareAB match, phase correct pwm
13
  TCCR1B = _BV(CS10); // no prescaler
14
  
15
  TCCR0 = _BV(WGM00) | _BV(COM01) | _BV(CS00);  //no prescaler, set/clear on compare match (OCR0)
16
17
  TIMSK = _BV(OCIE0) | _BV(OCIE1A) | _BV(OCIE1B); //enable interrupt on compare match timer0,1ab
18
  
19
  MCUCR = _BV(ISC01) | _BV(ISC00); //generates interrupt on INT0 on falling edge
20
  GICR = _BV(INT0); //enable interrupt on INT0
21
22
}
23
24
25
26
ISR (INT0_vect)
27
 {  
28
   _delay_ms(2000);
29
  
30
 }  
31
32
33
int main(void)
34
{
35
  
36
  init();
37
  
38
  
39
40
  int y = 0;
41
  sei();
42
  
43
  while(1)
44
  { 
45
    for (int i=0;i<255;i++)
46
    {  
47
      for (int x = 0;x<1000;x++)
48
      {}
49
      
50
      y++;
51
      OCR0 = y;
52
    }
53
    
54
    for (int i=0;i<255;i++)
55
    {
56
      y--;
57
      OCR0 = y;
58
      
59
    
60
      for (int x = 0;x<1000;x++)
61
      {}
62
    }
63
  }
64
}

von Thomas E. (thomase)


Lesenswert?

g457 schrieb:
> Karl Heinz schrieb:
>> Was soll der Quatsch eigentlich?
>> Selbst wen du das dann richtig stellst, optimiert es der Compiler wieder
>> raus.
>
> Nein, das darf er nicht, weil das eine Endlosschleife ist. Gcc macht das
> auch richtig offensichtlich wenn die Optimierungen an sind:

Was für einen Unsinn erzählst du uns hier jetzt?
Aber immerhin lieferst du den Nachweis, dass es wegoptimiert wird, 
gleich mit.

Irgendwie sinnfrei, oder?

mfg.

von Rolf M. (rmagnus)


Lesenswert?

doca schrieb:
> Die ISR schaut wie folgt aus:
>
> ISR (INT0_vect)
>  {
>      _delay_ms(2000);
>  }
>
> (Kann also eigentlich nicht viel falsch an der ISR sein, oder?)

Naja, da ist genau eine Zeile drin, und die ist verheerend. Sie führt 
dazu, daß immer beim Auftreten des INT0 der µC erstmal für zwei Sekunden 
komplett blockiert wird. Wozu sollte dieses Delay denn gut sein?

von Karl H. (kbuchegg)


Lesenswert?

g457 schrieb:
> Karl Heinz schrieb:
>> Was soll der Quatsch eigentlich?
>> Selbst wen du das dann richtig stellst, optimiert es der Compiler wieder
>> raus.
>
> Nein, das darf er nicht, weil das eine Endlosschleife ist.

Ich sagte doch: Selbst wenn du das dann richtig stellst.

Annahme: Er hat den Code im Datentyp korrigiert.
Folgerung: Der Compiler wirft die Schleife dann (nach Korrektur) raus.

von Karl H. (kbuchegg)


Lesenswert?

doca schrieb:
> Der gesamte Code schaut wie folgt aus(entschuldigt die lückenhafte
> Auskunft):

Und wo sind die restlichen ISR?


>   TIMSK = _BV(OCIE0) | _BV(OCIE1A) | _BV(OCIE1B); //enable interrupt on
> compare match timer0,1ab

du musst für JEDEN Interrupt, den du frei gibst, eine ISR schreiben!

Ergo: gib keinen Interrupt frei, den du nicht brauchst,

von doca (Gast)


Lesenswert?

Karl Heinz schrieb:
> doca schrieb:
>> Der gesamte Code schaut wie folgt aus(entschuldigt die lückenhafte
>> Auskunft):
>
> Und wo sind die restlichen ISR?
>
>>   TIMSK = _BV(OCIE0) | _BV(OCIE1A) | _BV(OCIE1B); //enable interrupt on
>> compare match timer0,1ab
>
> du musst für JEDEN Interrupt, den du frei gibst, eine ISR schreiben!
>
> Ergo: gib keinen Interrupt frei, den du nicht brauchst,

Toter Code ist schlechter Code! Danke für den Hinweis, das hab ich 
komplett übersehen. Der Timer Interrupt wird garnicht verwendet. Vielen 
Dank!

von Karl H. (kbuchegg)


Lesenswert?

doca schrieb:

> Toter Code ist schlechter Code! Danke für den Hinweis, das hab ich
> komplett übersehen. Der Timer Interrupt wird garnicht verwendet. Vielen
> Dank!

Es wird auch scheinbar der Timer 1 gar nicht (richtig) verwendet. Und 
was du mit dem externen Interrupt bezweckst, will ich glaub ich gar 
nicht wissen.

von wendelsberg (Gast)


Lesenswert?

Irgendwie nicht nachvollziehbar, ein Programm, das in der Hauptschleife 
laeuft, mit einem (vermutlich) Taster fuer 2 Sekunden zu blockieren und 
sonst nichts damit zu machen. Versteh ich nicht.

wendelsberg

von Rolf M. (rmagnus)


Lesenswert?

doca schrieb:
>> Ergo: gib keinen Interrupt frei, den du nicht brauchst,
>
> Toter Code ist schlechter Code!

Es geht nicht nur darum, toten Code zu vermeiden. Wenn ein Interrupt 
ausgelöst wird, für den du keine ISR definiert hast, wird das Programm 
beim Auftreten des Interrupts jedesmal neu gestartet.

von Thomas E. (thomase)


Lesenswert?

wendelsberg schrieb:
> Versteh ich nicht.

PB3 ist ein PWM-Ausgang. Der Duty-Cycle wird in der Hauptschleife erst 
rauf- und dann runtergezählt. Beides mit voller CPU-Geschwindigkeit. 
Drückt man den Taster, wird der momentane PWM-Zustand für 2 oder 4s, je 
nach Prellen, eingefroren.

Ich find das gut.

mfg.

von g457 (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> Aber immerhin lieferst du den Nachweis, dass es wegoptimiert wird,
> gleich mit.

Nein, es wird hier eben nicht ∗weg∗optimiert, sondern zu einem 'jump to 
self' (aka Endlosschleife) optimiert:

>        for (uint8_t x = 0; x < 1000; x++)
>        {}
>  4003c0:       eb fe                   jmp    4003c0 <main>
   ^^^^^^                                ^^^^^^^^^^^^^

Karl Heinz schrieb:
> Annahme: Er hat den Code im Datentyp korrigiert.

Das ist allerdings richtig, ein jeder andständige Compiler bügelt das 
dann ersatzlos weg.

von Thomas E. (thomase)


Lesenswert?

g457 schrieb:
> Nein, es wird hier eben nicht ∗weg∗optimiert, sondern zu einem 'jump to
> self' (aka Endlosschleife) optimiert:

Irgendwie raffst du das hier nicht, oder?

mfg.

von wendelsberg (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> PB3 ist ein PWM-Ausgang. Der Duty-Cycle wird in der Hauptschleife erst
> rauf- und dann runtergezählt. Beides mit voller CPU-Geschwindigkeit.
> Drückt man den Taster, wird der momentane PWM-Zustand für 2 oder 4s, je
> nach Prellen, eingefroren.

Hmm, so genau hatte ich das nicht untersucht.
Aber ehrlich, glaube nur ich, dass das nicht das ist, was das Programm 
eigentlich tun soll?

wendelsberg

von Thomas E. (thomase)


Lesenswert?

wendelsberg schrieb:
> Aber ehrlich, glaube nur ich, dass das nicht das ist, was das Programm
> eigentlich tun soll?

Bestimmt nicht. Aber er erzählt uns ja nicht, was er erwartet.

Ich kann es mir zwar vorstellen, aber ich bin ja nicht seine Oma.

mfg.

von Karl H. (kbuchegg)


Lesenswert?

wendelsberg schrieb:

> Hmm, so genau hatte ich das nicht untersucht.
> Aber ehrlich, glaube nur ich, dass das nicht das ist, was das Programm
> eigentlich tun soll?

Ooch. Ich glaub ihm das sogar, wenn er (=der TO) sagt das das Programm 
genau das tun soll. Interessant wird es erst, wenn es darum geht, was 
das Programm sonst noch tun soll. Denn immerhin steckt da im Programm ja 
noch ein 2.te Timer drinn, der momentan ja eigentlich nur so vor sich 
hinzählt bzw. eine halbseidene PWM erzeugt. Da kommt also noch was. Und 
dann lautet die spannende Frage: Hat er sich mit diesem Ansatz die 
Projektfortsetzung verbaut oder nicht.

Das man das Ganze anders rum aufziehen würde, den PWM-Durchlauf in einem 
Timer-Interrupt zusammen mit einem globalen Freigabe-Flag bzw. einer 
Timer-Interrupt getriebenen Zeitsteuerung, wodurch die Pause nur 
angestossen werden braucht und sich selbst terminiert, brauchen wir 
nicht diskutieren.

Ist in der Programmierung öfter so, dass man erst dann drauf kommt, 
warum andere einen scheinbar komplexeren Ansatz wählen, wenn man sich 
selbst mit dem banalen Ansatz in eine Sackgasse manövriert hat. Dann 
allerdings versteht man den Problemkreis und auch warum der scheinbar 
viel einfachere Ansatz im Endeffekt doch nicht so gut war.

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.