Forum: Mikrocontroller und Digitale Elektronik Probleme mit Zusammenspiel von Uart-Interrupts


von Tobias (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich möchte mehrere µC mit einander verbinden und mit RS485 ein Netzwerk 
aufbauen.

Dazu senden ein Master eine Nachricht (siehe Bild im Anhang), obere 
Nachricht.
Ein Atmega 8 als Slave soll darauf antworten. Da geht bis jetzt auch 
sehr gut. Ich habe allerdings 2 Probleme, die ich einfach nicht in den 
Griff bekomme.
1. Der slave senden irgenwoher noch ein "\0" (siehe 3. Zeile, rot 
eingekreist)
2. Der Slave hört danach nicht mehr auf Nachrichten vom Master.

Ich bin mir sicher, es sind meine Interrupts. Da es mein erstes großes 
Projekt mit Interrupts ist, lasse ich mir gern auch erklären, wie es 
richtig oder eleganter geht. Diese Anwendung der Interrupts für RX und 
TX habe ich aus einem bestehenden Quelltext.

Hier nun mein Quelltext des Slaves:
1
#define BAUDRATE 9600
2
#define F_CPU 8000000
3
#define MYADRESS 2
4
#define SLAVETYPE Akustik
5
6
#include <avr/io.h>
7
#include <avr/interrupt.h>
8
#include <util/delay.h>
9
#include <stdlib.h>
10
11
12
uint8_t inputbuf [10];
13
uint8_t outputbuf [10];
14
static uint8_t receivebytes, sendbytes=0;
15
static uint8_t zeichen;
16
static uint8_t protocollstart =0;
17
static uint8_t msgend=0;
18
19
void rs485_slave_init()
20
{
21
  DDRC |= (1 << PC0);              // PC0 als Output setzen
22
  PORTC &= ~(1 << PC0);            // Max481 auf empfangen stellen
23
  _delay_us(500);                // 500µs warten
24
25
  uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16UL*BAUDRATE) - 1);
26
27
  UBRRH = (uint8_t) (ubrr>>8);
28
  UBRRL = (uint8_t) (ubrr);
29
  
30
  // UART Receiver und Transmitter anschalten, Receive-Interrupt aktivieren
31
  // Data mode 8N1, asynchron
32
  UCSRA = 0;
33
  UCSRB = (1 << RXCIE)| (1 << RXEN) | (1 << TXEN);
34
  UCSRC = (1<<URSEL) | (1 << UCSZ1)| (1 << UCSZ0);
