Forum: Mikrocontroller und Digitale Elektronik UART soll nach externem Interrupt senden (C, ATM.8)


von Markus S. (Firma: A.S.) (xray)


Lesenswert?

1
//---------------------INCLUDES---------------------------------
2
#define F_CPU 3686400UL
3
#include <avr/delay.h>
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include <inttypes.h>
7
#include <avr/signal.h>
8
#include <avr/wdt.h>
9
//---------------------DEFINES---------------------------------
10
#define eDIP_IRQ PD2
11
#define Takt 3686400UL  //Controllertakt 3,4686 MHz
12
#define BAUD 9600UL    //Baudrate  
13
14
#include <UART\konsolfunc.h>
15
//-------------------INIT UART----------------------------------
16
//UCSRA:  RXC = INT wenn zeichen im empfänger angekommen. Wird gelöscht wenn Daten aus UDR gelesen werden.
17
//      TXC = INT wenn Zeichen aus dem sender geschickt wurde und Sendepuffer leer ist. Durch Interrupt-
18
//            annahme oder durch Einschreiben einer 1 wieder gelöscht.
19
//      UDRE = 1 wenn Puffer bereit für neue Datenübertragung.  (S.350)
20
21
//-------------------IRQ ausgelöst-------------------------//GIFR (Interrupt Flag = 01000000)
22
volatile double ISR_buffer;
23
24
//-------------------------FUNKTIONEN--------------------------------------------
25
26
//-------------------------Sendepuffer empfangen---------------------------------
27
int sendepuffer_empfangen()
28
{
29
  getch();
30
31
  switch(UDR)
32
  {
33
34
    case 0x01 : PORTB^=(1<<PB1);  //gelbe LED blinkt
35
    break;
36
    _delay_ms(50);
37
38
    case 0x02 : PORTB^=(1<<PB1);  //gelbe LED blinkt
39
    break;
40
    _delay_ms(50);
41
42
    default : PORTB^=((1<<PB1) | (1<<PB2));
43
    _delay_ms(50);
44
  }
45
  return(0);
46
}
47
48
//-------------------------Sendepuffer anfordern --------------------------------------
49
void sendepuffer_anfordern()
50
{
51
52
  initusart();
53
  _delay_ms(30);
54
  putch('0x12');   //<DC2>
55
  _delay_ms(1);
56
  putch('0x01');  //1(len)
57
  _delay_ms(1);
58
  putch('0x53');  //S
59
  _delay_ms(1);
60
  putch('0x66');  //66(bcc)
61
  _delay_ms(1);
62
63
  getch();    // Empfänger ein und auf Antwort des Displays warten
64
65
  if(UDR == '0x06')      //wenn "Ack" vom Display
66
  {
67
    PORTB=(1<<PB1);      // LED grün
68
    sendepuffer_empfangen;      
69
  }
70
else            //wenn "Nack" vom Display
71
  {
72
    PORTB=(1<<PB2);      //LED rot
73
  }
74
  for (int i=0; i<5; i++)
75
  {
76
    sendepuffer_anfordern;            //EVENTUELL SEPARAT !!!
77
  }
78
79
}
80
81
//-------------------------Daten senden--------------------------------------
82
83
// FÜR MENÜBEFEHLSROUTINE !!!
84
85
//-------------------------auf Daten warten--------------------------------------
86
87
int wait_for_data()
88
{
89
  ISR_buffer = PORTC  ;
90
  while(1)
91
  {PORTB=(1<<PB3);//DEBUGLEUCHTE
92
    if(ISR_buffer>0x00)              //prüfen ob Daten in Register
93
    {
94
      ISR_buffer = 0;          //Buffer zurücksetzen
95
      sendepuffer_anfordern;
96
      
97
    }
98
99
  }
100
  return(0);
101
}
102
103
//------------------------------------------------------------------------------
104
//-------------------------ISRs--------------------------------------
105
106
ISR (INT0_vect)          // SBUF Display hat Daten - jetzt abholen !
107
{  
108
  PORTC++;
109
//  GICR= (!(1<<INT0)) ;
110
}
111
112
//--------------------HAUPTPROGRAMM----------------------------
113
114
int main()                      
115
{
116
  wdt_reset();
117
  
118
  initusart();
119
  //---------------------INIT EXT INTERRUPT--------------------------
120
121
  MCUCSR |=(1<<ISC01);    //INT bei fallender Flanke an PIN D2
122
123
  GICR |= (1<<INT0) ;               // EXT INT aktiviert
124
125
  //------------------------------------------------------------------  
126
127
  //----------------------EIN/AUSGÄNGE festlegen----------------
128
  DDRB=0xff;
129
  DDRC=0xff;
130
  PORTD=0xff;  //PIN 2 EXT0 INTERRUPT Pullup
131
  //-----------------------------------------------------------
132
  sei();
133
  while(1)
134
  {
135
136
    PORTB^=(1<<PB0);    // Rote LED blinkt
137
    _delay_ms(50);  
138
    cli();      
139
    wait_for_data;
140
    sei();
141
  }
142
  // Arbeitsschleife Ende
143
144
}

