Forum: Mikrocontroller und Digitale Elektronik I2C / UART / LCD


von JeyBee66 (Gast)


Lesenswert?

Nabend

Ich habe ein kleines Problem. Und zwar habe ich an einem Mega16 sowohl 
UART und I2C in benutztung, als ist auch noch ein LCD dran.
Programmiert wird das ganze in C, benutzt werden die Peter Fleury 
libarys.

Nun zu meinem Problem:
Ich kann nicht den I2C-Bus ansteuern, und in der gleichen while dann 
noch das LCD ansteuern. Sobald ich also z.B. die I2C geschichte 
auskommentiere geht dann das LCD, ohne das aber nicht. Der I2C bus wird 
aber auch vor dem Ansteuern des LCDs relased und die Stop-Condition ist 
auch vorhanden.

Ich kann mir das nur so vorstellen, dass es irgend wo Interrupt Probleme 
gibt. Ich bin echt ratlos. Wie kann ich das Problem lösen?

Vielen dank im Voraus.
JeyBee66

von FlorianR (Gast)


Lesenswert?

Hängt ein I2C-Gerät am Bus? Ich hatte auch mal so ein ähnliches Problem. 
Dabei hat sich die I2C-Funktion aufgehängt, wenn kein Gerät am Bus hing.
mfg

von JeyBee66 (Gast)


Lesenswert?

Doch, da ist immer eines drann. Hier ist es ein LM75, später soll da 
noch ne RTC und ein EEprom ran.

von F. R. (freiling)


Lesenswert?

Stimmt die slave-adresse? Ist das Gerät auch aktiv? Es wäre auch etwas 
hilfreicher, den entsprechenden Code zu posten.
mfg

von JeyBee66 (Gast)


Lesenswert?

Naja, nur als info, das auslesen klapt noch nicht. Ich möchte die 
Temperatur jetzt einfach mal auf dem LCD ausgeben.

1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <avr/signal.h>
5
#include <avr/pgmspace.h>
6
#include <util/delay.h>
7
#include "i2cmaster.h"
8
#include "uart.h"
9
#include "lcd.h"
10
11
#ifndef F_CPU
12
#define F_CPU 16000000UL
13
#endif
14
15
#define UART_BAUD_RATE      9600
16
17
#define Dev24C02  0xA0
18
#define LM75    0xA0      
19
20
21
int main(void)
22
{
23
    uint8_t temp;
24
25
    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
26
  lcd_init(LCD_DISP_ON);
27
  i2c_init();
28
  sei();
29
  
30
  lcd_clrscr();
31
  lcd_home();
32
  lcd_puts("Bereit");
33
  _delay_ms(300);
34
35
36
    while(1)
37
  {
38
    i2c_start(Dev24C02+I2C_WRITE);
39
    temp = i2c_readNak();
40
    i2c_stop();
41
42
    lcd_clrscr();
43
    lcd_home();
44
      lcd_puts(temp);
45
    _delay_ms(300);
46
    
47
  }
48
}


So steht jetzt nur die ganze Zeit "Bereit" auf dem LCD. Wenn ich die 
ganze I2C sache direkt nach der While(1) auskommenitere und 
"lcd_puts(temp);" durch "lcd_puts("temp");" ändere, steht dann auch 
"temp" auf dem LCD. -> Das LCD geht.

mfg JeyBee

von JeyBee66 (Gast)


Lesenswert?

Doublepost:
Ja ich weiss, dass der LM75 und der M24C02 die gleiche adresse haben, es 
ist aber NUR das LM75 eingesteckt.

von F. R. (freiling)


Lesenswert?

Hast du die Möglichkeit, irgendwie ne LED anzuschließen? Ist für 
Debugzwecke immer ganz hilfreich, wenn du das so in deinen Code 
einbaust:
1
while(1)
2
  {
3
    toggleLED;
4
5
    i2c_start(Dev24C02+I2C_WRITE);
6
    temp = i2c_readNak();
7
    i2c_stop();
8
9
    lcd_clrscr();
10
    lcd_home();
11
      lcd_puts(temp);
12
    _delay_ms(300);
13
    
14
  }

toggleLED musst du natürlich irgendwie implementieren, als Funktion, 
Macro, oder wie auch immer.
Aber dann siehst du ob deine Schleife durchlaufen wird.
Wie kommst du eigentlich auf diese Slave-Adresse? Laut Datenblatt des 
LM75 ist diese nämlich 0x90, sofern A0-A2 an GND liegen. 24C02 und LM75 
unterscheiden sich in Bit4+5 der Adresse! Könntest also auch beide an 
den Bus anschließen.

