Forum: Compiler & IDEs i2c master empfängt falsche daten von µC Slave


von M. H. (dbzwerg)


Angehängte Dateien:

Lesenswert?

Hallo,


ich hab da ein Problem mit meinem Versuchsaufbau von 2 µC ( mega32 als 
Master, mega 8 als Slave) die per I2C daten austauschen sollen.

Zum Betrieb der i2c(twi) schnittstelle nutze ich die libs von 
http://www.jtronics.de .

Also ich habe es jetzt soweit hinbekommen das ich daten von master zum 
slave senden kann, diese kommen auch richtig an.
Allerdings bekomm ich die Daten nicht wieder vom Master aus zurück 
gelesen bzw. die datenbytes haben immer den inhalt "0".

Gedacht war es meinerseits so das (zu Testzwecken) der Master 3 Bytes an 
den Slave sendet und nach erfolgtem senden in ein defniertes Statusbyte 
das 1 Bit setzt. Dies klappt auch.
Allerdings wenn der Master dieses Statusbyte ausliest erhällt der Master 
immer ne "0".

Hoffe ihr könnt mir helfen

hier mal der code vom master:
1
 
2
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3
4
// Hauptprogramm für den ClockClock Master
5
6
// µC :ATmega32
7
8
// CPU Takt : 16MHz
9
10
// Funktionsbeschreibung:
11
12
//------------------------------
13
14
// Version: V0.1
15
// Datum: 07.08.12
16
17
18
19
//------------------------------
20
21
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
22
23
#include <avr/io.h>
24
#include <avr/interrupt.h> 
25
#include "uart.h" //Enthällt uart funktionen (Achtung uart.c muss in makefile eingetragen werden, wenn dies nicht von der ide gemacht wird)
26
#include <stdlib.h> // enthällt die Umwandlung von int zu char (itoa)
27
#include <util/delay.h> // Enthällt delay funktionen
28
#include <avr/wdt.h>  // Enthält Watchdog Funktionen
29
#include <cc_com.h> // Definitionen für die I2C Kommunikation zwischen den Baugruppen
30
31
#include <avr/pgmspace.h>
32
#include "i2cmaster.h"
33
34
// Definitionen
35
36
  #ifndef F_CPU
37
  #define F_CPU         16000000UL  // CPU Takt in Hz
38
  #endif
39
  #define UART_BAUD_RATE    9600  
40
41
  
42
43
//Deklaration der Variablen
44
45
  volatile unsigned char count_100ms       =  0;
46
  volatile unsigned char count_500ms       =   0;
47
  volatile unsigned char count_1s       =   0;  
48
  volatile unsigned char timestamp       =  0;     // Zeitstempel byte
49
                                //( Bit3 = 100ms; Bit4 =  500ms; Bit5= 1s)                    
50
  volatile unsigned char ccs_data        =  0;    // Buffer zur Speicherung der vom Slave emfpangenen Daten
51
  int data                 =0;    
52
53
//Deklaration der Funktionsprototypen
54
55
  void send_int_uart(int value); // Deklaration für UART INt SEND Unterfunktion
56
  
57
  
58
  void I2CWrite_CCS(uint8_t ADDR, uint8_t CMD, uint8_t DATA) // Funktion zum senden von Daten an I2C Slave ( CCS = ClocClock Slave)
59
    {
60
    i2c_start_wait(ADDR+I2C_WRITE);   // set device address and write mode
61
    i2c_write(CMD);                 // write command
62
    i2c_write(DATA);                  // write data
63
    i2c_stop();                       // set stop conditon = release bus
64
    }
65
  
66
  
67
  unsigned char I2CRead_CCS(uint8_t ADDR, uint8_t CMD) // Funktion zum lesen von Daten aus I2C Slave ( CCS = ClocClock Slave)
68
  {   
69
    int data;
70
    i2c_start_wait(ADDR+I2C_WRITE);   // set device address and write mode
71
    i2c_write(CMD);                 // write command, sendet Startpostion der Leseadresse an Slave
72
    i2c_rep_start   (ADDR+I2C_READ);   // Repeated Start
73
    data = i2c_readNak();      // Liest akutelle Bufferposition vom Slave aus und schrebit sie in die variable "ccs_data"
74
    i2c_stop();              // set stop conditon = release bus
75
    return data;            // Gibt das gelesene Byte an funktion zurück  
76
  }
77
  
78
79
//Interrupts
80
81
82
// Aktion bei Timer 1 Overflow (alle 100ms)
83
ISR (TIMER1_OVF_vect)
84
{
85
  ++count_100ms;      // Intervallzähler inkrementieren
86
  TCNT1 = 40536; // Timer1 vorladen damit er  nach 100ms überläuft
87
}
88
89
// Hauptschleife
90
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
91
  int main (void) // Start Hauptschleife