Hallo !

Ich mach gerade meine ersten Gehversuche mit nem eDIP 160 Touchdisplay 
und nem ATmega 8. Das Display steckt auf einem EVA Board und der ATmega 
auf dem MyAVR MK2. Nun habe ich beides über RS232 verbunden und der UART 
funktioniert auch mit den gemachten Einstellungen.
Jetzt mein Problem: Das Display zeigt ja mit Low Level an PIN 20 an, 
dass Daten im Sendepuffer vorhanden sind. Also hab ich diesen mit dem 
ExtINT0 des uC vebunden. Die ISR spricht auch an sobal ich am Display 
eine Taste drücke, aber anscheinend bleibt der uC dann in der ISR hängen 
und geht nicht auf die Sendefunktion. Ich habe in der Sendefunktion PB3 
aktiviert, um mir das Ansprechen über eine LED anzeigen zu lassen - da 
tut sich nicht. Drücke ich den Reset des Display, wird die Puffermeldung 
gelöscht und ds Programm läuft in der Mainroutine weiter. Wie krieg ich 
es jetzt hin, dass nach dem INT0 mein Sendeprog startet ???

von holger (Gast)


Lesenswert?

Alter das ist echt ne grosse Baustelle;)

  putch('0x12');   //<DC2>

Schwachsinn. Das geht in C nicht ohne massive Fehlermeldungen.
So macht man das.

  putch(0x12);   //<DC2>

Aus dieser Routine kommst du nie wieder raus.
1
int wait_for_data()
2
{
3
  while(1)
4
  {PORTB=(1<<PB3);//DEBUGLEUCHTE
5
    if(ISR_buffer>0x00)              //prüfen ob Daten in Register
6
    {
7
      ISR_buffer = 0;          //Buffer zurücksetzen
8
      sendepuffer_anfordern;
9
      
10
    }
11
12
  }
13
  return(0);
14
}



Na super erst mal alle Interrupts abschalten.

    cli();
    wait_for_data;
    sei();

Rekursiver Aufruf. Gute Idee!
1
//-------------------------Sendepuffer anfordern --------------------------------------
2
void sendepuffer_anfordern()
3
{
4
................
5
    sendepuffer_anfordern;            //EVENTUELL SEPARAT !!!
6
7
}

von Markus S. (Firma: A.S.) (xray)


Lesenswert?

Danke, das sind schonmal ein paar Dinge die ich angehen werde - bin noch 
nicht so vertraut mit C, aber dafür macht man ja die Fehler ;-)

von Stefan E. (sternst)


Lesenswert?

Markus S. schrieb:
> Danke, das sind schonmal ein paar Dinge die ich angehen werde

Hier hast du noch weitere:

- Reichlich fehlende () bei Funktionsaufrufen.

- Nicht erreichbarer Code im switch.

Allgemein:
Das ist ein Haufen Code mit so vielen Fehlern darin, dass der mit 
Sicherheit noch nie richtig funktioniert hat. Du musst in kleinen 
Schritten programmieren und nach jedem Schritt ausführlich Testen. Und 
erst wenn es funktioniert, gehst du den nächsten Schritt an. Und noch 
bevor du mit diesen Schritten anfängst, musst du dir erst mal eine 
Struktur für dein Programm überlegen (denn die kann ich im Code oben 
auch nicht so wirklich erkennen).

von Markus S. (Firma: A.S.) (xray)


Lesenswert?