von JeyBee66 (Gast)


Lesenswert?

Hi,

Die LED blinkt, wenn ich das I2C raus nehme. Wenn ich das I2C und das 
LCD drinn habe, dann leuchtet sie dauernt durch (Sie ist zwischen uC und 
GND)


Mfg JeyBee66

von F. R. (freiling)


Lesenswert?

F. Reiling schrieb:
> Wie kommst du eigentlich auf diese Slave-Adresse? Laut Datenblatt des
> LM75 ist diese nämlich 0x90, sofern A0-A2 an GND liegen. 24C02 und LM75
> unterscheiden sich in Bit4+5 der Adresse!

Änder mal die Adresse.

von JeyBee66 (Gast)


Lesenswert?

Hab ich eben....
0x90, aber selbes ergebnis, LED leuchtet durch, LCD bleibt mit "Bereit".

Mfg JeyBee66

von F. R. (freiling)


Lesenswert?

nimm mal: i2c_start(LM75+I2C_READ);
Du willst ja den Sensor auslesen. Hab ich total übersehen. Und als 
Adresse 0x90. Ich kenn zwar den LM75 nicht, aber dann sollte es 
funktionieren.
mfg

von JeyBee66 (Gast)


Lesenswert?

Die adresse 0x90 muss stimmen, da ich die drei Pins auch auf Masse habe 
und 1001 ja die ersten 4 Adressbits sind.
Aber auch so weiterhin eine leuchtende LED und ein LCD, das "Bereit" 
anzeigt.

Ratlos^2

hier nochmal der Code:
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <avr/signal.h>
5
#include <avr/pgmspace.h>
6
#include <util/delay.h>
7
#include "i2cmaster.h"
8
#include "uart.h"
9
#include "lcd.h"
10
11
#ifndef F_CPU
12
#define F_CPU 16000000UL
13
#endif
14
15
#define UART_BAUD_RATE      9600
16
17
#define Dev24C02  0xA0
18
#define LM75      0x90
19
20
21
int main(void)
22
{
23
    uint8_t temp;
24
25
    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
26
  lcd_init(LCD_DISP_ON);
27
  i2c_init();
28
  sei();
29
  
30
  lcd_clrscr();
31
  lcd_home();
32
  lcd_puts("Bereit");
33
  _delay_ms(300);
34
35
  DDRD = 0xFF;  //LED an PD3
36
37
    while(1)
38
  {
39
    PORTD ^=(1<<PD3);
40
41
    i2c_start(Dev24C02+I2C_READ);
42
    temp = i2c_readNak();
43
    i2c_stop();
44
45
    lcd_clrscr();
46
    lcd_home();
47
      lcd_puts(temp);
48
    _delay_ms(300);
49
  }
50
}

von F. R. (freiling)


Lesenswert?

JeyBee66 schrieb:
> while(1)
>   {
>     PORTD ^=(1<<PD3);
>
>     i2c_start(Dev24C02+I2C_READ);
>     temp = i2c_readNak();
>     i2c_stop();
>
>     lcd_clrscr();
>     lcd_home();
>       lcd_puts(temp);
>     _delay_ms(300);
>   }

Ist das der aktuelle Code? Und du hast den LM75 angeschlossen? Dann kann 
das nicht funktionieren, wenn du den 24C02 ansprechen willst. Da sich ja 
kein Gerät am Bus angesprochen fühlt mit der angegebenen Adresse.
Du solltest folgende Zeile korrigieren:
1
i2c_start(Dev24C02+I2C_READ);

von JeyBee66 (Gast)


Lesenswert?

Oh man, das tut mir  jetzt leid :/

hier aktualisiert, jedoch mim selben ergebnis:
1
    while(1)
2
  {
3
    PORTD ^=(1<<PD3);
4
5
    i2c_start(LM75+I2C_READ);
6
    temp = i2c_readNak();
7
    i2c_stop();
8
9
    lcd_clrscr();
10
    lcd_home();
11
      lcd_puts(temp);
12
    _delay_ms(300);
13
  }

von F. R. (freiling)


Lesenswert?

