Forum: Mikrocontroller und Digitale Elektronik Arduino - Ständige Serielle Ausgabe bei aktiviertem Timer2


von Prime (Gast)


Lesenswert?

Hallo,

ich stehe gerade vor einem Problem bei dem ich nicht weiterkomme.

Der Plan war es, den Inhalt einer Variable auf dem seriellen Monitor der 
Arduino Umgebung auszugeben.

Allerdings wird der Inhalt ununterbrochen ausgegeben, obwohl die 
"Serial.println" Anweisung in einem Bereich steht, der nur einmal 
durchlaufen werden sollte.


Wenn ich den Interrupt des Timer2 in TIMSK deaktiviere, wird der Inhalt 
wie gewünscht nur einmal ausgegeben.

Nutzt die serielle Verbindung irgendwie den Timer2?

Anbei der Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define XTAL 16000000                                 // Frequenz des Arduino
5
#define Phase_A (PINB & 1<<PB0)                       // PIN8 als Pin1 des Drehencoders 
6
#define Phase_B (PINB & 1<<PB1)                       // PIN9 als Pin2 des Drehencoders
7
8
byte tflags = 0x00;                                   // Übersicht der Eingangssignale (Global)
9
byte jflags = 0x00;                                   // Übersicht der zu erledigen Jobs (Global)
10
byte sflags = 0x00;                                   // Übersicht der verschiedenen Stati (Global)
11
12
volatile int8_t enc_delta;                            // Variable zur Speicherung der Encoder Richtung (Global)
13
static int8_t last;                                   // Variable zur Speicherung des letzten Encoder Wertes (Global)
14
15
ISR(TIMER2_COMPA_Vect)                                // Interrupt Service Routine Timer2
16
  {
17
    int8_t neu = 0, diff;
18
    if(Phase_A)
19
      {
20
        neu = 3;
21
        PORTB ^= (1<<PB2);                           //Testausgang toggeln, Anzeige PinA
22
      }
23
    if(Phase_B)
24
      {
25
        neu ^= 1;
26
        PORTB ^= (1<<PB3);                          //Testausgang toggeln, Anzeige PinB
27
      }
28
    diff = last - neu;
29
    if(diff & 1)                                     // prüfen ob ein Schritt vom Encoder aufgelaufen ist
30
      {                                              // wenn eine Änderung aufgelaufen ist
31
        last = neu;                                  // neuen Encoderzustand speichern
32
        enc_delta += (diff & 2) -1;                  // Drehrichtung bestimmen und enc_delta anpassen
33
      }
34
  }
35
int8_t encoder_einlesen(void)                        // Funktion zum periodischen Einlesen der Encoderschritte
36
  {
37
    int8_t val;
38
39
    cli();                                            // globale Interruptfreigabe sperren
40
    val = enc_delta;
41
    enc_delta = 0;                                    // Schrittänderung an die main-Funktion zurückgeben
42
    sei();                                            // globele Interruptfreigabe setzen
43
    return val;                                       // Inhalt von val an die main Funktion zurückgeben
44
  }
45
46
  
47
void setup() 
48
  {
49
  Serial.begin(9600);
50
  /*
51
  // I/O Pins initialisieren
52
  DDRB = 0x0C;                                        // PORTB Pins als Input
53
   
54
  // Timer1 als PWM initialisieren
55
  TCCR1A |= (1<<WGM11) | (1<<WGM10);                  // CTC Modus
56
  TCCR1B |= (1<<WGM12) | (1<<WGM13) | (1<<CS11);      // Prescaler auf 8
57
  TIMSK1 |= (1<<OCIE1A);                              // Interrupt für CTC-A aktivieren
58
  OCR0A = 84;                                         // Wert der verglichen werden soll (24kHz)
59
  ICS1 = 84;
60
*/
61
62
  // Timer2 initialisieren
63
  TCCR2A |= (1<<WGM21);                               // CTC Modus
64
  TCCR2B |= (1<<CS22);                                // Prescaler auf 64
65
  //TIMSK2 |= (1<<OCIE2A);                              // Interrupt für CTC-A aktivieren
66
  OCR2A  = 0xFF;                                       // Wert der verglichen werden soll (1ms)(250)
67
  
68
  //Encoder Variablen initialisieren
69
  int8_t neu = 0;
70
  if(Phase_A)
71
    {
72
      neu = 3;
73
    }
74
  if(Phase_B)
75
    {
76
      neu ^= 1;                                        // neu Xor verknüpfen
77
    }
78
    
79
  sei();                                              // globele Interruptfreigabe setzen 
80
  
81
  }
82
83
void loop() 
84
{
85
  int32_t val = 0;
86
  Serial.println(val);
87
  
88
  while(true)
89
  {
90
    val += encoder_einlesen();                        // Geänderte Schrittzahl zu val addieren
91
    
92
  }
93
94
}

MfG Prime

von Helmut -. (dc3yc)


Lesenswert?

Welche IDE, welcher Compiler? Wenn du Arduino verwendest, wird void 
loop() Sic! immer in der Schleife aufgerufen. Ansonsten nenne das halt 
void main().

von Prime (Gast)


Lesenswert?

Das void loop()eine Schleife ist, ist mir bekannt. Das Serial.println 
steht aber in der while(True) Anweisung, die eigentlich nie verlassen 
werden sollte.