1
//---------------------INCLUDES---------------------------------
2
#define F_CPU 3686400UL
3
#include <avr/delay.h>
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include <inttypes.h>
7
#include <avr/signal.h>
8
#include <avr/wdt.h>
9
//---------------------DEFINES---------------------------------
10
#define eDIP_IRQ PD2
11
#define Takt 3686400UL  //Controllertakt 3,4686 MHz
12
#define BAUD 9600UL    //Baudrate  
13
14
#include <UART\konsolfunc.h>
15
16
volatile double ISR_buffer;
17
18
//-------------------------FUNKTIONEN--------------------------------------------
19
20
//-------------------------Sendepuffer empfangen---------------------------------
21
int sendepuffer_empfangen()
22
{
23
  getch();
24
25
  switch(UDR)
26
  {
27
28
    case 0x01 : PORTB^=(1<<PB1);  //gelbe LED blinkt
29
    break;
30
    _delay_ms(50);
31
32
    case 0x02 : PORTB^=(1<<PB2);  //grüne LED blinkt
33
    break;
34
    _delay_ms(50);
35
36
    default : PORTB^=((1<<PB1) | (1<<PB2));
37
    _delay_ms(50);
38
  }
39
  return(0);
40
}
41
42
//-------------------------Sendepuffer anfordern --------------------------------------
43
void sendepuffer_anfordern()
44
{
45
46
  _delay_ms(30);
47
  putch(0x12);   //<DC2>
48
  _delay_ms(1);
49
  putch(0x01);  //1(len)
50
  _delay_ms(1);
51
  putch(0x53);  //S
52
  _delay_ms(1);
53
  putch(0x66);  //66(bcc)
54
  _delay_ms(1);
55
56
  getche();    // Empfänger ein und auf Antwort des Displays warten
57
58
  if(UDR == 0x06)      //wenn "Ack" vom Display
59
  {
60
    PORTB=(1<<PB1);      // LED grün
61
    sendepuffer_empfangen;      
62
  }
63
else            //wenn "Nack" vom Display
64
  {
65
    PORTB=(1<<PB2);      //LED rot
66
  }
67
68
}
69
70
//-------------------------Daten senden--------------------------------------
71
72
// FÜR MENÜBEFEHLSROUTINE !!!
73
74
//*******************************************************************
75
//-------------------------ISRs--------------------------------------
76
77
ISR (INT0_vect)          // SBUF Display hat Daten - jetzt abholen !
78
{
79
80
  PORTC++;
81
  //GICR= (!(1<<INT0)) ;
82
}
83
84
//--------------------HAUPTPROGRAMM----------------------------
85
86
int main()                      
87
{
88
  wdt_reset();
89
90
  initusart();
91
  //---------------------INIT EXT INTERRUPT--------------------------
92
93
  MCUCSR |=(1<<ISC01);    //INT bei fallender Flanke an PIN D2
94
95
  GICR |= (1<<INT0) ;               // EXT INT aktiviert
96
97
  //------------------------------------------------------------------  
98
99
  //----------------------EIN/AUSGÄNGE festlegen----------------
100
  DDRB=0xff;
101
  DDRC=0xff;
102
  PORTD=0xff;  //PIN 2 EXT0 INTERRUPT Pullup
103
  //-----------------------------------------------------------
104
  sei();
105
  while(1)
106
  {
107
108
    PORTB^=(1<<PB0);    // Rote LED blinkt
109
    _delay_ms(50);  
110
111
    if(PORTC>0)              //prüfen ob Daten in Register
112
    {
113
114
      PORTB=(1<<PB3);        //DEBUGLEUCHTE
115
      PORTC = 0;          //Buffer zurücksetzen
116
      sendepuffer_anfordern;
117
118
    }
119
    return (0);
120
  }
121
  // Arbeitsschleife Ende
122
123
}

Ich hab jetzt schonmal die angesprochenen Fehler beseitigt. Der Compiler 
meckert ja auch nicht. Aber Du hast recht, wahrscheinlich muss ich 
nochmal in kleinen Schritten loslegen.
Habe mir aber vorher nen PAP erstellt, nur durch diverse Korrekturen 
sieht es schon etwas anders aus.

von Markus S. (Firma: A.S.) (xray)


Lesenswert?

