Probleme mit dem richtigen setzten des sei() makros bei externem Interrupt ATmega16

Gast #3944736
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
#3944744
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.
Gast #3944746
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'?
#3944757
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."
Gast #3944763
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.)
Gast #3944764
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
(Firma: RUB) #3944766
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... >:[
Gast #3944775
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
}
#3944786
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.
#3944788
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?
#3944794
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.
#3944796
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,
Gast #3944800
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!
Gast #3944804
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
Gast #3944848
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.
Gast #3944859
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
#3944865
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.

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