Forum: Mikrocontroller und Digitale Elektronik I2C, Programm "crashed" beim Sende Versuch


von Julius (Gast)


Lesenswert?

Hi,


dies ist mein zweiter Versuch mit I2C, diesmal das Auslesen einer RTC 
(DS1307).
Sobald die Zeile:
1
i2c_start_wait(rtc_clock+I2C_WRITE);


aktiv ist stellt der Chip das LED blinken ein.
Die LED's blinken bei jedem Durchlauf der While Schleife einmal mehr als 
beim letzten Durchlauf - Ich hoffe das ist eine sichere Methode um 
festzustellen das der Chip nicht neu gestartet ist.

Hat jemand eine Idee warum der Code mit der oben genannten Zeile hängt?


1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <i2cmaster.h> 
4
5
6
#define BAUD 9600
7
#define MYUBRR ((uint16_t) ((F_CPU / ((BAUD) * 16.0)) + .5) - 1)
8
#define LED1 PD6
9
#define LED2 PD7
10
11
12
// contains what the bluetooth module received
13
uint8_t data;
14
15
void USART_Init(unsigned int ubrr) {
16
    // set baud rate
17
    UBRRH = (unsigned char)(ubrr>>8);
18
    UBRRL = (unsigned char)(ubrr);
19
    // enable receiver, transmitter and interrupts for rx/tx
20
    UCSRB = (1<<RXEN) | (1<<TXEN) | (1<<RXCIE) | (1<< TXCIE);
21
}
22
23
24
25
void USART_transmit(char c) {
26
    while ( !(UCSRA & (1<<UDRE)) ) {}
27
    UDR = c;
28
}
29
30
31
32
void transmit_char(char c) {
33
    USART_transmit(c);
34
    USART_transmit('\r');
35
    USART_transmit('\n');
36
}
37
38
39
40
void send_string(char s[]) {
41
    int i =0;
42
43
    while (s[i] != 0x00) {
44
        USART_transmit(s[i]);
45
        i++;
46
    }
47
    USART_transmit('\r');
48
    USART_transmit('\n');
49
50
}
51
52
53
void flash_leds(uint8_t count) {
54
    for (int n=1; n<=count; n++) {
55
        PORTD |= (1 << LED1); // Turn on LED1
56
        PORTD |= (1 << LED2); // Turn on LED2
57
        _delay_ms(200);
58
        PORTD &= ~(1 << LED1); // Turn off LED1
59
        PORTD &= ~(1 << LED2); // Turn off LED2
60
        _delay_ms(200);
61
    }
62
}
63
64
/*
65
0xD0 = 1   1   0   1   0   0   0   0 = write
66
0xD1 = 1   1   0   1   0   0   0   1 = read
67
68
the first 6 bits contain the device id, and the last one tells the device if we want to read from it
69
or write to it
70
*/
71
72
// adress of the rtc clock device/chip
73
#define rtc_clock 0xD0
74
75
76
77
/* example: http://exploreembedded.com/wiki/Real_Time_Clock%28DS1307%29_with_AVR
78
void RTC_Init(void)
79
{
80
    I2C_Init();                             // Initialize the I2c module.
81
    I2C_Start();                            // Start I2C communication
82
 
83
    I2C_Write(C_Ds1307WriteMode_U8);        // Connect to DS1307 by sending its ID on I2c Bus
84
    I2C_Write(C_Ds1307ControlRegAddress_U8);// Select the Ds1307 ControlRegister to configure Ds1307
85
 
86
    I2C_Write(0x00);                        // Write 0x00 to Control register to disable SQW-Out
87
 
88
    I2C_Stop();                             // Stop I2C communication after initializing DS1307
89
}*/
90
91
92
// my init, adapted from the above
93
void init_i2c(void) {
94
    // initialize, taken from peter fleurys i2c example (he wrote the i2c code)
95
    i2c_init();
96
    // connect to the device and tell it that we want to write to it
97
    
98
    i2c_start_wait(rtc_clock+I2C_WRITE);
99
    // this is from rtc.h from the exploreembeeded example: #define C_Ds1307ControlRegAddress_U8  0x07u   // Address to access Ds1307 CONTROL register
100
    // write 0x07 to it, telling it that we want to access the control register
101
    
102
    //i2c_write(0x07);
103
    // see above
104
    
105
    //i2c_write(0x00);
106
    //i2c_stop();                          
107
}
108
 
