Problem with temperature sensor SMT160-3

I want measure temperature with arduino uno and SMT160-30,

specification of SMT160 :
http://blogs.epfl.ch/document/3748

I used this code :

//Sample code to fetch temperature using SMT16030 sensor
//I'd suggest you to use powerline noise filtering and polarity damage protection RC kit with sensor.
//
//

int SensorPin= 7; //Digital pin
float DutyCycle = 0; //DutyCycle that need to calculate
unsigned long SquareWaveHighTime = 0; //High time for the square wave
unsigned long SquareWaveLowTime = 0; //Low time for the square wave
unsigned long Temperature = 0; //Calculated temperature using dutycycle

void setup()
{
Serial.begin(115200); //Initialized serial according to your wish
pinMode(SensorPin, INPUT); //Sets the specified digital pin as an input
}

void loop()
{
DutyCycle = 0; //Initialize to zero to avoid wrong reading
Temperature = 0; //due to incorrect sampling etc

//Read high time for square wave
SquareWaveHighTime = pulseIn(SensorPin, HIGH);
//Read low time for square wave
SquareWaveLowTime = pulseIn(SensorPin, LOW);

DutyCycle = SquareWaveHighTime; //Calculate Duty Cycle for the square wave
DutyCycle /= (SquareWaveHighTime + SquareWaveLowTime);
//Compute temperature reading according to D.C.
// where D.C. = 0.320 + 0.00470 * T
Temperature = (DutyCycle - 0.320) / 0.00470;

Serial.print("\nDuty Cycle: "); //Print for debugging if needed
Serial.print(DutyCycle);
Serial.print(" Calculated Temperature (*C): ");
Serial.println(Temperature);
//Wait for a while, I'm a micro guy. Can't compute as fast as you!
delay(1000);
}

but results are very unstable and measured temperature is jumping +-2°C.
What's wrong ? Is code ok ? How to improve ?

Thanks for help

Alda

what if u do this

 SquareWaveHighTime = pulseIn(SensorPin, HIGH); //Read low time for square wave
SquareWaveLowTime = pulseIn(SensorPin, LOW);

twice?

i guess, that ur "Serial.print()"-s steal some time from the "SquareWaveHighTime = pulseIn"...

So ? How to modify ?

special subroutine where I will read Pulsein ?

Alda

not just once

 SquareWaveHighTime = pulseIn(SensorPin, HIGH);
SquareWaveLowTime = pulseIn(SensorPin, LOW); //Read low time for square wave

but twice, like this:

 SquareWaveHighTime = pulseIn(SensorPin, HIGH);
SquareWaveLowTime = pulseIn(SensorPin, LOW); //Read low time for square wave
SquareWaveHighTime = pulseIn(SensorPin, HIGH);
SquareWaveLowTime = pulseIn(SensorPin, LOW); //Read low time for square wave

