C LCD Display 1602 am I2C Phillips PCF8574T

flecralf

Mitglied
25. Juli 2013
194
2
18
Sprachen
  1. ANSI C
Hallo alle zusammen,
um einen mobilen und den damit verbundenden Batteriebetrieb zu ermöglichen, möchte ich
eine 7-Segment-Anzeige (zieht 200 mA, 9 V-Block wäre da raus, höchsten ne Autobatterie... ;-) ) durch ein LCD-Display ersetzen.
Nun habe ich ein paar Quellen gefunden, welche sich auf die Arduino-Boards beziehen.
Ich habe hier lediglich einen einsamen Atmega8, lieblos auf einer öden schnödenLochraster-Platine
und kann mit den Arduino-libraries so kann nichts anfangen.

Es ist genau das mit der A0 A1 A2-Kennungm siehe Foto im Anhang, aus folgendem Link:
http://arduino-info.wikispaces.com/LCD-Blue-I2C#v1
Weitere technische Informationen habe ich hier gefunden:
https://www.openhacks.com/uploadsproductos/eone-1602a1.pdf

Meine Frage ist nun, bevor ich damit anfange und es eine wochenlange Aktion gibt, ob denn jemand so ein Ding schon mal zum Leben erweckt hat.
Erste Versuch der Adaption scheiterten kläglich..... das Ding reagiert auf nichts und verharrt stur mit einem demonstrativem Balken.....
Eilt aber nicht, ist nur die Kür eines Projektes und für die Galerie... :)

Peter Fleury wird des öfteren genannt..... er hat wohl einiges an Vorarbeit geleistet....
http://homepage.hispeed.ch/peterfleury/index.html

Gruß und Dank schon mal für Anregungen
Ralf
 

Anhänge

  • lcd1602_qapass_i2c_pcf_8574t_.png
    lcd1602_qapass_i2c_pcf_8574t_.png
    794,8 KB · Aufrufe: 18
Zuletzt bearbeitet:
Hallo alle zusammen,
um einen mobilen und den damit verbundenden Batteriebetrieb zu ermöglichen, möchte ich
eine 7-Segment-Anzeige (zieht 200 mA, 9 V-Block wäre da raus, höchsten ne Autobatterie... ;-) ) durch ein LCD-Display ersetzen.
Nun habe ich ein paar Quellen gefunden, welche sich auf die Arduino-Boards beziehen.
Ich habe hier lediglich einen einsamen Atmega8, lieblos auf einer öden schnödenLochraster-Platine
und kann mit den Arduino-libraries so kann nichts anfangen.

Es ist genau das mit der A0 A1 A2-Kennungm siehe Foto im Anhang, aus folgendem Link:
http://arduino-info.wikispaces.com/LCD-Blue-I2C#v1
Weitere technische Informationen habe ich hier gefunden:
https://www.openhacks.com/uploadsproductos/eone-1602a1.pdf

Meine Frage ist nun, bevor ich damit anfange und es eine wochenlange Aktion gibt, ob denn jemand so ein Ding schon mal zum Leben erweckt hat.
Erste Versuch der Adaption scheiterten kläglich..... das Ding reagiert auf nichts und verharrt stur mit einem demonstrativem Balken.....
Eilt aber nicht, ist nur die Kür eines Projektes und für die Galerie... :)

Peter Fleury wird des öfteren genannt..... er hat wohl einiges an Vorarbeit geleistet....
http://homepage.hispeed.ch/peterfleury/index.html

Gruß und Dank schon mal für Anregungen
Ralf
 
Hab' jetzt mal die i2c-Adaptierung von Fleury mit einer Erweiterung der Seite verbunden
http://computerheld.de/i2clcd/doc/index.html.


Im folgenden erscheinen vier Dateien:
main.c
i2clcd.c
i2clcd.h
i2cmaster.h
i2cmaster.S ist der Assembler-Code... den habe ich mal weg gelassen




CodeBox C
/*
MAIN.C
*/
#include <avr/io.h>
#include "i2cmaster.h" // i2c von Fleury
#include "i2clcd.h" // LCD-Erweiterung

#define Dev24C02  0xA2  // device address of EEPROM 24C02, see datasheet
int main(void)
{
  unsigned char ret;

  DDRB  = 0xff;  // use all pins on port B for output
  PORTB = 0xff;  // (active low LED's )
     lcd_init();  //-  Display initialization
  char string[] = "Hi World";
  lcd_print(string);  //-  Print a string
  lcd_gotolr(2,4);  //-  Move to position (line 2, row 4)

  //-  Turn cursor off and activate blinking
  lcd_command(LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKINGON);

}





CodeBox C
/*****************************************************************************
i2clcd.h - LCD over I2C library
  Designed for HD44870 based LCDs with I2C expander PCF8574X
  on Atmels AVR MCUs
Copyright (C) 2006 Nico Eichelmann and Thomas Eichelmann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
You can contact the authors at info@computerheld.de
*****************************************************************************/
#ifndef _I2CLCD_H
#define _I2CLCD_H

//--System-Configuration-Settings------------------------------------------------------------------------------------

#ifndef F_CPU
  #define F_CPU 8000000
#endif

#define wait1us _delay_loop_1((F_CPU * 0.000001) / 3)
#define wait1ms _delay_loop_2((F_CPU * 0.001) / 4)

//-------------------------------------------------------------------------------------------------------------------

#include <util/delay.h>
#include <stdbool.h>
#include <stdint.h>
#include "i2cmaster.h"

//--Display-Configuration-Settings-----------------------------------------------------------------------------------

#define LCD_I2C_DEVICE  0x40
#define LCD_LINES  2
#define LCD_ROWS  16
#define LCD_LINE1  0x00
#define LCD_LINE2  0x40
#define LCD_LINE3  0x10
#define LCD_LINE4  0x50

//-------------------------------------------------------------------------------------------------------------------

//--The-following-definitions-are-corresponding-to-the-PIN-Assignment-(see-above)------------------------------------

#define LCD_D4_PIN  0
#define LCD_D5_PIN  1
#define LCD_D6_PIN  2
#define LCD_D7_PIN  3
#define LCD_RS_PIN  4
#define LCD_RW_PIN  5
#define LCD_EMPTY_PIN  6
#define LCD_E_PIN  7

//-------------------------------------------------------------------------------------------------------------------

#define LCD_D0  (1 << LCD_D4_PIN)
#define LCD_D1  (1 << LCD_D5_PIN)
#define LCD_D2  (1 << LCD_D6_PIN)
#define LCD_D3  (1 << LCD_D7_PIN)
#define LCD_D4  (1 << LCD_D4_PIN)
#define LCD_D5  (1 << LCD_D5_PIN)
#define LCD_D6  (1 << LCD_D6_PIN)
#define LCD_D7  (1 << LCD_D7_PIN)
#define LCD_RS  (1 << LCD_RS_PIN)
#define LCD_RW  (1 << LCD_RW_PIN)
#define LCD_EMPTY  (1 << LCD_EMPTY_PIN)
#define LCD_E  (1 << LCD_E_PIN)


#define LCD_ADDRESS  0
#define LCD_DATA  1

//-LCD-COMMANDS------------------------------------------------------------------------------------------------------

#define LCD_CLEAR  0x01
#define LCD_HOME  0x02


#define LCD_ENTRYMODE  0x04
  #define LCD_INCREASE  LCD_ENTRYMODE | 0x02
  #define LCD_DECREASE  LCD_ENTRYMODE | 0x00
  #define LCD_DISPLAYSHIFTON  LCD_ENTRYMODE | 0x01
  #define LCD_DISPLAYSHIFTOFF  LCD_ENTRYMODE | 0x00


#define LCD_DISPLAYMODE  0x08
  #define LCD_DISPLAYON  LCD_DISPLAYMODE | 0x04
  #define LCD_DISPLAYOFF  LCD_DISPLAYMODE | 0x00
  #define LCD_CURSORON  LCD_DISPLAYMODE | 0x02
  #define LCD_CURSOROFF  LCD_DISPLAYMODE | 0x00
  #define LCD_BLINKINGON  LCD_DISPLAYMODE | 0x01
  #define LCD_BLINKINGOFF  LCD_DISPLAYMODE | 0x00


#define LCD_SHIFTMODE  0x10
  #define LCD_DISPLAYSHIFT  LCD_SHIFTMODE | 0x08
  #define LCD_CURSORMOVE  LCD_SHIFTMODE | 0x00
  #define LCD_RIGHT  LCD_SHIFTMODE | 0x04
  #define LCD_LEFT  LCD_SHIFTMODE | 0x00


#define LCD_CONFIGURATION  0x20
  #define LCD_8BIT  LCD_CONFIGURATION | 0x10
  #define LCD_4BIT  LCD_CONFIGURATION | 0x00
  #define LCD_2LINE  LCD_CONFIGURATION | 0x08
  #define LCD_1LINE  LCD_CONFIGURATION | 0x00
  #define LCD_5X10  LCD_CONFIGURATION | 0x04
  #define LCD_5X7  LCD_CONFIGURATION | 0x00

//-------------------------------------------------------------------------------------------------------------------

//-FUNCTIONS---------------------------------------------------------------------------------------------------------

//das extern habe ich mal probiert ohne Erfolg....
extern void lcd_init(void);  //-  Display initialization sequence

void lcd_write_i2c(unsigned char value);  //-  Write data to i2c

void lcd_write(unsigned char value);  //-  Write byte to display with toggle of enable-bit

bool lcd_gotolr(unsigned char line, unsigned char row); //-  Go to position

void lcd_putchar(unsigned char value);  //-  Put char to cursor position

bool lcd_putcharlr(unsigned char line, unsigned char row, unsigned char value); //-  Put char to position

void lcd_print(unsigned char *string);  //-  Print string to cursor position

bool lcd_printlr(unsigned char line, unsigned char row , unsigned char *string);  //-  Print string to position

