Go Down

Topic: Taking and displaying 10 temperature measurements (Read 3210 times) previous topic - next topic

andycarroll

Hi, I'm new to the forum and useless at coding.

I have an Arduino Uno connected with two buttons, two LEDs and a temperature sensor.  I want a program to do the following...

In standby mode, a message appears on my computer saying "stand-by mode" once.  The first LED blinks repeatedly waiting.  The message should appear once, not repeatedly every time the LED blinks.

When button A is pressed the program switches to measuring mode. 

In measuring mode, it will display "measurement mode" once, switch on the second LED and then record 10 temperature measurements.  The temperature sensor will take a measurement every time button B is pressed.  If button B is not pressed withing 5 seconds, it will record the temperature as missed and move onto the next one.  The temperatures will be displayed over the serial link. 

For example:

Standby mode
blinking LED
*button A pressed*
Measurement mode
*button B pressed within 5 s*
Count 1:  Temp = 30 C
*button B pressed within 5 s*
Count 2: Temp = 35 C
*button B not pressed within 5 s*
Count 3: Temp - missed.
repeats until count 10 and returns to standby mode.

If anyone can post the code to achieve this I would be most grateful.  Thanks.

groundFungus

#1
Nov 28, 2015, 03:50 pm Last Edit: Nov 28, 2015, 03:52 pm by groundfungus
We are here to help you learn to code, not write code for you.  The gigs and collaborations section is for people to have someone write code for them, usually for pay. 

If you have tried to write the code, post it here and give a description of what it does and what you want it to do.

groundFungus

I would like to help you with your project. Can you provide a schematic of the setup?  Please include component values and part numbers.

andycarroll

Hi groundfungus,

I'm just using the components that come in the Arduino starter kit.

The LEDs are connected to inputs 2 and 3 with 220 Ohm resistors on the returns.
The pushbuttons are connected to inputs 6 and 7 with 10 kOhms resistors on the returns.
The temperature sensor is TM36 and connected to input A0.


groundFungus

Quote
The pushbuttons are connected to inputs 6 and 7 with 10 kOhms resistors on the returns.
OK, first suggestion is to wire the button switches from ground to the input pin.  Lose the 10K resistor.  In setup you will enable the internal pullup resistor with the pinMode(pin, INPUT_PULLUP) statement.  Put a 100nf cap across the switch (to ground and the input).  The cap will help to debounce the switch to give clean transitions.

Quote
The LEDs are connected to inputs 2 and 3 with 220 Ohm resistors on the returns.
May just be semantics, but LEDs connected to inputs are not much good.  Outputs makes more sense.

I will start to work on the code with the above in mind and get back when I have a start.

andycarroll

Thanks groundfungus.  Regards the LEDs I meant outputs.  That was a typo.

Here is my terrible code so far:

<#include <EEPROM.h>

int detectionswitch = 0;
int measurementswitch = 0;
const int sensorPin = A0;

void setup()
{
  // open a serial port:
  Serial.begin(9600);

  // LED outputs:
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);

  // switch inputs:
  pinMode(6, INPUT);
  pinMode(7, INPUT);
}

void loop() {
   detectionswitch = digitalRead(6);
   measurementswitch = digitalRead(7);
   
   // standby mode:
   Serial.println("STAND-BY MODE");
   if (detectionswitch == LOW)
   {
    digitalWrite(2, HIGH);
    delay(250);
    digitalWrite(2, LOW);
    delay(1750);
   }
   
   // measurement mode:
   else
   {
    Serial.println("MEASUREMENT MODE. ");

    for (int counter = 0; counter < 10; counter++)
      {
        Serial.print("Count: ");
        Serial.print(counter+1);
        int sensorVal = analogRead(sensorPin);
        float voltage = (sensorVal/1024.0) * 5.0;
        float temperature = (voltage - .5) * 100;

        Serial.print(". \t Sensor value: ");
        Serial.print(sensorVal);
        Serial.print(". \t Voltage: ");
        Serial.print(voltage);
        Serial.print(" V. \t Temperature: ");
        Serial.println(temperature);
        digitalWrite(3, HIGH);
        delay(250);
        digitalWrite(3, LOW);
        delay(500);
       }
    }
}