Jetzt fällt mir auch nix mehr ein. Ganz blöde Frage: Ist der Sensor auch 
korrekt angeschlossen? Mit Pullups am Bus, ich glaube typischerweise 
werden 4k7 verwendet. Ist das ganze auf nem Breadboard? Liegen die drei 
Adressbits wirklich auf Masse? Hast du mal eine niedrigere 
I2C-Geschwindigkeit probiert, falls nicht sowieso schon verwendet? Kurze 
Verbindungen zwischen AVR und LM75? Da du am Anfang den Verdacht von 
irgendwelchen Interrupts geäußert hast, dann deaktiviere sie doch 
testweise mal. Denn eigentlich werden sie ja in diesem Fall nicht 
benötigt.
Ich muss mal nachschauen, ich hab irgendwann mal eine Funktion 
geschrieben, die den Bus scannt und die erste gefundene Slave-Adresse 
zurückgibt. Bedingung: Es ist überhaupt ein Gerät angeschlossen. Ich 
schau mal ob ich die finde.

von JeyBee66 (Gast)


Lesenswert?

Das ganze ist auf einer Lochrasterplatine. Pullups sind vorhanden, 
Sensor ist korrekt mit dem uC verbunden, Sensor wurde schon 
ausgetauscht. Das Deaktivieren der Interrupts brauchte kein Ergebnis, es 
ist alles so, wie es ssein sollte....

Ich weiss nicht weiter.

Mfg JeyBee66

von F. R. (freiling)


Lesenswert?

Ich hab die Funktion gefunden. Hatte ich mal geschrieben, da ich ein 
Gerät hatte, von dem ich die Adresse nicht wusste.
1
/* Sucht nach nächstem Slave der antwortet.
2
Rückgabe: Adresse des ersten gefundenen Slaves
3
0 = kein Gerät gefunden
4
*/
5
unsigned char i2c_findSlave(unsigned char startAdr)
6
{
7
  char fTrue = 1; // 0 -> Gerät gefunden
8
9
  while (fTrue && startAdr<256)
10
  {
11
    fTrue = i2c_start(startAdr);
12
    if (!fTrue)
13
    {
14
      i2c_stop(); // Stop I2C
15
      return startAdr;
16
    }
17
    else 
18
    {
19
      startAdr++;
20
    }
21
  }
22
  return 0;
23
}
Den Rückgabewert kannst du ja in ein lesbares Format auf deinem Display 
ausgeben lassen. Ich hab die Funktion damals mit mehreren Devices 
getestet und hatte auch zuverlässig funktioniert. Vielleicht bringt dich 
das weiter.
mfg

von JeyBee66 (Gast)


Lesenswert?

wieso muss ich das umwandeln, ich kann doch ne integer Zahl auf dem LCD 
ausgeben?

von F. R. (freiling)


Lesenswert?

Was für ein Display hast du angeschlossen? Und da würde ich mal 
vermuten, wenn du das
1
lcd_puts(temp);
ausführt, passiert was merkwürdiges, da die Funktion lcd_puts einen 
String erwartet und keinen Integer. Du musst die Zahl in einen 
ASCII-String umwandeln, geht mit itoa() und diesen dann auf dein Display 
ausgeben. Wie z.b. aus dem Tutorial 
(http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung):
1
...
2
    int variable = 42;
3
4
    lcd_init();
5
 
6
    // Ausgabe des Zeichens dessen ASCII-Code gleich dem Variablenwert ist
7
    // (Im Beispiel entspricht der ASCII-Code 42 dem Zeichen *)
8
    // http://www.code-knacker.de/ascii.htm
9
    lcd_data(variable);
10
 
11
    set_cursor(0,2);
12
 
13
    // Ausgabe der Variable als Text in dezimaler Schreibweise
14
    {
15
       // ... umwandeln siehe FAQ Artikel bei www.mikrocontroller.net
16
       // WinAVR hat eine itoa()-Funktion, das erfordert obiges #include <stdlib.h>
17
       char Buffer[20]; // in diesem {} lokal
18
       itoa( variable, Buffer, 10 ); 
19
 
20
       // ... ausgeben  
21
       lcd_string( Buffer );
22
    }

von JeyBee66 (Gast)


Lesenswert?

Interessant:
Wenn ich den Aufruf deiner Funktion auskommentiere, und einen normalen 
String auf dem LCD (zur kontrolle) ausgeben lassen will, gehts nicht. 
Wenn ich deinen Funktionsaufruf jedoch auskomentiere, gehts wieder... 
hier der Aktuelle code
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <avr/signal.h>
5
#include <avr/pgmspace.h>
6
#include <util/delay.h>
7
#include "i2cmaster.h"
8
#include "lcd.h"
9
10
#ifndef F_CPU
11
#define F_CPU 16000000UL
12
#endif
13
14
#define Dev24C02  0xA0
15
#define LM75      0x90
16
17
18
unsigned char i2c_findSlave(unsigned char startAdr)
19
{
20
  char fTrue = 1; // 0 -> Gerät gefunden
21
22
  while (fTrue && startAdr<256)
23
  {
24
    fTrue = i2c_start(startAdr);
25
    if (!fTrue)
26
    {
27
      i2c_stop(); // Stop I2C
28
      return startAdr;
29
    }
30
    else 
31
    {
32
      startAdr++;
33
    }
34
  }
35
  return 0;
36
}
37
38
39
int main(void)
40
{
41
    uint8_t temp;
42
43
  lcd_init(LCD_DISP_ON);
44
  i2c_init();
45
  
46
  lcd_clrscr();
47
  lcd_home();
48
  lcd_puts("Bereit");
49
  _delay_ms(300);
50
51
    //i2c_findSlave(0x00);
52
53
    lcd_clrscr();
54
    lcd_home();
55
    lcd_puts("startAdr");
56
    _delay_ms(300);
57
58
    while(1)
59
  {
60
61
  }    
62
}

