Forum: Mikrocontroller und Digitale Elektronik Beim Interrupt Variable in die main übergeben


von Interruptor (Gast)


Lesenswert?

Wir haben wieder ein kleines Problemchen. Wir machen ein Interrupt und
initialisieren in diesem Interrupt eine Variable. Wenn wir dann
allerdings wieder in unser main-Programm springen wird diese auf Eins
gesetzt und der vorher initialisierte Wert wird überschrieben. Hat einer
ne Idee was wir ändern könnten/müssen damits funktioniert?
Interrupt funktioniert, serielle Datenübertragung funktioniert, Display
funktioniert, volatile und sonstige Varianten alles schon ausprobiert,
alles läuft einwandfrei, nur die Variable will nich so wie wir wollen.
hier noch unser Quellcode:
1
#define F_CPU 12000000
2
#include <inttypes.h>
3
#include <stdint.h>
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include <util/delay.h>
7
#include "lcd-routines.h"
8
9
#define BAUD 9600
10
#define MYUBRR F_CPU/16/BAUD-1
11
#define CTS (PINB & 1)
12
13
/*Funktionsprototypen*/
14
void USART_Transmit( unsigned char data );
15
void USART_Init( unsigned int ubrr);
16
void Schreibe_in_Binaer(unsigned char test);
17
18
/*globale Variablen*/
19
unsigned char receive_old=0;
20
volatile unsigned char receive=1;
21
22
/*Interrupt*/
23
ISR(USART_RXC_vect)
24
{
25
  receive = UDR;
26
  lcd_setcursor(0,1);
27
  Schreibe_in_Binaer(receive);
28
}
29
30
31
/*Hauptprogramm*/
32
int main(void)
33
{
34
  DDRD = 0xF0;
35
  lcd_init();
36
    USART_Init( MYUBRR);
37
  sei();
38
39
  while(1)
40
  {
41
    /*Lauflicht*/
42
    PORTD = 0x80;
43
    _delay_ms(400);
44
    PORTD = 0x40;
45
    _delay_ms(200);
46
    PORTD = 0x20;
47
    _delay_ms(200);
48
    PORTD = 0x10;
49
    _delay_ms(400);
50
    PORTD = 0x20;
51
    _delay_ms(200);
52
    PORTD = 0x40;
53
    _delay_ms(200);
54
    USART_Transmit(0x53);
55
    //Befehl wird empfangen
56
57
    lcd_setcursor(0,2);
58
    Schreibe_in_Binaer(receive);
59
60
  }
61
62
  return 0;
63
}
64
65
66
void USART_Init( unsigned int ubrr)
67
{
68
/* Set baud rate */
69
UBRRH = (unsigned char)(ubrr>>8);
70
UBRRL = (unsigned char)ubrr;
71
/* Enable receiver and transmitter */
72
UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE);
73
/* Set frame format: 8data, 1stop bit */
74
UCSRC = (1<<URSEL)|(3<<UCSZ0);//(1<<USBS)|
75
}
76
77
void USART_Transmit( unsigned char data )
78
{
79
/* Wait for empty transmit buffer */
80
while ( (!( UCSRA & (1<<UDRE)))|| CTS )
81
;
82
/* Put data into buffer, sends the data */
83
UDR = data;
84
}
85
86
//Ausgabe eines Bytes in Binärem Code
87
void Schreibe_in_Binaer(unsigned char test)
88
{
89
  int i;
90
  unsigned char schreib[9];
91
  for(i=0; i<8; i++)
92
  {
93
    if (test & 1<<(7-i))
94
    {
95
      schreib[i] = '1';
96
    }
97
    else
98
    {
99
      schreib[i] = '0';
100
    }
101
  }
102
  schreib[8]=0;
103
  lcd_string( schreib);
104
}

: Gesperrt durch User
von H.Joachim S. (crazyhorse)


Lesenswert?

Vielleicht mal kurz anmerken, um welche Variable es geht??

von Interruptor (Gast)


Lesenswert?

receive = UDR; // Im Interrupt wird sie beschrieben
Schreibe_in_Binaer(receive); // In der main tritt das oben beschrieben 
Problem auf

von Karl H. (kbuchegg)


Lesenswert?

Sicher, dass ihr nur 1 einziges Zeichen von der Gegenstelle empfängt?

Vom Zeitpunkt an dem der µC die 0x53 wegschickt bis zum Zeitpunkt an dem 
das Zeichen dann irgendwann reinkommt, vergeht ja auch Zeit. D.h. es ist 
ziemlich unwahrscheinlich, dass in 1 und demselben Durchlauf durch die 
while Schleife, nach dem

    USART_Transmit(0x53);
    //Befehl wird empfangen

gleich danach an dieser Stelle

    lcd_setcursor(0,2);
    Schreibe_in_Binaer(receive);

ein empfangenes Zeichen sofort verfügbar ist. Da wird Zeit dazwischen 
vergehen. Nur dauert eure while Schleife durch die vielen Delays schon 
mal mindestens ein ca  einhalb Sekunden. Laufen in diesen 1.5 Sekunden 
mehrere Zeichen auf der UART ein, dann kriegt sie davon nichts mit, weil 
sie von den Delays ausgebremst wird.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Interruptor schrieb:
> Schreibe_in_Binaer(receive);

Warum wird das sowohl in main als auch in der ISR aufgerufen?

von spontan (Gast)


Lesenswert?

Delays sind meist Schwachsinn, sie machen fast immer Ärger.
Hier mit Sicherheit.

von Interruptor (Gast)


Lesenswert?

Durch das Aufrufen in der main un in dem ISR wollen wir ja die Variablen 
vergleichen (auf dem Display)

von Interruptor (Gast)


Lesenswert?

Wir haben jetzt auch mal mit dem Oszilloskop nachgemessen und es kommt 
wirklich nur ein einziges Zeichen an.

von (prx) A. K. (prx)


Lesenswert?

LCD-Ausgabe in einer ISR ist auch nicht der Weisheit letzter Schluss - 
insbesondere nicht, wenn auch im Hauptprogramm eine erfolgt und sich das 
munter mischen kann. Also beispielsweise wenn mittendrin im LCD-Code der 
Interrupt sich einmischt.

von Pako (Gast)


Lesenswert?

Interruptor schrieb:
> while(1)
>   {
>     ...
>     lcd_setcursor(0,2);
>     Schreibe_in_Binaer(receive);
>   }

Funktionen, die sowohl aus einer ISR als auch aus main() aufgerufen 
werden, müssen entweder
- reentrant programmiert sein (was Deine nicht sind), oder
- während des Aufrufes durch main() muß der Interrupt gesperrt sein (was 
Deiner nicht ist).

In Deinem Fall kann main() gerade in lcd_setcursor() sein, und dann 
kommt der Interrupt und geht nochmal in lcd_setcursor(). Was passiert 
dann? Datenmurks im Quadrat!

Du kommst mit sowas schnell in Teufels Küche, daher vermeidet man so 
einen Aufruf-Mix nach Möglichkeit.

von Karl H. (kbuchegg)


Lesenswert?


Dieser Beitrag ist gesperrt und kann nicht beantwortet werden.