109
110
111
uint8_t result;
112
113
uint8_t getSeconds(void) {
114
    // receive 1 byte (seconds)
115
    //i2c_start_wait(rtc_clock+I2C_READ);
116
    //result = i2c_readNak();                 
117
    //i2c_stop();
118
    result = 2;
119
    return result;
120
}
121
122
123
124
125
int main(void) {
126
    DDRD |= (1 << LED1);
127
    DDRD |= (1 << LED2);
128
129
    //USART_Init(MYUBRR);
130
    init_i2c();
131
    uint8_t count = 0;
132
    while (1) {
133
        
134
        uint8_t tmp = getSeconds();
135
        //USART_transmit(tmp);       
136
        //transmit_char(count + '0');
137
        count = count + 1;
138
        _delay_ms(3000);
139
        
140
        // flash two leds "count" times...since count is always growing
141
        // one can see if the chip crashed....started flashing from 0.
142
        flash_leds(count);
143
    }
144
}

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Julius schrieb:
> i2c_start_wait(rtc_clock+I2C_WRITE);

Das ist ein Wackeltanz und wird nie zurückkehren, wenn das Device ein 
Problem hat.
Probier mal:
1
uint8_t ret;
2
  ret = i2c_start(rtc_clock+I2C_WRITE);  // set device address and write mode
3
  if ( ret ) {
4
        /* failed to issue start condition, possibly no device found */
5
     i2c_stop();
6
// we can issue an error message here if the device failed to respond
7
8
     } else {
9
 /* issuing start condition ok, device accessible 
10
 we can now use i2c_write() to talk to the device*/
11
12
// and then issue 
13
  i2c_stop();                     // set stop conditon = release bus
14
  }
Denke daran, das wenn du die Soft-I²C Implementierung (i2cmaster.S) 
benutzt, in i2cmaster.S die benutzten Ports und Pins definierst. Das ist 
nicht nötig, wenn du twimaster.c inkludierst.

: Bearbeitet durch User
von Julius (Gast)


Lesenswert?

Habe die i2cmaster.S angepasst auf:

1
 
2
#define SDA             1           
3
#define SCL             0          
4
#define SDA_PORT        PORTC       
5
#define SCL_PORT        PORTC