35
}
36
37
int rs485_slave_send(uint8_t outdata [3])
38
{
39
  outputbuf[0]=0x02;                    //Startzeichen für Protokoll STX
40
  outputbuf[1]=MYADRESS;                  //Empfängeradresse in Array spreichern
41
  outputbuf[2]=0x42;
42
  outputbuf[3]=0;
43
  outputbuf[4]=0;
44
  outputbuf[5]=0;
45
  
46
  int x=0;
47
  for (int i=6;i <= 8;i++)
48
  {
49
    outputbuf[i]=outdata[x++];              //Datenarray in Outputbuf 3-5 schreiben
50
  }
51
  outputbuf[9]=0x03;
52
  
53
  PORTC |= (1 << PC0);                  // Max481 auf senden stellen
54
  
55
  cli();
56
  UCSRB &= ~(1 << RXEN);
57
  UCSRB |= (1 << UDRIE);                  //Interrupt zum Senden aktivieren
58
  sei();
59
  
60
  
61
  return 1;
62
}
63
64
int rs485_slave_read(uint8_t indata[], uint8_t size)
65
{
66
  uint8_t n=0;
67
  if (inputbuf[0]== 0x02)                  //Start einer Nachricht feststellen
68
  {
69
    while (n <= 9)
70
    {
71
      indata[n]=inputbuf[n];
72
      n++;
73
    }
74
    return n;
75
  }
76
  else
77
  {
78
    return 0;
79
  }
80
  
81
  
82
}
83
84
void deleteInputbuf()
85
{
86
  int i=0;
87
  while (i <= 11)
88
  {
89
    inputbuf[i++] = 0;
90
  }
91
}
92
93
94
int main(void)
95
{
96
  DDRD |= (1 << PD6) | (1 << PD7);              //PC0 als Ausgang für Signalisierung RX an Slave
97
  //DDRC &= ~(1 << PC1);
98
  
99
  uint8_t statusbyte[3];
100
  uint8_t inputdata [10];
101
  
102
  cli();
103
  //Initialisierung RS45
104
  rs485_slave_init();
105
  sei();
106
  
107
  
108
    while(1)
109
    {
110
    
111
    
112
    rs485_slave_read(inputdata, sizeof(inputdata));
113
    
114
    if(inputbuf[0] == 0x02 && msgend)
115
    {
116
      //Start und Ende von Frame erkannt, prüfen ob Nachricht für Teilnehmer ist
117
       if (inputbuf[1] == MYADRESS)
118
       {
119
        //Nachricht ist für diesen Teilnehmer
120
        //Auswerten der Steuerbytes
121
        PORTD |= (1 << PD7);
122
        if (inputbuf[3] & (1 << 2))
123
        {
124
          PORTD |= (1 << PD6);
125
        } 
126
        else if (!(inputbuf[3] & (1 << 2)))
127
        {
128
          PORTD &= ~(1 << PD6);
129
          
130
        }
131
       
132
      
133
       statusbyte[0]= (1 << 0);          //ACK Nachricht
134
       statusbyte[1]=0x58;
135
       statusbyte[2]=0x58;
136
       
137
       rs485_slave_send(statusbyte);
138
       deleteInputbuf();
139
       }
140
       else
141
       {
142
         PORTD &= ~(1 << PD7);
143
       }
144
    
145
    }  
146
  }
147
        
148
  return 0;
149
}
150
151
ISR(USART_RXC_vect)                //Interrupt-Routine, wird ausgelöst, wenn Zeichen empfangen wird
152
{
153
  zeichen = UDR;                
154
  
155
  if (zeichen == 0x02 && receivebytes==0)
156
  {
157
    protocollstart=1;  
158
  }
159
  
160
  
161
  if (protocollstart)
162
  {
163
    inputbuf[receivebytes++]=zeichen;
164
  }
165
  
166
  if (receivebytes==10 && protocollstart)
167
  {
168
    //Ende der Nachricht erreicht
169
    //UCSRA |= (1 << RXC);
170
    UCSRB &= ~(1 << RXCIE);
171
    msgend=1;
172
    receivebytes=0;
173
    protocollstart=0;
174
  }
175
}
176
177
ISR(USART_UDRE_vect)
178
{
179
  if (sendbytes==1)
180
  {
181
    UCSRB |= (1 << TXCIE);                //Transmit Complete Interrupt aktivieren
182
  }
183
  
184
  if (sendbytes == 10)
185
  {
186
    UCSRB &= ~(1 << UDRIE);                //Interrupt zum Senden deaktivieren
187
    UCSRA |= (1 << TXC);
188
    sendbytes =0;
189
  }
190
  else
191
  {
192
    //while (!(UCSRA & (1<<UDRE)))            // warten bis Senden moeglich ist
193
    //{
194
    //}
195
    UDR = outputbuf[sendbytes++];            //Zeichen senden aus Outputbuf
196
  }
197
}
198
199
200
//Transmit Complete Interrupt Routine
201
ISR(USART_TXC_vect)
202
{
203
  // Transmit is complete: terminate
204
  PORTC &= ~(1 << PC0);                  //MAX485 auf Receive stellen
205
  UCSRB &= ~(1 << TXEN);                  
206
  UCSRB |= (1 << RXEN) | (1 << RXCIE);          //Receive Interrupt einschalten
207
  UCSRB &= ~(1 << TXCIE);                  //Transmit Complete Interrupt deaktivieren
208
}

Wäre sehr dankbar, wenn mir jemand helfen würde.

Vielen Dank.

Gruß Tobias

von Mark R. (stevestrong)


Lesenswert?

Versuch mal die Variabeln die in IRQ benutz werden auch als "volatile" 
zu deklarieren.

: Bearbeitet durch User
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.