Forum: Mikrocontroller und Digitale Elektronik USART Interrupt Variablenwert zuweisen


von Pat K. (c63)


Lesenswert?

Hallo zusammen,

habe ein Problem mit folgendem Quellcode:
1
#ifndef _UART_H_
2
#define _UART_H_
3
4
#include <avr/io.h>
5
6
extern void uart_init(void);
7
8
9
10
static inline int
11
uart_putc (const uint8_t c)
12
{
13
  // Warten, bis UDR bereit ist für einen neuen Wert
14
  while (!(UCSRA & (1 << UDRE)))
15
  ;
16
17
  // UDR Schreiben startet die Übertragung
18
  UDR = c;
19
20
  return 1;
21
}
22
23
static inline uint8_t
24
uart_getc_wait(void)
25
{
26
  // Warten, bis etwas empfangen wird
27
  while (!(UCSRA & (1 << RXC)))
28
  ;
29
30
  // Das empfangene Zeichen zurückliefern
31
  return UDR;
32
}
33
34
static inline int
35
uart_getc_nowait(void)
36
{
37
  // Liefer das empfangene Zeichen, falls etwas empfangen wurde; -1 sonst
38
  return (UCSRA & (1 << RXC)) ? (int) UDR : -1;
39
}
40
41
#endif /* _UART_H_  */
42
43
#include <avr/io.h>
44
#include <avr/interrupt.h>
45
#include <util/delay.h>
46
#include <stdlib.h>
47
#include <stdio.h>
48
49
50
51
52
53
#define BAUDRATE 2400UL 
54
55
56
57
int Auslesen;
58
volatile unsigned char a = 0x00;
59
60
61
void uart_init()
62
{
63
  uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16*BAUDRATE) - 1);
64
  
65
  UBRRH = (uint8_t) (ubrr>>8);
66
  UBRRL = (uint8_t) (ubrr);
67
  
68
  // UART Receiver und Transmitter anschalten
69
  // Data mode 8N1, asynchron
70
  UCSRA = (1 << RXC);
71
  UCSRB = (1 << RXEN) | (1<<RXCIE);
72
  UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
73
74
  // Receive-Buffer leeren (entfernen evtl. vorhandener ungültiger Werte)
75
  do
76
  {
77
    UDR;
78
  }
79
  while (UCSRA & (1 << RXC));
80
81
  DDRD |= (1<<PD6);    // PortD als Ausgang deklarieren
82
  //DDRD |= (1<<PD5);
83
  //PORTD = 0x00;   // Ports auf LOW schalten
84
85
}
86
87
88
// Interupt wartet, bis Empfangsbit gesetzt wird und führt dann Routine aus
89
90
ISR(USART_RXC_vect) 
91
{
92
  a = UDR;
93
  
94
  if (a == '1') 
95
  {
96
    //PORTD |= (1<<PD6);
97
    Auslesen = 15;
98
  }
99
  else
100
  {
101
    if (a == '0')
102
    {
103
      PORTD &=~(1<<PD6);
104
    }
105
    
106
  }
107
108
}
109
110
ISR (TIMER1_COMPA_vect)
111
{
112
  static uint16_t swTeiler = 0;
113
  swTeiler++;
114
  //if (swTeiler == 120 )
115
  if (swTeiler == Auslesen )
116
  {
117
    swTeiler = 0;
118
    PORTD |= (1<<PD6);
119
    TCCR1B |= (1<<WGM12) | (1<<CS12);
120
    TIMSK |= (1<<OCIE1B);
121
    OCR1B = 3094;
122
    sei();
123
  }
124
}
125
126
ISR (TIMER1_COMPB_vect)
127
{
128
  static uint8_t vTeiler = 0;
129
  vTeiler++;
130
  if (vTeiler == 10)
131
  {
132
    vTeiler = 0;
133
    PORTD &=~ (1<<PD6);
134
  }
135
}
136
137
138
139
140
141
ISR (INT0_vect)
142
{
143
  PORTD |= (1<<PD6);
144
}
145
146
ISR (INT1_vect)
147
{
148
  PORTD &=~ (1<<PD6);
149
}
150
151
152
153
154
155
int main(void)
156
{
157
  
158
  DDRD &=~ (1<<PD2) | (1<<PD3);
159
  MCUCR |= (1<<ISC01) | (1<<ISC00) | (1<<ISC11) | (1<<ISC10);
160
  GICR |= (1<<INT0) | (1<<INT1);
161
162
TCCR1B |= (1<<WGM12)|(1<<CS12);
163
TIMSK |= (1<<OCIE1A);
164
165
OCR1A = 3906;
166
167
168
  uart_init();
169
  sei();
170
  
171
  int i = 0;
172
  
173
  while (i<2)
174
  {
175
    i++;
176
    PORTD |= (1<<PD6);
177
    _delay_ms(3000);
178
    PORTD &=~(1<<PD6);
179
    _delay_ms(3000);
180
  }
181
  
182
  while(1)
183
  {
184
    
185
  }
186
}