für Atmega32.
Das hatte ich bisher noch nirgends gelesen :(


Das init_i2c läuft jetzt durch, aber das Lesen der Sekunden klappt noch 
nicht.
Werde das Morgen Vormittag nochmal probieren.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Julius schrieb:
> für Atmega32.
> Das hatte ich bisher noch nirgends gelesen :(

Die Soft-Implementierung von I²C ist eigentlich nur dann nötig, wenn der 
verwendete Controller kein TWI (aka I²C) Hardware Interface hat oder du 
Pins benutzen musst, die andere sind als die vom TWI Interface.
Beim Mega32 kannst du also i2cmaster.s rauswerfen und stattdessen 
twimaster.c mit kompilieren, dann wird das Hardware Interface des Mega32 
benutzt.

Für twimaster.c sind keine weiteren Pindefinitionen notwendig, da 
natürlich die Pins SCA und SDL benutzt werden. Das passt ja bei dir.

: Bearbeitet durch User
von Julius (Gast)


Lesenswert?

Ah, danke für die Info.

Bin jetzt Erstmal mit der Software Implementierung weiter gekommen, der 
angehängte Code funktioniert auf einem ATmega16:

Ist jetzt auch ein anderes RTC Modul, kann sein das das erste defekt (zu 
heiß gelötet) oder Batterie leer war, aber zumindest der Code hier gibt 
schon einmal die Sekunden per Bluetooth aus.

Auf Android "Bluetooth Terminal" (Schwarzes Shell Symbol mit kleinem 
Bluetooth Zeichen in der rechten unteren Ecke) - Sehe den Author gerade 
nicht aber das Symbol ist einfach zu erkennen.


Problematisch ist jetzt noch die Umwandlung von uint8_t (Datenformat des 
I2C Chips) nach char (Eingabe für den Bluetooth Code)
Erstaunlich wieviele stumpfe Antworten es dafür gibt die man mit Google 
findet von denen keine funktioniert.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <i2cmaster.h> 
4
5
6
#define BAUD 9600
7
#define MYUBRR ((uint16_t) ((F_CPU / ((BAUD) * 16.0)) + .5) - 1)
8
#define LED1 PD6
9
#define LED2 PD7
10
11
12
// contains what the bluetooth module received
13
uint8_t data;
14
15
void USART_Init(unsigned int ubrr) {
16
    // set baud rate
17
    UBRRH = (unsigned char)(ubrr>>8);
18
    UBRRL = (unsigned char)(ubrr);
19
    // enable receiver, transmitter and interrupts for rx/tx
20
    UCSRB = (1<<RXEN) | (1<<TXEN) | (1<<RXCIE) | (1<< TXCIE);
21
}
22
23
24
25
void USART_transmit(char c) {
26
    while ( !(UCSRA & (1<<UDRE)) ) {}
27
    UDR = c;
28
}
29
30
31
32
void transmit_char(char c) {
33
    USART_transmit(c);
34
    USART_transmit('\r');
35
    USART_transmit('\n');
36
}
37
38
39
40
void send_string(char s[]) {
41
    int i =0;
42
43
    while (s[i] != 0x00) {
44
        USART_transmit(s[i]);
45
        i++;
46
    }
47
    USART_transmit('\r');
48
    USART_transmit('\n');
49
50
}
51
52
53
void flash_led1(uint8_t count) {
54
    for (int n=1; n<=count; n++) {
55
        PORTD |= (1 << LED1); // Turn on LED1
56
        //PORTD |= (1 << LED2); // Turn on LED2
57
        _delay_ms(300);
58
        PORTD &= ~(1 << LED1); // Turn off LED1
59
        //PORTD &= ~(1 << LED2); // Turn off LED2
60
        _delay_ms(300);
61
    }
62
}
63
64
65
void flash_led2(uint8_t count) {
66
    for (int n=1; n<=count; n++) {
67
        //PORTD |= (1 << LED1); // Turn on LED1
68
        PORTD |= (1 << LED2); // Turn on LED2
69
        _delay_ms(1000);
70
        //PORTD &= ~(1 << LED1); // Turn off LED1
71
        PORTD &= ~(1 << LED2); // Turn off LED2
72
        _delay_ms(1000);
73
    }
74
}
75
76
77
void flash_led2_long(uint8_t count) {
78
    for (int n=1; n<=count; n++) {
79
        //PORTD |= (1 << LED1); // Turn on LED1
80
        PORTD |= (1 << LED2); // Turn on LED2
81
        _delay_ms(3000);
82
        //PORTD &= ~(1 << LED1); // Turn off LED1
83
        PORTD &= ~(1 << LED2); // Turn off LED2
84
        _delay_ms(3000);
85
    }
86
}
87
88
89
void flash_all_leds(void) {
90
    for (uint8_t n = 0; n <= 3; n++) {
91
        PORTD |= (1 << LED1); // Turn on LED1
92
        PORTD |= (1 << LED2); // Turn on LED2
93
        _delay_ms(500);
94
        PORTD &= ~(1 << LED1); // Turn off LED1
95
        PORTD &= ~(1 << LED2); // Turn off LED2
96
        _delay_ms(500);
97
    }
98
}
99
100
/*
101
0xD0 = 1   1   0   1   0   0   0   0 = write
102
0xD1 = 1   1   0   1   0   0   0   1 = read
103
104
the first 6 bits contain the device id, and the last one tells the device if we want to read from it
105
or write to it
106
*/
107
108
// adress of the rtc clock device/chip
109
#define rtc_clock 0xD0
110
111
112
113
/* example: http://exploreembedded.com/wiki/Real_Time_Clock%28DS1307%29_with_AVR
114
void RTC_Init(void)
115
{
116
    I2C_Init();                             // Initialize the I2c module.
117
    I2C_Start();                            // Start I2C communication
118
 
119
    I2C_Write(C_Ds1307WriteMode_U8);        // Connect to DS1307 by sending its ID on I2c Bus
120
    I2C_Write(C_Ds1307ControlRegAddress_U8);// Select the Ds1307 ControlRegister to configure Ds1307
121
 
122
    I2C_Write(0x00);                        // Write 0x00 to Control register to disable SQW-Out
123
 
124
    I2C_Stop();                             // Stop I2C communication after initializing DS1307
125
}*/
126
127
128
// my init, adapted from the above
129
void init_i2c(void) {
130
    // initialize, taken from peter fleurys i2c example (he wrote the i2c code)
131
    i2c_init();
132
    // connect to the device and tell it that we want to write to it
133
    
134
    //i2c_start_wait(rtc_clock+I2C_WRITE);
135
    // this is from rtc.h from the exploreembeeded example: #define C_Ds1307ControlRegAddress_U8  0x07u   // Address to access Ds1307 CONTROL register
136
    // write 0x07 to it, telling it that we want to access the control register
137
    uint8_t ret;
138
    ret = i2c_start(rtc_clock+I2C_WRITE);  // set device address and write mode
139
    if ( ret ) {
140
        flash_led2_long(1);
141
        /* failed to issue start condition, possibly no device found */
142
        i2c_stop();
143
        // we can issue an error message here if the device failed to respond
144
145
     } else {
146
        flash_led1(1);
147
        i2c_write(0x07);
148
        // see above
149
    
150
        i2c_write(0x00);
151
        i2c_stop();     
152
    }
153
       
154
}
155
156
157
typedef struct {
158
      uint8_t sec;
159
      uint8_t min;
160
      uint8_t hour;
161
      uint8_t weekDay;
162
      uint8_t date;
163
      uint8_t month;
164
      uint8_t year;  
165
} rtc_t;
166
167
rtc_t rtc;
168
169
void setClock(rtc_t *rtc) {
170
  rtc->hour = 0x00; //  10:40:20 am
171
    rtc->min =  0x40;
172
    rtc->sec =  0x00;
173
174
    rtc->date = 0x01; //1st Jan 2016
175
    rtc->month = 0x01;
176
    rtc->year = 0x16;
177
    rtc->weekDay = 5;
178
    
179
  uint8_t ret;
180
    ret = i2c_start(rtc_clock+I2C_WRITE);  // set device address and write mode
181
    if ( ret ) {
182
        flash_led2_long(1);
183
        /* failed to issue start condition, possibly no device found */
184
        i2c_stop();
185
        // we can issue an error message here if the device failed to respond
186
187
     } else {
188
         i2c_write(0x00);
189
      i2c_write(rtc->sec);                    // Write sec from RAM address 00H
190
      i2c_write(rtc->min);                    // Write min from RAM address 01H
191
      i2c_write(rtc->hour);                    // Write hour from RAM address 02H
192
      i2c_write(rtc->weekDay);                // Write weekDay on RAM address 03H
193
      i2c_write(rtc->date);                    // Write date on RAM address 04H
194
      i2c_write(rtc->month);                    // Write month on RAM address 05H
195
      i2c_write(rtc->year);                    // Write year on RAM address 06h
196
      i2c_stop();
197
  }  
198
}
199
 
200
201
202
uint8_t result;
203
204
uint8_t getSeconds(void) {
205
    // receive 1 byte (seconds)
206
    
207
    /*i2c_start_wait(rtc_clock+I2C_READ);
208
    result = i2c_readNak();                 
209
    i2c_stop();
210
    result = 2;
211
    return result;*/
212
213
    uint8_t ret;
214
    ret = i2c_start(rtc_clock+I2C_WRITE);  // set device address and write mode
215
    if ( ret ) {
216
        flash_led2_long(3);
217
        /* failed to issue start condition, possibly no device found */
218
        i2c_stop();
219
        // we can issue an error message here if the device failed to respond
220
221
     } else {
222
        /* issuing start condition ok, device accessible 
223
        we can now use i2c_write() to talk to the device*/
224
          
225
        flash_led1(2);
226
227
        // request second ram adress
228
        i2c_write(0x00);
229
        i2c_stop();
230
231
        // _rep_start or _start? whats the difference?
232
        i2c_rep_start(rtc_clock+I2C_READ);
233
        result = i2c_readNak(); 
234
        i2c_stop();
235
    }
236
   return result;
237
238
    
239
}
240
241
242
243
244
int main(void) {
245
    DDRD |= (1 << LED1);
246
    DDRD |= (1 << LED2);
247
248
    // test the leds
249
    flash_all_leds();
250
    USART_Init(MYUBRR);
251
    init_i2c();
252
  setClock(&rtc);
253
    uint8_t count = 0;
254
    while (1) {
255
        
256
        uint8_t tmp = getSeconds();
257
        transmit_char(tmp);       
258
        //transmit_char(count + '0');
259
        count = count + 1;
260
        _delay_ms(2000);
261
        
262
        // flash LED1 "count" times to see if the program crashed
263
        
264
        //flash_led1(tmp);
265
        //flash_all_leds();
266
    }
267
}

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Julius schrieb:
> Problematisch ist jetzt noch die Umwandlung von uint8_t (Datenformat des
> I2C Chips) nach char (Eingabe für den Bluetooth Code)

Faule Leute mit Speicherplatz im Flash ziehen sich dafür die 'stdlib.h' 
ins Projekt und benutzen dann die 'itoa' Funktion. Allerdings gibts auch 
kleine Helferlein, die das ohne die stdlib hinkriegen, du solltest z.B. 
mal nach 'hex2asc' oder 'bin2asc' suchen.

von Julius (Gast)


Lesenswert?

Ja, die itoa benutze ich natürlich liebend gerne.

Momentan zählt er die Sekunden von 0 bis 89 hoch, keine Ahnung.
Aber generell tut die itoa.
Ein Ausschnitt aus dem lauffähigen Code:

1
          // second, minute, hour, weekday, date, month, year
2
uint8_t time[] = {0x10,0x15,0x20, 0x01, 0x02, 0x04, 0x17};
3
4
void setClock(void) {
5
  
6
  uint8_t ret;
7
    ret = i2c_start(rtc_clock+I2C_WRITE);  // set device address and write mode
8
    if ( ret ) {
9
        flash_led2_long(1);
10
        /* failed to issue start condition, possibly no device found */
11
        i2c_stop();
12
        // we can issue an error message here if the device failed to respond
13
14
     } else {
15
    i2c_write(0x00);
16
    
17
    i2c_write(time[0]);
18
    i2c_write(time[1]);
19
    i2c_write(time[2]);
20
    i2c_write(time[3]);
21
    i2c_write(time[4]);
22
    i2c_write(time[5]);
23
    i2c_write(time[6]);
24
25
    i2c_stop();
26
  }
27
28
}
29
 
30
31
32
uint8_t result;
33
34
void getSeconds(void) {
35
    uint8_t ret;
36
    ret = i2c_start(rtc_clock+I2C_WRITE);  // set device address and write mode
37
    if ( ret ) {
38
        flash_led2_long(3);
39
        /* failed to issue start condition, possibly no device found */
40
        i2c_stop();
41
        // we can issue an error message here if the device failed to respond
42
43
     } else {
44
        /* issuing start condition ok, device accessible 
45
        we can now use i2c_write() to talk to the device*/
46
          
47
        flash_led1(2);
48
49
        // request second ram adress
50
        i2c_write(0x00);
51
        i2c_stop();
52
53
        // _rep_start or _start? whats the difference?
54
        i2c_rep_start(rtc_clock+I2C_READ);
55
        
56
    time[0] = i2c_readAck();
57
    time[1] = i2c_readAck();
58
    time[2] = i2c_readAck();
59
    time[3] = i2c_readAck();
60
    time[4] = i2c_readAck();
61
    time[5] = i2c_readAck();
62
    time[6] = i2c_readNak();
63
64
65
        i2c_stop();
66
    }
67
68
    
69
}
70
71
72
73
int main(void) {
74
    DDRD |= (1 << LED1);
75
    DDRD |= (1 << LED2);
76
77
    // test the leds
78
    flash_all_leds();
79
    USART_Init(MYUBRR);
80
    init_i2c();
81
  
82
    setClock();
83
 
84
    
85
86
  char output[7][4];
87
    while (1) {
88
        
89
        getSeconds();
90
91
92
    for (uint8_t n=0; n<sizeof(time); n++) {
93
      itoa(time[n], output[n], 10);
94
    }
95
96
       
97
98
    send_string(output[2]);
99
    send_string(output[1]);
100
    send_string(output[0]);
101
  
102
    send_string(" ");
103
104
105
       
106
        _delay_ms(1000);
107
      
108
    }
109
}

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.