Forum: Mikrocontroller und Digitale Elektronik atmega644 UART-Ringpufferlösung - vollständiger Code: Letzter Fehler- Immer nur drei bytes


von Alex V. (bastel_alex) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo,

ich hatte hier vor kurzem bereits Hilfe und dann auch eine (dachte ich) 
funktionierende Version. Nun gibt es ein kleines Problem, auf dessen 
Lösung ich einfach nicht komme:

Ich habe einen Ringpuffer umgesetzt, um interruptgesteuerte 
UART-Kommunikation mit meinem atmega644 aufzubauen. Das merkwürdige:

Der Ringpuffer funktioniert gut, wenn ich max. drei bytes hintereinander 
hineinschreibe. Sende ich mehr, werden die zwischenliegenden Bytes 
zwischen den ersten beiden und dem letzten irgendwie verschluckt. Als 
Beispiel in der Routine unten:

Ich möchte 00 FF AB CD EF 00 schicken.
Am terminal kommt dann aber an: 00 FF 00.

Der Code ist eigentlich recht übersichtlich und funktioniert soweit, er 
kann also gerne verwendet werden (dann hat vll. jemand auch etwas davon, 
sobald der fehler gefunden ist). Wenn ihr mir irgendwie helfen könntet 
wäre das super!!
1
*/ RINGPUFFER: circbuf.h */
2
#ifndef CIRCBUF_H_
3
#define CIRCBUF_H_
4
5
#include <stdbool.h>
6
#include <avr/io.h>
7
#include <stdlib.h>
8
#include <avr/interrupt.h>
9
10
11
#define buffer_size 16      
12
13
struct circ_buffer {
14
  uint8_t data[buffer_size];
15
  uint8_t read_ptr;      // points to last input data
16
  uint8_t write_ptr;      // always points to empty field
17
  };
18
19
void buffer_init (struct circ_buffer *buf);
20
void buffer_write(struct circ_buffer *buf, uint8_t byte);
21
uint8_t buffer_read(struct circ_buffer *buf);
22
uint8_t buffer_is_full (struct circ_buffer *buf);
23
uint8_t buffer_is_empty (struct circ_buffer *buf);
24
25
#endif /*CIRCBUF_H_*/
26
/* END circbuf.h */
27
28
29
/* RINGPUFFER FUNCTIONS  circbuf.c*/
30
#include "circbuf.h"
31
32
void buffer_init (struct circ_buffer *buf)          // Initialization of circular buffer values
33
{
34
  buf->read_ptr=0;
35
  buf->write_ptr=0;
36
}
37
38
void buffer_write(struct circ_buffer *buf, uint8_t byte)  // Write byte into buffer, increment fillcounter and write pointer
39
{
40
  cli();
41
  buf->data[buf->write_ptr] = byte;
42
  
43
  if (buf->write_ptr >= buffer_size-1){
44
    buf->write_ptr = 0;
45
  }
46
  else{
47
    buf->write_ptr = buf->write_ptr + 1;
48
  }
49
  sei();
50
}
51
52
uint8_t buffer_read(struct circ_buffer *buf)        // Read byte out of buffer, decrement fillcounter, increment read ptr
53
{
54
  cli();
55
  uint8_t returnval =0;
56
  
57
  if  (buf->read_ptr == buf->write_ptr){
58
    sei();
59
    return 0;
60
  }
61
  else 
62
  {
63
    returnval= buf->data[buf->read_ptr];
64
    
65
    if (buf->read_ptr >= buffer_size-1){
66
      buf->read_ptr = 0;
67
    }
68
    else{
69
      buf->read_ptr = buf->read_ptr + 1;
70
    }
71
    sei();
72
    return returnval;
73
  }
74
75
}
76
77
uint8_t buffer_is_full (struct circ_buffer *buf)
78
{
79
  if (buf->write_ptr + 1 == buf->read_ptr || buf->read_ptr == 0 && buf->write_ptr + 1 == buffer_size)
80
  return 1;
81
  else return 0;
82
}
83
84
uint8_t buffer_is_empty (struct circ_buffer *buf)
85
{
86
  if (buf->read_ptr == buf->write_ptr) return 1;
87
  else return 0;
88
}
89
90
/* END RINGPUFFER FUNCTIONS circbuf.c */
91
92
93
94
/* UART_functions.h */
95
96
  #ifndef _M_UART_functions_h_