>

groundFungus

#6
Nov 28, 2015, 07:20 pm Last Edit: Nov 28, 2015, 07:58 pm by groundfungus
Here is my attempt.  I use a state machine to organize the steps and blink without delay method for timing.  Let me know if this is what you want.  I see that you include the EEPROM library.  Saving to EEPROM should be pretty easy, just add a state and use button b to save when in standby after measurement complete.  You will need to save the values to an array as they are recorded.

Note that my buttons are wired like I described before (from ground to input with 100nf cap across switch) so they are LOW when pushed.

Code: [Select]
/*
By C. Goulding
 temperature sensing and transmission program for forum poster
 using AD22100 temperature sensor in lieu of TMP36 sensor for now
 */


const byte ledAPin = 2;
const byte ledBPin = 3;
const byte buttonAPin = 6;
const byte buttonBPin = 7;
const byte tempInPin = A0;

// to keep track of state
byte state = 0;

// button variables
byte buttonACounter = 0;   // counter for the number of button presses
boolean buttonAState = HIGH;         // current state of the button
boolean lastButtonAState = HIGH;

byte buttonBCounter = 0;   // counter for the number of button presses
boolean buttonBState = HIGH;         // current state of the button
boolean lastButtonBState = HIGH;

// timers
unsigned long ledATimer, ledAlastTime;
unsigned long ledAInterval = 500;

unsigned long ledBTimer, ledBlastTime;
unsigned long ledBInterval = 500;

unsigned long measTimer, measlastTime;
unsigned long measInterval = 5000;

unsigned long currentMillis;


boolean isMeasInit = false;
boolean isSBInit = false;
byte measIndex = 0;
byte numMeasurements = 10;

void setup()
{
    Serial.begin(9600);
    delay(1000);
    pinMode(buttonAPin, INPUT_PULLUP);  
    pinMode(buttonBPin, INPUT_PULLUP);
    pinMode(ledAPin, OUTPUT);
    pinMode(ledBPin, OUTPUT);
    Serial.print(F("Program started \n"));

}

void loop()
{
    // time for timers
    currentMillis = millis();
    
    switch(state)
    {
    case 0: // standby
        //print "standby" once
        if(isSBInit == false)
        {
            Serial.println(F("STAND-BY MODE"));
            isSBInit = true;
        }
        // blink the led
        blinkLedA();
        // check button, if pushed go to measurement mode (state 1)
        if(ckButtonA() == true)
        {
            digitalWrite(ledAPin, LOW);
            isMeasInit = false;
            measIndex = 0;
            state = 1;
        }
        break;
    case 1:  //measure
        // print "measur mode" once
        if(isMeasInit == false)
        {
            Serial.println(F("MEASUREMENT MODE. "));
            isMeasInit = true;
            measTimer = currentMillis;
        }
        
        blinkLedB();
        // button a to abort back to sb
        if(ckButtonA() == true)  // back to standby
        {
            digitalWrite(ledBPin, LOW);
            isSBInit = false; // display message again
            state = 0;
        }
        // take measurements
        
        if(currentMillis - measTimer > measInterval) // has 5 sec elapsed?
        //if so print missed and check for done
        {
            Serial.println(F("MISSED"));
            if(measIndex > numMeasurements - 2)  // got ten go to SB
            {
                isSBInit = false;
                measIndex = 0;
                Serial.println(F("measurement complete"));
                state = 0;
            }
            measIndex++;
            measTimer = currentMillis;
        }
        // take and send on button press
        if(ckButtonB() == true)
        {

            Serial.print(F("Measurement # "));
            Serial.print(measIndex);
            Serial.print(F(" Temp C = "));
            Serial.println(getTemp());
            if(measIndex > numMeasurements - 2)  // got ten go to SB
            {
                isSBInit = false;
                digitalWrite(ledBPin, LOW);
                measIndex = 0;
                Serial.println(F("measurement complete"));
                state = 0;
            }
            measIndex++;
            measTimer = currentMillis;
        }
        break;
    }

}

