www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik I2C / UART / LCD


Autor: JeyBee66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: FlorianR (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: JeyBee66 (Gast)
Datum:

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

Autor: F. Reiling (freiling)
Datum:

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

Autor: JeyBee66 (Gast)
Datum:

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

#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "i2cmaster.h"
#include "uart.h"
#include "lcd.h"

#ifndef F_CPU
#define F_CPU 16000000UL
#endif

#define UART_BAUD_RATE      9600

#define Dev24C02  0xA0
#define LM75    0xA0      


int main(void)
{
    uint8_t temp;

    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
  lcd_init(LCD_DISP_ON);
  i2c_init();
  sei();
  
  lcd_clrscr();
  lcd_home();
  lcd_puts("Bereit");
  _delay_ms(300);


    while(1)
  {
    i2c_start(Dev24C02+I2C_WRITE);
    temp = i2c_readNak();
    i2c_stop();

    lcd_clrscr();
    lcd_home();
      lcd_puts(temp);
    _delay_ms(300);
    
  }
}


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

Autor: JeyBee66 (Gast)
Datum:

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

Autor: F. Reiling (freiling)
Datum:

Bewertung
0 lesenswert
nicht 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:
while(1)
  {
    toggleLED;

    i2c_start(Dev24C02+I2C_WRITE);
    temp = i2c_readNak();
    i2c_stop();

    lcd_clrscr();
    lcd_home();
      lcd_puts(temp);
    _delay_ms(300);
    
  }

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.

Autor: JeyBee66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: F. Reiling (freiling)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: JeyBee66 (Gast)
Datum:

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

Mfg JeyBee66

Autor: F. Reiling (freiling)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: JeyBee66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "i2cmaster.h"
#include "uart.h"
#include "lcd.h"

#ifndef F_CPU
#define F_CPU 16000000UL
#endif

#define UART_BAUD_RATE      9600

#define Dev24C02  0xA0
#define LM75      0x90


int main(void)
{
    uint8_t temp;

    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
  lcd_init(LCD_DISP_ON);
  i2c_init();
  sei();
  
  lcd_clrscr();
  lcd_home();
  lcd_puts("Bereit");
  _delay_ms(300);

  DDRD = 0xFF;  //LED an PD3

    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);
  }
}

Autor: F. Reiling (freiling)
Datum:

Bewertung
0 lesenswert
nicht 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:
i2c_start(Dev24C02+I2C_READ);

Autor: JeyBee66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh man, das tut mir  jetzt leid :/

hier aktualisiert, jedoch mim selben ergebnis:
    while(1)
  {
    PORTD ^=(1<<PD3);

    i2c_start(LM75+I2C_READ);
    temp = i2c_readNak();
    i2c_stop();

    lcd_clrscr();
    lcd_home();
      lcd_puts(temp);
    _delay_ms(300);
  }

Autor: F. Reiling (freiling)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: JeyBee66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: F. Reiling (freiling)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab die Funktion gefunden. Hatte ich mal geschrieben, da ich ein 
Gerät hatte, von dem ich die Adresse nicht wusste.
/* Sucht nach nächstem Slave der antwortet.
Rückgabe: Adresse des ersten gefundenen Slaves
0 = kein Gerät gefunden
*/
unsigned char i2c_findSlave(unsigned char startAdr)
{
  char fTrue = 1; // 0 -> Gerät gefunden

  while (fTrue && startAdr<256)
  {
    fTrue = i2c_start(startAdr);
    if (!fTrue)
    {
      i2c_stop(); // Stop I2C
      return startAdr;
    }
    else 
    {
      startAdr++;
    }
  }
  return 0;
}
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

Autor: JeyBee66 (Gast)
Datum:

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

Autor: F. Reiling (freiling)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was für ein Display hast du angeschlossen? Und da würde ich mal 
vermuten, wenn du das
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-Tu...
...
    int variable = 42;

    lcd_init();
 
    // Ausgabe des Zeichens dessen ASCII-Code gleich dem Variablenwert ist
    // (Im Beispiel entspricht der ASCII-Code 42 dem Zeichen *)
    // http://www.code-knacker.de/ascii.htm
    lcd_data(variable);
 
    set_cursor(0,2);
 
    // Ausgabe der Variable als Text in dezimaler Schreibweise
    {
       // ... umwandeln siehe FAQ Artikel bei www.mikrocontroller.net
       // WinAVR hat eine itoa()-Funktion, das erfordert obiges #include <stdlib.h>
       char Buffer[20]; // in diesem {} lokal
       itoa( variable, Buffer, 10 ); 
 
       // ... ausgeben  
       lcd_string( Buffer );
    }

Autor: JeyBee66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "i2cmaster.h"
#include "lcd.h"

#ifndef F_CPU
#define F_CPU 16000000UL
#endif

#define Dev24C02  0xA0
#define LM75      0x90