97
  #define _M_UART_functions_h_
98
  
99
  #define F_CPU 20E6 //Systemtakt in Hz
100
  #include <util/delay.h>
101
  
102
  #include "circbuf.h"
103
104
  // FUNCTIONS
105
  void UART_Init();
106
  uint8_t uart_ReceiveByte( struct circ_buffer *buf );
107
  void uart_TransmitByte( struct circ_buffer *buf, uint8_t data );
108
109
  #endif /*_M_UART_functions_h_*/
110
111
/* END UART_functions.h */
112
113
114
/* UART_functions.c */
115
116
#include <avr/io.h>
117
#include <avr/interrupt.h>
118
#include <stdlib.h>
119
120
#include "UART_functions.h"
121
#include <util/delay.h>
122
123
124
 void UART_Init()
125
 {
126
   // baud Calculation: baud = (fosc/ 16*Baudrate)-0.5
127
   // baud = (20 MHz / 16*9600)-0.5 = 129.708 --> = baud = 130
128
   unsigned int baud = 130;
129
   
130
   //* Set baud rate */
131
   UBRR0H = (unsigned char)(baud>>8);
132
   UBRR0L = (unsigned char)baud;
133
   /* Enable receiver and transmitter, Set Interrupts: RXCIE - RX-Complete */
134
   UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
135
   /* Set frame format: 8data, 2stop bit */
136
   UCSR0C = (1<<USBS0)|(3<<UCSZ00);
137
 }
138
 
139
uint8_t uart_ReceiveByte( struct circ_buffer *buf )
140
{
141
  while ( buffer_is_empty(buf) );  /* wait for incoming data */
142
  return buffer_read(buf); /* return data */
143
}
144
145
146
void uart_TransmitByte(struct circ_buffer *buf, uint8_t data )
147
{
148
  while ( buffer_is_full(buf) );
149
  buffer_write(buf,data);    /* store data in buffer */
150
  
151
  UCSR0B |= (1<<UDRIE0);      // Enable UDRIE- UART Data Register empty Interrupt - UDRE-ISR is going to put data in UDR
152
}
153
154
/* END UART_functions.c */
155
156
157
/* MAIN.c */
158
159
#include <avr/io.h>
160
#include <avr/interrupt.h>
161
#include <stdlib.h>
162
#include "stdbool.h"
163
#include <string.h>
164
165
#define F_CPU 20E6 //Systemtakt in Hz
166
167
#include "UART_functions.h"
168
#include "circbuf.h"
169
#include <util/delay.h>
170
171
// Global VARIABLES
172
unsigned char byte_buffer;
173
struct circ_buffer uart_rx_buffer;            // Receive-Circular-Buffer
174
struct circ_buffer uart_tx_buffer;            // Send-Circular-Buffer
175
176
177
// UART RX-Complete interrupt: 
178
// Receiving data + buffering (saving)
179
ISR(USART0_RX_vect) 
180
{
181
  unsigned char data;
182
  data = UDR0;
183
  buffer_write(&uart_rx_buffer, data);
184
}
185
186
// UART Data register empty interrupt:
187
// loading new data into UART sending register
188
ISR(USART0_UDRE_vect) 
189
{
190
  if (!buffer_is_empty(&uart_tx_buffer))          // Is buffer filled?
191
  {
192
    UDR0 = buffer_read(&uart_tx_buffer);
193
  }
194
  else
195
  {
196
    UCSR0B &= ~(1<<UDRIE0);              // Disable UDRIE- UART Data Register empty Interrupt 
197
  }
198
}
199
200
int main(void)
201
{
202
  /* Buffer Initialization */
203
  buffer_init(&uart_rx_buffer);
204
  buffer_init(&uart_tx_buffer);
205
  
206
  /* Variables */
207
  char controlbyte;
208
  uint8_t sendbuffer;  
209
  uint32_t adcrec;
210
      
211
  /*********************** Initialization ***********************/
212
  //Port Directions
213
  
214
  DDRA= 0b11011011;              
215
  DDRB= 0b10100110;                            
216
  DDRC= 0b01010001;        // SPI Slave select, LEDs                    
217
  DDRD= 0b00001010;        // UART
218
  
219
  UART_Init();          // UART initialization
220
  sei();              // Global Interrupt enable
221
  
222
  /*********** MAIN LOOP **************/
223
    while(1)
224
    {  
225
      
226
    if (!buffer_is_empty(&uart_rx_buffer))            // Received Commands?
227
    {
228
      controlbyte = uart_ReceiveByte(&uart_rx_buffer);
229
      
230
      switch (controlbyte)
231
      {
232
        case 0xAA: {
233
          sendbuffer =00;
234
          uart_TransmitByte(&uart_tx_buffer, sendbuffer);
235
          
236
          adcrec =  0xFFABCDEF;
237
          
238
          sendbuffer =(adcrec >>24);
239
          uart_TransmitByte(&uart_tx_buffer, sendbuffer);
240
          sendbuffer =(adcrec >>16);
241
          uart_TransmitByte(&uart_tx_buffer, sendbuffer);
242
          sendbuffer =(adcrec >>8);
243
          uart_TransmitByte(&uart_tx_buffer, sendbuffer);
244
          sendbuffer =adcrec;
245
          uart_TransmitByte(&uart_tx_buffer, sendbuffer);    
246
          sendbuffer =00;
247
          uart_TransmitByte(&uart_tx_buffer, sendbuffer);                          
248
          break;
249
        }
250
        case 0xBB: {
251
          break;
252
        }
253
        case 0xCC:{
254
          break;          
255
        }
256
      }
257
    }    
258
    }
259
}
260
261
/* END MAIN.C */