Und es funktioniert ja auch... wenn TIMSK2 deaktiviert ist.

IDE und Compiler sind die Originalen von Arduino

von Rainer U. (r-u)


Lesenswert?

Schwer zu sagen, evtl. prellt Deine Signalquelle, oder aus anderem Grund 
läuft der Stack über, und dein uC startet deshalb neu.

Es empfiehlt sich, die ISR möglichst kurz zu halten, also z.B. nur einen 
Trigger setzen, und im Hauptprogramm die Werte bei Trigger auszulesen / 
ausgeben. Dann kannst Du während dieser Aktion im Hauptprogramm 
testweise die Interrupts ausschalten, und schauen, ob dann Ruhe ist.

von Julia (Gast)


Lesenswert?

Welchen Wert hat denn die Ausgabe? Immer 0 könnte auch einen Reset des 
µC hinweisen. Vielleicht einfach in der Setup auchmal eine Ausgabe 
machen lassen, so nach dem Motto "Hello World". Wenn das dann immer 
abwechselnd mit dem Val 0 kommen würde hätten wir den Übeltäter.

von Rainer U. (r-u)


Lesenswert?

Julia schrieb:
> Reset des µC

Das meinte ich mit neu starten. Oder an B3/B3 ist ein Kurzschluss, oder 
eine Verbindung zum Reset-Eingang, oder... Mal testen ganz ohne 
Peripherie dran ist auch eine Idee.

von D. Nogees (Gast)


Lesenswert?

So wie Dein Program geschrieben ist wird der val Wert so schnell es die 
Loop erlaubt andauernd ausgegeben. Das darf nicht sein. Ändere Deinen 
Code mit einem millis() test so, daß die serielle Ausgabe nur einmal in 
der Sekunde sendet ohne zu blockieren. Dann sollte es funktionieren. 
Oder sende nur wenn sich der Encoder Wert verändert, einmal durch 
Vergleich mit dem vorherigen Zustand von val mit einer statisch 
deklarierten variable "old_val".

Die Encoder Abfrage Routinen sind übrigens von Peter D. Und 
funktionieren auf dem Arduino in der Regel einwandfrei.

von Karl M. (Gast)


Lesenswert?

Prime schrieb:
> while(true)
>   {
>     val += encoder_einlesen();                        // Geänderte
> Schrittzahl zu val addieren
>
>   }

Irgendwie deucht es mir, dass dies eine Endlosschleife ist.
So dass eine serielle Ausgabe, vorab im Code, nur einmalig erfolgt.

von D. Nogees (Gast)


Lesenswert?

Nachtrag: da habe ich auch falsch interpretiert und Mist mitgeteilt.

Die main loop wird ja von dem while(true) andauernd blockiert. In der 
versteckten main() ist ja auch noch code der dadurch blockiert wird. 
Schreibe Dein Programm so (wie von mir vorher geraten) um, daß loop() 
nicht mehr blockiert wird. Dann wird es funktionieren.
Ich habe das selber schon vor Jahren mal ähnlich gemacht um den 
Encoderwert von Peters Routine auf einen LCD Display laufend auszugeben.

von Dietrich L. (dietrichl)


Lesenswert?

Prime schrieb:
> Und es funktioniert ja auch... wenn TIMSK2 deaktiviert ist.

Und wenn es aktiviert ist, hast du dann auch eine Interrupt Service 
Routine? Und wenn ja, was steht da drin?
Wenn nicht gibt es beim Interrupt einen SW-Restart (ich hoffe, das ist 
bei Arduino auch so..) und damit jedesmal ein erneutes Senden.

von S. Landolt (Gast)


Lesenswert?

> ISR(TIMER2_COMPA_Vect)

Kommt da kein "... appears to be a misspelled signal handler ... " wegen 
des großen "V"?

von HildeK (Gast)


Lesenswert?

S. Landolt schrieb:
> Kommt da kein "... appears to be a misspelled signal handler ... " wegen
> des großen "V"?

LOL. Das wird es sein!

von S. Landolt (Gast)


Lesenswert?

Das ist es ziemlich sicher, wie ja auch schon Dietrich L. vermutete.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

Grundlegendes. In der Arduino IDE funktioniert das so nicht.
1
// Timer1 als PWM initialisieren
2
  TCCR1A |= (1<<WGM11) | (1<<WGM10);                  // CTC Modus
3
  TCCR1B |= (1<<WGM12) | (1<<WGM13) | (1<<CS11);      // Prescaler auf 8
4
  TIMSK1 |= (1<<OCIE1A);                              // Interrupt für CTC-A aktivieren
5
  OCR0A = 84;                                         // Wert der verglichen werden soll (24kHz)
6
  ICS1 = 84;
7
*/
8
9
  // Timer2 initialisieren
10
  TCCR2A |= (1<<WGM21);                               // CTC Modus
11
  TCCR2B |= (1<<CS22);                                // Prescaler auf 64
12
  //TIMSK2 |= (1<<OCIE2A);

Die Timer sind für PWM vorkonfiguriert. Deshalb müssen erst alle 
Timerregister genullt werden bevor man seine eigene Konfig einstellt.

Dein while(1) in der loop und cli/sei solltest du auch nochmal 
überdenken.

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.