bool lcd_printlc(unsigned char line, unsigned char row, unsigned char *string);  //-  Print string to position
  //-  (If string is longer than LCD_ROWS
  //-  overwrite first chars)

bool lcd_printlrc(unsigned char line, unsigned char row, unsigned char *string);  //-  Print string to position
  //-  (If string is longer than LCD_ROWS
  //-  continue in next line)

void lcd_command(unsigned char command);  //-  Issue a command to the display (use the defined commands above)

bool lcd_nextline(void);  //-  Go to nextline (if next line > LCD_LINES return false)

unsigned char lcd_read_i2c(void);  //-  Read data from i2c

unsigned char lcd_read(bool mode);  //-  Read data from display over i2c
  //-  (second nibble corresponds to highbyte or lowbyte)

unsigned char lcd_getbyte(bool mode);  //-  Read one complete byte over i2c from display

bool lcd_getlr(unsigned char *line, unsigned char*row); //-  Get line and row (target byte for line, target byte for row)

bool lcd_busy(void);  //-  Check if busy

void lcd_wait_us(unsigned short us);  //-  Wait some microseconds

void lcd_wait_ms(unsigned short ms);  //-  Wait some milliseconds

//-------------------------------------------------------------------------------------------------------------------
#endif









CodeBox C
/*****************************************************************************
i2clcd.c - LCD over I2C library
  Designed for HD44870 based LCDs with I2C expander PCF8574X
  on Atmels AVR MCUs
Copyright (C) 2006 Nico Eichelmann and Thomas Eichelmann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
You can contact the authors at info@computerheld.de
*****************************************************************************/

/*
  Version 0.1
  Requires I2C-Library from Peter Fleury http://jump.to/fleury

  See i2clcd.h for description and example.
*/

#include "i2clcd.h"

//-  Display initialization sequence
void lcd_init(void)
{
  lcd_wait_ms(16);  //-  Wait for more than 15ms after VDD rises to 4.5V
  lcd_write(LCD_D5 | LCD_D4);  //-  Set interface to 8-bit
  lcd_wait_ms(5);  //-  Wait for more than 4.1ms
  lcd_write(LCD_D5 | LCD_D4);  //-  Set interface to 8-bit
  lcd_wait_us(101);  //-  Wait for more than 100us
  lcd_write(LCD_D5 | LCD_D4);  //-  Set interface to 8-bit
  lcd_write(LCD_D5);  //-  Set interface to 4-bit

  //- From now on in 4-bit-Mode
  lcd_command(LCD_4BIT | LCD_2LINE | LCD_5X7);  //-  2-Lines, 5x7-Matrix
  lcd_command(LCD_DISPLAYOFF);  //-  Display off
  lcd_command(LCD_CLEAR);  //-  Clear Screen
  lcd_command(LCD_INCREASE | LCD_DISPLAYSHIFTOFF);  //-  Entrymode (Display Shift: off, Increment Address Counter)
  lcd_command(LCD_DISPLAYON);  //-  Display on
}

//-  Write data to i2c
void lcd_write_i2c(unsigned char value)
{
  i2c_start_wait(LCD_I2C_DEVICE+I2C_WRITE);
  i2c_write(value);
  i2c_stop();
}

//-  Write byte to display with toggle of enable-bit
void lcd_write(unsigned char value)
{
  lcd_write_i2c(value | LCD_E);  //-  Set enable to high
  lcd_write_i2c(value | LCD_E);  //-  Send data, keep enable high
  lcd_write_i2c(value & (!LCD_E));  //-  Set enable to low
}

//-  Print string to cursor position
void lcd_print(unsigned char *string)
{
  unsigned char i = 0;
  while(string[i] != 0x00)
  {
  lcd_putchar(string[i]);
  i++;
  }
}

//-  Put char to cursor position
void lcd_putchar(unsigned char value)
{
  unsigned char lcddata;
  lcddata = value;
  lcddata >>= 4;
  lcddata |= LCD_RS;
  lcd_write(lcddata);
  lcddata = value;
  lcddata &= 0x0F;
  lcddata |= LCD_RS;
  lcd_write(lcddata);
}

//-  Put char to position
bool lcd_putcharlr(unsigned char line, unsigned char row, unsigned char value)
{
  if(!lcd_gotolr(line, row)) return false;
  lcd_putchar(value);

  return true;
}

//-  Issue a command to the display (use the defined commands above)
void lcd_command(unsigned char command)
{
  unsigned char lcddata;
  lcddata = command;
  lcddata >>=  4;
  lcd_write(lcddata);
  lcddata = command;
  lcddata &= 0x0F;
  lcd_write(lcddata);
}

//-  Print string to position (If string is longer than LCD_ROWS overwrite first chars)(line, row, string)
bool lcd_printlc(unsigned char line, unsigned char row, unsigned char *string)
{
  unsigned char i;

  for(i = 0; string[i] != 0x00; i++)
  {
  if (!lcd_putcharlr(line, row, string[i])) return false;
  row++;
  if(row > LCD_ROWS)
  {
  row = 1;
  }
  }
  return true;
}

//-  Print string to position (If string is longer than LCD_ROWS continue in next line)(line, row, string)
bool lcd_printlrc(unsigned char line, unsigned char row, unsigned char *string)
{
  unsigned char i;

  for(i = 0; string[i] != 0x00; i++)
  {
  if(!lcd_putcharlr(line, row, string[i])) return false;
  row++;
  if(row > LCD_ROWS)
  {
  line++;
  row = 1;
  }
  if(line > LCD_LINES)
  {
  line = 1;
  }
  }
  return true;
}

//-  Print string to position (line, row, string)
bool lcd_printlr(unsigned char line, unsigned char row, unsigned char *string)
{
  if(!lcd_gotolr(line, row)) return false;
  lcd_print(string);

  return true;
}

//-  Go to position (line, row)
bool lcd_gotolr(unsigned char line, unsigned char row )
{
  unsigned char lcddata;

  if(line > LCD_LINES) return false;
  if(row > LCD_ROWS) return false;
  if((line == 0) || (row == 0) ) return false;

  lcddata = LCD_D7;
#if LCD_LINES>=2
  if (line == 2) lcddata = LCD_D7 |  (LCD_LINE2 >> 4);
#endif
#if LCD_LINES>=3
  if (line == 3) lcddata = LCD_D7 |  (LCD_LINE3 >> 4);
#endif
#if LCD_LINES>=4
  if (line == 4) lcddata = LCD_D7 |  (LCD_LINE4 >> 4);
#endif
  lcd_write(LCD_E | lcddata);
  lcddata = (row-1);
  lcd_write(LCD_E | lcddata);

  return true;
}

//-  Go to nextline (if next line > LCD_LINES return false)
bool lcd_nextline(void)
{
  unsigned char line = 0x00, row = 0x00;
  lcd_getlr(&line, &row);
  if (!lcd_gotolr(line + 1, 1)) return false;
  else return true;
}

//-  Read data from i2c
unsigned char lcd_read_i2c(void)
{
  unsigned char lcddata = 0x00;
  i2c_start_wait(LCD_I2C_DEVICE+I2C_READ);
  lcddata = i2c_readNak();
  i2c_stop();
  return lcddata;
}

//-  Read data from display over i2c (second nibble corresponds to highbyte or lowbyte)
unsigned char lcd_read(bool mode)
{
  unsigned char lcddata;
  if(mode == LCD_DATA)
  lcd_write_i2c(LCD_E | LCD_RS | LCD_RW | LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7);
  else
  lcd_write_i2c(LCD_E | LCD_RW | LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7);

  lcddata = lcd_read_i2c();
  lcd_write_i2c(0x00);
  return lcddata;
}

//-  Read one complete byte over i2c from display
unsigned char lcd_getbyte(bool mode)
{
  unsigned char hib, lob;
  hib = lcd_read(mode);
  lob = lcd_read(mode);
  return (hib << 4) + (lob & 0x0F);
}

//-  Get line and row (target byte for line, target byte for row)
bool lcd_getlr(unsigned char *line, unsigned char *row)
{
  unsigned char lcddata, tmp;
  lcddata =  lcd_getbyte(LCD_ADDRESS);
  if (lcddata & (1 << 7)) return false;
  tmp = lcddata;
  tmp &= 0xF0;
  switch(tmp)
  {
  case LCD_LINE1:
  *line = 1;
  break;
#if LCD_LINES>=2
  case LCD_LINE2:
  *line = 2;
  break;
#endif
#if LCD_LINES>=3
  case LCD_LINE3:
  *line = 3;
  break;
#endif
#if LCD_LINES>=4
  case LCD_LINE4:
  *line = 4;
  break;
#endif
  default:
  return false;
  }
  lcddata &= 0x0F;
  *row = lcddata + 1;
  return true;
}

//-  Check if busy
bool lcd_busy(void)
{
  unsigned char state = lcd_getbyte(LCD_ADDRESS);
  if (state & (1 << 7)) return true;
  else return false;
}

//-  Wait some microseconds
void lcd_wait_us(unsigned short us)
{
  unsigned short i;
  for(i = 0; i < us; i++)
  {
  wait1us;
  }
}

//-  Wait some milliseconds
void lcd_wait_ms(unsigned short ms)
{
  unsigned short i;
  for(i = 0; i < ms; i++)
  {
  wait1ms;
  }
}





CodeBox C
// pfleury_ic2master I2C Master library