92
  {
93
  
94
    // Eingänge definieren
95
    
96
97
98
    // Ausgänge definieren
99
      DDRD |=(1<< PD1);       //UART Tx
100
      DDRD |=(1<< PD5);       //Test Led1
101
      DDRD |=(1<< PD6);       //Test Led2
102
    
103
    // UART initialisieren
104
105
      uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );   
106
107
    
108
    // Startkonfig Timer 1 
109
  
110
      TCCR1B |= (1<<CS10);   // Prescaler /64 = Overflow alle 100ms und Timer starten
111
      TCCR1B |= (1<<CS11);   //
112
      
113
      TIMSK |= (1<<TOIE1);   // Overlfow ISR erlauben
114
115
      
116
      TCNT1 = 40536;      // TImer1 vorladen damit er  nach 100ms überläuft
117
    
118
    // I2C initialisieren
119
    
120
      i2c_init();
121
    
122
    
123
    // Global Interrupts aktivieren
124
      sei();  
125
126
      
127
128
  while(1)  // Start Dauerschleife
129
  {
130
      
131
    //Zeit setzen
132
      if ( count_100ms == 1) // 100ms
133
        {
134
          timestamp |= ((1 << 3));
135
          ++count_500ms;
136
          count_100ms = 0;
137
        }
138
139
      if ( count_500ms == 5) // 500ms
140
        {
141
          timestamp |= ((1 << 4));
142
          ++count_1s;
143
          count_500ms = 0;
144
        }
145
146
      if ( count_1s ==2) // 1s
147
        {
148
          timestamp |= ((1 << 5));
149
          count_1s = 0;
150
        }
151
152
153
// Test Taster
154
155
  if((PIND &(1<<PD2)))
156
  {
157
  
158
    for(int address = CCS_ADDRESS_START ; address<= CCS_ADDRESS_END;address++)
159
    {
160
        uart_puts("Statusabfrage von Slaveadresse:");
161
        send_int_uart(address);
162
        ccs_data = I2CRead_CCS(address,CCS_STATUS);// Status des akutellen Slaves prüfen
163
        uart_puts("Status:");
164
        send_int_uart(ccs_data);
165
        uart_puts("\n\r");
166
        
167
        if(ccs_data & CCS_NEW_DATA)
168
        
169
        {
170
        // Wenn noch Daten vom Slave verarbeitet werden passiert nix
171
        uart_puts("Slaveadresse:");
172
        send_int_uart(address);
173
        uart_puts("verarbeit noch alte Daten");
174
        uart_puts("\n\r");
175
        
176
        }
177
        
178
        else
179
        
180
        {
181
          data = 0;
182
          
183
        uart_puts("Neue Daten werden an Slave gesendet...");
184
        uart_puts("\n\r");
185
          
186
          for (int i = CC_DATA_START; i<= CC_DATA_END; i++)  
187
              {
188
                ++data;              // Testdaten
189
                I2CWrite_CCS(address, i, data);
190
                uart_puts("Block Nr.");
191
                send_int_uart(i);
192
                uart_puts(", Inhalt:");
193
                send_int_uart(data);
194
                uart_puts("\n\r");
195
              }
196
          I2CRead_CCS(address,CCS_STATUS);// Status des akutellen Slaves prüfen
197
          ccs_data |= CCS_NEW_DATA;
198
          I2CWrite_CCS(address, CCS_STATUS, ccs_data);  // Für Slave markieren das neue Daten da sind
199
        }
200
    }
201
  }
202
  
203
  
204
//Zeitgesteuerte Aktionen
205
    
206
  //100ms
207
    if ((timestamp & (1<<3))) 
208
    {
209
      
210
      timestamp &= ~((1 << 3)); // Zetistempelbit 100ms löschen
211
    }
212
213
  //500ms
214
    if ((timestamp & (1<<4)))   
215
    {
216
      
217
      timestamp &= ~((1 << 4)); // Zetistempelbit 500ms löschen
218
    }
219
  //1s
220
    if ((timestamp & (1<<5))) 
221
    {
222
      
223
      
224
225
  
226
      timestamp &= ~((1 << 5)); // Zetistempelbit 1s löschen  
227
    }
228
  }//Ende Dauerschleife
229
  }//Ende Hauptschleife
230
231
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
232
233
//Unterfunktion Integerwert über uart ausgeben
234
  void send_int_uart(int value)
235
  {
236
    char buffer [33];
237
    itoa (value,buffer,10);
238
    uart_puts(buffer);
239
  }


und hier der vom Slave:


1
 