float getTemp()  // using ad22100 temp sensor
{
    int rawin = analogRead(tempInPin);
    float vin = rawin * (5.0/1023.0);
    float tempc = (vin-1.375) / 0.0225;
    float tempf =  1.8*tempc+32;
    return tempc;
}

void blinkLedA()
{
    if(currentMillis - ledATimer > ledAInterval)
    {
        digitalWrite(ledAPin, !digitalRead(ledAPin));
        ledATimer = currentMillis;
    }
}

void blinkLedB()
{
    if(currentMillis - ledBTimer > ledBInterval)
    {
        digitalWrite(ledBPin, !digitalRead(ledBPin));
        ledBTimer = currentMillis;
    }
}

boolean ckButtonA()
{
    boolean pushed = false;
    buttonAState = digitalRead(buttonAPin);
    if (buttonAState != lastButtonAState) {
        if (buttonAState == LOW) {
            buttonACounter++;
            pushed = true;
        }
        else {
            pushed = false;
        }
    }
    lastButtonAState = buttonAState;
    return pushed;
}

boolean ckButtonB()
{
    boolean pushed = false;
    buttonBState = digitalRead(buttonBPin);
    if (buttonBState != lastButtonBState) {
        if (buttonBState == LOW) {
            buttonBCounter++;
            pushed = true;
        }
        else {
            pushed = false;
        }
    }
    lastButtonBState = buttonBState;
    return pushed;
}

/*Standby mode
 blinking LED
 *button A pressed*
 Measurement mode
 *button B pressed within 5 s*
 Count 1:  Temp = 30 C
 *button B pressed within 5 s*
 Count 2: Temp = 35 C
 *button B not pressed within 5 s*
 Count 3: Temp - missed.
 repeats until count 10 and returns to standby mode.

 Voltage at pin in milliVolts = (reading from ADC) * (5000/1024)
 This formula converts the number 0-1023 from the ADC into 0-5000mV (= 5V)

 Then, to convert millivolts into temperature, use this formula:
 Centigrade temperature = [(analog voltage in mV) - 500] / 10
 */



andycarroll

Hello groundfungus,

Thank you ever so much.  Your code is brilliant!  I've just tried it and it works very well.  The only thing I would change is to make it so, once measurement mode has started, pressing button A has no effect.  Can you help me with that?

I use a state machine to organize the steps and blink without delay method for timing.  Let me know if this is what you want.
Sorry, I haven't got a clue what that means, so I don't know if I want it or not!

I see that you include the EEPROM library.  Saving to EEPROM should be pretty easy, just add a state and use button b to save when in standby after measurement complete.  You will need to save the values to an array as they are recorded.
Yes, I do want to save the measurements to memory.  Can this to happen automatically rather than pressing button B?  and I really want to send them via a wireless communications link to a computer.  

groundfungus, can you help with any of this please?

Again, many thanks for this.

groundFungus

Quote
The only thing I would change is to make it so, once measurement mode has started, pressing button A has no effect.  Can you help me with that?
Remove these lines to disable abort with button A during measure mode

Code: [Select]
// button a to abort back to sb
        if(ckButtonA() == true)  // back to standby
        {
            digitalWrite(ledBPin, LOW);
            isSBInit = false; // display message again
            state = 0;
        }


Quote
Quote from: groundfungus on Nov 28, 2015, 06:20 pm

    I use a state machine to organize the steps and blink without delay method for timing.  Let me know if this is what you want.