unsigned char i2c_findSlave(unsigned char startAdr)
{
  char fTrue = 1; // 0 -> Gerät gefunden

  while (fTrue && startAdr<256)
  {
    fTrue = i2c_start(startAdr);
    if (!fTrue)
    {
      i2c_stop(); // Stop I2C
      return startAdr;
    }
    else 
    {
      startAdr++;
    }
  }
  return 0;
}


int main(void)
{
    uint8_t temp;

  lcd_init(LCD_DISP_ON);
  i2c_init();
  
  lcd_clrscr();
  lcd_home();
  lcd_puts("Bereit");
  _delay_ms(300);

    //i2c_findSlave(0x00);

    lcd_clrscr();
    lcd_home();
    lcd_puts("startAdr");
    _delay_ms(300);

    while(1)
  {

  }    
}

Autor: F. Reiling (freiling)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: JeyBee66 (Gast)
Datum:

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

Autor: JeyBee66 (Gast)
Datum:

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

Autor: F. Reiling (freiling)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: JeyBee66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Okay, ich danke dir schonmal dazu.
ich dreh hier innerlich durch :/

Mfg JeyBee66

Autor: F. Reiling (freiling)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: JeyBee66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: F. Reiling (freiling)
Datum:

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

Autor: JeyBee66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: F. Reiling (freiling)
Datum:

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

Autor: JeyBee66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <string.h>
#include "i2cmaster.h"
#include "lcd.h"

#ifndef F_CPU
#define F_CPU 16000000UL
#endif

#define M24C02    0xA0         // Device Adresse des EEproms (10100000)
#define LM75    0x90      // Device Adresse des LM75    (10010000)
#define DS1307    0xD0      // Device Adresse des DS2307  (11010000)

unsigned char eeprom_adresse;  // Speicheradresse
unsigned char eeprom_output;  // Byte aus EEprom lesen
unsigned char eeprom_input;    // Byte in EEprom schreiben
unsigned char temp;        // Temperatur aus LM75
unsigned char buffer1[10];    // Buffer für itoa
unsigned char buffer2[10];
unsigned char buffer3[10];


char eeprom_write(unsigned char eeprom_adresse, unsigned char eeprom_input)
{
    i2c_start(M24C02+I2C_WRITE);
    i2c_write(eeprom_adresse);
    i2c_write(eeprom_input);
    i2c_stop();
}

char eeprom_read(unsigned char eeprom_adresse)
{
    i2c_start(M24C02+I2C_WRITE);     
  i2c_write(eeprom_adresse);
    i2c_start_wait(M24C02+I2C_READ);       
    eeprom_output = i2c_readNak();                   
    i2c_stop();
}

char get_temp()
{
    i2c_start_wait(LM75+I2C_READ);       
    temp = i2c_readNak();                   
    i2c_stop();
}


int main(void)
{
  DDRD = 0xFF;
  lcd_init(LCD_DISP_ON);
  i2c_init();

  while(1)
  {
    PORTD ^= (1<<PD3);
    //get_temp();    //Wenn auskiommentiert, okay
    eeprom_read(0x00);
    _delay_ms(300);
    itoa(temp, buffer1, 10);
    itoa(eeprom_output, buffer2, 2);
    
    lcd_clrscr();
    lcd_home();
    lcd_puts("Temperatur: ");
    lcd_puts(buffer1);
    lcd_gotoxy(0,1);
    lcd_puts(buffer2);
    _delay_ms(500);
  }    
}
Mfg JeyBee66

Autor: F. Reiling (freiling)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, probier mal in der Funktion getTemp(): anstatt i2c_start_wait die 
Funktion i2c_start zu verwenden.
Und hier mein Code:
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "i2cmaster.h"
#include "lcd_routines.h"

#define F_CPU 20000000UL

#define Dev24C02  0xA0
#define LM75      0x90


unsigned char i2c_findSlave(unsigned char startAdr)
{
  char fTrue = 1; // 0 -> Gerät gefunden

  while (fTrue && startAdr<128)
  {
    fTrue = i2c_start(startAdr*2);
    if (!fTrue)
    {
      i2c_stop(); // Stop I2C
      return startAdr*2;
    }
    else 
    {
    i2c_stop();
      startAdr++;
    }
  }
  return 0;
}


int main(void)
{
    uint8_t temp;
  char buffer[10];
  DDRB = 0xFF;
  PORTB = 0x00;
   i2c_init();
   temp = i2c_findSlave(0x00);
  lcd_init();
  lcd_clear();
  lcd_home();
  lcd_string("Bereit...");
  set_cursor(0,2);
  lcd_string("I2C-Slave: 0x");
  lcd_string(itoa(temp,buffer,16));

  while (1)
  {
    PORTB ^=(1<<PB0);
    i2c_start(temp);
    i2c_write(0x40);
    i2c_stop();

    _delay_ms(300);
  }
 
}
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.