MOD-TC interface example (TC=Thermo Couple)

Download pre-release library modules and new examples to use with Astrobe for LPC2000. Forum members can also upload their own source code examples.
Post Reply
4GlCoder
Posts: 27
Joined: Fri Jul 22, 2011 2:47 pm

MOD-TC interface example (TC=Thermo Couple)

Post by 4GlCoder » Sat Oct 27, 2012 12:41 pm

With this Olimex module you can measure the temperature inside of your oven! The module measures temperatures of up to 1000 deg. Celsius.

I didn't try that, but made it show the Room-temperature.
The MOD-TC interface uses MAX6675 IC and uses a pseudo SPI-interface. With pseudo I mean that it is using a wiring scheme that allows it to be used in a real SPI setup, but does need it's own software driver.

As this is UEXT plugin compatible, after studying the schematic I came up with the following:

Code: Select all

MODULE MAX6675;
(* The primary use of the library is to easily interface with a MAX6675 chip via it's 
   PSEUDO-SPI interface. Use the following code to initialize the library. 

   units is one of the following: 
   0 = raw 0-4095 value
   1 = temp in °C
   2 = temp in °F

  Following this you can use the ReadTemp() function to return the temperature
  as a REAL.
  temperature := MAX6675.readTemp();
*)

IMPORT SYSTEM, Out, LPC := LPC2378, Timer;

PROCEDURE ToggleCS(high : BOOLEAN);
BEGIN
  IF high THEN
    SYSTEM.PUT(LPC.FIO0SET, {6});  (* Set P0.6 high *)
  ELSE
    SYSTEM.PUT(LPC.FIO0CLR, {6});  (* Set P0.6 low *)
  END
END ToggleCS;

PROCEDURE ToggleClock(high : BOOLEAN);
BEGIN
  IF high THEN
    SYSTEM.PUT(LPC.FIO0SET, {7});  (* Set P0.7 high *)
  ELSE
    SYSTEM.PUT(LPC.FIO0CLR, {7});  (* Set P0.7 low *)
  END
END ToggleClock;

(* returns 1 or 0 for p0[8]=input data *)
PROCEDURE ReadDataBit() : INTEGER;
VAR
  val : INTEGER;
BEGIN
  IF SYSTEM.BIT(LPC.FIO0PIN, 8) THEN
    val := 1
  ELSE
    val := 0
  END;
  RETURN val
END ReadDataBit;

(* out : FALSE means error, so value is not meaningful. 
         TRUE means ok, it looks like the TC is hooked up *)
        
PROCEDURE RawRead(VAR value : INTEGER) : BOOLEAN;
CONST
  dly = 1000;  (* unit= microseconds *)
VAR
  i, v : INTEGER;
  iserror : BOOLEAN;
BEGIN
(* 
  Initiate a temperature conversion. According to MAX's tech notes FAQ's 
  for the chip, Line going high initiates a conversion, which means, we 
  need to clock the chip low to high to initiate the conversion, then wait 
  for the conversion to be complete before trying to read the data from 
  the chip.
*)
  ToggleCS(FALSE);                (* start conversion *)
  Timer.uSecDelay(2*dly);         (* delay a bit *)
  value := 0; i := 16;
  WHILE i > 0 DO
    DEC(i);
    ToggleClock(FALSE);           (* read data on falling edge *)
    IF i IN {0,1,15} THEN         (* Ignore these bits *)
      v := ReadDataBit()
    ELSIF i = 2 THEN              (* is a TC connected? *)
      iserror := ReadDataBit()=1
    ELSE                          (* read the value-bit *)
      value := LSL(value,1) + ReadDataBit();
    END;
    Timer.uSecDelay(dly);         (* delay a bit *)
    ToggleClock(TRUE);            (* Reading on the falling edge of the clock *)
    Timer.uSecDelay(dly)          (* delay a bit *)
  END;
  ToggleCS(TRUE);
  RETURN iserror
END RawRead;

(* Binary display of 12 lsb bits of value 'v' *)
PROCEDURE DumpBits(v : INTEGER);
VAR
  idx : INTEGER;
  sbits : SET;