Die Mainloop wartet hier auf den Eingang eines Control-Chars über UART 
und sendet dann (im Falle von 0xAA) die Testsequenz.

Kann mir da jemand helfen? Ich habe die Files auch oben angehängt.

Beste Grüße

Alex

von jibi (Gast)


Lesenswert?

>sendbuffer =00;

Wasn das`?

von Alex V. (bastel_alex) Benutzerseite


Lesenswert?

jibi schrieb:
>>sendbuffer =00;
>
> Wasn das`?

nen flüchtigkeitsfehler (0x00), daran liegts aber nicht ;)

Alles in der switch-case loop ist unter vorbehalt zu genießen, da habe 
ich jetzt dauernd herumgefummelt um auf den fehler zu kommen.

: Bearbeitet durch User
von jibi (Gast)


Lesenswert?

>nen flüchtigkeitsfehler (0x00), daran liegts aber nicht ;)

>Alles in der switch-case loop ist unter vorbehalt zu genießen, da habe
>ich jetzt dauernd herumgefummelt um auf den fehler zu kommen.

Fürn Programmierer bist du aber schwer nachlässig ;).
Das musst du ändern.

Gruß Jonas

von Stefan F. (Gast)


Lesenswert?

> struct circ_buffer uart_rx_buffer;
> struct circ_buffer uart_tx_buffer;

Mach diese beiden Puffer mal volatile und sorge dafür, dass cli() und 
sei() nicht aus dem Interrupt heraus aufgerufen werden.

Siehe FAX 1. und 8.

von jibi (Gast)


Lesenswert?

Im Übrigen fehlt in deinem Zip ein File.

#include "Mainboard_UART_functions.h"

von Alex V. (bastel_alex) Benutzerseite


Lesenswert?

Stefan us schrieb:
> Mach diese beiden Puffer mal volatile und sorge dafür, dass cli() und
> sei() nicht aus dem Interrupt heraus aufgerufen werden.

DAS WARS!!
Vielen herzlichen Dank stefan! Mist ja klar, in den USART ISRs wurden 
über die ringpuffer-funktionen die interrupts global umgeschaltet. Hach 
super. ich danke dir.

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.