#ifndef _I2CMASTER_H
#define _I2CMASTER_H
/*************************************************************************
* Title:  C include file for the I2C master interface
*  (i2cmaster.S or twimaster.c)
* Author:  Peter Fleury <pfleury@gmx.ch>
* File:  $Id: i2cmaster.h,v 1.12 2015/09/16 09:27:58 peter Exp $
* Software: AVR-GCC 4.x
* Target:  any AVR device
* Usage:  see Doxygen manual
**************************************************************************/
/**
@file
@defgroup pfleury_ic2master I2C Master library
@code #include <i2cmaster.h> @endcode

@brief I2C (TWI) Master Software Library
Basic routines for communicating with I2C slave devices. This single master
implementation is limited to one bus master on the I2C bus.
This I2c library is implemented as a compact assembler software implementation of the I2C protocol
which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c).
Since the API for these two implementations is exactly the same, an application can be linked either against the
software I2C implementation or the hardware I2C implementation.
Use 4.7k pull-up resistor on the SDA and SCL pin.

Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module
i2cmaster.S to your target when using the software I2C implementation !

Adjust the  CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion.
@note
  The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted
  to GNU assembler and AVR-GCC C call interface.
  Replaced the incorrect quarter period delays found in AVR300 with
  half period delays.

@author Peter Fleury pfleury@gmx.ch  http://tinyurl.com/peterfleury
@copyright (C) 2015 Peter Fleury, GNU General Public License Version 3

@par API Usage Example
  The following code shows typical usage of this library, see example test_i2cmaster.c
@code
#include <i2cmaster.h>
#define Dev24C02  0xA2  // device address of EEPROM 24C02, see datasheet
int main(void)
{
  unsigned char ret;
  i2c_init();  // initialize I2C library
  // write 0x75 to EEPROM address 5 (Byte Write)
  i2c_start_wait(Dev24C02+I2C_WRITE);  // set device address and write mode
  i2c_write(0x05);  // write address = 5
  i2c_write(0x75);  // write value 0x75 to EEPROM
  i2c_stop();  // set stop conditon = release bus
  // read previously written value back from EEPROM address 5
  i2c_start_wait(Dev24C02+I2C_WRITE);  // set device address and write mode
  i2c_write(0x05);  // write address = 5
  i2c_rep_start(Dev24C02+I2C_READ);  // set device address and read mode
  ret = i2c_readNak();  // read one byte from EEPROM
  i2c_stop();
  for(;;);
}
@endcode
*/
/**@{*/
#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"
#endif
#include <avr/io.h>
/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_READ  1
/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_WRITE  0
/**
@brief initialize the I2C master interace. Need to be called only once
@return none
*/
extern void i2c_init(void);
/**
@brief Terminates the data transfer and releases the I2C bus
@return none
*/
extern void i2c_stop(void);
/**
@brief Issues a start condition and sends address and transfer direction

@param  addr address and transfer direction of I2C device
@retval  0  device accessible
@retval  1  failed to access device
*/
extern unsigned char i2c_start(unsigned char addr);
/**
@brief Issues a repeated start condition and sends address and transfer direction
@param  addr address and transfer direction of I2C device
@retval  0 device accessible
@retval  1 failed to access device
*/
extern unsigned char i2c_rep_start(unsigned char addr);
/**
@brief Issues a start condition and sends address and transfer direction

If device is busy, use ack polling to wait until device ready
@param  addr address and transfer direction of I2C device
@return  none
*/
extern void i2c_start_wait(unsigned char addr);

/**
@brief Send one byte to I2C device
@param  data  byte to be transfered
@retval  0 write successful
@retval  1 write failed
*/
extern unsigned char i2c_write(unsigned char data);
/**
@brief  read one byte from the I2C device, request more data from device
@return  byte read from I2C device
*/
extern unsigned char i2c_readAck(void);
/**
@brief  read one byte from the I2C device, read is followed by a stop condition
@return  byte read from I2C device
*/
extern unsigned char i2c_readNak(void);
/**
@brief  read one byte from the I2C device

Implemented as a macro, which calls either @ref i2c_readAck or @ref i2c_readNak

@param  ack 1 send ack, request more data from device<br>
  0 send nak, read is followed by a stop condition
@return  byte read from I2C device
*/
extern unsigned char i2c_read(unsigned char ack);
#define i2c_read(ack)  (ack) ? i2c_readAck() : i2c_readNak();
/**@}*/
#endif




Probleme gibt es beim Kompilieren....
Wie muss man das linken?
So:


CodeBox C
#!/bin/bash
avr-gcc -c -Wall -Os -mmcu=atmega8 -g lcd_vs_i2c.c
avr-gcc -c -Wall -Os -mmcu=atmega8 -g i2clcd.c
avr-gcc -mmcu=atmega8 i2clcd.o lcd_vs_i2c.o -o lcd_vs_i2c.hex


erhalte die Fehler:


CodeBox C
lcd_vs_i2c.c:33: undefined reference to `lcd_init'
lcd_vs_i2c.c:35: undefined reference to `lcd_print'
lcd_vs_i2c.c:36: undefined reference to `lcd_gotolr'
lcd_vs_i2c.c:39: undefined reference to `lcd_command'


Gruß
Ralf
 
Zuletzt bearbeitet:
Hab' jetzt mal die i2c-Adaptierung von Fleury mit einer Erweiterung der Seite verbunden
http://computerheld.de/i2clcd/doc/index.html.


Im folgenden erscheinen vier Dateien:
main.c
i2clcd.c
i2clcd.h
i2cmaster.h
i2cmaster.S ist der Assembler-Code... den habe ich mal weg gelassen




CodeBox C
/*
MAIN.C
*/
#include <avr/io.h>
#include "i2cmaster.h" // i2c von Fleury
#include "i2clcd.h" // LCD-Erweiterung

#define Dev24C02  0xA2  // device address of EEPROM 24C02, see datasheet
int main(void)
{
  unsigned char ret;

  DDRB  = 0xff;  // use all pins on port B for output
  PORTB = 0xff;  // (active low LED's )
     lcd_init();  //-  Display initialization
  char string[] = "Hi World";
  lcd_print(string);  //-  Print a string
  lcd_gotolr(2,4);  //-  Move to position (line 2, row 4)

  //-  Turn cursor off and activate blinking
  lcd_command(LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKINGON);

}





CodeBox C
/*****************************************************************************
i2clcd.h - LCD over I2C library
  Designed for HD44870 based LCDs with I2C expander PCF8574X
  on Atmels AVR MCUs
Copyright (C) 2006 Nico Eichelmann and Thomas Eichelmann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
You can contact the authors at info@computerheld.de
*****************************************************************************/
#ifndef _I2CLCD_H
#define _I2CLCD_H

//--System-Configuration-Settings------------------------------------------------------------------------------------

#ifndef F_CPU
  #define F_CPU 8000000
#endif

#define wait1us _delay_loop_1((F_CPU * 0.000001) / 3)
#define wait1ms _delay_loop_2((F_CPU * 0.001) / 4)

//-------------------------------------------------------------------------------------------------------------------

#include <util/delay.h>
#include <stdbool.h>
#include <stdint.h>
#include "i2cmaster.h"

//--Display-Configuration-Settings-----------------------------------------------------------------------------------

#define LCD_I2C_DEVICE  0x40
#define LCD_LINES  2
#define LCD_ROWS  16
#define LCD_LINE1  0x00
#define LCD_LINE2  0x40
#define LCD_LINE3  0x10
#define LCD_LINE4  0x50

//-------------------------------------------------------------------------------------------------------------------

//--The-following-definitions-are-corresponding-to-the-PIN-Assignment-(see-above)------------------------------------

#define LCD_D4_PIN  0
#define LCD_D5_PIN  1
#define LCD_D6_PIN  2
#define LCD_D7_PIN  3
#define LCD_RS_PIN  4
#define LCD_RW_PIN  5
#define LCD_EMPTY_PIN  6
#define LCD_E_PIN  7

//-------------------------------------------------------------------------------------------------------------------

#define LCD_D0  (1 << LCD_D4_PIN)
#define LCD_D1  (1 << LCD_D5_PIN)
#define LCD_D2  (1 << LCD_D6_PIN)
#define LCD_D3  (1 << LCD_D7_PIN)
#define LCD_D4  (1 << LCD_D4_PIN)
#define LCD_D5  (1 << LCD_D5_PIN)
#define LCD_D6  (1 << LCD_D6_PIN)
#define LCD_D7  (1 << LCD_D7_PIN)
#define LCD_RS  (1 << LCD_RS_PIN)
#define LCD_RW  (1 << LCD_RW_PIN)
#define LCD_EMPTY  (1 << LCD_EMPTY_PIN)
#define LCD_E  (1 << LCD_E_PIN)


#define LCD_ADDRESS  0
#define LCD_DATA  1

//-LCD-COMMANDS------------------------------------------------------------------------------------------------------

#define LCD_CLEAR  0x01
#define LCD_HOME  0x02


#define LCD_ENTRYMODE  0x04
  #define LCD_INCREASE  LCD_ENTRYMODE | 0x02
  #define LCD_DECREASE  LCD_ENTRYMODE | 0x00
  #define LCD_DISPLAYSHIFTON  LCD_ENTRYMODE | 0x01
  #define LCD_DISPLAYSHIFTOFF  LCD_ENTRYMODE | 0x00


#define LCD_DISPLAYMODE  0x08
  #define LCD_DISPLAYON  LCD_DISPLAYMODE | 0x04
  #define LCD_DISPLAYOFF  LCD_DISPLAYMODE | 0x00
  #define LCD_CURSORON  LCD_DISPLAYMODE | 0x02
  #define LCD_CURSOROFF  LCD_DISPLAYMODE | 0x00
  #define LCD_BLINKINGON  LCD_DISPLAYMODE | 0x01
  #define LCD_BLINKINGOFF  LCD_DISPLAYMODE | 0x00


#define LCD_SHIFTMODE  0x10
  #define LCD_DISPLAYSHIFT  LCD_SHIFTMODE | 0x08
  #define LCD_CURSORMOVE  LCD_SHIFTMODE | 0x00
  #define LCD_RIGHT  LCD_SHIFTMODE | 0x04
  #define LCD_LEFT  LCD_SHIFTMODE | 0x00


