Go Down

Topic: TC74 temperature sensor (Read 5067 times) previous topic - next topic

baconsniffer

After much searching I could not find any good examples of using the TC74 with an Arduino except for one Instructable. That inspired me to add TC74 support to a DS1307 based clock and share it with everyone. My project consists of a HD44780 display in 4-bit mode as described in the LiquidCrystal library and a DS1307 on the IIC bus. The code is fairly simple and assumes that the clock is already setup and running. Here it is:

Code: [Select]
// Date and time functions using a DS1307 RTC
// and temperature from a TC74
// connected via I2C and Wire lib.

// 2011/11/14, Paul Jenkins
// smellin_bacon@yahoo.ca

// Based on lots of stuff I found elsewhere
// and stuff I put together myself. I take
// no credit for anything. I release this in
// the spirit of open, free software. Hopefully
// someone will learn from it as I have learned.

#include <Wire.h>
#include "RTClib.h"
#include <LiquidCrystal.h>

// led pin to blink
#define ledPin 13

// Address of TC74A7 temperature sensor (from datasheet)
// listed in 7-bit form as 1001 111 or 0 1001 111 or 0x4F.
// Check the TC74 datasheet to see which TC74 you have.
#define tc74a7 0x4f

RTC_DS1307 RTC;

// Initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {

    pinMode(ledPin, OUTPUT);           // Setup blink pin as output

    // Setup the LCD's number of columns and rows:
    lcd.begin(16, 2);
   
    Wire.begin();                      // Setup iic/twi
   
    RTC.begin();                       // Setup rtc
    // Note that this code assumes:
    // a) Your DS1307 is running
    // b) Your DS1307 is set to the correct date and time
}

// Storage for temperature
int temp;
   
// Flag for negative temperature   
int neg;
   
void loop() {

    // set the cursor to column 0, line 1
    // (note: line 1 is the second row, since counting begins with 0):
    lcd.setCursor(0, 0);

    // Get date and time into RTC structure
    DateTime now = RTC.now();
   
    // Get a reading from the temperature sensor
    // talk with tc74
    Wire.beginTransmission(tc74a7);
    // command is 'read'
    Wire.send(0x00);
    // end sequence and send bytes
   
    // request 1 byte from sensor
    Wire.requestFrom(tc74a7,1);
   
    if (Wire.available()) {
       temp = Wire.receive();
       }
    neg = false;
    if (temp > 127) {
       temp = 255 - temp + 1;
       neg = true;
       }
       
    // End conversation with TC74
    Wire.endTransmission();
   
    lcd.print(now.year(), DEC);
    lcd.print('/');

    if (now.month()<10)
       lcd.print('0');
    lcd.print(now.month(), DEC);
    lcd.print('/');

    if (now.day()<10)
       lcd.print('0');
    lcd.print(now.day(), DEC);
    lcd.print("  ");

    // Display temperature
    if (neg == true) {
       lcd.print('-');
       }
    lcd.print(temp, DEC);
    // Display degree symbol on LCD
    lcd.write(0xdf);
    lcd.print('C');

    // Move to line 2 of display
    lcd.setCursor(0, 1);

    if (now.hour()<10)
       lcd.print('0');
    lcd.print(now.hour(), DEC);

    lcd.print(':');

    if (now.minute()<10)
       lcd.print('0');
    lcd.print(now.minute(), DEC);

    lcd.print(':');

    if (now.second()<10)
       lcd.print('0');
    lcd.print(now.second(), DEC);
       
    digitalWrite(ledPin, HIGH);
    delay(250);
    digitalWrite(ledPin, LOW);
    delay(500);
}

/*
// Code something like this can handle reading
// and formatting temperature for LCD.
// I will consider adding this to the next version.
// A PIC program was the inspiration for this - thanks.

char temperature[] = " 000 C";

num = ReadTemp();

// Check for negative temperature
if (num > 127) {
   temperature[0] = '-';
   num = ~num + 1;
}
else temperature[0] = ' ';

temperature[1] = num/100 + 48;     // 100's
temperature[2] = (num/10)%10 + 48; // 10's
temperature[3] = num%10 + 48;      // 1's
temperature[4] = ' ';              // find code for degree sym
temperature[5] = 223;              // 'C'

// eliminate 0's at beginning
if (temperature[1] == '0') {
   temperature[1]=' ';
   if (temperature[2]=='0') temperature[2]=' ';
}
*/
Fun = Arduino + Imagination

robtillaart

Thanks for sharing,

Do you have a link to the datasheet?

It would be a nice improvement if the sensor was "Classified" so one could write :

Code: [Select]

TC74 tempSensor;

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  int t = tempSensor.getTemperature();
  Serial.println(t);
  delay(10000);
}


based upon your sketch it should not be to difficult. A bit similar to the RTC class ..
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

baconsniffer

Thanks for the feedback robtillaart.

The datasheet is at: http://ww1.microchip.com/downloads/en/DeviceDoc/21462c.pdf

I like the idea of "class-ifying" this device. Since this is only the second Arduino sketch I've written, the details of doing this are beyond me at the moment. However, this is a great opportunity to expand so I will look into it. Perhaps I can take what was done with the RTC and modify it. One this different about the TC74 is can have one of 8 different addresses depending on exactly which part you purchase. You could have up to 8 of these on one bus so there are lots of possibilities for remote sensing.
Fun = Arduino + Imagination

