The LED's will change state when the analog output is within six or seven numbers of the threshold, making accurate transitions impossible. The colors oscillate back and forth. There must be a better way! Would appreciate your thoughts.
unsigned long starTime;
int flashRed = 20000;
const int numReadings = 3;
int readings[numReadings]; // the readings from the analog input
int index = 0; // the index of the current reading
int total = 0; // the running total
int average = 0;
#define blueLED 11
#define redLED 12
#define greenLED 13
#define AnIn 1
#define redThresh 670
#define blueThresh 660
#define greenThresh 0
int val;
void setup()
{
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
starTime = millis(); //timer
pinMode(redLED,OUTPUT);
pinMode(blueLED,OUTPUT);
pinMode(greenLED,OUTPUT);
Serial.begin(9600);
}
void loop()
{
// subtract the last reading:
total= total - readings[index];
// read from the sensor:
readings[index] = analogRead(AnIn);
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;
// if we're at the end of the array...
if (index >= numReadings)
// ...wrap around to the beginning:
index = 0;
// calculate the average:
average = total / numReadings;
starTime = millis(); //timer
//val = analogRead(AnIn);
// val = val/2;
if(average >= redThresh){
digitalWrite(redLED,HIGH);
digitalWrite(blueLED,LOW);
digitalWrite(greenLED,LOW);
delay(1000);
}
else {
digitalWrite(redLED,LOW);
if((average>= blueThresh) && (average <= redThresh))
{
digitalWrite(blueLED,HIGH);
digitalWrite(redLED,LOW);
digitalWrite(greenLED,LOW);
delay(1000);
}
else {
digitalWrite(blueLED,LOW);
if((average>= greenThresh) && (average <= blueThresh))
{
digitalWrite(greenLED,HIGH);
digitalWrite(blueLED,LOW);
digitalWrite(redLED,LOW);
delay(1000);
}
else {
digitalWrite(greenLED,LOW);
}
}
Serial.println(average);
}
}
Analog inputs on the Arduino are pretty noisy. I usually shift off the 2 low order bits as it is generally all noise. In this case, you may need to do three bits.
Sorry, I have no idea how to shift off lower order bits but I certainly need to learn. Would you please write a snippet that illustrates the procedure? Thanks.
That is more simple than expected. Thanks. I have tried to plug this filter into the sketch but the results are quacky; the red flashes, the blue stay on, and the green is never high. I have rewritten this sketch a bunch of different ways but the LED's will not cooperate. Analog readings from 640~680
// subtract the last reading:
total= total - readings[index];
// read from the sensor:
readings[index] = analogRead(AnIn) >> FILTER_SHIFT;
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;
// if we're at the end of the array...
if (index >= numReadings)
...
You might consider printing the inputs & outputs of the filter to aid in debugging.
Seems that no matter which way the sketch is tweaked, the odd ball reading sneaks in and makes the lights change state even when their is nothing but silence. I've seen somewhere a procedure that compares new data with old and if there is not close to the current figure, nothing happens. After an exhausting search, I can't find it. Would this eliminate the problem? A sample of the analog input is listed below the code.
#define FILTER_SHIFT 1
int val;
int ledRed =12;
int ledYellow = 11;
int ledGreen = 13;
unsigned long starTime;
int flashRed = 20000;
const int numReadings = 5;
int readings[numReadings]; // the readings from the analog input
int index = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
int inputPin = 1;
void setup()
{
val = 0;
pinMode(ledRed,OUTPUT);
pinMode(ledYellow,OUTPUT);
pinMode(ledGreen,OUTPUT);
pinMode(inputPin, INPUT);
// initialize serial communication with computer:
Serial.begin(9600);
// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
starTime = millis(); //timer
}
void loop() {
// subtract the last reading:
total= total - readings[index];
// read from the sensor:
readings[index] = analogRead(inputPin) >> FILTER_SHIFT ;
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;
// if we're at the end of the array...
if (index >= numReadings)
// ...wrap around to the beginning:
index = 0;
// calculate the average:
average = total / numReadings;
delay(100);
starTime = millis(); //timer
// if ((average >200) && (average < 300)) { // code here will execute if average > 100
if (average > 342) {
digitalWrite(ledRed,HIGH);
digitalWrite(ledYellow,LOW);
digitalWrite(ledGreen,LOW);
delay(1000);
val= val +1;
if((val >8) && (starTime> flashRed )) {
digitalWrite(ledRed,HIGH);
delay(1000);
digitalWrite(ledRed,LOW);
delay(1000);
digitalWrite(ledRed,HIGH);
delay(1000);
digitalWrite(ledRed,LOW);
delay(1000);
digitalWrite(ledRed,HIGH);
delay(1000);
digitalWrite(ledRed,LOW);
delay(1000);
digitalWrite(ledRed,HIGH);
delay(1000);
digitalWrite(ledRed,LOW);
delay(1000);
if (val>8){
val = 0;
}
}
}
else if ((average > 332) && (average < 341)) { // code here will execute if average <= 100 and average > 80
digitalWrite(ledRed,LOW);
digitalWrite(ledYellow,HIGH);
digitalWrite(ledGreen,LOW);
delay(1000);
}
else { // code here will execute if average <= 80
digitalWrite(ledRed,LOW);
digitalWrite(ledYellow,LOW);
digitalWrite(ledGreen,HIGH);
delay (200);
}
// Serial.println(average, DEC);
Serial.println(average, DEC);
//val = 0;
}
An easier way is you have a counter and an analog-read total. Every time you take an analog read you add it to your total and increment the counter. At some point you divide the total by the counter and there is your average. Then you start over. That is a simple way that works for many applications.
Last edited by zener on Mon Nov 09, 2009 4:03 pm, edited 1 time in total.
We want a noise monitor for our cafeteria, which is near riot every lunch hour. Similar commercial units are about $70 but we need one for each classroom if I can persuade the circuit/sketch to turn red, blue, and green LED's on when the noise exceeds their relative threshold.
Before going much further, your original code shows a difference of 10 between the blue and red thresholds. But your sample output shows a range of 14 for a steady-state input. I think you will have some trouble separating the signal from the noise here. You may want to re-evaluate your sensor.
On the processing side, your application can tolerate a fairly aggressive low-pass filter. A running average of 20 (or more!) samples over several seconds should smooth things out a bit. But you should also consider adding some hysteresis to prevent flickering around the threshold levels. For example, once the device is in the "red" state, the raw input level should have to go several counts below the red threshold before changing state to "blue".