#define LCD_CONFIGURATION  0x20
  #define LCD_8BIT  LCD_CONFIGURATION | 0x10
  #define LCD_4BIT  LCD_CONFIGURATION | 0x00
  #define LCD_2LINE  LCD_CONFIGURATION | 0x08
  #define LCD_1LINE  LCD_CONFIGURATION | 0x00
  #define LCD_5X10  LCD_CONFIGURATION | 0x04
  #define LCD_5X7  LCD_CONFIGURATION | 0x00

//-------------------------------------------------------------------------------------------------------------------

//-FUNCTIONS---------------------------------------------------------------------------------------------------------

//das extern habe ich mal probiert ohne Erfolg....
extern void lcd_init(void);  //-  Display initialization sequence

void lcd_write_i2c(unsigned char value);  //-  Write data to i2c

void lcd_write(unsigned char value);  //-  Write byte to display with toggle of enable-bit

bool lcd_gotolr(unsigned char line, unsigned char row); //-  Go to position

void lcd_putchar(unsigned char value);  //-  Put char to cursor position

bool lcd_putcharlr(unsigned char line, unsigned char row, unsigned char value); //-  Put char to position

void lcd_print(unsigned char *string);  //-  Print string to cursor position

bool lcd_printlr(unsigned char line, unsigned char row , unsigned char *string);  //-  Print string to position

bool lcd_printlc(unsigned char line, unsigned char row, unsigned char *string);  //-  Print string to position
  //-  (If string is longer than LCD_ROWS
  //-  overwrite first chars)

bool lcd_printlrc(unsigned char line, unsigned char row, unsigned char *string);  //-  Print string to position
  //-  (If string is longer than LCD_ROWS
  //-  continue in next line)

void lcd_command(unsigned char command);  //-  Issue a command to the display (use the defined commands above)

bool lcd_nextline(void);  //-  Go to nextline (if next line > LCD_LINES return false)

unsigned char lcd_read_i2c(void);  //-  Read data from i2c

unsigned char lcd_read(bool mode);  //-  Read data from display over i2c
  //-  (second nibble corresponds to highbyte or lowbyte)

unsigned char lcd_getbyte(bool mode);  //-  Read one complete byte over i2c from display

bool lcd_getlr(unsigned char *line, unsigned char*row); //-  Get line and row (target byte for line, target byte for row)

bool lcd_busy(void);  //-  Check if busy

void lcd_wait_us(unsigned short us);  //-  Wait some microseconds

void lcd_wait_ms(unsigned short ms);  //-  Wait some milliseconds

//-------------------------------------------------------------------------------------------------------------------
#endif









CodeBox C
/*****************************************************************************
i2clcd.c - LCD over I2C library
  Designed for HD44870 based LCDs with I2C expander PCF8574X
  on Atmels AVR MCUs
Copyright (C) 2006 Nico Eichelmann and Thomas Eichelmann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
You can contact the authors at info@computerheld.de
*****************************************************************************/

/*
  Version 0.1
  Requires I2C-Library from Peter Fleury http://jump.to/fleury

  See i2clcd.h for description and example.
*/

#include "i2clcd.h"

//-  Display initialization sequence
void lcd_init(void)
{
  lcd_wait_ms(16);  //-  Wait for more than 15ms after VDD rises to 4.5V
  lcd_write(LCD_D5 | LCD_D4);  //-  Set interface to 8-bit
  lcd_wait_ms(5);  //-  Wait for more than 4.1ms
  lcd_write(LCD_D5 | LCD_D4);  //-  Set interface to 8-bit
  lcd_wait_us(101);  //-  Wait for more than 100us
  lcd_write(LCD_D5 | LCD_D4);  //-  Set interface to 8-bit
  lcd_write(LCD_D5);  //-  Set interface to 4-bit

  //- From now on in 4-bit-Mode
  lcd_command(LCD_4BIT | LCD_2LINE | LCD_5X7);  //-  2-Lines, 5x7-Matrix
  lcd_command(LCD_DISPLAYOFF);  //-  Display off
  lcd_command(LCD_CLEAR);  //-  Clear Screen
  lcd_command(LCD_INCREASE | LCD_DISPLAYSHIFTOFF);  //-  Entrymode (Display Shift: off, Increment Address Counter)
  lcd_command(LCD_DISPLAYON);  //-  Display on
}

//-  Write data to i2c
void lcd_write_i2c(unsigned char value)
{
  i2c_start_wait(LCD_I2C_DEVICE+I2C_WRITE);
  i2c_write(value);
  i2c_stop();
}

//-  Write byte to display with toggle of enable-bit
void lcd_write(unsigned char value)
{
  lcd_write_i2c(value | LCD_E);  //-  Set enable to high
  lcd_write_i2c(value | LCD_E);  //-  Send data, keep enable high
  lcd_write_i2c(value & (!LCD_E));  //-  Set enable to low
}

//-  Print string to cursor position
void lcd_print(unsigned char *string)
{
  unsigned char i = 0;
  while(string[i] != 0x00)
  {
  lcd_putchar(string[i]);
  i++;
  }
}

//-  Put char to cursor position
void lcd_putchar(unsigned char value)
{
  unsigned char lcddata;
  lcddata = value;
  lcddata >>= 4;
  lcddata |= LCD_RS;
  lcd_write(lcddata);
  lcddata = value;
  lcddata &= 0x0F;
  lcddata |= LCD_RS;
  lcd_write(lcddata);
}

//-  Put char to position
bool lcd_putcharlr(unsigned char line, unsigned char row, unsigned char value)
{
  if(!lcd_gotolr(line, row)) return false;
  lcd_putchar(value);

  return true;
}

//-  Issue a command to the display (use the defined commands above)
void lcd_command(unsigned char command)
{
  unsigned char lcddata;
  lcddata = command;
  lcddata >>=  4;
  lcd_write(lcddata);
  lcddata = command;
  lcddata &= 0x0F;
  lcd_write(lcddata);
}

//-  Print string to position (If string is longer than LCD_ROWS overwrite first chars)(line, row, string)
bool lcd_printlc(unsigned char line, unsigned char row, unsigned char *string)
{
  unsigned char i;

  for(i = 0; string[i] != 0x00; i++)
  {
  if (!lcd_putcharlr(line, row, string[i])) return false;
  row++;
  if(row > LCD_ROWS)
  {
  row = 1;
  }
  }
  return true;
}

//-  Print string to position (If string is longer than LCD_ROWS continue in next line)(line, row, string)
bool lcd_printlrc(unsigned char line, unsigned char row, unsigned char *string)
{
  unsigned char i;

  for(i = 0; string[i] != 0x00; i++)
  {
  if(!lcd_putcharlr(line, row, string[i])) return false;
  row++;
  if(row > LCD_ROWS)
  {
  line++;
  row = 1;
  }
  if(line > LCD_LINES)
  {
  line = 1;
  }
  }
  return true;
}

//-  Print string to position (line, row, string)
bool lcd_printlr(unsigned char line, unsigned char row, unsigned char *string)
{
  if(!lcd_gotolr(line, row)) return false;
  lcd_print(string);

  return true;
}

//-  Go to position (line, row)
bool lcd_gotolr(unsigned char line, unsigned char row )
{
  unsigned char lcddata;

  if(line > LCD_LINES) return false;
  if(row > LCD_ROWS) return false;
  if((line == 0) || (row == 0) ) return false;

  lcddata = LCD_D7;
#if LCD_LINES>=2
  if (line == 2) lcddata = LCD_D7 |  (LCD_LINE2 >> 4);
#endif
#if LCD_LINES>=3
  if (line == 3) lcddata = LCD_D7 |  (LCD_LINE3 >> 4);
#endif
#if LCD_LINES>=4
  if (line == 4) lcddata = LCD_D7 |  (LCD_LINE4 >> 4);
#endif
  lcd_write(LCD_E | lcddata);
  lcddata = (row-1);
  lcd_write(LCD_E | lcddata);

  return true;
}

//-  Go to nextline (if next line > LCD_LINES return false)
bool lcd_nextline(void)
{
  unsigned char line = 0x00, row = 0x00;
  lcd_getlr(&line, &row);
  if (!lcd_gotolr(line + 1, 1)) return false;
  else return true;
}

//-  Read data from i2c
unsigned char lcd_read_i2c(void)
{
  unsigned char lcddata = 0x00;
  i2c_start_wait(LCD_I2C_DEVICE+I2C_READ);
  lcddata = i2c_readNak();
  i2c_stop();
  return lcddata;
}

//-  Read data from display over i2c (second nibble corresponds to highbyte or lowbyte)
unsigned char lcd_read(bool mode)
{
  unsigned char lcddata;
  if(mode == LCD_DATA)
  lcd_write_i2c(LCD_E | LCD_RS | LCD_RW | LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7);
  else
  lcd_write_i2c(LCD_E | LCD_RW | LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7);

  lcddata = lcd_read_i2c();
  lcd_write_i2c(0x00);
  return lcddata;
}

//-  Read one complete byte over i2c from display
unsigned char lcd_getbyte(bool mode)
{
  unsigned char hib, lob;
  hib = lcd_read(mode);
  lob = lcd_read(mode);
  return (hib << 4) + (lob & 0x0F);
}

//-  Get line and row (target byte for line, target byte for row)
bool lcd_getlr(unsigned char *line, unsigned char *row)
{
  unsigned char lcddata, tmp;
  lcddata =  lcd_getbyte(LCD_ADDRESS);
  if (lcddata & (1 << 7)) return false;
  tmp = lcddata;
  tmp &= 0xF0;
  switch(tmp)
  {
  case LCD_LINE1:
  *line = 1;
  break;
#if LCD_LINES>=2
  case LCD_LINE2:
  *line = 2;
  break;
#endif
#if LCD_LINES>=3
  case LCD_LINE3:
  *line = 3;
  break;
#endif
#if LCD_LINES>=4
  case LCD_LINE4:
  *line = 4;
  break;
#endif
  default:
  return false;
  }
  lcddata &= 0x0F;
  *row = lcddata + 1;
  return true;
}

