Forum: Mikrocontroller und Digitale Elektronik c++ Variable zählt nich hoch! Warum?


von Gert B. (gbirkner)


Lesenswert?

Der Timer ISR wird alle 1ms aufgerufen und führt die entsprechende 
inline Methode auf.
Das funktioniert auch, aber aus irgendeinem Grund wird die Variable 
tcADCPower nicht hochgezählt und dementsprechend wird
1
if(tcADPower >= 10)
 nie wahr.

In der Klasse RobotMotor wird die Variable erstellt und im Konstruktor 
auf 0 gesetzt.
Die ISR ruft dann folgende private inline Methode auf:
1
void RobotMotor::isrTimer0COMPA()
2
{
3
  PORTD ^= (1<<PORTD3);
4
  PORTD |= (1 << PORTD2);
5
  tcADCPower++;
6
  
7
  if (tcADCPower >= 10)
8
  {
9
    PORTD &= ~(1<<PORTD2);
10
    tcADCPower = 0;
11
  }
12
}

PORTD3 wird alle 1ms getoggelt, PORTD2 bleibt aber immer gesetzt, sollte 
aber nach 10 Durchgängen immer wieder für 1ms gelöscht werden.
Ich weiß, der Code macht nicht viel Sinn, aber in der if sollte dann 
alle 10ms etwas "sinnvolles" ausgeführt werden.
Ich kontrolliere das mit dem Oszi, habe auch schon die Pins vertauscht 
usw. und komme in das if nicht hinein!
An der ISR kann es nicht direkt liegen, da ja PORTD3 brav getoggelt wird 
und wenn ich PORTD2 toggle wird das auch in der gewünschten Frequenz 
gemacht.
Wo kann hier das Problem liegen?
(Atmel Studio 6.2; Atmega328)

von Peter II (Gast)


Lesenswert?

Gert Birkner schrieb:
> Wo kann hier das Problem liegen?

variable nicht volatile.

von Gert B. (gbirkner)


Lesenswert?

Peter II schrieb:
> Gert Birkner schrieb:
>> Wo kann hier das Problem liegen?
>
> variable nicht volatile.
hab ich schon ausprobiert, hilft aber nichts.
Ich habe auch die variable global definiert (anstatt in der Klasse) und 
auch static in der Methode -> hat alles nichts geholfen. Kompiliert 
wurde es immer fehlerlos.

von Peter II (Gast)


Lesenswert?

Gert Birkner schrieb:
> hab ich schon ausprobiert, hilft aber nichts.

dann bitte Quellcode zeigen, sonst wird wohl keiner helfen können.

von Martin (Gast)


Lesenswert?

Und wenn du es so versuchst... den PD2 alle 10 ms toggeln?
1
void RobotMotor::isrTimer0COMPA()
2
{
3
  PORTD ^= (1<<PORTD3);
4
  
5
  if (++tcADCPower >= 10)
6
  {
7
    PORTD ^= (1<<PORTD2);
8
    tcADCPower = 0;
9
  }
10
}

von Gert B. (gbirkner)


Lesenswert?

OK, die Klasse in der .h Datei sieht im Wesentlichen so aus:
1
extern "C" void TIMER0_COMPA_vect(void) __attribute__ ((signal));
2
3
class RobotMotor
4
{
5
//variables
6
private:
7
   uint16_t tcADCPower;  // Zähler für Timerverzögerung
8
9
   friend void TIMER0_COMPA_vect();
10
   inline void isrTimer0COMPA();
11
12
public:
13
  RobotMotor(); 
14
15
};
16
17
extern RobotMotor rmotor

die Implementierung in der .cpp:
1
#include "RobotMotor.h"
2
3
RobotMotor rmotor;
4
5
// default constructor
6
RobotMotor::RobotMotor()
7
{
8
   tcADCPower = 0;
9
   // .. Timer0 initialisierungen
10
}
11
12
void TIMER0_COMPA_vect(void)
13
{
14
  rmotor.isrTimer0COMPA();
15
}
16
17
void RobotMotor::isrTimer0COMPA()
18
{
19
  PORTD ^= (1<<PORTD3);
20
  PORTD |= (1 << PORTD2);
21
  tcADCPower++;
22
  
23
  if (tcADCPower >= 10)
24
  {
25
    PORTD &= ~(1<<PORTD2);
26
    tcADCPower = 0;
27
  }
28
}

Also: die isrTimer0COMPA wird ordnungsgemaess ausgeführt. PORTD3 
getoggelt und PORTD2 gesetzt. aber irgendwie wird der code in der if nie 
ausgeführt.

Danke für die schnellen Reaktionen
gert

von Gert B. (gbirkner)


Lesenswert?

Martin schrieb:
> Und wenn du es so versuchst... den PD2 alle 10 ms toggeln?
>
>
1
> void RobotMotor::isrTimer0COMPA()
2
> {
3
>   PORTD ^= (1<<PORTD3);
4
> 
5
>   if (++tcADCPower >= 10)
6
>   {
7
>     PORTD ^= (1<<PORTD2);
8
>     tcADCPower = 0;
9
>   }
10
> }
11
>

Das ändert leider nichts!

von Gert B. (gbirkner)


Lesenswert?

Problem teilweise gelöst!
Ich habe ein neues Projekt erstellt und es funktioniert. Ich habe keine 
Ahnung warum!
Das muss ich erst herausfinden.