Sorry, I haven't got a clue what that means, so I don't know if I want it or not!
My turn to be sorry.  What I meant was does the code (in its entirety) do what you want.
A state machine is a way of programming that breaks the program into a number of states.  In this case I had a standby state and a measure state.  That way it is easy to add on to the program, just add states and call each state depending on the program's inputs.

Quote
Yes, I do want to save the measurements to memory.  Can this to happen automatically rather than pressing button B?  and I really want to send them via a wireless communications link to a computer. 
So you will push button A and the program will take 10 measurements and save to memory (EEPROM)?
How much time between readings?  Button B is no longer used at all?  Please describe, in detail, how the program will flow once the button A is pushed.

As for the wireless part I have to ask, what is the distance for the data to be transmitted?  The answer to that question is necessary to be able to choose a wireless method.  What is at the receiving end?  I mean just to serial monitor or do you have a program on the PC to receive and process the data?

I am happy to help.  Over the last few years I have been learning and have written many many sketches for myself.  It is rewarding to me to put my learning to use for others.


PaulMurrayCbr

http://paulmurraycbr.github.io/ArduinoTheOOWay.html

cedarlakeinstruments

I mean just to serial monitor or do you have a program on the PC to receive and process the data?
Or do you need to have that program written also?
Electronics and firmware/software design and assistance. No project too small

andycarroll

So you will push button A and the program will take 10 measurements and save to memory (EEPROM)?
How much time between readings?  Button B is no longer used at all?  Please describe, in detail, how the program will flow once the button A is pushed.
I want button A to do is act as a trigger to switch the device out of standby mode.  I plan to power this device by batteries so I want as little power consumption as possible.  My rationale in saving the 10 measurements to memory is in case the communications link is busy.  

Button B simulates a detector which detects the passing targets.  As soon a button B detects the target, I need it to take the temperature.  The targets pass in groups of 10, but may vary in speed.  The target is only 30 mm in diameter and could be passing at a speeds up to 10 m/s so the reading could be as quick as 3 ms.  The minimum time between readings would be approximately 150 ms.

Once the 10 measurements have been successfully transmitted, they can be deleted.  Then the device can return to standby mode.  The only trouble would be if another set of 10 targets comes along before the first set of 10 have been sent. 


As for the wireless part I have to ask, what is the distance for the data to be transmitted?  The answer to that question is necessary to be able to choose a wireless method.  What is at the receiving end?  I mean just to serial monitor or do you have a program on the PC to receive and process the data?
The maximum distance would be 1 km.  More likely 500 m.  I was hoping that it would be received and sent to a PC.  The PC would then display an alarm if any of the targets are overheating.  I don't have a program to do this yet.


I am happy to help.  Over the last few years I have been learning and have written many many sketches for myself.  It is rewarding to me to put my learning to use for others.
Thanks, that's very kind.

groundFungus

#12
Nov 30, 2015, 03:11 pm Last Edit: Nov 30, 2015, 03:32 pm by groundfungus
   
Quote
I want button A to do is act as a trigger to switch the device out of standby mode.  I plan to power this device by batteries so I want as little power consumption as possible.  My rationale in saving the 10 measurements to memory is in case the communications link is busy.
Writing to 10 float values to EEPROM is no problem.  Using a full up Uno is problematic when considering low power.  The USB-serial subsystem, various LEDs, running at 16Mhz, etc consume power (around 50 mA, I think).  A stand alone 328 running at 8Mhz can consume less than 1/4 the power.  Then there is sleeping the processor (something new for me) to get current consumption into the micro amp range.    low power



   
Quote
Button B simulates a detector which detects the passing targets.  As soon a button B detects the target, I need it to take the temperature.  The targets pass in groups of 10, but may vary in speed. 
Is button B is some sort of detector?  What exactly?  So the sampling of the temperature for each object triggered by the "button B detector" as well as sensing the arrival of the first object?  So, button A is pressed, the unit enters measurement mode, the detector senses the first of ten, takes the reading, stores the reading, senses and reads 9 more objects and reads each of their temperatures, storing each reading then returns to standby?  Now the temperatures are stored in EEPROM and the unit is in standby mode, do we use a button to send the data?   



 
Quote
The target is only 30 mm in diameter and could be passing at a speeds up to 10 m/s so the reading could be as quick as 3 ms.
Will the temperature sensor respond quickly enough?



   
Quote
The minimum time between readings would be approximately 150 ms.
That must be the time between sets of 10 readings?



   
Quote
The maximum distance would be 1 km.  More likely 500 m.  I was hoping that it would be received and sent to a PC.  The PC would then display an alarm if any of the targets are overheating.  I don't have a program to do this yet.
The wireless module that I have experience with that has that sort of range (claimed, unobstructed line of sight) is the APC220 radio.  I have read of the XBee radios that might have that sort of range.  Long range wireless is not a area where I have much expertise.