//-  Check if busy
bool lcd_busy(void)
{
  unsigned char state = lcd_getbyte(LCD_ADDRESS);
  if (state & (1 << 7)) return true;
  else return false;
}

//-  Wait some microseconds
void lcd_wait_us(unsigned short us)
{
  unsigned short i;
  for(i = 0; i < us; i++)
  {
  wait1us;
  }
}

//-  Wait some milliseconds
void lcd_wait_ms(unsigned short ms)
{
  unsigned short i;
  for(i = 0; i < ms; i++)
  {
  wait1ms;
  }
}





CodeBox C
// pfleury_ic2master I2C Master library

#ifndef _I2CMASTER_H
#define _I2CMASTER_H
/*************************************************************************
* Title:  C include file for the I2C master interface
*  (i2cmaster.S or twimaster.c)
* Author:  Peter Fleury <pfleury@gmx.ch>
* File:  $Id: i2cmaster.h,v 1.12 2015/09/16 09:27:58 peter Exp $
* Software: AVR-GCC 4.x
* Target:  any AVR device
* Usage:  see Doxygen manual
**************************************************************************/
/**
@file
@defgroup pfleury_ic2master I2C Master library
@code #include <i2cmaster.h> @endcode

@brief I2C (TWI) Master Software Library
Basic routines for communicating with I2C slave devices. This single master
implementation is limited to one bus master on the I2C bus.
This I2c library is implemented as a compact assembler software implementation of the I2C protocol
which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c).
Since the API for these two implementations is exactly the same, an application can be linked either against the
software I2C implementation or the hardware I2C implementation.
Use 4.7k pull-up resistor on the SDA and SCL pin.

Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module
i2cmaster.S to your target when using the software I2C implementation !

Adjust the  CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion.
@note
  The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted
  to GNU assembler and AVR-GCC C call interface.
  Replaced the incorrect quarter period delays found in AVR300 with
  half period delays.

@author Peter Fleury pfleury@gmx.ch  http://tinyurl.com/peterfleury
@copyright (C) 2015 Peter Fleury, GNU General Public License Version 3

@par API Usage Example
  The following code shows typical usage of this library, see example test_i2cmaster.c
@code
#include <i2cmaster.h>
#define Dev24C02  0xA2  // device address of EEPROM 24C02, see datasheet
int main(void)
{
  unsigned char ret;
  i2c_init();  // initialize I2C library
  // write 0x75 to EEPROM address 5 (Byte Write)
  i2c_start_wait(Dev24C02+I2C_WRITE);  // set device address and write mode
  i2c_write(0x05);  // write address = 5
  i2c_write(0x75);  // write value 0x75 to EEPROM
  i2c_stop();  // set stop conditon = release bus
  // read previously written value back from EEPROM address 5
  i2c_start_wait(Dev24C02+I2C_WRITE);  // set device address and write mode
  i2c_write(0x05);  // write address = 5
  i2c_rep_start(Dev24C02+I2C_READ);  // set device address and read mode
  ret = i2c_readNak();  // read one byte from EEPROM
  i2c_stop();
  for(;;);
}
@endcode
*/
/**@{*/
#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"
#endif
#include <avr/io.h>
/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_READ  1
/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_WRITE  0
/**
@brief initialize the I2C master interace. Need to be called only once
@return none
*/
extern void i2c_init(void);
/**
@brief Terminates the data transfer and releases the I2C bus
@return none
*/
extern void i2c_stop(void);
/**
@brief Issues a start condition and sends address and transfer direction

@param  addr address and transfer direction of I2C device
@retval  0  device accessible
@retval  1  failed to access device
*/
extern unsigned char i2c_start(unsigned char addr);
/**
@brief Issues a repeated start condition and sends address and transfer direction
@param  addr address and transfer direction of I2C device
@retval  0 device accessible
@retval  1 failed to access device
*/
extern unsigned char i2c_rep_start(unsigned char addr);
/**
@brief Issues a start condition and sends address and transfer direction

If device is busy, use ack polling to wait until device ready
@param  addr address and transfer direction of I2C device
@return  none
*/
extern void i2c_start_wait(unsigned char addr);

/**
@brief Send one byte to I2C device
@param  data  byte to be transfered
@retval  0 write successful
@retval  1 write failed
*/
extern unsigned char i2c_write(unsigned char data);
/**
@brief  read one byte from the I2C device, request more data from device
@return  byte read from I2C device
*/
extern unsigned char i2c_readAck(void);
/**
@brief  read one byte from the I2C device, read is followed by a stop condition
@return  byte read from I2C device
*/
extern unsigned char i2c_readNak(void);
/**
@brief  read one byte from the I2C device

Implemented as a macro, which calls either @ref i2c_readAck or @ref i2c_readNak

@param  ack 1 send ack, request more data from device<br>
  0 send nak, read is followed by a stop condition
@return  byte read from I2C device
*/
extern unsigned char i2c_read(unsigned char ack);
#define i2c_read(ack)  (ack) ? i2c_readAck() : i2c_readNak();
/**@}*/
#endif




Probleme gibt es beim Kompilieren....
Wie muss man das linken?
So:


CodeBox C
#!/bin/bash
avr-gcc -c -Wall -Os -mmcu=atmega8 -g lcd_vs_i2c.c
avr-gcc -c -Wall -Os -mmcu=atmega8 -g i2clcd.c
avr-gcc -mmcu=atmega8 i2clcd.o lcd_vs_i2c.o -o lcd_vs_i2c.hex


erhalte die Fehler:


CodeBox C
lcd_vs_i2c.c:33: undefined reference to `lcd_init'
lcd_vs_i2c.c:35: undefined reference to `lcd_print'
lcd_vs_i2c.c:36: undefined reference to `lcd_gotolr'
lcd_vs_i2c.c:39: undefined reference to `lcd_command'


Gruß
Ralf
 
Zuletzt bearbeitet:
Die Fehlermeldungen sind nun weg....
Es fehlten die "extern"-Prefixe (extern void) vor den Funktionen in der .h-Datei.


CodeBox C
#!/bin/bash
avr-gcc -c -Wall -Os -mmcu=atmega8 -g lcd_vs_i2c.c
avr-gcc -c -Wall -Os -mmcu=atmega8 -g i2clcd.c
avr-gcc -c -Wall -Os -mmcu=atmega8 -g i2cmaster.S
avr-gcc -mmcu=atmega8 i2clcd.o lcd_vs_i2c.o i2cmaster.o -o test.hex
avrdude -B 10 -c usbasp -p atmega8 -U flash:w:test.hex

Display immer noch keine Funktion....
Blickt noch jemand durch? Ich gerade nicht mehr... ist ja auch gleich 3....
 
Hallo Ralf,

ich finde keinen Aufruf der Funktion i2c_init. I2C muss initialisiert werden, bevor du Daten zum Display sendest.

In main() sollte eine while(1) {} Schleife vorhanden sein.

Gibt es sonst noch Warnmeldungen?
Sind bei dir die Funktionen wait1us und wait1ms bekannt bzw. vorhanden? Zum Beispiel in
void lcd_wait_ms(unsigned short ms).


Dirk :ciao:
 
Hallo Ralf,

ich finde keinen Aufruf der Funktion i2c_init. I2C muss initialisiert werden, bevor du Daten zum Display sendest.

In main() sollte eine while(1) {} Schleife vorhanden sein.

Gibt es sonst noch Warnmeldungen?
Sind bei dir die Funktionen wait1us und wait1ms bekannt bzw. vorhanden? Zum Beispiel in
void lcd_wait_ms(unsigned short ms).


Dirk :ciao:

Moin Dirk,



CodeBox C
i2clcd.h:141:6: note: expected ‘unsigned char *’ but argument is of type ‘char *’

lcd_vs_i2c.c: In function ‘main’:
lcd_vs_i2c.c:35:9: warning: pointer targets in passing argument 1 of ‘lcd_print’ differ in signedness [-Wpointer-sign]
In file included from lcd_vs_i2c.c:17:0:
i2clcd.h:141:6: note: expected ‘unsigned char *’ but argument is of type ‘char *’
lcd_vs_i2c.c:25:19: warning: unused variable ‘ret’ [-Wunused-variable]
lcd_vs_i2c.c:43:1: warning: control reaches end of non-void function [-Wreturn-type]




Was ich vermisse. ist die Einstellung der Ports am Atmega.......

Gefunden... in der Assembler-Datei....
Warnungen sind jetzt auch weg.....



CodeBox Assembler
#define SDA  7  // SDA Port D, Pin 7   
#define SCL  6  // SCL Port D, Pin 6
;*************************************************************************
   .global i2c_init
   .func i2c_init
i2c_init:
   cbi SDA_DDR,SDA     ;release SDA
   cbi SCL_DDR,SCL     ;release SCL
   cbi SDA_OUT,SDA
   cbi SCL_OUT,SCL
   ret
   .endfunc

Frage:
Bei


CodeBox C
#define SDA  7  // SDA Port D, Pin 7   
#define SCL  6  // SCL Port D, Pin 6

Ist Pin 7 gleich PD7 ???
 
Zuletzt bearbeitet:
Hab ich:


CodeBox C und C++ C C++12#define SDA_PORT PORTD // SDA Port D#define SCL_PORT PORTD // SCL Port D

Das passt nun nicht direkt zu den verwendeten IO Registern
SDA_DDR
SCL_DDR
SDA_OUT

Ob das in der Software aufgrund von SDA_PORT und SCL_PORT richtig zugeordnet wird, kann ich nicht sagen, da ich ja nicht das komplette Programm sehe.
 
Das passt nun nicht direkt zu den verwendeten IO Registern
SDA_DDR
SCL_DDR
SDA_OUT

Ob das in der Software aufgrund von SDA_PORT und SCL_PORT richtig zugeordnet wird, kann ich nicht sagen, da ich ja nicht das komplette Programm sehe.