von F. R. (freiling)


Lesenswert?

Wie gesagt, meine Funktion funktioniert nur, wenn der Bus korrekt 
funktioniert und auch ein Gerät angeschlossen ist, anderweitig hängt 
sich die Funktion aus der Bibliothek auf, da kein Timeout standardmäßig 
implementiert ist.
Weitere Fragen: welchen Compiler/Entwicklungsumgebung verwendest du?

von JeyBee66 (Gast)


Lesenswert?

Sensor ist 100%ig korrekt angeschlossen..... Sensor wurde ausgetauscht, 
gleiches erebnis... where the hell ist der fehler?!

von JeyBee66 (Gast)


Lesenswert?

Enwicklungsumgebung ist AVR Studio4, aber ja, die MCU ist richtig 
gewählt, Optimierung auf -Os und die Frequenz ist auch auf 16000000Hz 
gelegt....

von F. R. (freiling)


Lesenswert?

Ich hab so langsam echt keine Ahnung mehr, woran es noch liegen könnte. 
Ich kann heute abend mal mein Breadboard rauskramen und versuchen, 
nachzubauen. Hab jetzt aber keine Möglichkeit dazu.
mfg

von JeyBee66 (Gast)


Lesenswert?

Okay, ich danke dir schonmal dazu.
ich dreh hier innerlich durch :/

Mfg JeyBee66

von F. R. (freiling)


Lesenswert?

Hallo,
bin gestern abend nicht mehr zum schreiben gekommen. Allerdings habe ich 
mal wieder mein Breadboard rausgekramt und getestet. Seltsamerweise hat 
bei mir die lcd bibliothek (p.fleury) nicht richtig funktioniert, i2c 
schon. Auch die Funktion zum Scannen des Busses hat problemlos 
funktioniert. Mit der LCD-Bibliothek aus dem GCC-Tutorial hatte ich 
keine Probleme mehr.

von JeyBee66 (Gast)


Lesenswert?

Grml...
Kannst du mir mal deinen gesammten Code posten? Also der der 
Funktioniert (mit slaveadresse rausfinden). Das würde mir als sehr 
hilfreich erscheinen.

Viele Dank für deine Hilfe

JeyBee66

von F. R. (freiling)


Lesenswert?

Muss dich leider auf heute abend vertrösten, hab den Code gerade nicht 
griffbereit.
mfg

von JeyBee66 (Gast)


Lesenswert?

Gute Neuigkeiten, es funktioniert jetzt..

Wenn du mich nun töten willst, nur zu, ansonsten mach ich es selbst....
Ich hatte den PullUp am SCL leider als Pulldown :/

Vielen dank für deine bemühungen, ich bin dir was schuldig.

P.S. krieg ich dann deinen Code trotzdem noch?



Mfg JeyBee66

von F. R. (freiling)


Lesenswert?

... Sag ich mal nix dazu. Aber hauptsache es funktioniert.
Code kann ich dir heute abend schicken, ist aber nichts besonderes.

von JeyBee66 (Gast)


Lesenswert?

ich hab mir jetzt funktionen geschrieben, um ein Byte in ein externe I2C 
EEprom zu schreiben und auch wieder auszulesen. Das selbe, um dem LM75 
auszulesen.
Wenn ich in der main den Funktionsaufruf drin habe, um den LM75 
auszulesen, gehts nix, die LED blinkt nicht, das LCD bleibt leer, wenn 
ich NUR diese eine Funktion auskommentiere, gehts prima. Woran kann denn 
dass nun liegen?

