Program help on Arduino Uno - c++

So I was building this: http://www.instructables.com/id/Automatically-water-your-small-indoor-plant-using-/?ALLSTEPS
Problem: I set the water time to 5 min and the wait time to 1 hour, the water still kept running and hasn't stop after 5 min.
Is there another way to write this program?
The program he provide was
int motorPin = A0;
int blinkPin = 13;
int watertime = 300000; // how long to water in miliseconds
int waittime = 3600000; // how long to wait between watering
void setup()
{
pinMode(motorPin, OUTPUT);
pinMode(blinkPin, OUTPUT);
}
void loop()
{
digitalWrite(motorPin, HIGH);
digitalWrite(blinkPin, HIGH);
delay(watertime);
digitalWrite(motorPin, LOW);
digitalWrite(blinkPin, LOW);
delay(waittime);
}

Arduino UNO maximum integer value is 32767 (16-bit signed integer). So both watertime and waittime are too large to store in int variables. Try slowing the timebase by using delay(1000) to control a loop that runs once every second, then express watertime and waittime using seconds instead of miliseconds.
Incidentally, there is a stackoverflow site that specializes in Arduino: https://arduino.stackexchange.com/

Arduino UNO integers are 16bit wide, just use unsigned long variables or a #define.
#define watertime 300000
#define waittime 3600000
// some code...
delay(watertime);
// more code...
delay(waittime);

Related

Breaking a While loop C++

I have a quick question and I think that a more experienced firmware developer will be able to help me out with. So the main goal I have with this code is:
Run a loop (detect) that will "listen" for something to happen and then increment a variable (voltscount in this case) once that threshold is hit. Once voltscount is hit twice within a specified time, the 1st while loop inside of the sampling loop will listen more closely (via a FFT).
I want to then break out of the while loop (stop listening with the FFT) when the threshold in the detect loop isn't hit in a certain time period (3 secs in this example).
Number 1 is achieve but I'm having trouble with number 2. The code seems to remain in the 1st while loop inside of sampling (the serial window keeps displaying the FFT values instead of 0,1 or 2 -voltscount value) well after 3 sec of that volts threshold remaining below 4.8.
I didn't include my void setup and all that jazz, let me know if that is needed in order to answer my question.
void loop(){
detect();
sampling();
}
void detect(){
unsigned long startMillis= millis(); // Start of sample window
unsigned int peakToPeak = 0; // peak-to-peak level
unsigned int signalMax = 0;
unsigned int signalMin = 1024;
// collect data for 50 mS
while (millis() - startMillis < sampleWindow)
{
sample = analogRead(0);
if (sample < 1024) // toss out spurious readings
{
if (sample > signalMax)
{
signalMax = sample; // save just the max levels
}
else if (sample < signalMin)
{
signalMin = sample; // save just the min levels
}
}
}
peakToPeak = signalMax - signalMin; // max - min = peak-peak amplitude
volts = (peakToPeak * 5.0) / 1024; // convert to volts
Serial.println(voltscount);
}
void sampling(){
unsigned long currentMillis = millis();
if(volts >=4.8){
voltscount++;
previousMillis = millis();
}
while(voltscount >= 2){
/////SAMPLING
for(int i=0; i<samples; i++)
{
microseconds = micros(); /* Overflows after around 70 minutes! */
vReal[i] = analogRead(0);
vImag[i] = 0;
while(micros() < (microseconds + sampling_period_us)){
}
}
double x;
double v;
FFT.MajorPeak(vReal, samples, samplingFrequency, &x, &v);
Serial.print(x, 0);
Serial.print(", ");
Serial.println(v, 0);
delay(10); /* Repeat after delay */
/*
// 3 tests for smoke detector chirps and code to light up the LEDs
if (x > 4000 and x < 4900 and v > 80) {
digitalWrite(blueLEDpin, HIGH);
digitalWrite(uvLEDpin, HIGH);
delay(blueLEDdelay);
digitalWrite(blueLEDpin, LOW);
delay(uvLEDdelay);
digitalWrite(uvLEDpin, LOW);
}
if (x > 1700 and x < 1800 and v > 40) {
digitalWrite(blueLEDpin, HIGH);
digitalWrite(uvLEDpin, HIGH);
delay(blueLEDdelay);
digitalWrite(blueLEDpin, LOW);
delay(uvLEDdelay);
digitalWrite(uvLEDpin, LOW);
}
*/
if (v > 1400) {
digitalWrite(blueLEDpin, HIGH);
digitalWrite(uvLEDpin, HIGH);
delay(blueLEDdelay);
digitalWrite(blueLEDpin, LOW);
delay(uvLEDdelay);
digitalWrite(uvLEDpin, LOW);
}
if (currentMillis - previousMillis > 3000){
voltscount = 0;
break;
}
}
}
Assume the state where voltscount is 1. You enter sampling(). You first set the current mills to the current time. Assume it's 1000 (Hypothetical since I don't know what that function returns). Then since your volts is greater than 4.8 you increment voltscount to 2. And you set the previousMillis to something like 1500 because millis() is called for the second time. Then you enter the first while loop and at the end of it, you check if currentMillis - previousMillis > 3000. But this is never true since previouslMillis have a greater value than currentMillis. I guess what you could do is to read the currentmillis right before you check if the difference is greater than 3000.
if (millis() - previousMillis > 3000){
voltscount = 0;
break;
}
In Arduino programming, most beginner's while loops are simply wrong.
Especially, if you feel the need to break them somehow.
The Arduino environment provides a loop() function prototype, which you should use properly.
Typically, any while() {...} can be replaced by an if() {...}, which is called again in the next loop() run. Sometimes, you need a few more state variables, but the important change is to follow the paradigm that loop() should not take noticeable time to run and should not describe sequential actions by listing them one after the other in loop().
The basic BlinkWithoutDelay sample applies everywhere, not only to blinking. The important part is not only calling millis(), but keeping the state of your sketch in appropriate variables (like those previousmillis)