CodeBox Assembler
;*************************************************************************
; Title   :  I2C (Single) Master Implementation
; Author:  Peter Fleury <pfleury@gmx.ch>
;  based on Atmel Appl. Note AVR300
; File:  $Id: i2cmaster.S,v 1.13 2015/09/16 11:21:00 peter Exp $
; Software:  AVR-GCC 4.x
; Target:  any AVR device
;
; DESCRIPTION
;    Basic routines for communicating with I2C slave devices. This
;   "single" master implementation is limited to one bus master on the
;   I2C bus.  
;   
;  Based on the Atmel Application Note AVR300, corrected and adapted  
;  to GNU assembler and AVR-GCC C call interface
;  Replaced the incorrect quarter period delays found in AVR300 with  
;  half period delays.  
;
; USAGE
;   These routines can be called from C, refere to file i2cmaster.h.
;  See example test_i2cmaster.c  
;    Adapt the SCL and SDA port and pin definitions and eventually  
;   the delay routine to your target !
;    Use 4.7k pull-up resistor on the SDA and SCL pin.
;
; NOTES
;   The I2C routines can be called either from non-interrupt or
;   interrupt routines, not both.
;
;*************************************************************************
#include <avr/io.h>
#undef SCL_PORT
#undef SCL_DDR
;******----- Adapt these SCA and SCL port and pin definition to your target !!
;
#define SDA  7  // SDA Port D, Pin 4   
#define SCL  6  // SCL Port D, Pin 5
#define SDA_PORT  PORTD  // SDA Port D
#define SCL_PORT  PORTD  // SCL Port D   
;******----------------------------------------------------------------------
;-- map the IO register back into the IO address space
#define SDA_DDR     (_SFR_IO_ADDR(SDA_PORT) - 1)
#define SCL_DDR     (_SFR_IO_ADDR(SCL_PORT) - 1)
#define SDA_OUT     _SFR_IO_ADDR(SDA_PORT)
#define SCL_OUT     _SFR_IO_ADDR(SCL_PORT)
#define SDA_IN     (_SFR_IO_ADDR(SDA_PORT) - 2)
#define SCL_IN     (_SFR_IO_ADDR(SCL_PORT) - 2)
#ifndef __tmp_reg__
#define __tmp_reg__ 0
#endif
   .section .text
;*************************************************************************
; delay half period
; For I2C in normal mode (100kHz), use T/2 > 5us
; For I2C in fast mode (400kHz),  use T/2 > 1.25us
;*************************************************************************
   .stabs   "",100,0,0,i2c_delay_T2
   .stabs   "i2cmaster.S",100,0,0,i2c_delay_T2
   .func i2c_delay_T2   ; delay 5.0 microsec with 4 Mhz crystal   
i2c_delay_T2:  ; 3 cycles
#if F_CPU <= 4000000UL
   rjmp 1f  ; 2  "
1:   rjmp 2f  ; 2  "
2:   rjmp 3f  ; 2  "
3:   rjmp 4f  ; 2  "
4:   rjmp 5f  ; 2  "
5:    rjmp 6f  ; 2  "
6:   nop  ; 1  "
   ret  ; 4  "  total 20 cyles = 5.0 microsec with 4 Mhz crystal  
#elif F_CPU <= 8000000UL
  push r24  ; 2 cycle
  ldi    r24, 7  ; 1 cycle
   nop  ; 1 cycle
1:   sbiw r24, 1  ; 2 cycle
   brne 1b  ; 2 or 1 cycle, 4 cycles per loop
   pop  r24  ; 2 ycle
   ret  ; 4 cycle = total 60 cycles = 5.0 microsec with 12 Mhz crystal
#elif F_CPU <= 12000000UL
  push r24  ; 2 cycle
  ldi    r24, 12 ; 1 cycle
   nop  ; 1 cycle
1:   sbiw r24, 1  ; 2 cycle
   brne 1b  ; 2 or 1 cycle, 4 cycles per loop
   pop  r24  ; 2 ycle
   ret  ; 4 cycle = total 60 cycles = 5.0 microsec with 12 Mhz crystal
#elif F_CPU <= 16000000UL
  push r24  ; 2 cycle
  ldi    r24, 17 ; 1 cycle
   nop  ; 1 cycle
1:   sbiw r24, 1  ; 2 cycle
   brne 1b  ; 2 or 1 cycle, 4 cycles per loop
   pop  r24  ; 2 ycle
   ret  ; 4 cycle = total 80 cycles = 5.0 microsec with 16 Mhz crystal
#else
  push r24  ; 2 cycle
  ldi    r24, 22 ; 1 cycle
   nop  ; 1 cycle
1:   sbiw r24, 1  ; 2 cycle
   brne 1b  ; 2 or 1 cycle, 4 cycles per loop
   pop  r24  ; 2 ycle
   ret  ; 4 cycle = total 100 cycles = 5.0 microsec with 20 Mhz crystal
#endif   
   .endfunc  ;  
;*************************************************************************
; Initialization of the I2C bus interface. Need to be called only once
;  
; extern void i2c_init(void)
;*************************************************************************
   .global i2c_init
   .func i2c_init
i2c_init:
   cbi SDA_DDR,SDA     ;release SDA
   cbi SCL_DDR,SCL     ;release SCL
   cbi SDA_OUT,SDA
   cbi SCL_OUT,SCL
   ret
   .endfunc
;*************************************************************************   
; Issues a start condition and sends address and transfer direction.
; return 0 = device accessible, 1= failed to access device
;
; extern unsigned char i2c_start(unsigned char addr);
;   addr = r24, return = r25(=0):r24
;*************************************************************************
   .global i2c_start
   .func  i2c_start
i2c_start:
   sbi    SDA_DDR,SDA   ;force SDA low
   rcall    i2c_delay_T2   ;delay T/2
   
   rcall    i2c_write   ;write address
   ret
   .endfunc     
;*************************************************************************
; Issues a repeated start condition and sends address and transfer direction.
; return 0 = device accessible, 1= failed to access device
;
; extern unsigned char i2c_rep_start(unsigned char addr);
;   addr = r24,  return = r25(=0):r24
;*************************************************************************
   .global i2c_rep_start
   .func   i2c_rep_start
i2c_rep_start:
   sbi   SCL_DDR,SCL   ;force SCL low
   rcall    i2c_delay_T2   ;delay  T/2
   cbi   SDA_DDR,SDA   ;release SDA
   rcall   i2c_delay_T2   ;delay T/2
   cbi   SCL_DDR,SCL   ;release SCL
   rcall    i2c_delay_T2   ;delay  T/2
   sbi    SDA_DDR,SDA   ;force SDA low
   rcall    i2c_delay_T2   ;delay   T/2
   
   rcall   i2c_write   ;write address
   ret
   .endfunc
;*************************************************************************   
; Issues a start condition and sends address and transfer direction.
; If device is busy, use ack polling to wait until device is ready
;
; extern void i2c_start_wait(unsigned char addr);
;   addr = r24
;*************************************************************************
   .global i2c_start_wait
   .func  i2c_start_wait
i2c_start_wait:
   mov   __tmp_reg__,r24
i2c_start_wait1:
   sbi    SDA_DDR,SDA   ;force SDA low
   rcall    i2c_delay_T2   ;delay T/2
   mov   r24,__tmp_reg__
   rcall    i2c_write   ;write address
   tst   r24     ;if device not busy -> done
   breq   i2c_start_wait_done
   rcall   i2c_stop   ;terminate write operation
   rjmp   i2c_start_wait1   ;device busy, poll ack again
i2c_start_wait_done:
   ret
   .endfunc   
;*************************************************************************
; Terminates the data transfer and releases the I2C bus
;
; extern void i2c_stop(void)
;*************************************************************************
   .global   i2c_stop
   .func   i2c_stop
i2c_stop:
   sbi   SCL_DDR,SCL   ;force SCL low
   sbi   SDA_DDR,SDA   ;force SDA low
   rcall   i2c_delay_T2   ;delay T/2
   cbi   SCL_DDR,SCL   ;release SCL
   rcall   i2c_delay_T2   ;delay T/2
   cbi   SDA_DDR,SDA   ;release SDA
   rcall   i2c_delay_T2   ;delay T/2
   ret
   .endfunc
;*************************************************************************
; Send one byte to I2C device
; return 0 = write successful, 1 = write failed
;
; extern unsigned char i2c_write( unsigned char data );
;   data = r24,  return = r25(=0):r24
;*************************************************************************
   .global i2c_write
   .func   i2c_write
i2c_write:
   sec       ;set carry flag
   rol    r24     ;shift in carry and out bit one
   rjmp   i2c_write_first
i2c_write_bit:
   lsl   r24     ;if transmit register empty
i2c_write_first:
   breq   i2c_get_ack
   sbi   SCL_DDR,SCL   ;force SCL low
   brcc   i2c_write_low
   nop
   cbi   SDA_DDR,SDA   ;release SDA
   rjmp   i2c_write_high
i2c_write_low:
   sbi   SDA_DDR,SDA   ;force SDA low
   rjmp   i2c_write_high
i2c_write_high:
   rcall    i2c_delay_T2   ;delay T/2
   cbi   SCL_DDR,SCL   ;release SCL
   rcall   i2c_delay_T2   ;delay T/2
   rjmp   i2c_write_bit
   
i2c_get_ack:
   sbi   SCL_DDR,SCL   ;force SCL low
   cbi   SDA_DDR,SDA   ;release SDA
   rcall   i2c_delay_T2   ;delay T/2
   cbi   SCL_DDR,SCL   ;release SCL
i2c_ack_wait:
   sbis   SCL_IN,SCL   ;wait SCL high (in case wait states are inserted)
   rjmp   i2c_ack_wait
   
   clr   r24     ;return 0
   sbic   SDA_IN,SDA   ;if SDA high -> return 1
   ldi   r24,1
   rcall   i2c_delay_T2   ;delay T/2
   clr   r25
   ret
   .endfunc