1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <avr/signal.h>
5
#include <avr/pgmspace.h>
6
#include <util/delay.h>
7
#include <string.h>
8
#include "i2cmaster.h"
9
#include "lcd.h"
10
11
#ifndef F_CPU
12
#define F_CPU 16000000UL
13
#endif
14
15
#define M24C02    0xA0         // Device Adresse des EEproms (10100000)
16
#define LM75    0x90      // Device Adresse des LM75    (10010000)
17
#define DS1307    0xD0      // Device Adresse des DS2307  (11010000)
18
19
unsigned char eeprom_adresse;  // Speicheradresse
20
unsigned char eeprom_output;  // Byte aus EEprom lesen
21
unsigned char eeprom_input;    // Byte in EEprom schreiben
22
unsigned char temp;        // Temperatur aus LM75
23
unsigned char buffer1[10];    // Buffer für itoa
24
unsigned char buffer2[10];
25
unsigned char buffer3[10];
26
27
28
char eeprom_write(unsigned char eeprom_adresse, unsigned char eeprom_input)
29
{
30
    i2c_start(M24C02+I2C_WRITE);
31
    i2c_write(eeprom_adresse);
32
    i2c_write(eeprom_input);
33
    i2c_stop();
34
}
35
36
char eeprom_read(unsigned char eeprom_adresse)
37
{
38
    i2c_start(M24C02+I2C_WRITE);     
39
  i2c_write(eeprom_adresse);
40
    i2c_start_wait(M24C02+I2C_READ);       
41
    eeprom_output = i2c_readNak();                   
42
    i2c_stop();
43
}
44
45
char get_temp()
46
{
47
    i2c_start_wait(LM75+I2C_READ);       
48
    temp = i2c_readNak();                   
49
    i2c_stop();
50
}
51
52
53
int main(void)
54
{
55
  DDRD = 0xFF;
56
  lcd_init(LCD_DISP_ON);
57
  i2c_init();
58
59
  while(1)
60
  {
61
    PORTD ^= (1<<PD3);
62
    //get_temp();    //Wenn auskiommentiert, okay
63
    eeprom_read(0x00);
64
    _delay_ms(300);
65
    itoa(temp, buffer1, 10);
66
    itoa(eeprom_output, buffer2, 2);
67
    
68
    lcd_clrscr();
69
    lcd_home();
70
    lcd_puts("Temperatur: ");
71
    lcd_puts(buffer1);
72
    lcd_gotoxy(0,1);
73
    lcd_puts(buffer2);
74
    _delay_ms(500);
75
  }    
76
}
Mfg JeyBee66

von F. R. (freiling)


Lesenswert?

Hallo, probier mal in der Funktion getTemp(): anstatt i2c_start_wait die 
Funktion i2c_start zu verwenden.
Und hier mein Code:
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <avr/interrupt.h>
5
#include <avr/pgmspace.h>
6
#include <util/delay.h>
7
#include "i2cmaster.h"
8
#include "lcd_routines.h"
9
10
#define F_CPU 20000000UL
11
12
#define Dev24C02  0xA0
13
#define LM75      0x90
14
15
16
unsigned char i2c_findSlave(unsigned char startAdr)
17
{
18
  char fTrue = 1; // 0 -> Gerät gefunden
19
20
  while (fTrue && startAdr<128)
21
  {
22
    fTrue = i2c_start(startAdr*2);
23
    if (!fTrue)
24
    {
25
      i2c_stop(); // Stop I2C
26
      return startAdr*2;
27
    }
28
    else 
29
    {
30
    i2c_stop();
31
      startAdr++;
32
    }
33
  }
34
  return 0;
35
}
36
37
38
int main(void)
39
{
40
    uint8_t temp;
41
  char buffer[10];
42
  DDRB = 0xFF;
43
  PORTB = 0x00;
44
   i2c_init();
45
   temp = i2c_findSlave(0x00);
46
  lcd_init();
47
  lcd_clear();
48
  lcd_home();
49
  lcd_string("Bereit...");
50
  set_cursor(0,2);
51
  lcd_string("I2C-Slave: 0x");
52
  lcd_string(itoa(temp,buffer,16));
53
54
  while (1)
55
  {
56
    PORTB ^=(1<<PB0);
57
    i2c_start(temp);
58
    i2c_write(0x40);
59
    i2c_stop();
60
61
    _delay_ms(300);
62
  }
63
 
64
}
Das Programm scannt den I2C-Bus, gibt die Adresse in Hex-Form auf dem 
Display aus. Ausserdem blinkt eine LED an PB0 und es wird dauerhaft der 
Wert 0x40 über I2C an das Gerät 0x58 geschickt. Habe da einen 
I2c-Motorcontroller dranhängen. der lag grad so hier rum.
achja, die lcd-Routinen sind die hier aus dem tutorial
mfg

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.