Kann es sein, wenn in einer Solution mehrere Projekte erstellt werden, 
diese sich gegenseitig beeinflussen (stören)? - obwohl keine 
Querverweise vorhanden sind!

Danke für die Hilfe

gert

von Christian (Gast)


Lesenswert?

Hallo,
ich hatte auch mal ein ähnliches Problem. Die Uhrsache war, dass das 
Compilieren/Erstellen die .hex Datei nicht überschrieben hat. War bei 
mir so im AVR Studio. Einfach .hex Datei manuell löschen und neu 
erstellen bzw. mal ausprobieren auf Release/Debug als Ausgabepfad 
umstellen.

MfG

Christian

von Gert B. (gbirkner)


Lesenswert?

Das Problem habe ich auch schon vermutet, daher kontrolliere ich beim 
Überspielen der hex Datei immer die Uhrzeit der Erstellung.

Ich konnte aber jetzt folgendes feststellen:
Im Programm wird noch der Timer1 als fast PWM verwendet, der immer beim 
Erreichen von ICR1 seinen nächsten OCR1A und OCR1B berechnet. Schalte 
ich den per Prescaler aus, zählt meine Variable ordnungsgemäß hoch, 
sonst nicht.
Hier ist sich irgendwas im Weg.

von Norbert B. (norbert_b)


Lesenswert?

1
uint8_t zaehler = 0;
2
3
static inline void initTimer1(void) { //Minutenzähler
4
  /* Normal mode (default), just counting */
5
6
  TCCR1A |= (1 << COM1A0);  //Toggle OCA1A oder PB1
7
  TCCR1B |= (1 << WGM12);   // CTC-Mode (Clear Timer on Compare Match)
8
  TCCR1B |= (1 << CS12) | (1 << CS10); /* Clock speed: 1 MHz / 1024,
9
                    each tick is 976,6 microseconds ~= 1 per ms  */
10
  TIMSK1 |= (1 << OCIE1A);  //Enable Interupt
11
  OCR1A = 1000;      // 0xE679 Tics entsprechen 1 Minute 
12
}
13
14
//ISR(TIMER1_COMPA_vect) {  //Zähler inkrementieren wenn OCR1A matches
15
//  zaehler++;
16
//}
17
18
static inline void initTimer0(void) { //Stundenzähler
19
/* Normal mode (default), just counting */
20
  TCCR0A |= (1 << COM0A0) | (1 << WGM01);  //Toggle OCA0A oder PD6/12 |  CTC-Mode (Clear Timer on Compare Match)
21
  TCCR0B |= (1 << CS02) | (1 << CS01); // External Clock on T0/PB4/6,
22
  TIMSK0 |= (1 << OCIE0A);  //Output Compare Match A Interrupt Enable
23
24
  OCR0A = 10                 ;      // 60 Tics entsprechen 1h 
25
}
26
27
ISR(TIMER0_COMPA_vect) {  //Zähler inkrementieren wenn OCR0A matches
28
        zaehler++;  
29
  LED_PORT = 0b00000100;
30
}
31
32
int main(void)
33
{
34
  DDRB = 0b00000111; //PB0 - PB2 als Output
35
  DDRD = 0b01000000; //PD6 als Output
36
37
  initTimer1(); //zählt bis 60 Sekunden dann Toggle auf PD6
38
  initTimer0(); //wird von PB1 getaktet (anPB4)
39
        initUSART_new(9600, 8, 'N');
40
  sei(); /* set (global) interrupt enable bit */
41
  
42
  while(1) 
43
  {
44
45
    if (zaehler > 5)
46
    {
47
      //cli();
48
      LED_PORT = 0b00000100;
49
      _delay_ms(1000);
50
      LED_PORT = 0b00000001;
51
      printString("zahler > 60 ");
52
      transmitByte(zaehler);
53
      zaehler = 0;
54
      //sei();
55
    }    
56
    _delay_ms(1000);
57
  }
58
}
Die ISR(TIMER1_COMPA_vect) zählt zaehler problemlos hoch, mit der 
ISR(TIMER0_COMPA_vect) ist die Variable zaehler immer 0 und das obwohl 
PB2 high wird. Hat irgend jemand eine Idee?
Programm läuft auf einem ATMEGA168PA.

mfg
ncb

von Georg G. (df2au)


Lesenswert?

Norbert B. schrieb:
> Hat irgend jemand eine Idee?

"volatile" ist das Suchwort für dich.

volatile uint8_t zaehler = 0;

Der Interrupt zählt schon hoch, nur in main() wird das nicht bemerkt.

von Lutz H. (luhe)


Lesenswert?

Ungefähr 62.900.000 Ergebnisse (0,42 Sekunden) :-)

von Norbert B. (norbert_b)


Lesenswert?

Georg G. schrieb:
> Norbert B. schrieb:
>> Hat irgend jemand eine Idee?
>
> "volatile" ist das Suchwort für dich.
>
> volatile uint8_t zaehler = 0;
>
> Der Interrupt zählt schon hoch, nur in main() wird das nicht bemerkt.

Jooo.., sorry und ich habe mindestens 1 Stunde draufgeschaut und es 
nicht gesehen. Zu meiner Entschuldigung, irritierend war, das der Timer 
1 ein Ergebnis brachte.

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.