I can help to get to the reading, storing and sending of the data to the serial monitor via serial.  From there adding wireless should be pretty easy once a wireless method is chosen.  A simple Processing Processing.org/ program could read the serial data and do pretty much what ever you need with the data.

andycarroll

Writing to 10 float values to EEPROM is no problem.  Using a full up Uno is problematic when considering low power.  The USB-serial subsystem, various LEDs, running at 16Mhz, etc consume power (around 50 mA, I think).  A stand alone 328 running at 8Mhz can consume less than 1/4 the power.  Then there is sleeping the processor (something new for me) to get current consumption into the micro amp range.    low power
I don't want to have a bare bones board, so please don't worry too much about power consumption at this stage.

   
Is button B is some sort of detector?  What exactly? 
I haven't got one at this stage.  Perhaps some sort of ferro-resonant detector.  This will detect the target and trigger the measurement.

So the sampling of the temperature for each object triggered by the "button B detector" as well as sensing the arrival of the first object?  So, button A is pressed, the unit enters measurement mode, the detector senses the first of ten, takes the reading, stores the reading, senses and reads 9 more objects and reads each of their temperatures, storing each reading then returns to standby? 
There should be a gap of at least 60 s between groups of 10 targets.  Ideally I would like the group of 10 temperatures to be saved to memory and then sent over the comms link.  Once sent successfully then return to standby.

Now the temperatures are stored in EEPROM and the unit is in standby mode, do we use a button to send the data?   
I would prefer this to be sent automatically.

Will the temperature sensor respond quickly enough?
I'm still researching fast non-temperature detectors.  Specifically IR detectors.

That must be the time between sets of 10 readings?
No.  In the perfect scenario, the target will pass in pairs.  Ideally the pattern of targets will be a gap of 150 ms between targets 1 and 2 and then a gap of approximately 1 s between 2 and 3.  The a gap of 150 ms between 3 and 4.  This pattern is repeated for the group of 10.

The wireless module that I have experience with that has that sort of range (claimed, unobstructed line of sight) is the APC220 radio.  I have read of the XBee radios that might have that sort of range.  Long range wireless is not a area where I have much expertise.
I would be happy with a wifi link for the moment, just to prove the wireless communications.

I can help to get to the reading, storing and sending of the data to the serial monitor via serial.  From there adding wireless should be pretty easy once a wireless method is chosen.  A simple Processing Processing.org/ program could read the serial data and do pretty much what ever you need with the data.
Thanks very much, I will have a look at this.

groundFungus

Since I don't have the actual hardware to work with I must simulate the hardware.  So I think the way to go forward is to go back to using the button B to sim the detector and the use temp sensor that I have.  Since the reading of the button and temperature are in functions, those functions can be replaced in the final code with functions that use the actual hardware.  That is the beauty of breaking the program into functions.  

I can write the program to send the data via serial to the serial monitor,  a Processing app or another app that accepts data from the serial port.  Inserting the code for a wireless module can be done when the communication method is finalized.  WIFI and networking is beyond my experience.  Maybe someone else can help there.

Go Up