BEGIN
  sbits := SYSTEM.VAL(SET, v);
  FOR idx := 11 TO 0 BY -1 DO
    IF idx IN sbits THEN
      Out.Char("1")
    ELSE
      Out.Char("0")
    END
  END;
  Out.Ln;
END DumpBits;

PROCEDURE ReadTemp*() : REAL;
CONST
  units = 1;            (* Units to readout temp (0 = raw, 1 = °C, 2 = °F)*)
VAR
    value : INTEGER;
    temp  : REAL;
BEGIN
  IF ~RawRead(value) THEN
    DumpBits(value);  
    (* 
      Keep in mind that the temp that was just read is on the digital scale
      from 0°C to 1023.75°C at a resolution of 2^12.  We now need to convert
      to an actual readable temperature.  Now multiply by 0.25. = divide by 4
    
      2 = temp in deg F
      1 = temp in deg C
      0 = raw chip value 0-4095 
    *)
    temp := FLT(value);
    IF units = 2 THEN 
      temp := temp * 0.25 * 9.0 / 5.0 + 32.0
    ELSIF units = 1 THEN
      temp := temp * 0.25
    (* else no further conversion needed *)
    END;
  ELSE
    temp := -1.0
  END;
    (* Output negative if there is a TC error, otherwise return 'temp' *)
  RETURN temp
END ReadTemp;

(* Configured for use/test with LPC2378-STK *)

PROCEDURE Init*;
VAR
  mbits : SET;
BEGIN
  (* MISO1 = P0[8] = input  = reading data from MOD-TC
      SCK1 = P0[7] = output = pseudo clock 
      SSEL = P0[6] = output = Select *)
      
  SYSTEM.GET(LPC.SCS, mbits);
  IF ~(0 IN mbits) THEN
    SYSTEM.PUT(LPC.SCS, mbits +{0});    (* Although we're not in a hurry, select FastIO *)
  END;
  SYSTEM.GET(LPC.PINSEL0, mbits);
  SYSTEM.PUT(LPC.PINSEL0, mbits - {12..17}); (* P0[6,7,8] = is GPIO*)
  SYSTEM.GET(LPC.PINMODE0, mbits);
  SYSTEM.PUT(LPC.PINMODE0, mbits + {13,15,17} - {12,14,16}); (* No pulls, already wired *)
  SYSTEM.GET(LPC.FIO0DIR, mbits); 
  SYSTEM.PUT(LPC.FIO0DIR, mbits - {8} + {6,7});           (* P0[6,7] output, P0[8] = input *)
  ToggleCS(TRUE);     (* CS HIGH *)
  ToggleClock(FALSE); (* Clock Low *)
END Init;

END MAX6675.
It is always good practice to study given documents, so after an initial attempt with SPI interfacing and a view with a Logic Scipe I concluded that this wasn't the right way. So I came with the above code.

Creating a final demo program:

Code: Select all

MODULE DemoReader;
(*
  Example using the MAX6675 Module.
 *)
IMPORT MAX6675, Timer, Reals, Out, Main;

(*  MAX6675 Module already sets pin modes for MAX6675 chip! *)

PROCEDURE run;
VAR
  temperature : REAL;  (* Temperature output variable *)
  buf : ARRAY 10 OF CHAR;
BEGIN
  Timer.Init(Timer.uSecs);  (* Initialize and use microseconds as unit of delay *)
  MAX6675.Init;
  REPEAT
  	(* Read the temp from the MAX6675 *)
  	temperature := MAX6675.ReadTemp();
  	IF temperature < 0.0 THEN
    	(* If there is an error with the TC, temperature will be < 0 *)
  		Out.String("Thermocouple Error on CS")
  	ELSE
  		Out.String("Current Temperature=")
  	END;
              Reals.RealToStrF(temperature, 5, buf);  
              Out.String(buf); Out.Ln;
  	(* Wait 15 seconds before reading again *)
  	Timer.uSecDelay(15000000)
  UNTIL FALSE
END run; 

BEGIN
  run
END DemoReader.
As You can see, not a lot of code is needed to get things going, but keep in mind:

- Apart from the module, you need to connect the thermocouple wire, which is an additional buy.
- Connect the thermocouple wire correct to get accurate results,
- Carefully arrange electricity , moisture and heat!

Cheers.

Post Reply