1
//---------------------INCLUDES---------------------------------
2
3
#include <avr/delay.h>
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include <inttypes.h>
7
#include <avr/signal.h>
8
#include <avr/wdt.h>
9
//---------------------DEFINES---------------------------------
10
#define eDIP_IRQ PD2
11
#define Takt 3686400UL  //Controllertakt 3,4686 MHz
12
#define BAUD 9600UL    //Baudrate  
13
14
#include <UART\konsolfunc.h>
15
16
volatile int SBUF_EDIP;
17
volatile int transfer_error;
18
19
//********************FUNKTIONEN******************************
20
21
//--------------------DATEN IM EDIP-PUFFER--------------------
22
int paket_fordern()
23
24
{
25
  putch(0x12);   //<DC2>
26
  putch(0x01);  //1(len)
27
  putch(0x53);  //S
28
  putch(0x66);  //66(bcc)
29
  _delay_ms(10);      
30
  return(0);
31
}
32
//--------------------DATENPAKET AUSWERTEN---------------------
33
int get_package()
34
{
35
36
  switch(UDR)
37
  {
38
39
    case 0x01 : PORTB^=(1<<PB0);  //rote LED blinkt
40
    break;
41
    _delay_ms(50);
42
43
    case 0x02 : PORTB^=(1<<PB2);  //grüne LED blinkt
44
    break;
45
    _delay_ms(50);
46
47
    default : PORTB^=((1<<PB1) | (1<<PB2));  //beide blinken
48
    _delay_ms(50);
49
  }
50
  return(0);
51
}
52
//--------------------ANTWORT AUF ACK PRÜFEN------------------ 
53
54
int pruefe_ack()
55
{
56
57
  if(UDR==0x06)
58
  {
59
    get_package;PORTB=(1<<PB3);
60
  }
61
  //hole Paket
62
63
else 
64
  {
65
    transfer_error++;
66
  }
67
  if(transfer_error>5){return false;}      // FEHLERPUFFER
68
  return(0);    
69
  
70
}
71
72
//-------------------------ISRs--------------------------------------
73
74
ISR (INT0_vect)          // SBUF Display hat Daten - jetzt abholen !
75
{
76
  SBUF_EDIP++;  
77
}
78
79
//**********************HAUPTPROGRAMM*********************************
80
81
int main()                      
82
{
83
  //---------------------INIT EXT INTERRUPT--------------------------
84
85
  MCUCSR |=(1<<ISC01);    //INT bei fallender Flanke an PIN D2
86
87
  GICR |= (1<<INT0) ;               // EXT INT aktiviert
88
89
  //------------------------------------------------------------------  
90
91
  //----------------------EIN/AUSGÄNGE festlegen----------------
92
  DDRB=0xff;
93
  DDRC=0xff;
94
  DDRD=0x00;
95
  PORTD=0xff;  //PIN 2 EXT0 INTERRUPT Pullup
96
  //-----------------------------------------------------------
97
  initusart();
98
  sei();
99
  while(1)
100
  {
101
102
    if(SBUF_EDIP>1)
103
    {
104
      paket_fordern();
105
    }
106
107
  else 
108
    {
109
      PORTB=(1<<PB1);  
110
    }
111
112
    pruefe_ack();              // Rückmeldung des Displays prüfen
113
    if(transfer_error==1)
114
    {
115
      paket_fordern;
116
    }
117
    // Wenn kein "ACK" kam, Paket neu anfordern
118
119
  }
120
121
}


SO- Bis hierhin hab ichs jetzt hinbekommen, das mit dem Interrupt und 
dem Auslesen des Datenpuffers vom Display funktioniert nun. Jetzt steh 
ich vor dem nächsten Problem - wie lege ich das ankommende Datenpaket 
ab, um es auswerten zu können. Der UDR speichert doch immer nur ein BYte 
richtig ? Das Display sendet aber immer mindestens "ESC,A,1,CODE" bis zu 
32Byte. Wie mach ich das ? mit nem FIFO ? Und wenn dann weiss ich nicht 
so richtig wie !

von mani (Gast)


Lesenswert?

Sorry,aber das kann nicht funktionieren!
1
if(transfer_error==1) 
2
{ paket_fordern; } 
3
// Wenn kein "ACK" kam, Paket neu anfordern

Es fehlen immer noch Klammern für die Funktionsaufrufe .
Hab mir den Code nicht angesehen,steckt bestimmt noch mehr drin!

von Sam P. (Gast)


Lesenswert?

C hat eine recht konsequente logische Sprachdefinition, was zu einigen 
seltsamen Konstruktionen führt, die offiziell erlaubt sind, aber selten 
Sinn machen. GCC kann, wenn man ihn drum bittet, solche problematischen 
Ausdrücke
und Befehle anmeckern.

Ich empfehle "-Wall -Wextra -Werror" als Compiler-Optionen (ich nehme 
mal an, du benutzt einen GCC). Damit werden solche zweifelhafte 
Konstrukte angemahnt und als Fehler gemeldet.

Gerade mit deinem unsteten C-Wissen solltest du dann zu jeder 
Fehlermeldung die Ursache bestimmen und beheben. Und nicht schummeln! 
Die Warnungen/Fehler sind zu deinem Besten! Dadurch lernst du nämlich 
auch noch einiges.

von Karl H. (kbuchegg)


Lesenswert?

Weil ichs gerade gesehen hab und weil das der Compiler nicht anmeckern 
wird (demist das prinizipiell egal)


Du darfst UDR pro Zeichen nur ein einziges mal auslesen!
Nach dem ersten auslesen ist UDR futsch.


Und wenn du C nicht so gut kannst, warum lernst du es nicht erst mal und 
fängst mit etwas einfacherem an? Du machst den Kardinalfehler 
schlechthin: Viel zu viel Code, den du nicht getestet hast und dann 
weiußt du nicht, wo du mit Fehlersuche anfangen sollst, weil so gut wie 
überall, quer durch den ganzen Code Probleme sind.

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.