I had a similar problem with my LM34 temp sensor. (http://arduino.cc/forum/index.php/topic,111366.0.html) Poor stability with inaccurate temp readings. I finally realized the 5v coming from the USB was the problem. Every time the hard disk spun or with heavy processing the PC USB would lag in its voltage output. (Dell Studio XPS)

Remedy: Switch to an external power supply. I don’t know about the SMT160-3 but the LM34 needs +5 to +20 on the Vs. I found running at a supply of 7v fixed my problem.

I am not an expert and this information may be inaccurate.

RIDDICK:
not just once

 SquareWaveHighTime = pulseIn(SensorPin, HIGH);

SquareWaveLowTime = pulseIn(SensorPin, LOW); //Read low time for square wave




but twice, like this:


SquareWaveHighTime = pulseIn(SensorPin, HIGH);
SquareWaveLowTime = pulseIn(SensorPin, LOW); //Read low time for square wave
SquareWaveHighTime = pulseIn(SensorPin, HIGH);
SquareWaveLowTime = pulseIn(SensorPin, LOW); //Read low time for square wave

No improvement :
Results which I can see on serial port :

Duty Cycle: 0.46 Calculated Temperature (*C): 29

Duty Cycle: 0.46 Calculated Temperature (*C): 28

Duty Cycle: 0.45 Calculated Temperature (*C): 26

Duty Cycle: 0.44 Calculated Temperature (*C): 24

Duty Cycle: 0.45 Calculated Temperature (*C): 26

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Duty Cycle: 0.46 Calculated Temperature (*C): 29

Duty Cycle: 0.46 Calculated Temperature (*C): 28

Duty Cycle: 0.44 Calculated Temperature (*C): 24

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Alda

ok...

oh oh...
i just had a look at the source code and it wont work, because it skips an important pulse...
so u measure skip HIGH skip skip LOW skip skip HIGH, i think...

u could try instead of this (in ur original code):

//Read high time for square wave  
SquareWaveHighTime = pulseIn(SensorPin, HIGH);
//Read low time for square wave
SquareWaveLowTime = pulseIn(SensorPin, LOW);

this:

const uint8_t beg = digitalRead(SensorPin);
while (digitalRead(SensorPin)==beg);
const uint32_t start = micros();
while (digitalRead(SensorPin)!=beg);
const uint32_t middle = micros();
while (digitalRead(SensorPin)==beg);
const uint32_t end = micros();
SquareWaveHighTime = beg?(end-middle):(middle-start);
SquareWaveLowTime = (!beg)?(end-middle):(middle-start) ;

it might help to enclose the sequence in noInterrupts() and interrupts()...
http://arduino.cc/en/Reference/Interrupts

still bad :

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Duty Cycle: 0.47 Calculated Temperature (*C): 31

Duty Cycle: 0.46 Calculated Temperature (*C): 28

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Duty Cycle: 0.46 Calculated Temperature (*C): 28

Duty Cycle: 0.46 Calculated Temperature (*C): 28

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Duty Cycle: 0.46 Calculated Temperature (*C): 28

Duty Cycle: 0.46 Calculated Temperature (*C): 28

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Duty Cycle: 0.46 Calculated Temperature (*C): 28

Duty Cycle: 0.44 Calculated Temperature (*C): 26

Duty Cycle: 0.46 Calculated Temperature (*C): 28

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Duty Cycle: 0.46 Calculated Temperature (*C): 28

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Duty Cycle: 0.46 Calculated Temperature (*C): 28

now I will try code with interrups

Alda

with interrups :

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Duty Cycle: 0.44 Calculated Temperature (*C): 25

Duty Cycle: 0.46 Calculated Temperature (*C): 28

Duty Cycle: 0.44 Calculated Temperature (*C): 26

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Duty Cycle: 0.46 Calculated Temperature (*C): 30

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Duty Cycle: 0.45 Calculated Temperature (*C): 27

Duty Cycle: 0.45 Calculated Temperature (*C): 27

code was :
int SensorPin= 7; //Digital pin
float DutyCycle = 0; //DutyCycle that need to calculate
unsigned long SquareWaveHighTime = 0; //High time for the square wave
unsigned long SquareWaveLowTime = 0; //Low time for the square wave
unsigned long Temperature = 0; //Calculated temperature using dutycycle

void setup()
{
Serial.begin(9600); //Initialized serial according to your wish
pinMode(SensorPin, INPUT); //Sets the specified digital pin as an input
}

void loop()
{
DutyCycle = 0; //Initialize to zero to avoid wrong reading
Temperature = 0; //due to incorrect sampling etc

noInterrupts();
// critical, time-sensitive code here

const uint8_t beg = digitalRead(SensorPin);
while (digitalRead(SensorPin)==beg);
const uint32_t start = micros();
while (digitalRead(SensorPin)!=beg);
const uint32_t middle = micros();
while (digitalRead(SensorPin)==beg);
const uint32_t end = micros();
SquareWaveHighTime = beg?(end-middle):(middle-start);
SquareWaveLowTime = (!beg)?(end-middle):(middle-start) ;

interrupts();
// other code here

DutyCycle = SquareWaveHighTime; //Calculate Duty Cycle for the square wave
DutyCycle /= (SquareWaveHighTime + SquareWaveLowTime);
//Compute temperature reading according to D.C.
// where D.C. = 0.320 + 0.00470 * T
Temperature = (DutyCycle - 0.320) / 0.00470;

Serial.print("\nDuty Cycle: "); //Print for debugging if needed
Serial.print(DutyCycle);
Serial.print(" Calculated Temperature (*C): ");
Serial.println(Temperature);
//Wait for a while, I'm a micro guy. Can't compute as fast as you!
delay(1000);
}

blush :blush:

last try: :wink:

noInterrupts();// critical, time-sensitive code
const uint8_t beg = digitalRead(SensorPin);
while (digitalRead(SensorPin)==beg);
uint32_t first = 0;
while (digitalRead(SensorPin)!=beg) first++;
uint32_t second = 0;
while (digitalRead(SensorPin)==beg) second++;
interrupts();
SquareWaveHighTime = (!beg)?first:second;
SquareWaveLowTime = beg?first:second;

is the power supply stable and the voltage high enough?

instead of "digitalRead(SensorPin)" u might want to use "(PORTD&(1<<sensorPin))" (for sensorPin<=7)...

still nok :

Duty Cycle: 0.43 Calculated Temperature (*C): 22

Duty Cycle: 0.43 Calculated Temperature (*C): 23

Duty Cycle: 0.43 Calculated Temperature (*C): 23

Duty Cycle: 0.43 Calculated Temperature (*C): 22

Duty Cycle: 0.42 Calculated Temperature (*C): 21

Duty Cycle: 0.42 Calculated Temperature (*C): 21

Alda

Best results till now I have with this code :

//pro teplotu
int SensorPin= 7; //Digital pin
double DutyCycle = 0; //DutyCycle that need to calculate
unsigned int SquareWaveHighTime = 0; //High time for the square wave
unsigned int SquareWaveLowTime = 0; //Low time for the square wave
double Temperature = 0; //Calculated temperature using dutycycle
int sampleSize;

void setup()
{
Serial.begin(9600);
Serial.println("Zacatek mereni");

}
void loop()
{
SquareWaveHighTime = 0;
SquareWaveLowTime = 0;
sampleSize = 0;
do
{
sampleSize++;
SquareWaveHighTime = SquareWaveHighTime + pulseIn(SensorPin, HIGH);
SquareWaveLowTime = SquareWaveLowTime + pulseIn(SensorPin, LOW);

}
while (sampleSize < 200);

DutyCycle = SquareWaveHighTime; //Calculate Duty Cycle for the square wave
DutyCycle /= (SquareWaveHighTime + SquareWaveLowTime);
//Compute temperature reading according to D.C.
// where D.C. = 0.320 + 0.00470 * T
Temperature = (DutyCycle - 0.320) / 0.00470;
Serial.print(" Calculated Temperature (*C): ");
Serial.println(Temperature);

delay (5000);
}

Alda

then it is not caused by the software... i think...

did u check the power supply?
it must not go below 4.75V...
do u use a capacitor (about 1uF) near the sensor across its supply pins (not the PWM pin)?

yup - building that average surely helps... it is like a low pass... :slight_smile:

I already tested use PoE and also capacitor, but results are still the same.
Measured voltage is 4.926 V

Alda

I think the errors are coming from pulsein and from the fact that you only take one reading at a time. If you average over several readings you can smooth the input. You might try something like the following.

#define tempPin_PIN PIND
#define tempPin 2

void setup() {
pinMode(tempPin,INPUT);
Serial.begin(115200);
}

void loop() {
static float temp = 0;
unsigned long highCount = 0;
unsigned long lowCount = 0;
unsigned int cycles = 175;

for(int n = 0; n < cycles; n++ ) { //This reduces error by sampling over several high/low cycles

while((tempPin_PIN >> tempPin) & 1) { //This line checks the digital pin register and is true if the pin is HIGH. Its faster than a digital read.
if(n !=0) { //Avoid error causd by starting to monitor in the middle of a cycle
highCount++;
}
}

while(!((tempPin_PIN >> tempPin) & 1)) { //This line checks the digital pin register and is true if the pin is not HIGH.
if(n !=0) { //Avoid error causd by starting to monitor in the middle of a cycle
lowCount++;
}
}

}

temp = (((float)highCount / (lowCount+highCount)) - .32) / .00470; //It would be nice to avoid floating point math here!
Serial.println(temp);
}

Also don't forget to put in a calibration variable - while this sensor is very precise (highly repeatable results) you need to verify accuracy (avg distance from true temp) against another trusted source. Finally, in my method, it is worth pointing out that I measure a set number of cycles and the timing of those cycles depends on the sensor frequency. Since the frequency of the smt160-30 is temperature dependent, this code will take slightly longer to run (and may be slightly more accurate) when measuring something cold. Good luck!

-Nate

in your code with pulseIn function, you must check if pulseIn return Zero. (no pulse started in timeout)

you can use this arduino library:
https://github.com/HosseinLachini/SMT160/