Ursprünglich wollte ich über die Serielle Schnittstelle einen ASCII 
string empfangen, mit #include <sstream> in eine Zahl umwandeln und 
diese Zahl an meine Variable "Auslesen" weitergeben, welche für den 
Interrupt des Timers zuständig ist.
Naja, weit entfernt von einem Resultat.
Konnte jetzt für mich persönlich den Fehler soweit begrenzen, dass der 
Variable "Auslesen" der Wert "15" wohl nicht übergeben wird, bzw die 
Variable von der einen Interrupt-Routine in die andere nicht übertragen 
wird?
Wo genau liegt mein Verständnisproblem?

Für eure Hilfe bedanke ich mich schon mal im Voraus.
mfg
c63

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Problem Ungelöst schrieb:
> int Auslesen;

Mach die mal 'volatile'. Generell sollte Variablen in ISR immer volatile 
sein, weil der Kompiler sie sonst wegrationalisieren möchte. ISR werden 
ja im Programm nicht aufgerufen und der Kompiler probiert eine 
Optimierung. Apropos Optimierung, wie steht die bei dir?

von Peter II (Gast)


Lesenswert?

Matthias Sch. schrieb:
> Mach die mal 'volatile'. Generell sollte Variablen in ISR immer volatile
> sein, weil der Kompiler sie sonst wegrationalisieren möchte. ISR werden
> ja im Programm nicht aufgerufen und der Kompiler probiert eine
> Optimierung. Apropos Optimierung, wie steht die bei dir?

nein ist hier nicht notwendig, weil er sie nur ein 2 ISR verwendet. Sie 
wird nicht in Main verwendet!

Und die Aussage "Generell sollte Variablen in ISR immer volatile sein" 
ist Unsinn.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Peter II schrieb:
> weil er sie nur ein 2 ISR verwendet

Öhh, was willst du uns sagen? Die Variable steht auch nicht in der 
ISR, sondern ist global deklariert.

von Pat K. (c63)


Lesenswert?

Danke euch beiden für die Hilfe,

lag am fehlenden volatile :-)

@Matthias Sch.: Bin totaler newbie, was c programmieren betrifft, 
deshalb bin ich mir nicht ganz sicher was du mit "Apropos Optimierung, 
wie steht die bei dir?" meinst.
Hab mir mal im AVR Studio den Compiler Output durchgelesen, allerdings 
nicht wirklich etwas in Richtung Optimierung seitens Compiler gefunden.

von Peter II (Gast)


Lesenswert?

Matthias Sch. schrieb:
> Öhh, was willst du uns sagen? Die Variable steht auch nicht in der
> ISR, sondern ist global deklariert.

sie wird in zwei verschieden ISR verwendet, darum muss sich auch global 
sein.

das volatile bringt hier überhaupt nichts, das ist nur notwendig wenn 
eine Variable in einer ISR geändert wird und in der main( oder daraus 
aufgerufenen Funktionen) abgefragt wird.

von Pat K. (c63)


Lesenswert?

Ok lag doch nicht am volatile, sonder daran, dass der Timer zum 
Zeitpunkt des Sendens via Schnittstelle schon über dem zugewiesenen 
Variablenwert lag und somit der Interrupt erst nach weiteren 65536 
Sekunden ausgelöst wird.

von ISR (Gast)


Lesenswert?

Peter II schrieb:
> das volatile bringt hier überhaupt nichts, das ist nur notwendig wenn
> eine Variable in einer ISR geändert wird und in der main( oder daraus
> aufgerufenen Funktionen) abgefragt wird.

auch wenn die Variable in der einen ISR geändert wurde und dann in der 
anderen verwendet wird (oder auch dort wieder geändert), ist volatile 
genauso sinnvoll. Es muß nicht die main mit beteiligt sein. Einfach nur 
zwei Programmstellen, die keine direkte sichtbare verbindung miteinander 
haben, so daß der compiler sie nicht erkennen kann.

von Peter II (Gast)


Lesenswert?

ISR schrieb:
> auch wenn die Variable in der einen ISR geändert wurde und dann in der
> anderen verwendet wird (oder auch dort wieder geändert), ist volatile
> genauso sinnvoll. Es muß nicht die main mit beteiligt sein. Einfach nur
> zwei Programmstellen, die keine direkte sichtbare verbindung miteinander
> haben, so daß der compiler sie nicht erkennen kann.

nein. Du hast scheinbar das Problem nicht wirklich verstanden.

Am ende einer ISR muss der Compiler die Variable immer in den Ram 
zurückschreiben und kann sie nicht im Register behalten. Damit kann 
überhaupt kein Problem mit wegen Optimierung entstehen. Nur wenn Main 
beteiligt ist, kann er sie im Register blassen, weil main nicht 
verlassen wird.

von Stefan E. (sternst)


Lesenswert?

Peter II schrieb:
> das volatile bringt hier überhaupt nichts, das ist nur notwendig wenn
> eine Variable in einer ISR geändert wird und in der main( oder daraus
> aufgerufenen Funktionen) abgefragt wird.

Ist aber auch nicht ganz korrekt. Der "umgekehrte" Fall (in Main 
geändert und in ISR nur gelesen) erfordert ebenso das volatile.

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.