problems with PCF8591

Hi
I'm new here, but may someone can help me with my problem to get the right data from the PCF8591. In the moment I get on all channels the same value of "128". I'm addressing the addr #48 (72). I need to read the value's of 4 pot's to set the value for a PWM controlled heater circuit. It's no problem to read the pot's through Arduino duce. Atmega328 direct with the ADC's but not with the PCF8591.
The circuit is as attachment. For testing I have set up the pot's to 1V , 2V , 3V, 4V. I used different code's - the last one I found in an earlier topic, but all displaying the same. I changed the chip with the same result. Have anyone a idea? Thanks

Wire.beginTransmission(0x48);
Wire.send(0x00);
Wire.endTransmission();
Wire.requestFrom(0x48, 1);
while(Wire.available())
{
var = Wire.receive();
} Wire.requestFrom(0x48, 1);
while(Wire.available())
{
var = Wire.receive();
}
Serial.println(var);
delay(1000);
var =0;

.

Hi,
I´ve got the same problem, but I start the Topic in the german Thread.
http://arduino.cc/forum/index.php/topic,77741.0.html

My problem is that the Atmega328P stop working by the comand Wire.request(72, 2); .
I use the comand in the interruptroutine of FlexiTimer2, maybe that´s the problem, but I'm not sure.

A easy testcode does work:

#include <Wire.h>
char c;
void setup()
{
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop()
{
  Wire.requestFrom(72, 2);    // request 2 bytes from slave device #2

  while(Wire.available())    // slave may send less than requested
  { 
   c = Wire.receive(); // receive a byte as character
    Serial.print(c);         // print the character
  }

  delay(50);
}

The interruptroutine that not work is following (the lcd.print("x"); is only to see where the Atmega stops):

void Get_Analog (){
    if (Analog_Neu == false){
  //Analog_Wert = analogRead(0);
  lcd.print("0");
  Wire.requestFrom(72, 2);
  lcd.print("1");
  while(Wire.available()){
        lcd.print("2");
 Analog_Wert = Wire.receive();
    lcd.print("3");
  Analog_Neu = true;
  }
    //Analog_Neu = true;
  }
  else
  {
    FlexiTimer2::stop();
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Fehler 1");
  }
}

The full Code is:

#include <FlexiTimer2.h>
#include <LiquidCrystal.h>
#include <Wire.h>

LiquidCrystal lcd(12,11,5,4,3,2); //Interface definieren

int Analog_Wert = 0;
boolean Analog_Neu = false;

void setup(){
  FlexiTimer2::set(50,Get_Analog);//(interruptinterval in ms, ISR)
  Serial.begin(115200);
  lcd.begin(16,2); //Spalten/Zeilen
  lcd.clear();
  Wire.begin();
  
  Wire.beginTransmission(72);
  Wire.send(48);//Anzwählen der richtigen PCF8591P Funktion
  Wire.endTransmission();
}
void loop (){
  int Rec = 0;
  int x = 0; //Schleifendurchlaufzähler, wird ggf an mehreren Stellen
         //verwendet. Der Zählerstand hat nach der Schleife keine
         //Relevanz mehr und wird vor beginn der Schleife neu 
         //initialisiert wird.

  if (Analog_Neu == true){
    //Serial.print (Analog_Wert);
    Serial.write (Analog_Wert);
    //Serial.print(" ");
    Analog_Neu =false;
    /*lcd.clear();
    lcd.setCursor(0,1);
    lcd.print (int((Analog_Wert/1023.0)*5000));
    lcd.print("mV");*/
  }
  if (Serial.available()){
    FlexiTimer2::stop();//Interrupt anhalten damit USB ohne unterbrechung gelesen werden kann
    Rec = Serial.read();
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print(Rec,DEC);
  }
  switch (Rec)
  {
  case 49: //ASCII 1 Interrupt starten
    FlexiTimer2::start();
    break;        
  
  case 50: //ASCII 2 Interrupt stop
    FlexiTimer2::stop();
    break;        
  
  case 51: //ASCII 3 Abtastrate setzen
      FlexiTimer2::stop();
     x=0;
    do{
    if (Serial.available()){
      Abtastrate_setzen(Serial.read());
    }
    delay(1);
    x++;
    }
    while (x!=1500);
    break;
    
  case 52: //ASCII 4 Spannungsbereich setzen
    FlexiTimer2::stop();
    x=0;
    do{
    if (Serial.available()){
      Spannungsbereich_setzen(Serial.read());
    }
    delay(1);
    x++;
    }
    while (x!=1500);
    break;    
    
  /*case 53: //ASCII 5 Triggerpunkt setzen
    x=0;
    do{
    if (Serial.available()){
      Set_Trigger(Serial.read());
    }
    delay(1);
    x++;
    }
    while (x!=1500);
    break;*/
  }
}
void Analog(){

}
void Get_Analog (){
    if (Analog_Neu == false){
  //Analog_Wert = analogRead(0);
  lcd.print("0");
  Wire.requestFrom(72, 2);
  lcd.print("1");
  while(Wire.available()){
        lcd.print("2");
 Analog_Wert = Wire.receive();
    lcd.print("3");
  Analog_Neu = true;
  }
    //Analog_Neu = true;
  }
  else
  {
    FlexiTimer2::stop();
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Fehler 1");
  }
}

void Abtastrate_setzen (int Abtastrate){
  lcd.clear();
  lcd.setCursor(0,1);
  lcd.print(Abtastrate);
  
  switch (Abtastrate){
  case 49:
    FlexiTimer2::set(50,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 50:
    FlexiTimer2::set(100,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 51:
    FlexiTimer2::set(250,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 52:
    FlexiTimer2::set(500,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 53:
    FlexiTimer2::set(1000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 54:
    FlexiTimer2::set(2500,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 55:
    FlexiTimer2::set(5000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 56:
    FlexiTimer2::set(10000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 57:
    FlexiTimer2::set(25000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 48:
    FlexiTimer2::set(100000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  }
}

void Spannungsbereich_setzen (int Spannungsbereich){
  switch (Spannungsbereich){
  case 49:  Wire.beginTransmission(32);
            Wire.send(254); //K1 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 50:  Wire.beginTransmission(32);
            Wire.send(253); //K2 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 51:  Wire.beginTransmission(32);
            Wire.send(251); //K3 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 52:  Wire.beginTransmission(32);
            Wire.send(247); //K4 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 53:  Wire.beginTransmission(32);
            Wire.send(239); //K5 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 54:  Wire.beginTransmission(32);
            Wire.send(255); //alle Relais werden abgeschalten
            Wire.endTransmission();
  break;
  }
}

The Code is for a smal USB-Ozilloskop.
I hope you understand my english, I haven't speak it for a long time.
MfG Jago

PS.: What I forgot to say, it seem´s to be no problem with the PCF8591, the same problem appears when I use the PCF8574 instead.

Thanks , I will try tommorow morning.

Hi,
coud you post your full code? I like to see in wich environment you use the I2C function´s.
Maybe there is a generel problem with I2C funktion´s and Interruptserviceroutines.
But I´ve no idea what the solution for this problem coud be. Normaly the Timer and the I2C are two totaly diverent parts of the ATmega and I see no way how they affect each other.
MfG Jago

Hallo Jago
Ich werde mal in deutsch schreiben, da du der einzige bist der sich zu Wort gemeldet hast.
Beschreibung des Projects :
Ich habe 4 Heizfolien als Fussbodenheizung in meinem Wohnmobil, die ich per PWM steuern moechte. Im Augenblick sind sie direct an 230 V angeschlossen , was bei 24h approx 10 KW bedeutet bei 3 DKr/ KW = 300 Dkr / Tag. Hinzu kommen noch die Heizkabel fuer Wasserleitungen und Abfluss die ueber einen Temperature Controller gesteuert sind. Meinen taeglichen Verbrauch moechte ich senken. Mit dem PCF8591 moechte ich 4 Potis einlesen , die mir den Wert fuer die PWM's liefern, damit ich mit den Einsstellungen experimentieren kann um die geeigneten Werte zu finden. Meine Basis Platine hat eine Real Time Clock (DS1307) und einen SD-Card reader um Werte mitzuschreiben. Das LCD-Display und 4 Button Keyboard wird mit 2 PCF8574 controlliert. Ich werde noch einen zweiten PCF8591 einsetzen um die Batteriespannungen meiner drei 100 Ah Batterien zu ueberwachen und gegebenenfalls abzuschalten oder den Charger aktivieren, wenn die Spannung unter 11 V sinkt. An meiner Batterie haengt zudem noch ein 4KW DC/AC wandler der aktiviert wird , wenn ich kein Outboard power habe.
Im letzten Winter hatte ich zuviel Gas verbraucht und eingefrorene Leitungen gehabt ( bis -25 deg C ) - Wintercamping is great !!.
Gestern hatte ich den Kanal 1 einlesen koennen (nicht stabil, kommen zwischendurch falsche Werte , Kanal 2 hat manchmal funktioniert( nicht stabil ) und 3 - 4 noch garnicht. Im Augenblick experiementiere ich nur mit PCF8591 einzeln und veraendere nur den Kanal zum auslesen. Ich habe letzte Nacht eine neue Platine geroutet, die ich gleich im Labor herstellen werde. Es ist moeglich das das Problem von der Platine kommt.

Ach, ich war ja mal total auf dem Holzweg.
Dein Fehler ist ein anderer als bei mir, du mußt EXT auf GND legen.
Hab mir dein Layout garnicht so genau angeschaut.
EXT muss auf GND damit der interne Oszillator benutzt wird, denke dann sollte alles laufen.
MfG Jago

PS.: Sorry das ich so kurz angebunden bin, sitz in einer Vorlesung.

In meinen neuen Layout habe ich EXT auf GND und habe noch ein paar Zener verbaut als Safety.

Oh, das Layout würd ich gern mal sehen.
Vorallem die von dir verwendeten Zenerdioden interessieren mich.
Bei meiner Anwendung arbeite ich mit +-2,5V, hab mich für 2*4 in Reihe geschaltene 1N4007 entschieden, die beiden Stränge hab ich dann Antiparallel nebeneinander gesetzt(ich benutzte zwei Differenzeingänge). Leider fängt die Kennlinie ab 2,2V-2,3V an zu steigen, sodass ich bei 2,5V ca. 1mA Verlust hab. Naja immernoch besser als Zenerdioden, da sieht die Kennlinie schlimmer aus. Philips sagt ja leider nicht wie viel Überspannung die Differenzeingänge vertragen.
Was mir übrigens noch aufgefallen ist, deine Widerstände an SDA und SCL sind recht klein, kenn das eigentlich mit 10k (ich selbst verwende garkeine externen, hab nur kurze Leitungen von ca 30cm). Nicht das deine IC´s Probleme bekommen die Leitung auf GND zu ziehen.

Hej Jago
Mein fehler wahr , das ich EXT nicht gegrounded habe. Nun kann ich jeden kanal einwandfrei auslesen. Fuer den I2C Bus verwende ich 4K7 welches standard ist. Als Zener benutze ich 4 x ZD5V6 fuer jeden Eingang und noch eine fuer den Ref eingang gegen GND. Ich werde mir wahrscheinlich noch den TLV274 ein Rail to Rail OpAmp davor setzen anstatt der Zener. Ich gute erfahrung mit diesem Teil in einigen Project's gemacht.

Arduino-I2C-ADC-V1.2.sch (115 KB)

PCB

Arduino-I2C-ADC-V1.2.pdf (18.1 KB)

Mir gefällt deine Lösung mit dem TLV274, das ist eigentlich genau das richtige für mein Projekt :smiley:
Ich glaub bei dir sind die Zenerdioden schon fast zu übertrieben Vorsichtig.
Na denn, ich Wünsch dir noch dir noch viel Erfolg bei deinen Projekt, wär schön wenn bei mir auch alles so klappen würde....
MfG Jago