Take voltage every 60 seconds C++ Sketch

Can someone explain how to modify this program to "ReadAnalogVoltage" once every 60 seconds, forever.
Right now it reads the voltage every millisecond (I think), forever.
Too much information is being generated.
Any suggestions would be appreciated.
Rob.
> /*
ReadAnalogVoltage
Reads an analog input on pin 0, converts it to voltage, and prints
the result to the serial monitor.
Attach the center pin of a potentiometer to pin A0, and the outside
pins to +5V and ground.
This example code is in the public domain.
*/
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
float voltage = sensorValue * (5.0 / 1023.0);
// print out the value you read:
Serial.println(voltage);
}
There are several ways to lower the sampling rate. Place a counter inside your loop and only print when the counter reaches a certain value. Be sure to reset the value after printing.
int counter = 0;
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
float voltage = sensorValue * (5.0 / 1023.0);
// print out the value you read:
if(counter >= 1000000){
Serial.println(voltage);
counter = 0;
}
}
The best way to solve this is with an time interrupt. The actual mechanics of setting the interrupt will depend on what hardware you are using.

Arduino interrupt frequency

I am using an Arduino uno to measure the speed of a dc motor.
I have a opto sensor that gives a pulse when the motor has made a full turn.
The problem I've got starts when the motor has a speed > 90Hz.
As soon as I reach 90Hz, the Arduino doesn't enter the interrupt function.
My code:
int pin = 13;
volatile int state = LOW;
volatile unsigned long startTijd = 0;
volatile unsigned long eindTijd = 0;
unsigned int frequentie = 0;
volatile int count = 0;
void setup()
{
pinMode(pin, OUTPUT);
attachInterrupt(0, blink, FALLING); //LOW, HIGH, FALLING, RISING, CHANGE
Serial.begin(19200);
}
void loop()
{
noInterrupts();
digitalWrite(pin, state);
interrupts();
}
void blink()
{
if (count == 0) {
startTijd = micros();
}
count++;
if (count == 31) {
count = 0;
eindTijd = micros();
eindTijd -= startTijd;
Serial.print(eindTijd);
Serial.print(" ms. - ");
frequentie = 30 * 1000000 / eindTijd;
Serial.print(frequentie);
Serial.println(" Hz.");
}
state = !state;
}
My question is : When the Arduino receives interrupts at 90Hz, it doesn't execute the code in the interrupt. When the motor goes below 90Hz after that, the code works again. What am I doing wrong ?
It looks as though blink is your ISR. If that's the case, you shouldn't be doing debug I/O within that routine for 2 reasons. The first is that you are calling a process that could block. The second is that ISRs should do their thing and finish (should be highly efficient). My guess is that if you remove the debug I/O from your ISR and pass info back to the interrupted task instead (safely, of course) you will be able to service interrupts at greater than 90 hz.
Just to add to #Bruce answer. You are using serial IO in the interrupt. Each time you are printing around 15-20 characters (depending on the values calculated). Each character is encoded by 8 bit data + 1 start bit + 1 stop bit = 10 bits. So, say 20*10=200 bits. The baud rate is 19200bps, so time required to transmit 200 bits is 200/19200 sec, or in terms of frequency 19200/200=96Hz. So this is the maximum frequency achievable for transmission of 20 characters, which is close to your measured 90Hz (take in account that I am not considering any time spacing overhead between the transmits).

Arduino Lily Pad mp3, Loop in Loop in Loop with timing