2
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3
4
// Demoprogramm für den ClockClock Slave
5
6
// µC :ATmega8
7
8
// CPU Takt : 8MHz
9
10
// Funktionsbeschreibung:
11
12
//------------------------------
13
14
// Version: V0.1
15
// Datum: 05.08.12
16
17
18
19
//------------------------------
20
21
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
22
23
#include <avr/io.h>
24
#include <avr/interrupt.h> 
25
#include "uart.h"         //Enthällt uart funktionen (Achtung uart.c muss in makefile eingetragen werden, wenn dies nicht von der ide gemacht wird)
26
#include <stdlib.h>       // enthällt die Umwandlung von int zu char (itoa)
27
#include <util/delay.h>     // Enthällt delay funktionen
28
#include <avr/wdt.h>        // Enthält Watchdog Funktionen
29
#include <cc_com.h>       // Definitionen für die I2C Kommunikation zwischen den Baugruppen
30
31
#include <avr/pgmspace.h>
32
33
#include "twislave.h"
34
35
// Definitionen
36
37
  #define TIMER1_preload     53036
38
39
  #ifndef F_CPU
40
  #define F_CPU         8000000UL  // CPU Takt in Hz
41
  #endif
42
  #define UART_BAUD_RATE    9600  
43
  #define SLAVE_ADRESSE 0x40                 // Slave-Adresse, wenn niederwertigstes Bit = 1 ist, 
44
                              // sind General Call Anfragen erlaubt 
45
46
47
//Deklaration der Variablen
48
49
 int read                   =  0;    
50
51
volatile unsigned char count_100ms       =  0;
52
volatile unsigned char count_500ms       =   0;
53
volatile unsigned char count_1s       =   0;  
54
volatile unsigned char timestamp       =  0;     // Zeitstempel byte
55
//( Bit3 = 100ms; Bit4 =  500ms; Bit5= 1s) 
56
                               
57
58
//Deklaration der Funktionsprototypen
59
60
void send_int_uart(int value); // Deklaration für UART INt SEND Unterfunktion
61
62
63
void Initialisierung(void)
64
  {
65
  cli();
66
67
  init_twi_slave(SLAVE_ADRESSE);      //TWI als Slave mit Adresse slaveadr starten 
68
  
69
  sei();
70
  }
71
72
73
//Interrupts
74
75
76
// Aktion bei Timer 1 Overflow (alle 100ms)
77
ISR (TIMER1_OVF_vect)
78
{
79
  ++count_100ms;      // Intervallzähler inkrementieren
80
  TCNT1 = 53036;       // Timer1 vorladen damit er  nach 100ms überläuft
81
}
82
83
84
85
86
87
// Hauptschleife
88
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
89
  int main (void) // Start Hauptschleife
90
  {
91
  
92
  
93
  
94
  
95
    // Eingänge definieren
96
    
97
98
99
    // Ausgänge definieren
100
      DDRD |=(1<< PD1);       //UART Tx
101
      DDRD |=(1<< PD5);       //Test Led1
102
      DDRD |=(1<< PD6);       //Test Led2
103
    
104
    // UART initialisieren
105
106
      uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );   
107
108
    
109
      // Startkonfig Timer 1 
110
  
111
        TCCR1B |= (1<<CS10);   // Prescaler /64 = Overflow alle 100ms und Timer starten
112
        TCCR1B |= (1<<CS11);   //
113
        
114
        TIMSK |= (1<<TOIE1);   // Overlfow ISR erlauben
115
116
        
117
        TCNT1 = 53036;      // TImer1 vorladen damit er  nach 100ms überläuft
118
        
119
        
120
      Initialisierung();  //I2C init
121
    
122
    
123
    // Global Interrupts aktivieren
124
      sei();  
125
126
      
127
128
  while(1)  // Start Dauerschleife
