TechZone A-D With OneWire

From RepRap
Revision as of 12:03, 19 December 2011 by Glenn (talk | contribs) (catchg)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

This article assumes a certain level of understanding of circuits and of the Arduino environment. It shows the circuit and the code necessary to use a DS2760 High-Precision Li+ Battery Monitor chip to measure the temperature of the tip with a thermocouple. You can order the assembled circuit here and you can see how to hook it up and download the firmware from TechZone_Tip_Assembly. If you need help getting this to work you can contact us.


Where the idea came from

This thermocouple circuit is based on the Parallax kit using the DS2760 High-Precision Li+ Battery Monitor. The DS2760 has internal temperature measurement capabilities as well as a high precision A-D used for measuring current. It is capable of measuring 15.625uV per step. Another benefit of this chip is that it is designed to read current in both directions. This allows the thermocouple to be hooked up in either direction with just a little work in the code.


The Circuit

The circuit is simple, the thermocouple is hooked across the current sense pins, the enable pins are tied low and the communications pin is hooked up to one of the I2C data pins. See the schematic below.

Schematic

A-DSchematic.jpg


The Code

The first thing needed is a library for One Wire communications that can be obtained here. Thanks to Paul Stoffregen for compiling the work of several people into a complete and easily used library for one wire communications. Full credits can be viewed on the bottom of the page at that link. The code and table I used are based on the sample code shown with the Parallax kit linked to above. It was written for their basic stamp board, so it took some changes to make it work. Also they read the value of the thermocouple and then do math to convert it from 15.625uV steps to actual uV. I decided instead to convert the table from the uv value to a 15.625uV value. I only converted the one table, but other types of thermocouples can be read if you convert the table in the Parallax sample to the same 15.625uV steps.

Edit config.h

Set the temperature options

First a couple of changes in the configuration file to allow this temperature option to be selected and to tell the processor which pins to use.

near the top comment out the other temperature options and add #define USE_DS2760

//#define USE_THERMISTOR
//#define AD595_THERMOCOUPLE
//#define MAX6675_THERMOCOUPLE
#define USE_DS2760


Set the pins for OneWire Communications

further down add the pins to use for the OneWire communications

change:

#ifdef MAX6675_THERMOCOUPLE
// I2C pins for the MAX 6675 temperature chip
#define SO 18    // MISO
#define SCK 19   // Serial Clock
#define TC_0 2  // CS Pin of MAX6607
#else
#define TEMP_PIN 7
#endif

to:

#ifdef MAX6675_THERMOCOUPLE
// I2C pins for the MAX 6675 temperature chip
#define SO 18    // MISO
#define SCK 19   // Serial Clock
#define TC_0 2  // CS Pin of MAX6607
#else
#ifdef USE_DS2760
// I2C pins for the DS2760 temperature circuit
#define OW 19    // Pin used for the OneWire communications
#define OWTroubleshoot 18    // Pin used for troubleshooting output and as a second pin to check for the presence of the temperature circuit 
#define ReadNet 0x33
#define SkipNet 0xCC
#define RdReg 0x69
#define thermoTypeK  //Currently this is the only table i have set up.  When i am showing the tables i will tell you how you can get a table for the other types of thermocouples if you need them.  Type K is the most common.
//#define thermoTypeJ
//#define thermoTypeT
#else
#define TEMP_PIN 7
#endif
#endif


Edit temperature.h

In the temperature.h add the followning

#ifdef USE_DS2760
#ifdef thermoTypeK
//Table for looking up temperatures based on units of 15.625uV (the DS2760 voltage measurement value is 15.625uV per  unit) of thermocouple. 
#define NUMTEMPS 40
short temptable[NUMTEMPS][2] = {
   {0,0},
   {25, 10},
   {51, 20},
   {77, 30},
   {103, 40},
   {129, 50},
   {156, 60},
   {182, 70},
   {209, 80},
   {236, 90},
   {262, 100},
   {289, 110},
   {315, 120},
   {341, 130},
   {367, 140},
   {393, 150},
   {419, 160},
   {444, 170},
   {470, 180},
   {495, 190},
   {521, 200},
   {546, 210},
   {572, 220},
   {598, 230},
   {624, 240},
   {650, 250},
   {676, 260},
   {702, 270},
   {728, 280},
   {755, 290},
   {781, 300},
   {808, 310},
   {834, 320},
   {861, 330},
   {888, 340},
   {915, 350},
   {942, 360},
   {968, 370},
   {995, 380},
   {1022, 390}
};
#endif
#endif


Edit extruder_class

Include OneWire library

at the top:

#include "OneWire.h"

OneWire temperature read function

further down add:


#ifdef USE_DS2760
int readDS2760(int useWire)
{
  
  word vIn;
  word tmpCJ;
  word tCuV;
  byte sign;
  word cjComp;
  word tempC;
  word tblLo;
  word tblHi;
  word eePntr;
  word testVal;
  byte error;
  byte tmpRead;
  int i;
  int tries=0;
  
  OneWire myWire(useWire); 
	 
  myWire.reset();
  myWire.write(SkipNet,0);
  myWire.write(RdReg,0);
  myWire.write(0x18,0);
  tmpRead=myWire.read();
  myWire.reset();
  
  if(bitRead(tmpRead,7))
  {
    tmpCJ=0;
  } else {
    tmpCJ=tmpRead;
  }	
  
  
  myWire.reset();
  myWire.write(SkipNet,0);
  myWire.write(RdReg,0);
  myWire.write(0x0E,0);
  tmpRead=myWire.read();
  tCuV=tmpRead;
  tCuV=tCuV << 8;
  tmpRead=myWire.read();
  myWire.reset();
  tCuV=tCuV | tmpRead;
  tCuV=tCuV >> 3;
  if(bitRead(tCuV,12))
  {
     tCuV = tCuV | 0xF000;
     tCuV = tCuV ^ 0xFFFF;
  }
   
 
    cjComp=temptable[(int)(tmpCJ/10)][0] + (tmpCJ-temptable[(int)(tmpCJ/10)][1])*(temptable[(int)(tmpCJ/10)+1][0]-temptable[(int)(tmpCJ/10)][0])/10;

    cjComp=cjComp+tCuV;
  if(cjComp>temptable[NUMTEMPS-1][0])
  {
    return temptable[NUMTEMPS-1][1];
  }
  for (i=1; i<NUMTEMPS; i++)
  {
    if (temptable[i][0]>cjComp)
    {
      return temptable[i-1][1] + (cjComp-temptable[i-1][0])*(temptable[i][1]-temptable[i-1][1])/(temptable[i][0]-temptable[i-1][0]);
      
    }
  }
  return 2000;  //if it fails to get a temperature return 2000 so it will turn off the heat.
}
#endif


Debugging Tools

As i was working on this circuit and code i needed some debug info so i used my OWTroubleshoot pin i set earlier to output data in a way i could read on my oscilloscope. If you need it you can add this inside the ifdef block above


void outputDebugInfo(int outNum)
{
  int dataDelay = 20;
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(10);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(10);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(3);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(3);
digitalWrite(OWTroubleshoot,1);
        delayMicroseconds(3);
digitalWrite(OWTroubleshoot,0);
digitalWrite(OWTroubleshoot,bitRead(outNum,0));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,1));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,2));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,3));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
        delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,4));
        delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,5));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,6));
	delayMicroseconds(dataDelay);
 digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
  digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
  digitalWrite(OWTroubleshoot,bitRead(outNum,7));
	delayMicroseconds(dataDelay);
 digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
  digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,8));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,9));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,10));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,11));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
        delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,12));
        delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,13));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,14));
	delayMicroseconds(dataDelay);
 digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
  digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
  digitalWrite(OWTroubleshoot,bitRead(outNum,15));
	delayMicroseconds(dataDelay);
}
void outputDebugInfoByte(byte outNum)
{
  int dataDelay = 20;
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(10);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(10);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(3);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(3);
digitalWrite(OWTroubleshoot,1);
        delayMicroseconds(3);
digitalWrite(OWTroubleshoot,0);
digitalWrite(OWTroubleshoot,bitRead(outNum,0));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,1));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,2));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,3));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
        delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,4));
        delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
 	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,5));
	delayMicroseconds(dataDelay);
digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
digitalWrite(OWTroubleshoot,bitRead(outNum,6));
	delayMicroseconds(dataDelay);
 digitalWrite(OWTroubleshoot,0);
	delayMicroseconds(1);
  digitalWrite(OWTroubleshoot,1);
	delayMicroseconds(1);
  digitalWrite(OWTroubleshoot,bitRead(outNum,7));
	delayMicroseconds(dataDelay);
}


Code for communications and fail safe

inside of the function extruder::internalTemperature() add the following code.

#ifdef USE_DS2760
  
  word vIn;
  word tmpCJ;
  word tCuV;
  byte sign;
  word cjComp;
  word tempC;
  word tblLo;
  word tblHi;
  word eePntr;
  word testVal;
  byte error;
  byte tmpRead;
  int i;
  int useWire;
  int tries=0;
  
  useWire=OW;
  OneWire myWire(useWire);
     //In this do loop i try to read from the OW pin and then the OWtroubleshoot pin.  This is so that either of the pins in the I2C connection will work.  Also if it fails to read the chip after a few tries it returns a 2000 to prevent overheating the tip if communications are lost.
  do {
  OneWire myWire(useWire);
	 
  myWire.reset();
  myWire.write(SkipNet,0);
  myWire.write(RdReg,0);
  myWire.write(0x18,0);
  tmpRead=myWire.read();
  myWire.reset();
  
  if(bitRead(tmpRead,7))
  {
    tmpCJ=0;
  } else {
    tmpCJ=tmpRead;
  }	
    if(tmpCJ==0)
    {
      tries+=1;
      if(useWire==OW)
      {
         useWire=OWTroubleshoot;
      } else {
        useWire=OW;
      }
    } else {
      tries=10;
    } 
	} while (tries<5);
  
 if(tries<10)
 {
   return 2000;
 }
    //After finding the correct pin to use i read the thermocouple and then check the value.  If the temperature is 0 i return 1999 to prevent overheating and to distinguish the difference from a fail to communicate.
  tmpRead=readDS2760(useWire);
  
  if(tmpRead==0)
  {
    return 1999;
  } else {
    return tmpRead;
  }
#endif


This code went through several changes as i was troubleshooting, so there may be some unused variables in there. If anyone notices any feel free to let me know and i will clean it up. I didn't want to make any changes as i was posting this since i knew the current code is working.