the best way to explain my problem is in codeform.
const int ringerPin = A0;
const int offhook = A4;
const int onhook = A5;
void setup(){
pinMode(ringerPin, OUTPUT);
pinMode(offhook, INPUT);
pinMode(onhook, INPUT);
randomSeed(analogRead(0));
}
int randCall = random(60000, 3600000); // generate a random number between 1 min and 60 min
//ring every 1 to 60 minutes if the phone is down (hookon) and dont ring if the phone is picked up (no hookon)
void loop()
{
if (digitalRead(hookon) == HIGH)
void loop(){
delay(randCall);
//i dont know how to let this loop below here run for 30 seconds.
void loop()
{
//turn audio off - i dont know how to.
for(int x = 0; x < 15; x++){
digitalWrite(ringerPin, HIGH);
delay(50);
digitalWrite(ringerPin, LOW);
delay(80);
}
delay(2500);
}
else
//play one randomly choosen audiofile out of 10 - i dont know how to
}
}
I would be greatful if there is anybody who can give me some suggestions to my coding problems.?
I wrote them inside the code descriptions.
loop() is not a way to create a loop. loop() is the function that Arduino calls over and over when it can.
To create loops, use while or for. You can think of the loop() function as being the body of a while(true) loop.
That said, you should probably not use loops for what you are trying to do. There is a useful function called millis() that returns the number of milliseconds since the device was turned on. The value overflows every 50 days. You will need to handle that, but I suggest you write the loop() function to check if enough time has passed, and then do what it is supposed to. See this for an example.

Calling constant complexity O(1) 5 line function significantly impacts performance, why?

I have the following code:
#include <ros.h>
#include <ros/time.h>
#include <sensor_msgs/Range.h>
#define sensNumber 3
#define firstTrigPin 3
#define firstEchoPin 9
ros::NodeHandle nh;
sensor_msgs::Range range_msg;
ros::Publisher pub_range( "/ultrasound", &range_msg);
char frameid[] = "/ultrasound";
int trigPin=firstTrigPin;
int echoPin=firstEchoPin;
void increasepins(){
trigPin++;
echoPin++;
if(trigPin>firstTrigPin+sensNumber){
trigPin=firstTrigPin;
}
if(echoPin>firstEchoPin+sensNumber){
echoPin=firstEchoPin;
}
}
void setup(){
nh.initNode();
nh.advertise(pub_range);
for(int i=0;i<sensNumber;i++){
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
increasepins();
}
range_msg.radiation_type = sensor_msgs::Range::ULTRASOUND;
range_msg.header.frame_id = frameid;
range_msg.field_of_view = 0.1;
range_msg.min_range = 0.0;
range_msg.max_range = 6.47;
}
long range_time;
void loop()
{
increasepins();
//publish the adc value every 50 milliseconds
//since it takes that long for the sensor to stablize
long duration, distance;
digitalWrite(trigPin, LOW); // should be high?
delayMicroseconds(2); // make this 20
digitalWrite(trigPin, HIGH);
delayMicroseconds(10); // reset value?
digitalWrite(trigPin, LOW);
distance = pulseIn(echoPin, HIGH)/ 58,2; //sensor constant is 3.4
range_msg.range = distance;
range_msg.header.stamp = nh.now();
range_time = millis() + 50;
range_msg.field_of_view = trigPin;
range_msg.min_range = echoPin;
pub_range.publish(&range_msg);
nh.spinOnce();
}
This above code runs at my funduino at aprox 2 times a second for the whole loop. If I however remove the increasePins method it runs at around 100 times per second. Why the big chance? It seems like such a trivial piece of code (just increase 2 variables and then compare them) make such a large difference?
For reference we are talking about this function:
void increasepins(){
trigPin++;
echoPin++;
if(trigPin>firstTrigPin+sensNumber){
trigPin=firstTrigPin;
}
if(echoPin>firstEchoPin+sensNumber){
echoPin=firstEchoPin;
}
}
Which to me looks really simple when compared to having to wait for the echo to come back and getting the time and that sort of things required for the rest of the code.
I believe that one of the problem is that if you comment the increasePins function in the loop, the compiler will decide to take some of the logic outside the loop. For that you need to look # the assembly code and see what's being done inside the loop.
Another problem may be related to the pin behavior. For example, I read that "pulseIn" function sends a pulse to the pin and measures it's duration. You use it to pulse the "echoPin". I suspect that if you don't change the echoPin you will have a rather constant duration. However, changing the echoPin may lead to a situation where another pin's pulse duration would be longer. To test this, you can try and use pulsePin(echoPin, HIGH, timeout) with a timeout parameter for the case when you did not comment the increasePins function. I expect the loop to run faster.
So i think that the increasePins is not a bottleneck. I recommend making it inline however (could add some speedup if the compiler hasn't done this already).