129
  {
130
      
131
    //Zeit setzen
132
      if ( count_100ms == 1) // 100ms
133
        {
134
          timestamp |= ((1 << 3));
135
          ++count_500ms;
136
          count_100ms = 0;
137
        }
138
139
      if ( count_500ms == 5) // 500ms
140
        {
141
          timestamp |= ((1 << 4));
142
          ++count_1s;
143
          count_500ms = 0;
144
        }
145
146
      if ( count_1s ==2) // 1s
147
        {
148
          timestamp |= ((1 << 5));
149
          count_1s = 0;
150
        }
151
152
    
153
    //Zeitgesteuerte Aktionen
154
    
155
    //100ms
156
    if ((timestamp & (1<<3))) 
157
    {
158
159
      timestamp &= ~((1 << 3)); // Zetistempelbit 100ms löschen
160
    }
161
162
    //500ms
163
    if ((timestamp & (1<<4)))   
164
    {
165
                    uart_puts("CCS Status:");
166
        uart_puts("\t");
167
        send_int_uart(rxbuffer[CCS_STATUS]);
168
        uart_puts("\n\r");
169
      timestamp &= ~((1 << 4)); // Zetistempelbit 500ms löschen
170
    }
171
172
173
174
    //1s
175
    if ((timestamp & (1<<5))) 
176
    {
177
178
      timestamp &= ~((1 << 5)); // Zetistempelbit 1s löschen  
179
    }
180
181
    
182
    if((rxbuffer[CCS_STATUS] & CCS_NEW_DATA  ) && (read == 0) ) //
183
    
184
      
185
    {
186
        uart_puts("CCS Status:");
187
        uart_puts("\t");
188
        send_int_uart(rxbuffer[CCS_STATUS]);
189
        uart_puts("\n\r");
190
      
191
      read = 0;
192
193
      uart_puts("Daten von Master erhalten:");
194
      uart_puts("\n\r");
195
      
196
        uart_puts("CCS Status:");
197
        uart_puts("\t");
198
        send_int_uart(rxbuffer[CCS_STATUS]);
199
        uart_puts("\n\r");
200
      
201
      
202
      
203
      for (int i = CC_DATA_START; i<= CC_DATA_END; i++)
204
      {
205
        uart_puts("Datenblock Nr:");
206
        send_int_uart(i);uart_puts("\t");
207
        uart_puts("Inhalt:");
208
        send_int_uart(rxbuffer[i]);
209
        uart_puts("\n\r");
210
      }
211
    
212
      read = 1;
213
    }
214
215
216
    if((PIND &(1<<PD2)))
217
    {
218
      
219
      rxbuffer[CCS_STATUS] &= ~(CCS_NEW_DATA); // Alle neuen Daten verarbeitet, bit löschen
220
      
221
      uart_puts("Taster 1 beaetigt, Datenempfang wird dem Master bestaetigt:");
222
      uart_puts("\n\r");
223
    }
224
    
225
      
226
227
  }//Ende Dauerschleife
228
  }//Ende Hauptschleife
229
230
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
231
232
//Unterfunktion Integerwert über uart ausgeben
233
  void send_int_uart(int value)
234
  {
235
    char buffer [33];
236
    itoa (value,buffer,10);
237
    uart_puts(buffer);
238
  }

von Karl H. (kbuchegg)


Lesenswert?

Wenn man sich besonders viele Freunde in einem Forum machen will, dann 
knallt man einfach einen Link hin und die potentiellen Helfer dürfen 
sich dann selbst auf der Website raussuchen, was du wohl an fertigen 
Libs benutzt hast :-)

Soviel zum Thema http://www.jtronics.de

Ich geh mal davon aus, dass du die
LiB_TWI_ATmega_Slave
benutzt.


Hast du den Anfang von twislave.c gelesen?

Diese Lib benutzt 2 Buffer,
* rxbuffer,   da kommt alles rein, was der Master gesendet hat
* txbuffer    von da weg werden die Bytes genommen, die ZUM Master
              gesendet werden.


d.h. in deinem Slave-Code
1
   if((PIND &(1<<PD2)))
2
    {
3
      
4
      rxbuffer[CCS_STATUS] &= ~(CCS_NEW_DATA); // Alle neuen Daten verarbeitet, bit löschen

das ist zwar nett, kriegt der Master aber nie zu Gesicht, weil die TWI 
Routine die Bytes, die sie zum Mater schickt, aus txbuffer entnimmt.
Genauso wie ein Empfang des Status Bytes mittels rxbuffer nicht 
automatisch dafür sorgt, dass die entsprechende Array Position im 
txbuffer gesetzt wird.

von Karl H. (kbuchegg)


Lesenswert?

d.h. deinen Slave Code machst du so
1
    ...
2
3
    if(rxbuffer[CCS_STATUS] & CCS_NEW_DATA)
4
    {
5
      txbuffer[CCS_STATUS] |= CCS_NEW_DATA;    // Master: I am busy
6
      rxbuffer[CCS_STATUS] &= ~(CCS_NEW_DATA);
7
8
      ....
9
10
    }
11
12
13
    if((PIND &(1<<PD2)))
14
    {
15
      txbuffer[CCS_STATUS] &= ~(CCS_NEW_DATA);  // Master: I am ready
16
      
17
      uart_puts("Taster 1 beaetigt, Datenempfang wird dem Master bestaetigt:");
18
      uart_puts("\n\r");
19
    }


Alternativ könnte man das setzen des Status-Busy Flags auch in den TWI 
Interrupt Routinen direkt machen, damit längere Rechenzeit in main nicht 
dazu führt, dass der Master schon das Busy Flag abfragt, noch ehe der 
Slave die Chance hatte es zu setzen.

von M. H. (dbzwerg)


Lesenswert?

Oh mann wie blind muss man sein....vielen dank das hatte ich total 
übersehen!!!

Sorry das ich nur den Link gepostet habe, dachte die seite bzw. die libs 
wären bekannter, daher hatte ich sie nicht extra angefügt.

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.