;*************************************************************************
; read one byte from the I2C device, send ack or nak to device
; (ack=1, send ack, request more data from device  
;  ack=0, send nak, read is followed by a stop condition)
;
; extern unsigned char i2c_read(unsigned char ack);
;   ack = r24, return = r25(=0):r24
; extern unsigned char i2c_readAck(void);
; extern unsigned char i2c_readNak(void);
;    return = r25(=0):r24
;*************************************************************************
   .global i2c_readAck
   .global i2c_readNak
   .global i2c_read     
   .func   i2c_read
i2c_readNak:
   clr   r24
   rjmp   i2c_read
i2c_readAck:
   ldi   r24,0x01
i2c_read:
   ldi   r23,0x01   ;data = 0x01
i2c_read_bit:
   sbi   SCL_DDR,SCL   ;force SCL low
   cbi   SDA_DDR,SDA   ;release SDA (from previous ACK)
   rcall   i2c_delay_T2   ;delay T/2
   
   cbi   SCL_DDR,SCL   ;release SCL
   rcall   i2c_delay_T2   ;delay T/2
   
i2c_read_stretch:
  sbis SCL_IN, SCL  ;loop until SCL is high (allow slave to stretch SCL)
  rjmp   i2c_read_stretch
     
   clc       ;clear carry flag
   sbic   SDA_IN,SDA   ;if SDA is high
   sec       ;  set carry flag
   
   rol   r23     ;store bit
   brcc   i2c_read_bit   ;while receive register not full
   
i2c_put_ack:
   sbi   SCL_DDR,SCL   ;force SCL low   
   cpi   r24,1
   breq   i2c_put_ack_low   ;if (ack=0)
   cbi   SDA_DDR,SDA   ;  release SDA
   rjmp   i2c_put_ack_high
i2c_put_ack_low:  ;else
   sbi   SDA_DDR,SDA   ;  force SDA low
i2c_put_ack_high:
   rcall   i2c_delay_T2   ;delay T/2
   cbi   SCL_DDR,SCL   ;release SCL
i2c_put_ack_wait:
   sbis   SCL_IN,SCL   ;wait SCL high
   rjmp   i2c_put_ack_wait
   rcall   i2c_delay_T2   ;delay T/2
   mov   r24,r23
   clr   r25
   ret
   .endfunc

 
#define SDA 7 // SDA Port D
#define SCL 6 // SCL Port D
#define SDA_PORT PORTD // SDA Port D
#define SCL_PORT PORTD // SCL Port D

Ja, es wird richtig umgesetzt.

Im oberen Fall sind es die IOs
PD7 (SDA) und PD6 (SCL)
 
Die Fehlermeldungen sind nun weg....
Es fehlten die "extern"-Prefixe (extern void) vor den Funktionen in der .h-Datei.


CodeBox C
#!/bin/bash
avr-gcc -c -Wall -Os -mmcu=atmega8 -g lcd_vs_i2c.c
avr-gcc -c -Wall -Os -mmcu=atmega8 -g i2clcd.c
avr-gcc -c -Wall -Os -mmcu=atmega8 -g i2cmaster.S
avr-gcc -mmcu=atmega8 i2clcd.o lcd_vs_i2c.o i2cmaster.o -o test.hex
avrdude -B 10 -c usbasp -p atmega8 -U flash:w:test.hex

Display immer noch keine Funktion....
Blickt noch jemand durch? Ich gerade nicht mehr... ist ja auch gleich 3....


Die Funktion lcd_init führt nicht automatisch ein i2c_init durch? - wenn ich das richtig sehe...
also erstmal den I2C initialisieren.

Verwendest du die richtige I2C - Adresse? - auf dem Bild sieht man, dass keine Widerstände an A0/A1/A2 eingelötet sind .... also hängen diese wohl auf Masse? - wenn ja, dann würds passen....

Dann würde ich mal zum testen einfach mal die Funktion i2c_start ausführen lassen, und den return Wert anschauen, damit du weißt, ob der PCF überhaupt erreichbar ist....

EDIT: wo ist die i2C_init Funktion überhaupt ... ich finde sie nicht / oder ich bin blind :) - wird er I2C überhaupt richtig initalisiert?
 
Die Funktion lcd_init führt nicht automatisch ein i2c_init durch? - wenn ich das richtig sehe...
Nein, die Funktion lcd_init ruft i2c_init nicht auf, auch wurde i2c_init nicht vorher aufgerufen.
wo ist die i2C_init Funktion überhaupt ...
Im Assembler Bereich, dieser Beitrag.
Verwendest du die richtige I2C - Adresse?
Ja, dies wäre auch noch wichtig :)

Dirk :ciao:
 


CodeBox Assembler
;*************************************************************************
; Title   :  I2C (Single) Master Implementation
; Author:  Peter Fleury <pfleury@gmx.ch>
;  based on Atmel Appl. Note AVR300
; File:  $Id: i2cmaster.S,v 1.13 2015/09/16 11:21:00 peter Exp $
; Software:  AVR-GCC 4.x
; Target:  any AVR device
;
; DESCRIPTION
;    Basic routines for communicating with I2C slave devices. This
;   "single" master implementation is limited to one bus master on the
;   I2C bus.
;
;  Based on the Atmel Application Note AVR300, corrected and adapted
;  to GNU assembler and AVR-GCC C call interface
;  Replaced the incorrect quarter period delays found in AVR300 with
;  half period delays.
;
; USAGE
;   These routines can be called from C, refere to file i2cmaster.h.
;  See example test_i2cmaster.c
;    Adapt the SCL and SDA port and pin definitions and eventually
;   the delay routine to your target !
;    Use 4.7k pull-up resistor on the SDA and SCL pin.
;
; NOTES
;   The I2C routines can be called either from non-interrupt or
;   interrupt routines, not both.
;
;*************************************************************************
#include <avr/io.h>
#undef SCL_PORT
#undef SCL_DDR
;******----- Adapt these SCA and SCL port and pin definition to your target !!
;
#define SDA  7  // SDA Port D, Pin 4
#define SCL  6  // SCL Port D, Pin 5
#define SDA_PORT  PORTD  // SDA Port D
#define SCL_PORT  PORTD  // SCL Port D
;******----------------------------------------------------------------------
;-- map the IO register back into the IO address space
#define SDA_DDR     (_SFR_IO_ADDR(SDA_PORT) - 1)
#define SCL_DDR     (_SFR_IO_ADDR(SCL_PORT) - 1)
#define SDA_OUT     _SFR_IO_ADDR(SDA_PORT)
#define SCL_OUT     _SFR_IO_ADDR(SCL_PORT)
#define SDA_IN     (_SFR_IO_ADDR(SDA_PORT) - 2)
#define SCL_IN     (_SFR_IO_ADDR(SCL_PORT) - 2)
#ifndef __tmp_reg__
#define __tmp_reg__ 0
#endif
   .section .text
;*************************************************************************
; delay half period
; For I2C in normal mode (100kHz), use T/2 > 5us
; For I2C in fast mode (400kHz),  use T/2 > 1.25us
;*************************************************************************
   .stabs   "",100,0,0,i2c_delay_T2
   .stabs   "i2cmaster.S",100,0,0,i2c_delay_T2
   .func i2c_delay_T2   ; delay 5.0 microsec with 4 Mhz crystal
i2c_delay_T2:  ; 3 cycles
#if F_CPU <= 4000000UL
   rjmp 1f  ; 2  "
1:   rjmp 2f  ; 2  "
2:   rjmp 3f  ; 2  "
3:   rjmp 4f  ; 2  "
4:   rjmp 5f  ; 2  "
5:    rjmp 6f  ; 2  "
6:   nop  ; 1  "
   ret  ; 4  "  total 20 cyles = 5.0 microsec with 4 Mhz crystal
#elif F_CPU <= 8000000UL
  push r24  ; 2 cycle
  ldi    r24, 7  ; 1 cycle
   nop  ; 1 cycle
1:   sbiw r24, 1  ; 2 cycle
   brne 1b  ; 2 or 1 cycle, 4 cycles per loop
   pop  r24  ; 2 ycle
   ret  ; 4 cycle = total 60 cycles = 5.0 microsec with 12 Mhz crystal
#elif F_CPU <= 12000000UL
  push r24  ; 2 cycle
  ldi    r24, 12 ; 1 cycle
   nop  ; 1 cycle
1:   sbiw r24, 1  ; 2 cycle
   brne 1b  ; 2 or 1 cycle, 4 cycles per loop
   pop  r24  ; 2 ycle
   ret  ; 4 cycle = total 60 cycles = 5.0 microsec with 12 Mhz crystal
#elif F_CPU <= 16000000UL
  push r24  ; 2 cycle
  ldi    r24, 17 ; 1 cycle
   nop  ; 1 cycle
1:   sbiw r24, 1  ; 2 cycle
   brne 1b  ; 2 or 1 cycle, 4 cycles per loop
   pop  r24  ; 2 ycle
   ret  ; 4 cycle = total 80 cycles = 5.0 microsec with 16 Mhz crystal
#else
  push r24  ; 2 cycle
  ldi    r24, 22 ; 1 cycle
   nop  ; 1 cycle
1:   sbiw r24, 1  ; 2 cycle
   brne 1b  ; 2 or 1 cycle, 4 cycles per loop
   pop  r24  ; 2 ycle
   ret  ; 4 cycle = total 100 cycles = 5.0 microsec with 20 Mhz crystal
#endif
   .endfunc  ;
;*************************************************************************
; Initialization of the I2C bus interface. Need to be called only once
;
; extern void i2c_init(void)
;*************************************************************************
   .global i2c_init
   .func i2c_init
i2c_init:
   cbi SDA_DDR,SDA     ;release SDA
   cbi SCL_DDR,SCL     ;release SCL
   cbi SDA_OUT,SDA
   cbi SCL_OUT,SCL
   ret
   .endfunc
