What a great learning experience my first Arduino project is turning out to be.. I would now like to add a countdown until a sensor reading is taken and displayed, which will repeat infinitely. I've got the sensor and LCD display working fine but my loop is not quite right.. Should I be using a while() of some sort? How do I keep the timer ticking during the big delay between readings?
/*Code for self-watering plant with LCD readout*/
// value for LCD params
char ESC = 0xFE;
// analog input pin that the soil moisture sensor is attached to
const int analogInPin = A1;
// value read from the soil moisture sensor
int sensorValue = 0;
// if the readings from the soil sensor drop below this number, then turn on the pump
int dryValue;
// countdown timer until next soil reading
int timerValue = 9;
void setup() {
pinMode(12, OUTPUT);
// initialize serial communications at 9600 bps:
Serial.begin(9600);
// Set the "dry" value of soil on turning on the device
dryValue = analogRead(analogInPin);
// pause before intialize LCD
delay(2000);
// Initialize LCD module
Serial.write(ESC);
Serial.write(0x41);
Serial.write(ESC);
Serial.write(0x51);
// Set Contrast
Serial.write(ESC);
Serial.write(0x52);
Serial.write(40);
// Set Backlight
Serial.write(ESC);
Serial.write(0x53);
Serial.write(5);
//print the dry value to serial
Serial.print("Dry = " );
Serial.print(dryValue);
Serial.print(" ");
}
void loop(){
watering();
// wait some time (really should be delay(86400000))
delay(10000);
}
void printTimer(){
// Set cursor line 1, column 16
Serial.write(ESC);
Serial.write(0x45);
Serial.write(0x0F);
// print the timer value
Serial.print(timerValue);
timerValue = timerValue - 1;
if(timerValue == 0){
timerValue = 9;
}
}
void printVal(){
// set cursor line 2, column 1
Serial.write(ESC);
Serial.write(0x45);
Serial.write(0x40);
// print the sensor to the serial monitor:
Serial.print("Sensor = " );
Serial.print(sensorValue);
Serial.print(" ");
printTimer();
}
void watering(){
// read the analog in value:
sensorValue = analogRead(analogInPin);
//turn on the water pump for some time if the soil is too dry
if(sensorValue < dryValue){
digitalWrite(12, HIGH);
delay(2000);
digitalWrite(12, LOW);
}
else {
printVal();
}
}
It's actually really simple: Don't delay. Instead, initialize a timer to run a routine whenever it overflows or hits a certain value. Examine the datasheet for the microcontroller used in your Arduino for the specific bits to frob (note that the Arduino libraries use the timer 0 overflow vector for themselves), and the avr-libc documentation for how to denote the ISR(s) for the timer. Your loop() then becomes a big sleep while the timer runs the entire show for you.
I would use a timer library for Arduino like this http://playground.arduino.cc//Code/SimpleTimer
Just download the library, put it in the "libraries" folder in your sketchbook and restart your Arduino IDE to load the new library.
Then your code would look something like this. Basically what it does it updates the screen every loop and then once every 86400000 ms it checks the "watering" function. Just so you know this code would only check the soil once every 24 hours (86400000ms). I think a better solution would be to constantly check the soil and water anytime it is needed. But Im no gardener so maybe there is a reason for just checking once a day.
#include <SimpleTimer.h>
// the timer object
SimpleTimer timer;
void setup() {
Serial.begin(9600);
timer.setInterval(86400000, watering); // how often you would call your watering function is set with the first variable
}
void loop() {
timer.run();
printTimer();
}
void printTimer(){
// Set cursor line 1, column 16
Serial.write(ESC);
Serial.write(0x45);
Serial.write(0x0F);
// print the timer value
Serial.print(timerValue);
timerValue = timerValue - 1;
if(timerValue == 0){
timerValue = 9;
}
}
void printVal(){
// set cursor line 2, column 1
Serial.write(ESC);
Serial.write(0x45);
Serial.write(0x40);
// print the sensor to the serial monitor:
Serial.print("Sensor = " );
Serial.print(sensorValue);
Serial.print(" ");
printTimer();
}
void watering(){
// read the analog in value:
sensorValue = analogRead(analogInPin);
// send it to the display
printVal();
//turn on the water pump for some time if the soil is too dry
if(sensorValue < dryValue){
digitalWrite(12, HIGH);
delay(2000);
digitalWrite(12, LOW);
}
}
Related
I have connected coin hopper and coin acceptor to one arduino uno, coin acceptor connected to pin 2, coin hopper to pin 3 - sensor and pin 7 - relay. When coin hopper switch relay, it is executing coininterrupt
for coin hopper I am using this script link
coin acceptor script: link
I need this 2 scripts working on 1 arduino
my code:
#define SENSOR 3
#define RELAY 7
#define ACCEPTOR 2
volatile boolean insert = false;
int pulse=0,count;
char sen;
int temp=0;
unsigned long int timer;
void setup()
{
Serial.begin(9600);
pinMode(SENSOR,INPUT_PULLUP);
pinMode(RELAY,OUTPUT);
sen=digitalRead(SENSOR);
digitalWrite(RELAY, HIGH);
attachInterrupt(digitalPinToInterrupt(ACCEPTOR), coinInterrupt, RISING);
}
void loop()
{
if (insert) {
insert = false;
Serial.println("coin");
delay(1000);
}
if(Serial.available())
{
timer=millis();
// temp is amount to dispense send to arduino
temp=Serial.parseInt();
if(temp>0){
digitalWrite(RELAY,LOW);}
}
sen=(sen<<1)|digitalRead(SENSOR);
// if hopper sensor read drop coin
if(sen==1)
{
timer=millis();
pulse++;
sen&=0x03;
Serial.println("out 1");
//if dispensed coins equal with coins to dispense stop engine
if(pulse==temp)
{
digitalWrite(RELAY,HIGH);
pulse=0;
temp=0;
}
}
// if amount dispensed is not equal with amount to dispense and engine running, stop
if((digitalRead(RELAY)==LOW)&(millis()-timer>2000))
{
digitalWrite(RELAY,HIGH);
pulse=0;
temp=0;
}
}
void coinInterrupt() {
insert = true;
}
I was trying to change pins (arduino uno support interrupts on pin 2 and 3 only) but problem still appears so I guess there is issue in the code
your sketch does not run in this state :
first fix errors :
declare insert as volatile
remove cpulse (not used anywhere)
change 'if()' to (I suppose) 'if (insert) ....'
remove stuff with 'sen' var : simply use if(digitalRead(SENSOR)) or if(!digitalRead(SENSOR))
except if you need to store relay state.
use logical operators like || or && unless you really need bitwise operations
example of result sketch :
#define SENSOR 3
#define RELAY 7
volatile boolean insert = false;
byte amountToDispense = 0;
int pulse = 0;
int temp = 0;
unsigned long int timer;
void setup()
{
Serial.begin(9600);
pinMode(SENSOR, INPUT_PULLUP);
pinMode(RELAY, OUTPUT);
digitalWrite(RELAY, HIGH);
attachInterrupt(digitalPinToInterrupt(2), coinInterrupt, RISING);
}
void loop()
{
if (insert ) {
insert = false;
Serial.println("coin");
delay(1000);
}
if (Serial.available())
{
timer = millis();
temp = Serial.parseInt();
if (temp > 0) {
//amountToDispense = Serial.read() - 48;
digitalWrite(RELAY, LOW);
}
}
if (digitalRead(SENSOR))
{
timer = millis();
pulse++;
Serial.println("out 1");
if (pulse >= temp)
{
digitalWrite(RELAY, HIGH);
pulse = 0;
temp = 0;
}
}
if (!digitalRead(RELAY) && (millis() - timer > 2000))
{
digitalWrite(RELAY, HIGH);
pulse = 0;
temp = 0;
}
}
void coinInterrupt() {
insert = true;
}
What is this supposed to do?
sen=(sen<<1)|digitalRead(SENSOR);
You init sen with digitalRead(SENSOR);
Assuming that pin is LOW when you start the sketch and turns HIGH, sen will become 1.
Next you do sen &= 0x03 so sen is still 1.
Again sen=(sen<<1)|digitalRead(SENSOR); , sen will either be 2 or 3.
Next loop run sen=(sen<<1)|digitalRead(SENSOR); sen is now 4 or 6. and so on...
I don't have time to think about what you want to achieve but this is definitely a problem as you'll only enter if (sen == 1) once and never again.
If this is not sufficient you should probably improve your post as it is unclear what arduino sends bad signal to interrup pin is supposed to mean. That doesn't make sense. Explain the expected behaviour of your program and how it behaves instead. add more comments so it becomes clear what you intend to do with each block of code so we don't have to interpret
Currently I have a diesel engine with magnetic pickup attached to it. I want to use Arduino (Uno/Nano) to measure engine RPM.
Magnetic Pickup Description: A magnetic pickup is installed over a gear, (most commonly the flywheel inside a vehicle’s bell housing) and as the gear turns the pickup will create an electric pulse for each tooth on the gear. These pulses are then read by the instrument which interprets it to indicate the correct RPMs or speed.The signal from the magnetic speed Sensor, teeth per second(HZ), is directly proportional to engine speed.
Magnetic Pickup Image:
MP - Self Powered
I've tried to rectify the signal using diode then limit the current using a resistor with .1Uf capacitor to filter the noise, then connected it to Optocopler 4N35 and the output from Opto to Arduino interrupt pin, by just observing Arduino interrupt ping is highly affected by surroundings.
Also I have tried to directly connect the magnetic pickup to "A0" pin and use analogue read and connect a led to pin 13 just to monitor the pulses from MP.
int sensorPin = A0;
int ledPin = 13;
int sensorValue = 0;
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
// read the value from the sensor:
sensorValue = analogRead(sensorPin);
digitalWrite(ledPin, HIGH);
delay(sensorValue);
digitalWrite(ledPin, LOW);
Serial.println(sensorValue);
Serial.println(" ");
}
Using analogueRead works with the LED as indicator for pulses generated by pickup. (Tested using small motor and small gear to protect Arduino).
Also I tried to use LM139 Comparator but the readings make no sense
(ex: 60 RPM, 1500 RPM,2150 RPM, 7150 RPM).
LM139 Circuit
Code used with LM139:
// read RPM
volatile int rpmcount = 0;
//see http://arduino.cc/en/Reference/Volatile
int rpm = 0;
unsigned long lastmillis = 0;
void setup() {
Serial.begin(9600);
attachInterrupt(0, rpm_fan, RISING);
//interrupt cero (0) is on pin two(2).
}
void loop() {
if (millis() - lastmillis == 500) {
/*Update every one second, this will be equal to reading frequency (Hz).*/
detachInterrupt(0); //Disable interrupt when calculating
rpm = rpmcount * 60;
/* Convert frequency to RPM, note: this works for one interruption per full rotation. For two interrupts per full rotation use rpmcount * 30.*/
Serial.print(rpm); // print the rpm value.
Serial.println(" ");
rpmcount = 0; // Restart the RPM counter
lastmillis = millis(); // Update lastmillis
attachInterrupt(0, rpm_fan, RISING); //enable interrupt
}
}
void rpm_fan() {
/* this code will be executed every time the interrupt 0 (pin2) gets low.*/
rpmcount++;
}
// Elimelec Lopez - April 25th 2013
What is the best way or approach to interface a magnetic pickup with Arduino to display RPM?
Your use of analogRead is wrong. Besides, analogRead will not get you anywhere close to what you want to achieve.
What you want from your pickup is a clear 0-5v digital signal. You can obtain that by playing with the input resistor on your opto-coupler. I'd do some measurements, and place a trimpot + resistors on the board do the actual value can be tweaked after the system is installed.
Once you get the electrical signal as clean as you can get, you can the use an interrupt pin on the Arduino to keep count of the number of pulses.
#define SENSOR_PIN (2) // using define instead of variable for constants save memory.
#define LED_PIN (13)
#define READ_DELAY (100) // in milliseconds.
// we'll get a reading every 100ms, so 8 bits are enough to keep
// track of time. You'd have to widen to unsigned int if you want
// READ_DELAY to exceed 255 ms.
//
typedef delay_type unsigned char;
typedef unsigned int counter_type; // You may want to use
// unsigned long, if you
// experience overflows.
volatile counter_type pulseCount = 0; // volatile is important here
counter_type lastCount = 0;
delay_type lastTime = 0;
// pulse interrupt callback, keep short.
void onSensorPulse()
{
++pulseCount;
// the following may already be too long. Use for debugging only
// digitalWrite() and digitalRead() are notoriously slow.
//
//
// digitalWrite(LED_PIN, !digitalRead(LED_PIN));
//
// using fastest direct port access instead. (for ATMega)
//
if (pulseCount & 1)
PORTB |= (1 << PB5);
else
PORTB &= ~(1 << PB5);
}
void setup()
{
pinMode(SENSOR_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(SENSOR_PIN), onSensorPulse, RISING);
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
}
void loop()
{
// control frequency of readings
//
delay_type now = (delay_type)millis();
if (now - lastTime < READ_DELAY)
{
return;
}
lastTime = now;
// get a reading. must disable interrupts while doing so.
// because pulseCount is multi-bytes.
//
noInterrupts();
counter_type curCount = pulseCount;
interrupts();
// get the number of pulses since last reading.
//
counter_type delta = curCount - lastCount;
lastCount = curCount;
// to convert to RPMs, you will need to use this formula:
// note the use of long (UL) to avoid overflows in the
// computation. 60000 = miliseconds per minute.
//
// RPM = delta * 60000UL / (READ_DELAY * TEETH_COUNT);
// send delta to client for now.
//
Serial.println(delta);
}
I have put together an Arduino circuit that turns the led's off when the button is pressed. How do I code it so when I press it once it comes on and stays on and will only turn off once its pressed again? Any help would be appreciated
My Current code is:
int ledred = 12;
int ledgreen = 8;
int BUTTON = 4;
int speakerPin = 1;
void setup() {
// initialize the digital pin as an output.
Serial.begin(9600);
pinMode(ledgreen, OUTPUT);
pinMode(ledred, OUTPUT);
pinMode(BUTTON,INPUT);
}
void loop() {
if(digitalRead(BUTTON) == HIGH){
digitalWrite(ledred,HIGH);
digitalWrite(ledgreen,HIGH);
}else
{
digitalWrite(ledred,LOW);
digitalWrite(ledgreen,LOW);
}
}
If all you want is do this, you can use one of the interrupt pins and watch for the RISING (or FALLING) event.
Something similar to this example:
const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, RISING);
}
void loop() {
digitalWrite(ledPin, state);
}
void blink() {
state = !state;
}
Mind that you may still need some debouncing strategy.
Also, you don't need to use an interrupt for that, but then you'd need some edge-detection algorithm. These are quite well explained in the debouncing article above. I personally prefer these, since interrupt pins in the UNO board are precious enough not to be used with humble button pressings... :o)
/*
Debounce
Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
press), the output pin is toggled from LOW to HIGH or HIGH to LOW. There's a
minimum delay between toggles to debounce the circuit (i.e. to ignore noise).
The circuit:
- LED attached from pin 13 to ground
- pushbutton attached from pin 2 to +5V
- 10 kilohm resistor attached from pin 2 to ground
- Note: On most Arduino boards, there is already an LED on the board connected
to pin 13, so you don't need any extra components for this example.
created 21 Nov 2006
by David A. Mellis
modified 30 Aug 2011
by Limor Fried
modified 28 Dec 2012
by Mike Walters
modified 30 Aug 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Debounce
*/
// constants won't change. They're used here to set pin numbers:
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin
// Variables will change:
int ledState = HIGH; // the current state of the output pin
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin
// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
void setup() {
pinMode(buttonPin, INPUT);
pinMode(ledPin, OUTPUT);
// set initial LED state
digitalWrite(ledPin, ledState);
}
void loop() {
// read the state of the switch into a local variable:
int reading = digitalRead(buttonPin);
// check to see if you just pressed the button
// (i.e. the input went from LOW to HIGH), and you've waited long enough
// since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;
// only toggle the LED if the new button state is HIGH
if (buttonState == HIGH) {
ledState = !ledState;
}
}
}
// set the LED:
digitalWrite(ledPin, ledState);
// save the reading. Next time through the loop, it'll be the lastButtonState:
lastButtonState = reading;
}
I currently have an arduino LCD and one SPDT switch connected to my board. The the common pin of the SPDT is grounded and the outer pins are each connected to a digital input. My program should increment and decrement the counter being printed to the LCD screen. I have one input working that increments the counter I do not know how to implement code for the input to decrement the counter. Code posted below.
Thank you
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5,4,3,2);
const byte buttonPin = 8;
int counter = 0; // set your counter to zero to begin with
byte buttonState; // the current reading from the input pin
byte lastButtonState = HIGH; // the previous reading from the input pin
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
void setup()
{
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP);
lcd.begin(16, 2); // for 2x16 lcd display
}
void loop() {
// read the state of the switch into a local variable:
byte reading = digitalRead(buttonPin);
// check to see if you just pressed the button
// (i.e. the input went from HIGH to LOW), and you've waited
// long enough since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) >= debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;
if (buttonState == LOW) {
counter ++;
Serial.println(counter);
lcd.setCursor(0, 1);
lcd.print(counter);
}
}
}
lastButtonState = reading;
}
You cannot simply connect one pole of a switch to an input pin an other to the ground. This will detect LOW but when when you are suppose to detect HIGH on the pin, it will be floating. Connect a pull-up resistor to your input pins.
Or you can use pinMode(InPin, INPUT_PULLUP);
This will pull your input pin to high internally and then you can detect the swithces and implememnt the code.
This code is for reading potentiometer and print the value to arduino serial monitor
but you get values even if you dont move the pot.
What do I have to change in the code to get values only when you move the potentiometer?
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);
// print out the value you read:
Serial.println(sensorValue);
delay(1); // delay in between reads for stability
}
int oldValue = 0;
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);
// print out the value you read:
if (sensorValue != oldValue){
Serial.println(sensorValue);
oldValue = sensorValue;
}
delay(1); // delay in between reads for stability
}
You need to use a variable to hold the old value and compare it to the new reading.
If they differ print the new value and update the old value