I'm using 2 temperature sensors (ds18b20) to read foot temperature alongside force sensors.
my problem is that a high resolution temperature takes around 750ms according to the datasheet of the sensor. I don't mind a delay in the temp reading (even in minutes), but I have to read force values approximately every 50ms.
I saw that it's possible to read other sensors in background while the temp sensor requests and displays the value, probably using millis function. but due to my limited experience in programming, I don't know how to do it.
is there any clear way on how to do so? any help would be appreciated.
How about a solution that uses one microcontroller for aquiring temperaturedata every 750 milliseconds and whenever the temperature changed sending it over a serial interface as a 16bit integer wher 12345 means 123.45 °C to the microcontroller that does the force-sensor-measurings?
I tried using this example after editing a little bit. I don't care about the minimum acquisition time at each resolution so I fixed the temp time at 1000ms, I can even change it to a whole minute later. then I used the text "Force" to indicate force values and it seems like it's working as it's supposed to.
could you please check my code and give me your feedback. Although it's working, but i would be more comfortable knowing that I'm utilizing the sensors functions correctly.
also, what is your personal experience with this sensor? I heard it's and accurate one, did you have any problems with it.
here's my code:
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
DeviceAddress tempDeviceAddress;
float temperature;
int pause_t = 1000;
int pause_f = 100;
unsigned long lastTime_t = millis();
unsigned long lastTime_f = millis();
void setup()
{
sensors.begin();
sensors.setResolution(12);
sensors.setWaitForConversion(false);
sensors.requestTemperatures();
Serial.begin(115200);
}
void loop()
{
String dataString = ""; // string to store measurements
//temperature timing
if ( millis() - lastTime_t > pause_t)
{
temperature = sensors.getTempCByIndex(0);
sensors.requestTemperatures(); // ask for next reading
lastTime = millis();
// process temperature here
dataString += String(temperature);
}
else{
dataString += ("null");
}
// force timing
if ( millis() - lastTime_f > pause_f)
{
dataString += ("|| Force_1");
dataString += (" Force_2");
dataString += (" Force_3");
lastTime2 = millis();
Serial.println(dataString);
}
}
Me personal I do not use the variable-type String.
The variable-type String can be dangerous because repeated assigning new values to a variable of type String can eat up all memory and then start overwriting other data which might lead to corrupted data or a program-crash
I always use a library called SafeString which offers almost the same comfort as String but is safe to use and never eats up more memory than shown at compiling
here is a short demo-code how to use it
#include <SafeString.h>
createSafeString(myDemo_SS, 32);
createSafeString(mySecondDemo_SS, 32);
unsigned long myCounter;
// if program starts printout the source-code filename etc. to the serial monitor
void PrintFileNameDateTime() {
Serial.println( F("Code running comes from file ") );
Serial.println(__FILE__);
Serial.print( F(" compiled ") );
Serial.print(__DATE__);
Serial.print( F(" ") );
Serial.println(__TIME__);
}
//useful function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - periodStartTime >= TimePeriod )
{
periodStartTime = currentMillis; // set new expireTime
return true; // more time than TimePeriod) has elapsed since last time if-condition was true
}
else return false; // not expired
}
unsigned long MyTestTimer = 0; // variables MUST be of type unsigned long
const byte OnBoard_LED = 13; // Arduino-Uno Onboard-LED is IO-pin 13
// make onboard-LED blink to show: "program is running"
void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
static unsigned long MyBlinkTimer;
pinMode(IO_Pin, OUTPUT);
if ( TimePeriodIsOver(MyBlinkTimer,BlinkPeriod) ) {
digitalWrite(IO_Pin,!digitalRead(IO_Pin) );
}
}
void setup() {
Serial.begin(115200);
Serial.println( F("Setup-Start") );
PrintFileNameDateTime();
myCounter = 0;
myDemo_SS = "Hello world!";
}
void loop() {
BlinkHeartBeatLED(OnBoard_LED,500);
myCounter++;
// loop is running very fast counting up very fast
// but only once every 1234 milliseconds print
if ( TimePeriodIsOver(MyTestTimer,1234) ) {
mySecondDemo_SS = myDemo_SS; // assigning a SafeString to another SafeString
mySecondDemo_SS += " "; // append a SPACE
mySecondDemo_SS += myCounter; // append integer-number
Serial.println(mySecondDemo_SS);
}
}
you can install the library with the library-manager
My experience with DS18B20-sensors is: their accuracy is within the specs.
This means 0.5°C. So if you have two sensors at the exact same temperature one sensor can show 20.00°C and the other 20.25°C or another 19.75°C
Using the ```
setWaitForConversion(false);
command means start a measuring with the first requestTemperatures and retrieve the data on the next call.
best regards Stefan
So you have called temperature a float. It comes as a float and all you need do is print the float. None of that String stuff is necessary, and is likely to cause you grief. Take the long view and seriously consider what you want to do, and do you really need all that text anyway. If you're serious about logging data, I'm betting you will probably delete it.
the line to set the resolution is there to check the validity of the sensor since I was getting weird readings at some point. that was because I didn't call the initializing commands for the sensor properly, so I can remove that line now.
Regarding the String format I'm hearing many negative comments on it. I used this format from the DataLogger example on SD library. Later in my application, these readings will be either written on an SD card or sent by Bluetooth. is it still better to ditch the string and print them directly in that case?
The problematic thing is repeatedassigning values to a String-variable.
The difference in using String or SafeString isn't that big
String:
dataString += String(temperature); // needs a conversion with String()
SafeString:
#include SafeString.h
createSafeString(dataString , 256); //256 is the length of characters the variable can hold can be any value until no RAM is left
dataString = "";
dataString += temperature; // needs no conversion (the conversion is done by the SafeString-library
some functions will accept only a character-sequence that is defined as "c_string"
easy thing for the library SafeString.h
simply code
Thanks for the explanation, I checked the description of the library, applied it to my code and got the same result as before. I initialized the safestring and kept the same structure as it was, except I wrote
dataString.clear();
instead of
dataString = "";
Can you please explain the last statement? what are these functions, and what does SpecialObject refer to in that case?
for example if you would like to use a library that is sending a "string" to a LCD or send a string via TCP/IP
these functions don't provide a variant for each type of variable like the
print-function of the serial-object
serial.print() works for all and any "simple" datatype like
byte, integer, char, unsigned int, long, unsigned long String etc.
because the library provides a special version for each datatype.
If a library does not provide a special version of a function for each datatype the compiler will complain "wrong data-type"
I encountered this problem for example for udp:
the udp-oject accepts only bytes.
This means sending a string needs a conversion and the conversion requieres a c_string to work
if you lok inside the library of the serial object you will find a lot of variants if the print-function.
If a library does not provide all these variants you have to use a certain type
And libraries that expect a character-sequence often expect datatype "c_str"
the name "SpecialObject" is just a place-holder for such libraries.