I am an absolute beginner to Arduino, but I am currently working on an IoT project. The goal is to see if temperature and humidity are changing drasticaly over a few minutes.
I am working with an ESP 8266, a DHT11 and the BLYNK App.
I have the following code, where I delay the time between two temperature reads, to calculate the difference between them. I know that delay() is not a good way to work, so I tried to rewrite it with a millis() timer. But it is not working! tempA just stays the same as tempB.
Can someone tell me, what it should look like correctly?
unsigned long previousMillis = 0;
const long interval = 5000;
void tempChange()
{
float tempA;
float tempB;
float tempDiff;
unsigned long currentMillis = millis();
tempA = dht.readTemperature();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
tempB = dht.readTemperature();
}
Serial.print(tempA);
Serial.print(" ");
Serial.println(tempB);
}
void setup()
{
dht.begin();
timer.setInterval(5000L, tempChange);
}
void loop()
{
Blynk.run();
timer.run();
}
If you know any better way, to record a change over time I am open to it. This was just the best (or worst) idea I have come up with.
Thank you!
The problem is that you are reading the same value twice. First you read it and assign it to tempA and then you do the same to tempB. tempA is equal to tempB because it's the same reading!
What you want to do is keep track of the previous temperature in a global variable and then, each time you call tempChange(), read the value of the sensor and get the difference. Then, change the value of the last temperature to the actual one for the next call.
//Create a global variable to keep track of the previous temperature
float previousTemp = dht.readTemperature();
//Call this every "interval" milliseconds
void tempChange()
{
//Get current temperature and calculate temperature difference
float currentTemp = dht.readTemperature();
float tempDiff = currentTemp-previousTemp;
//Keep track of previous temp
previousTemp = currentTemp
//Print results
Serial.println(previousTemp + " " + currentTemp);
Serial.println("Change: " + tempDiff);
}
Also, you don't need to check the interval with millis() when calling the function because you are already calling it every "interval" milliseconds.
Related
first of all I would like to apologise for not speaking English very well.
My problem is the following: I have an arduino sensor (the iDuino SE049). I need to transform the analog value into BPM value.
So first I have to eliminate the drift (slide, (I don't know the precise word)) that the sensor can encounter. To do this I am advised to :
❶Work on an array of X values
❷Calculate the average
❸Subtract the average from each of the values
After I need to find the optimal value for X with the curve on Arduino IDE (I work on 1.8.19 version).
(Start with X = 50 for the size of the array, my teacher told me that)
Once I have this average, I need to make the system robust to light changes.
Problem: The amplitude varies so we can't work with a fixed threshold.
The heart rate is hidden in temporal information. You just need to be able to measure the characteristic time.
Solution : I can work with a curve that always has maximum amplitude of 1, then find an ideal threshold.
❶Work on the table of X values after eliminating the drift.
❷Look for the maximum
❸Divide all values by this maximum
❹Split by a threshold value
And then I have to do the study to find the threshold value
I tried to do a code that didn't worked well for the drift/slide, and average of the signal. But it didn't worked well because I can't get the value of the average outside of my loop to substract it to the analog value readed by the sensor.
I want to get all the value readed by the sensor during a time of 20 milliseconds, thats why I use the function millis(). And all this values needs to be stored in my array.
#include <Arduino.h>
int Sensor = 0;
//#define start_read 0
float tab[20]={0};
float sum = 0;
int i;
void setup() {
Serial.begin(9600);
}
void loop ()
{
unsigned long currentTime=0;
while (millis() - currentTime > 20)
{
tab[i] = analogRead(Sensor);
i++;
sum += tab[i];
float average = sum/20;
Serial.println(average);
}
currentTime = millis();
i = 0;
}
I have another code to test, I should work but it's not I don't know why : The variable names are in French but you can copy it and change the name to work on it if it's clearer, I'll understand the changes.
#include <Arduino.h>
int sensor=A0, comp=1, var=0;
float bpm=0;
double temps;
const int nbr=50;
float tab[nbr]={0}, moyenne=0, maximum=0;
void setup() {
Serial.begin(9600);
pinMode(sensor, INPUT);
}
void loop() {
maximum=0;
moyenne=0;
for (int i = 0; i < nbr; i++)
{
tab[i]=analogRead(sensor);
moyenne=moyenne+tab[i];
delay(40);
}
moyenne=moyenne/nbr;
for (int i = 0; i < nbr; i++)
{
tab[i]=tab[i]-moyenne;
}
maximum=tab[0];
for (int i = 0; i < nbr; i++)
{
if (tab[i]>maximum)
{
maximum=tab[i];
}
}
for (int i = 0; i < nbr; i++)
{
tab[i]=tab[i]/maximum;
}
for (int i = 0; i < nbr; i++)
{
if (tab[i]>(0.950))
{
bpm++;
}
}
temps=(millis()/1000);
var=15*comp;
if (temps/(var)>=1)
{
bpm=bpm*4;
//Serial.setCursor(0,10);
Serial.print("BPM : ");
Serial.print(bpm);
Serial.println("♥️");
//Serial.display();
//Serial.clearDisplay();
comp=comp+1;
bpm=0;
}
}
I can't get the value of the average outside of my loop
average is declared inside the loop so when an iteration ends it goes out of scope. You should declare it outside the while loop.
I want to get all the value readed by the sensor during a time of 20 milliseconds
You probably want to get something like 1 value per millisecond because all the values readed in 20 milliseconds are not 20 also you may not be able to know the exact number of values as it depends on the sensor's sample rate among other things.
If you need to reed those values to get a fixed threshold (i.e. use the code to study some behavior and get a const that will be used in the second code), put the code in void setup() instead of void loop() otherwise it will loop forever.
void loop ()
{
unsigned long currentTime=0;
while (millis() - currentTime > 20)
{
tab[i] = analogRead(Sensor);
i++;
sum += tab[i];
float average = sum/20;
Serial.println(average);
}
currentTime = millis();
i = 0;
}
Here there are some problems. Every time void loop() ends and executes again currentTime its going to be deleted and declared again holding the value 0. This makes the while loop execute for an infinite amount of time causing i to increment over tab's length leading to memory errors.
Also analogRead() does not return a float (returns an integer between 0 and 1023).
That's what I found about the first code, but about the second one I don't understand what is the problem. It is a compiling error? You don't get the expected output in the serial monitor? If it's the last thing, what is the output?
I am working with an hall sensor for counting the RPM of my wheel. I am using following sensor :
My code as follows :
int hall_pin = 3; // digital pin
float hall_threshold = 5.0;
float count = 0;
void setup() {
pinMode(hall_pin,INPUT);// put your setup code here, to run once:
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(hall_pin),hall_ISR,RISING);
}
void loop() {
count = 0.0;
float start = micros();
while(1){
if(count >= hall_threshold){
break;
}
}
float end_time = micros();
float time_passed = (end_time - start)/1000000.0; // in seconds
float rpm = (count/time_passed)*60.0;
Serial.println(rpm);
delay(10000);
}
void hall_ISR()
{
count+=1.0;
}
I am using digital pin 3 to read from sensor and count the number of times it detects magnetic field using interrupt. Since the sensor outputs 1 on detecting, I have used a RISING interrupt. Once the count is greater than 5 then the control comes out of the infinite loop and calculates the RPM. The problem is this interrupt is getting triggered multiple times. I have tried using detachInterrupt(hall_pin) but it is not working. I also tried to decrease the sensitivity of hall sensor using the trimmer provided.
I am sure the problem is not with the sensor, it is with the interrupt, I guess. Where am I going wrong?
Any help is very much appreciated!
Thank you.
I am working on a smart greenhouse project using an ESP32 as a microcontroller.
Data comes from a DHT22 temperature and humidity sensor and a soil moisture sensor. Those two tend to use delay() functions to read, because they need some time to warm up.
Example:
void loop() {
// Wait a few seconds between measurements.
delay(2000);
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
float f = dht.readTemperature(true);
}
I am planning on posting this data on a web interface, which would have manual controls available too.
Since I am using delays, if I press the button on the website, first the delay executes, then the button press, so it's not instant. What could I do to fix that?
Don't use delay(). I'm not clear on exactly what you're trying to do here or how you're trying to handle the button, but in general you're better off doing something like this:
#define SENSOR_UPDATE_WARMUP 2000
#define SENSOR_UPDATE_INTERVAL 1000
void loop() {
static unsigned long next_sensor_update = SENSOR_UPDATE_WARMUP;
if(millis() > next_sensor_update) {
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
float f = dht.readTemperature(true);
next_sensor_update = millis() + SENSOR_UPDATE_INTERVAL;
}
}
This allows you to other processing in loop() while still having the warmup time and only updating the sensor readings periodically (adjust SENSOR_UPDATE_INTERVAL to the number of milliseconds between updates).
If you need to have other delays for other devices just repeat the pattern of having a static variable that tracks the timing for those devices.
Even simpler, you could just put the two second delay at the end of setup() rather than inside loop(), but I suspect you're not going to want to update the sensor values constantly, so you'll want to structure your program similarly to the code above.
It is possible to serial print how milliseconds every output high. Let say i write an code analogRead. If analogread bigger than 600, then digitalwrite 13, high. If output pin 13 high, then capture how millisecond until the pin 13 goto low.
I try millis() but it cannot reset back to zero... It there anyway to reset millis() to zero?
You need a variable to keep track of your millis() count between events, kind of like a stop watch: you need to remember you started counting, so you can measure the difference when you stop.
Here's a quick sketch to illustrate the idea. Code isn't tested on an Arduino, but you should be able to understand the concept from the comments:
long lastTime;
int ledState = 0;
void setup() {
Serial.begin(115200);
pinMode(13,OUTPUT);
}
void loop() {
int analogValue = analogRead(0);
int newLedState = (analogValue > 600);//need to check, hoping boolean will evaluat to 1 when true
if(ledState == 0 && newLedState == 1){//if the led was of, but will be turned on, start the stop watch
lastTime = millis();//store the current time
ledState = newLedState;
}
if(ledState == 1 && newLedState == 0){//if the led was on, but will be turned off, get the difference between the last time we started counting time
long difference = millis() - lastTime; //get the current time, but subtract the last stored time
ledState = newLedState;
Serial.println(difference);
}
digitalWrite(13,ledState);
}
Okay so I think I understand what you want here. You want to capture the time difference between 2 pins changing their electrical state. To do this you can use pulseIn().
Using your example in your question we get...
if (13 == HIGH) {
millis = pulseIn(13, LOW);
}
That will give you the duration between the pin going high and then going low, stored in the variable millis. It's good practice to store it in a long.
I do have a small Arduino programming that simply stops after first loop. I might overlook something...but I'm simply clueless about what is happening.
Here is the code
int led = 13;
//int led = 10;
unsigned long windtime = 1000 * 2; // 2 seconds
unsigned long pausetime = 1000 * 60; // 1 minute
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
Serial.print("Wind");
digitalWrite(led, HIGH);
delay(windtime);
Serial.print("Pause");
digitalWrite(led, LOW);
delay(pausetime);
}
I used Serial only as debug echo.
Any idea?
It seems that you need to explicitly set numeric literals to long (L) and they use them. Otherwise it does not work. If anyone can explain if there is any kind of automatic conversion it will be awesome but until then simply use:
unsigned long seconds = 1000L; // !!! SEE THE CAPITAL "L" USED!!!
unsigned long minutes = seconds * 60;
unsigned long hours = minutes * 60;
and then simply use delay(millisec) as usual:
delay(5 * minutes);
It worked for me.
in your line:
unsigned long pausetime = 1000 * 60; // 1 minute
the Arduino will look at 1000 (integer) and 60 (integer) and so will work out an answer that it will try to slot into... an integer! This means the biggest answer it can give to pausetime is 32,767. Anything bigger than this will wrap round, so 60,000 minus two lots of 32,768 comes out at -5536.
To see it in action add Serial.print(1000 * 60); to the setup and watch in your Tools>Serial Monitor:
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
Serial.begin(9600);
Serial.print(1000 * 60);
}
To force the Arduino to use your constants as unsigned longs add ul or UL to the end of the number.
It could be that the unsigned longs are getting over-written. As a debugging method try a hardcoding constant value like delay(6000) for six seconds. This will prove if your hardware is working.
Finally, not sure if the delay value should be unsigned long, I usually use int and not for 60,000 which is greater than what an int (2 bytes) on the Arduino can store. Remember, embedded systems really are smaller systems.
this example: http://arduino.cc/en/Tutorial/BlinkWithoutDelay implies that the value for delay must be an int.
Hope this helps.
instead of using
unsigned long windtime = 1000 * 2; // 2 seconds
unsigned long pausetime = 1000 * 60; // 1 minute
use
unsigned long windtime = 2000; // 2 seconds
unsigned long pausetime = 60000; // 1 minute
and done.