I am working on updating a project and I have a thread over in the Arduino forum which helped me out, but I'm a bit stuck, and there isn't much activity going on there.
This code is for use with a one wire temperature sensor, however, each time it retrieves data for the sensor, it has a 750ms delay as seen here:
ds.reset();
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite power on at the end
delay(750); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
Now, I'm going to be using a momentary button as a toggle, but for this I need to debounce it, using a delay. With the 750ms delay present for the temperature sensor, that just isn't feasible, it makes it too unpredictable and difficult to use.
I need to replace this delay with a millis
counter, but I'm not sure if I can without hanging up the rest of the script. I gave it a try like so, but it completely screwed up the reading.
if (owcurrentMillis - owpreviousMillis >= owinterval) {
owpreviousMillis = owcurrentMillis;
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
}
I then tried it like so, and the readout does still work, however, I have an LED which lights up when the temperature has "Stabilized", which it's supposed to check every one second, but that has stopped working, and it's basically instant making it useless. I don't know why that millis
loop does not work though, it was only working due to the 750ms delay.
if (owcurrentMillis - owpreviousMillis >= owinterval) {
owpreviousMillis = owcurrentMillis;
ds.reset();
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite power on at the end
}
Here is the bit of code controlling the LED illumination.
if (currentMillis - previousMillis >= interval) { //If it has been 20 seconds, check to turn LED on
previousMillis = currentMillis;
if ((delta < 00.03) && (delta > -00.03)) { //If temperature hasn't changed by +/- .05 turn led on.
digitalWrite(A0, HIGH);
}
}
if (delta >= 00.06) { //If temperature has changed by more than .1 turn LED off
digitalWrite(A0, LOW);
}
if (delta <= -00.06) {
digitalWrite(A0, LOW); // If temperature has changed by more than -.1 turn LED off
}
I think if I can get that one to work properly, instead of messing up like it is now I should be good, then I just need the 50ms delay to debounce the button which will trigger what I need, I just can't figure out why it will not work.
You can see the version which works best here (with the 750ms delay in place):
#include <OneWire.h>
#include <LiquidCrystal.h>
#include <SPI.h>
#include <SD.h>
const int chipSelect = 10;
OneWire ds(9); //Onewire + lcd setup
LiquidCrystal lcd(6, 7, 5, 4, 3, 2);
float lasttemp; //Variable for last temperature
float delta; //Variable for temperaturechange
long previousMillis = 0;
const long interval = 1000; //Check once every 20 seconds
const long sdinterval = 5000;
long sdpreviousMillis = 0;
File myFile;
void setup(void) {
pinMode(A0, OUTPUT);
pinMode(A3, OUTPUT);
Serial.begin(115200); //Start serial + LCD/Light test
lcd.begin(8, 2);
lcd.setCursor(0,0);
lcd.print("STARTING");
lcd.setCursor(0, 1);
lcd.print("VER. 1.2");
digitalWrite(A0, HIGH);
digitalWrite(A3, LOW);
delay(1000);
digitalWrite(A0, LOW);
digitalWrite(A3, HIGH);
lcd.clear(); //End of LCD/Light test
if (!SD.begin(10)) { // Check for SD card
digitalWrite(A3, LOW);
lcd.setCursor(0,0);
lcd.print("SD CHECK");
lcd.setCursor(0,1);
lcd.print(" FAIL ");
delay(1000);
lcd.clear();
digitalWrite(A3, HIGH);
} else {
delay(1000);
digitalWrite(A3, LOW);
lcd.setCursor(0,0);
lcd.print("SD CHECK");
lcd.setCursor(0,1);
lcd.print(" PASS ");
delay(1000);
lcd.clear();
digitalWrite(A3, HIGH);
}
}
void loop(void) {
unsigned long sdcurrentMillis = millis();
unsigned long currentMillis = millis();
{
}
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius, fahrenheit;
if ( !ds.search(addr)) {
Serial.println("No more addresses.");
Serial.println();
ds.reset_search();
delay(250);
return;
}
Serial.print("ROM =");
for( i = 0; i < 8; i++) {
Serial.write(' ');
Serial.print(addr[i], HEX);
}
if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return;
}
Serial.println();
// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10:
Serial.println(" Chip = DS18S20"); // or old DS1820
type_s = 1;
break;
case 0x28:
Serial.println(" Chip = DS18B20");
type_s = 0;
break;
case 0x22:
Serial.println(" Chip = DS1822");
type_s = 0;
break;
default:
Serial.println("Device is not a DS18x20 family device.");
return;
}
ds.reset();
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite power on at the end
delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
Serial.print(" Data = ");
Serial.print(present, HEX);
Serial.print(" ");
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
Serial.print(data[i], HEX);
Serial.print(" ");
}
Serial.print(" CRC=");
Serial.print(OneWire::crc8(data, 8), HEX);
Serial.println();
// Convert the data to actual temperature
// because the result is a 16 bit signed integer, it should
// be stored to an "int16_t" type, which is always 16 bits
// even when compiled on a 32 bit processor.
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// "count remain" gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
}
else {
byte cfg = (data[4] & 0x60);
// at lower res, the low bits are undefined, so let's zero them
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
//// default is 12 bit resolution, 750 ms conversion time
}
celsius = (float)raw / 16.0;
fahrenheit = celsius * 1.8 + 32.0;
Serial.print(" Temperature = ");
Serial.print(celsius);
Serial.print(" Celsius, ");
Serial.print(fahrenheit);
Serial.println(" Fahrenheit");
delta = celsius - lasttemp; //Create value to check how much temperature has changed
if (currentMillis - previousMillis >= interval) { //If it has been 20 seconds, check to turn LED on
previousMillis = currentMillis;
if ((delta < 00.03) && (delta > -00.03)) { //If temperature hasn't changed by +/- .05 turn led on.
digitalWrite(A0, HIGH);
}
}
if (delta >= 00.06) { //If temperature has changed by more than .1 turn LED off
digitalWrite(A0, LOW);
}
if (delta <= -00.06) {
digitalWrite(A0, LOW); // If temperature has changed by more than -.1 turn LED off
}
if (sdcurrentMillis - sdpreviousMillis >= sdinterval) { //Write to SD card every 5 seconds.
sdpreviousMillis = sdcurrentMillis;
digitalWrite(A3, LOW);
myFile = SD.open("Log.txt", FILE_WRITE);
myFile.print(celsius);
myFile.println(" C ");
myFile.close();
digitalWrite(A3, HIGH);
}
lcd.setCursor(0, 0);
lcd.print(celsius);
lcd.print(" C ");
lcd.setCursor(0, 1);
lcd.print(fahrenheit);
lcd.print(" F ");
lasttemp = celsius;
}
and this is the one I'm working on as I write this, with the illumination delay messing up:
#include <OneWire.h>
#include <LiquidCrystal.h>
#include <SPI.h>
#include <SD.h>
unsigned long owpreviousMillis = 0;
const long owinterval = 750;
//---------------------------------------------------------------------------------- One wire temperature sensor stuff
OneWire ds(9); //Setting one wire bus pin
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius, fahrenheit; //Variables for celsius and farenheit conversions
long previousMillis = 0;
float lasttemp; //Variable for last temperature
float delta; //Variable for temperaturechange
const long interval = 1000; //Check once every 1 second
//---------------------------------------------------------------------------------- End of one wire temperature sensor stuff.
LiquidCrystal lcd(6, 7, 5, 4, 3, 2); //Defining pins for the LCD
//---------------------------------------------------------------------------------- SD card stuff
const int chipSelect = 10; //Setting SD chip select pin (obviously)
File myFile;
long sdpreviousMillis = 0;
const long sdinterval = 5000; //SD card write interval
//-----------------------------------------------------------------------------------End of pre-setup
void setup(void) {
pinMode(A2, INPUT);
pinMode(A0, OUTPUT); //Green LED for temperature stability indication
pinMode(A3, OUTPUT); //Red LED for sd card activity indication
Serial.begin(115200);
//------------------------- Testing LCD and LED's, displaying version number and checking for SD card.
lcd.begin(8, 2);
lcd.setCursor(0,0);
lcd.print("STARTING");
lcd.setCursor(0, 1);
lcd.print("VER. 1.5");
digitalWrite(A0, HIGH);
digitalWrite(A3, LOW);
delay(1000);
digitalWrite(A0, LOW);
digitalWrite(A3, HIGH);
lcd.clear();
if (!SD.begin(10)) { // Check for SD card
digitalWrite(A3, LOW);
lcd.setCursor(0,0);
lcd.print("SD CHECK");
lcd.setCursor(0,1);
lcd.print(" FAIL ");
delay(1000);
lcd.clear();
digitalWrite(A3, HIGH);
} else {
delay(1000);
digitalWrite(A3, LOW);
lcd.setCursor(0,0);
lcd.print("SD CHECK");
lcd.setCursor(0,1);
lcd.print(" PASS ");
delay(1000);
lcd.clear();
digitalWrite(A3, HIGH);
}
//----------------------------------- Setting up one wire temperature sensor.
if ( !ds.search(addr)) {
Serial.println("No more addresses.");
Serial.println();
ds.reset_search();
delay(250);
return;
}
Serial.print("ROM =");
for( i = 0; i < 8; i++) {
Serial.write(' ');
Serial.print(addr[i], HEX);
}
if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return;
}
Serial.println();
// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10:
Serial.println(" Chip = DS18S20"); // or old DS1820
type_s = 1;
break;
case 0x28:
Serial.println(" Chip = DS18B20");
type_s = 0;
break;
case 0x22:
Serial.println(" Chip = DS1822");
type_s = 0;
break;
default:
Serial.println("Device is not a DS18x20 family device.");
return;
}
}
//----------------------------------------------------------------------------- End of setup.
void loop(void) {
unsigned long sdcurrentMillis = millis();
unsigned long currentMillis = millis();
unsigned long owcurrentMillis = millis();
if (owcurrentMillis - owpreviousMillis >= owinterval) {
owpreviousMillis = owcurrentMillis;
ds.reset();
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite power on at the end
}
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
Serial.print(" Data = ");
Serial.print(present, HEX);
Serial.print(" ");
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
Serial.print(data[i], HEX);
Serial.print(" ");
}
Serial.print(" CRC=");
Serial.print(OneWire::crc8(data, 8), HEX);
Serial.println();
// Convert the data to actual temperature
// because the result is a 16 bit signed integer, it should
// be stored to an "int16_t" type, which is always 16 bits
// even when compiled on a 32 bit processor.
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// "count remain" gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
}
else {
byte cfg = (data[4] & 0x60);
// at lower res, the low bits are undefined, so let's zero them
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
//// default is 12 bit resolution, 750 ms conversion time
}
celsius = (float)raw / 16.0;
fahrenheit = celsius * 1.8 + 32.0;
Serial.print(" Temperature = ");
Serial.print(celsius);
Serial.print(" Celsius, ");
Serial.print(fahrenheit);
Serial.println(" Fahrenheit");
delta = celsius - lasttemp; //Create value to check how much temperature has changed
if (currentMillis - previousMillis >= interval) { //If it has been 20 seconds, check to turn LED on
previousMillis = currentMillis;
if ((delta < 00.03) && (delta > -00.03)) { //If temperature hasn't changed by +/- .05 turn led on.
digitalWrite(A0, HIGH);
}
}
if (delta >= 00.06) { //If temperature has changed by more than .1 turn LED off
digitalWrite(A0, LOW);
}
if (delta <= -00.06) {
digitalWrite(A0, LOW); // If temperature has changed by more than -.1 turn LED off
}
if (sdcurrentMillis - sdpreviousMillis >= sdinterval) { //Write to SD card every 5 seconds.
sdpreviousMillis = sdcurrentMillis;
digitalWrite(A3, LOW);
myFile = SD.open("Log.txt", FILE_WRITE);
myFile.print(celsius);
myFile.println(" C ");
myFile.close();
digitalWrite(A3, HIGH);
}
lcd.setCursor(0, 0);
lcd.print(celsius);
lcd.print(" C ");
lcd.setCursor(0, 1);
lcd.print(fahrenheit);
lcd.print(" F ");
lasttemp = celsius;
}
This is the post on the Arduino forum which sort of explains what I'm doing a bit better, if it does not make sense: Best way to set up a button to toggle a second function? (millis issue now).
Edit/update
Alright, so I think it has to do with how I structured that bit of the code, it seems like the arguments to turn the LED off weren't in the if statement which used the delay, so changed it to this, and unfortunately now it is on constantly, but I think I am on the right track.
if (currentMillis - previousMillis >= interval) { //If it has been 20 seconds, check to turn LED on
previousMillis = currentMillis;
if ((delta < 00.03) && (delta > -00.03)) { //If temperature hasn't changed by +/- .05 turn led on.
digitalWrite(A0, HIGH);
} else {
if ((delta >= 00.06) && (delta <= -00.06)) {
digitalWrite(A0, LOW);
}
}
}
It seems like this should work but perhaps there's an issue with having two if
statements set up on top of each other like that. I also gave it a try like this, to no avail.
(currentMillis - previousMillis >= interval) { //If it has been 20 seconds, check to turn LED on
previousMillis = currentMillis;
if ((delta < 00.03) && (delta > -00.03)) { //If temperature hasn't changed by +/- .05 turn led on.
digitalWrite(A0, HIGH);
} else {
if (delta >= 00.06){
digitalWrite(A0, LOW);
} else {
if (delta <= -00.06){
digitalWrite(A0, LOW);
}
}
}
}
Edit/update
Quick clarification, I managed to get rid of the delay and use millis instead but it introduced an issue with the LED which indicates stable temperature not working (being lit most of the time, and then flashing off/on fairly quickly as the temperature changes, instead of remaining off until it stabilizes again). It seems to be ignoring the delay I have it waiting for.
Now, after going through it a lot, it seems like this is how I need it set up. It checks if the interval has been reached, if so, it checks if the temperature has changed less than x amount, if so it lights the LED.
However, if the temperature has changed more than that, it checks if it exceeds y amount, and if so turns the light off.
I have tried reversing these and it has had no effect, it just seems like the boolean arguments aren't working and I don't know why, but at least the delay issue is solved.
if (currentMillis - previousMillis >= interval) { //If it has been 20 seconds, check to turn LED on
previousMillis = currentMillis;
if ((delta < 00.03) && (delta > -00.03)) { //If temperature hasn't changed by +/- .05 turn led on.
digitalWrite(A0, HIGH);
} else if ((delta >= 00.06) || (delta <= -00.06)) {
digitalWrite(A0, LOW);
}
}
there isn't much activity going on there
- maybe everyone's eating dinner? Try to let a little longer elapse before running off cross-posting that "nothing is happening" on another site. Like, 12 hours. – Nick Gammon♦ Mar 24 '16 at 10:42Especially at this time of day when the majority of people who use this forums north america) will be asleep?
However on the Arduino forum I note that you also got answers 49 mins, 83 mins, and 102 mins after the post I referred to.so they will likely not visit it again
- apparently not. – Nick Gammon♦ Mar 24 '16 at 21:36