robtillaart


That means you should give the address as a parameter in the constructor of the class

check - http://www.arduino.cc/en/Hacking/LibraryTutorial -
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

baconsniffer

I've been through the library tutorial and now I'm trying to get the TC74 code wrapped into the library. Still getting weird compilation error but I think I am close. Will try to post my current code in a bit.
Fun = Arduino + Imagination

baconsniffer

Ok, so I've read through the tutorial on libraries and examined the code of several to see how things are done and now I've written a simple library to handle reading from multiple TC74 sensors. The problem is that I'm getting compilation errors under Arduino IDE 1.0 and I'm not sure what to do. Not that I'm expecting anyone to fix the code for me. I need to learn this. What I need is a little nudge in the right direction.

First, the sample sketch that prints the current temperature value to the serial monitor every few seconds:

Code: [Select]
#include <Wire.h>

// Test TC74 library
#include <TC74.h>

TC74 sensor(0);  //Data object for sensor

void setup() {
  Serial.begin(9600);
}

void loop() {
  while(1) {
    Serial.println(sensor.read());
    delay(5000);
  }
}


Since I'm not sure on the maximum posting length the header and cpp files will follow.
Fun = Arduino + Imagination

baconsniffer

This is the header TC74.h

Code: [Select]
/*
  TC74.h - Library for Microchip TC74 temperature sensors.
  Created by Paul Jenkins, November 17, 2011.
  Released into the public domain.
*/

#ifndef TC74_h
#define TC74_h

// Allow for compilation in 0022 or 1.0
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "Wire.h"

class TC74 {
public:
    TC74(byte addr);
    TC74();
    int read();
private:
    byte _addr;
};

#endif


And this is the meat of the library TC74.cpp


Code: [Select]
/*
  TC74.cpp - Library for Microchip TC74 temperature sensors.
  Created by Paul Jenkins, November 17, 2011.
  Released into the public domain.
*/

// Allow for compilation in 0022 or 1.0
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "TC74.h"
#include "Wire.h"

//First, the constructor where an address is supplied
TC74::TC74(byte addr) {
//  byte _addr;
  if (addr == 0) _addr = 0x48;
  if (addr == 1) _addr = 0x49;
  if (addr == 2) _addr = 0x4a;
  if (addr == 3) _addr = 0x4b;
  if (addr == 4) _addr = 0x4c;
  if (addr == 5) _addr = 0x4d;
  if (addr == 6) _addr = 0x4e;
  if (addr == 7) {
    _addr = 0x4f;
  }
  else {
    _addr = 0x48;   //Set a default address
  }
}

//Second, a constructor where no address is specified
TC74::TC74(void) {
byte _addr = 0x4f;
}

int TC74::read(void)
{
int _temp = 255;
// Get a reading from the temperature sensor
        Wire.beginTransmission(_addr);
        Wire.write((uint8_t) 0);
        Wire.endTransmission();
   
        // request 1 byte from sensor
        Wire.requestFrom(_addr,1);
   
        _temp = Wire.read();
       
        if (_temp > 127) {
           _temp = 255 - _temp + 1;
        }
       
        return _temp;
}
Fun = Arduino + Imagination

baconsniffer

The errors I was getting from the compiler indicated that the compiler was unhappy with the type of variable I was passing to the Wire functions.

My code was calling the Wire.receive method as follows:

Code: [Select]
        // request 1 byte from sensor
        Wire.requestFrom( _addr, 1);


Where _addr is defined as type byte

The resulting compiler error is:

Quote
R:\sketches\libraries\TC74\TC74.cpp: In member function 'int TC74::read()':
R:\sketches\libraries\TC74\TC74.cpp:49: error: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
C:\Arduino\libraries\Wire/Wire.h:54: note: candidate 1: uint8_t TwoWire::requestFrom(int, int)
C:\Arduino\libraries\Wire/Wire.h:53: note: candidate 2: uint8_t TwoWire::requestFrom(uint8_t, uint8_t)


However, if, when calling Wire.receive, I do a cast on the arguments passed

Code: [Select]
// request 1 byte from sensor
//        Wire.requestFrom((int) _addr, (int) 1);


the sketch compiles correctly.

Is this a result of my poor coding or is this an aspect of the IDE 1.0 or am I just completely out to lunch. I welcome any comments or suggestions.
Fun = Arduino + Imagination

robtillaart


Code can be a bit shorter, here a partial refactoring
Code: [Select]

#define BASEADDR 0x48

TC74::TC74(byte addr)
{
  _addr = BASEADDR + addr;
  if (addr > 7) _addr = BASEADDR;
}

TC74::TC74(void)
{
_addr = BASEADDR; 
}

int TC74::read(void)
{
        Wire.beginTransmission(_addr);
        Wire.write( (uint8_t) 0);
        int rv = Wire.endTransmission();                        // note the return code indicating connection!! look in the lib for details
        Wire.requestFrom( _addr, (uint8_t)1 );               // only cast one is enough
        int _temp = Wire.read();
        if (_temp > 127)
        {
             _temp = 256 - _temp;
        }
        return _temp;
}


The casting problem is caused by the fact that there are two prototypes which are an equal match as you call the function with one uint8_t and one int as the value 1 is interpreted as an int by the compiler.


Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up