;*************************************************************************
; Issues a start condition and sends address and transfer direction.
; return 0 = device accessible, 1= failed to access device
;
; extern unsigned char i2c_start(unsigned char addr);
;   addr = r24, return = r25(=0):r24
;*************************************************************************
   .global i2c_start
   .func  i2c_start
i2c_start:
   sbi    SDA_DDR,SDA   ;force SDA low
   rcall    i2c_delay_T2   ;delay T/2

   rcall    i2c_write   ;write address
   ret
   .endfunc 
;*************************************************************************
; Issues a repeated start condition and sends address and transfer direction.
; return 0 = device accessible, 1= failed to access device
;
; extern unsigned char i2c_rep_start(unsigned char addr);
;   addr = r24,  return = r25(=0):r24
;*************************************************************************
   .global i2c_rep_start
   .func   i2c_rep_start
i2c_rep_start:
   sbi   SCL_DDR,SCL   ;force SCL low
   rcall    i2c_delay_T2   ;delay  T/2
   cbi   SDA_DDR,SDA   ;release SDA
   rcall   i2c_delay_T2   ;delay T/2
   cbi   SCL_DDR,SCL   ;release SCL
   rcall    i2c_delay_T2   ;delay  T/2
   sbi    SDA_DDR,SDA   ;force SDA low
   rcall    i2c_delay_T2   ;delay   T/2

   rcall   i2c_write   ;write address
   ret
   .endfunc
;*************************************************************************
; Issues a start condition and sends address and transfer direction.
; If device is busy, use ack polling to wait until device is ready
;
; extern void i2c_start_wait(unsigned char addr);
;   addr = r24
;*************************************************************************
   .global i2c_start_wait
   .func  i2c_start_wait
i2c_start_wait:
   mov   __tmp_reg__,r24
i2c_start_wait1:
   sbi    SDA_DDR,SDA   ;force SDA low
   rcall    i2c_delay_T2   ;delay T/2
   mov   r24,__tmp_reg__
   rcall    i2c_write   ;write address
   tst   r24     ;if device not busy -> done
   breq   i2c_start_wait_done
   rcall   i2c_stop   ;terminate write operation
   rjmp   i2c_start_wait1   ;device busy, poll ack again
i2c_start_wait_done:
   ret
   .endfunc
;*************************************************************************
; Terminates the data transfer and releases the I2C bus
;
; extern void i2c_stop(void)
;*************************************************************************
   .global   i2c_stop
   .func   i2c_stop
i2c_stop:
   sbi   SCL_DDR,SCL   ;force SCL low
   sbi   SDA_DDR,SDA   ;force SDA low
   rcall   i2c_delay_T2   ;delay T/2
   cbi   SCL_DDR,SCL   ;release SCL
   rcall   i2c_delay_T2   ;delay T/2
   cbi   SDA_DDR,SDA   ;release SDA
   rcall   i2c_delay_T2   ;delay T/2
   ret
   .endfunc
;*************************************************************************
; Send one byte to I2C device
; return 0 = write successful, 1 = write failed
;
; extern unsigned char i2c_write( unsigned char data );
;   data = r24,  return = r25(=0):r24
;*************************************************************************
   .global i2c_write
   .func   i2c_write
i2c_write:
   sec       ;set carry flag
   rol    r24     ;shift in carry and out bit one
   rjmp   i2c_write_first
i2c_write_bit:
   lsl   r24     ;if transmit register empty
i2c_write_first:
   breq   i2c_get_ack
   sbi   SCL_DDR,SCL   ;force SCL low
   brcc   i2c_write_low
   nop
   cbi   SDA_DDR,SDA   ;release SDA
   rjmp   i2c_write_high
i2c_write_low:
   sbi   SDA_DDR,SDA   ;force SDA low
   rjmp   i2c_write_high
i2c_write_high:
   rcall    i2c_delay_T2   ;delay T/2
   cbi   SCL_DDR,SCL   ;release SCL
   rcall   i2c_delay_T2   ;delay T/2
   rjmp   i2c_write_bit

i2c_get_ack:
   sbi   SCL_DDR,SCL   ;force SCL low
   cbi   SDA_DDR,SDA   ;release SDA
   rcall   i2c_delay_T2   ;delay T/2
   cbi   SCL_DDR,SCL   ;release SCL
i2c_ack_wait:
   sbis   SCL_IN,SCL   ;wait SCL high (in case wait states are inserted)
   rjmp   i2c_ack_wait

   clr   r24     ;return 0
   sbic   SDA_IN,SDA   ;if SDA high -> return 1
   ldi   r24,1
   rcall   i2c_delay_T2   ;delay T/2
   clr   r25
   ret
   .endfunc
;*************************************************************************
; read one byte from the I2C device, send ack or nak to device
; (ack=1, send ack, request more data from device
;  ack=0, send nak, read is followed by a stop condition)
;
; extern unsigned char i2c_read(unsigned char ack);
;   ack = r24, return = r25(=0):r24
; extern unsigned char i2c_readAck(void);
; extern unsigned char i2c_readNak(void);
;    return = r25(=0):r24
;*************************************************************************
   .global i2c_readAck
   .global i2c_readNak
   .global i2c_read 
   .func   i2c_read
i2c_readNak:
   clr   r24
   rjmp   i2c_read
i2c_readAck:
   ldi   r24,0x01
i2c_read:
   ldi   r23,0x01   ;data = 0x01
i2c_read_bit:
   sbi   SCL_DDR,SCL   ;force SCL low
   cbi   SDA_DDR,SDA   ;release SDA (from previous ACK)
   rcall   i2c_delay_T2   ;delay T/2

   cbi   SCL_DDR,SCL   ;release SCL
   rcall   i2c_delay_T2   ;delay T/2

i2c_read_stretch:
  sbis SCL_IN, SCL  ;loop until SCL is high (allow slave to stretch SCL)
  rjmp   i2c_read_stretch
 
   clc       ;clear carry flag
   sbic   SDA_IN,SDA   ;if SDA is high
   sec       ;  set carry flag

   rol   r23     ;store bit
   brcc   i2c_read_bit   ;while receive register not full

i2c_put_ack:
   sbi   SCL_DDR,SCL   ;force SCL low
   cpi   r24,1
   breq   i2c_put_ack_low   ;if (ack=0)
   cbi   SDA_DDR,SDA   ;  release SDA
   rjmp   i2c_put_ack_high
i2c_put_ack_low:  ;else
   sbi   SDA_DDR,SDA   ;  force SDA low
i2c_put_ack_high:
   rcall   i2c_delay_T2   ;delay T/2
   cbi   SCL_DDR,SCL   ;release SCL
i2c_put_ack_wait:
   sbis   SCL_IN,SCL   ;wait SCL high
   rjmp   i2c_put_ack_wait
   rcall   i2c_delay_T2   ;delay T/2
   mov   r24,r23
   clr   r25
   ret
   .endfunc

Nein, die Funktion lcd_init ruft i2c_init nicht auf, auch wurde i2c_init nicht vorher aufgerufen.

Im Assembler Bereich, dieser Beitrag.

Ja, dies wäre auch noch wichtig :)

Dirk :ciao:

:) jo..... aber wo steht die?
 
Ist das die 0x3F?
Oder 0x27?

Du müsstest schauen, was da eingesetzt wurde und wie A2..0 konfiguriert ist.

So wie ich es verstehe musst du bei LCD_I2C_DEVICE die tatsächlich 7bit I2C Adresse mit 2 multipliziert angeben (um 1 nach link shift). Wegen dem Read/Write Bit ...



CodeBox C
void lcd_write_i2c(unsigned char value)
{
  i2c_start_wait(LCD_I2C_DEVICE+I2C_WRITE);
  i2c_write(value);
  i2c_stop();
}


#define I2C_READ  1
#define I2C_WRITE  0




PCF8574 address map.png
 
Du müsstest schauen, was da eingesetzt wurde und wie A2..0 konfiguriert ist.

So wie ich es verstehe musst du bei LCD_I2C_DEVICE die tatsächlich 7bit I2C Adresse mit 2 multipliziert angeben (um 1 nach link shift). Wegen dem Read/Write Bit ...



CodeBox C
void lcd_write_i2c(unsigned char value)
{
  i2c_start_wait(LCD_I2C_DEVICE+I2C_WRITE);
  i2c_write(value);
  i2c_stop();
}


#define I2C_READ  1
#define I2C_WRITE  0




Anhang anzeigen 7249

Danke Dirk !
Nun die nächste Frage.... A0, A1 und A2? Da sehe ich drei offene Brücken auf der Platine.... also alle LOW?
 
Du müsstest schauen, was da eingesetzt wurde und wie A2..0 konfiguriert ist.

So wie ich es verstehe musst du bei LCD_I2C_DEVICE die tatsächlich 7bit I2C Adresse mit 2 multipliziert angeben (um 1 nach link shift). Wegen dem Read/Write Bit ...



CodeBox C
void lcd_write_i2c(unsigned char value)
{
  i2c_start_wait(LCD_I2C_DEVICE+I2C_WRITE);
  i2c_write(value);
  i2c_stop();
}


#define I2C_READ  1
#define I2C_WRITE  0




Anhang anzeigen 7249

Laut dem Artikel könnte es ja nur 0x20 oder 0x3F sein.... also HIGH...
Bei mir dann 0x3F, da ich den PCF858574(A)T habe..
 
Nun die nächste Frage.... A0, A1 und A2? Da sehe ich drei offene Brücken auf der Platine.... also alle LOW?

Laut Datenblatt (NXP) sind keine internen Pullup Widerstände vorhanden. Ich vermute auf der Platine sind welche vorhanden?!

Wenn Pullup, dann ist die Adresse 0x3F.
Also eventuell
#define LCD_I2C_DEVICE (0x3F<<1)
Adresse Bit7..1
RW Bit0
To conserve power, no internal pull-up resistors are incorporated on A2, A1 or A0, so they must be externally held HIGH or LOW.
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)