What i am trying to achieve is a simple serial log of sorts. This device will be monitoring audio voltage on a remote computer and i want the serial monitor to be up and running. I want it print once while the unit is in alarm and once when its cleared. When i remote into the PC i will see when it alarmed and when it cleared.
Below is the code. I have read till my eyes hurt and have tried various things. I am just not getting a grasp on how to either use what I read and import it into the code or that what i have read was even correct.
Thanks for taking the time to look at this.
int relay1 = 6;
int ledState = LOW; // ledState used to set the LED
int belowBaselineVoltage = false;
const int ledPin = LED_BUILTIN;// the number of the LED pin
const float baselineVoltage = 1.00;
unsigned long turnOnAt;
unsigned long previousMillis = 0; // will store last time LED was updated
const unsigned long turnOnDelay = 30 * 1000; // delay in seconds for no signal and alarm to trip
const unsigned long HeartBeat = 1 * 1000;
const long interval = 1000; // interval at which to blink (milliseconds)
void setup() {
Serial.begin(9600);
pinMode(relay1, OUTPUT);
pinMode(ledPin, OUTPUT);
}
void loop() {
int sensorValue = analogRead(A0);
float voltage = sensorValue * (5.0 / 1023.0);
//Serial.println(voltage);
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
if (voltage < baselineVoltage)
{
if (belowBaselineVoltage == true)
{
if (millis() >= turnOnAt)
{
digitalWrite(relay1, HIGH);
digitalWrite(ledPin, HIGH);
// Serial.println("ALARMED");
}
}
else
{
belowBaselineVoltage = true;
turnOnAt = millis() + turnOnDelay;
}
}
else
{
belowBaselineVoltage = false;
digitalWrite(relay1, LOW);
}
}
It does something. We can't see your computer or your setup, and you forgot to tell us.
You expect it to do something, but you didn't tell us what you expect.
Now, I think we can reasonably conclude that what it does is not what you want. But, really, we can't help you get from point A to point B without knowing where A and B are.
Try writing what you want to do in your own language first. I can make several assumptions about the code you have written and suggest where it appears incorrect to me, but the truth is, I don't know what your intended behavior is.
Pin Constants
Constants
Global Variables
void setup() {
Serial.begin(9600);
pinModes
digitalWrites
}
void loop() {
flash LED once every 1000 milliseconds
poll analog pin for analog_value
if (analog_value >= alarm_value) {
turn on relay
transmit serial data {
millis()
alarm is on
}
}
else {// analog pin < alarm value
turn off relay
transmit serial data {
millis()
alarm is off
}
}
}
I tried looking at the state change and spent about an hour trying to get it working within the code. I may have to spend time on it when my eyes and brain are fresh as i think i just confused the hell out of myself.
Sorry, what the code does is listen to the audio port and measure the voltage. if the voltage is above 1 volt then it is not in alarm. When it goes into alarm, when the relay engages and the voltage is below 1 volt for more then 30 seconds.
The code as it sits works and works well. i just dont have the serial output coded in it yet as my attempts have failed LOL. Where the serial.Println("alarmed") is commented out is a place holder where i thought the "In Alarm code should go.
I am clearly missing something here. and thanks for the help. I added the boolean and added the code. I think i have it all wrong as the unit now never goes into alarm. I think its just a matter of where im putting the code. This is the same thing i ran into when i tried the boolean earlier in the day. Just a poor understanding still of the code structure.
fogkeebler:
I am clearly missing something here. and thanks for the help. I added the boolean and added the code. I think i have it all wrong as the unit now never goes into alarm.
I believe it is how you are handling turnOnAt:
if (millis() >= turnOnAt){
...
turnOnAt = millis() + turnOnDelay;
should be rewritten as follows:
if (millis() - turnOnAt >= turnOnDelay){
...
turnOnAt = millis();
the absolute original code worked. tested in a live environment over the past 2 weeks. I got a wild hair and said "Hey lets muck this up and learn something new" LOL.
This is the absolute original code that is currently working on a live system.
int relay1 = 6;
int ledState = LOW; // ledState used to set the LED
int belowBaselineVoltage = false;
const int ledPin = LED_BUILTIN;// the number of the LED pin
const float baselineVoltage = 1.00;
unsigned long turnOnAt;
unsigned long previousMillis = 0; // will store last time LED was updated
const unsigned long turnOnDelay = 30 * 1000; // delay in seconds for no signal and alarm to trip
const unsigned long HeartBeat = 1 * 1000;
const long interval = 1000; // interval at which to blink (milliseconds)
void setup() {
Serial.begin(9600);
pinMode(relay1, OUTPUT);
pinMode(ledPin, OUTPUT);
}
void loop() {
int sensorValue = analogRead(A0);
float voltage = sensorValue * (5.0 / 1023.0);
Serial.println(voltage);
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
if (voltage < baselineVoltage)
{
if (belowBaselineVoltage == true)
{
if (millis() >= turnOnAt)
{
digitalWrite(relay1, HIGH);
digitalWrite(ledPin, HIGH);
}
}
else
{
belowBaselineVoltage = true;
turnOnAt = millis() + turnOnDelay;
}
}
else
{
belowBaselineVoltage = false;
digitalWrite(relay1, LOW);
}
}
Now through trial and error with the stuff i have tried. this resulted in the unit saying it was in alarm in the serial monitor but the LED still blinking instead of being solid. I am using a separate board for testing the serial output as well as a serial monitor.
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
This is a complete and independent loop. It will toggle the LED on, then off, then on, then off... forever, independent of any of your other code.
Read this to understand why it is better to subtract when using millis() than to add, however, I don't think that is the problem why you are never entering "alarm".
So for simplicity and testing further i removed the LED stuff. Also played with the code a little. the below code results in the unit going into alarm at the right threshold, and going out of alarm at the right threshold but serial monitor continuously displays in alarm until the alarm goes away.
The !beenThereDoneThat if statement should ONLY surround sending the message. The device can BE in alarm mode millions of times, but you only want to send the message ONCE. Don't you?
Here is my code, based on the OP code and what has been described as the intended behavior, with my own flair. It's not the cleanest and most efficient approach, and it's untested, but I hope you can learn from it and modify it to serve your purpose.
//PIN CONSTANTS
const byte RelayOnePin = 6;// physical pin 12, Atmel PD6/AIN0
const byte LEDPin = LED_BUILTIN;// 13, physical pin 19, Atmel PB5/SCK, connected to ISP port pin 4
const byte ThingOnePin = A0;// 14, physical pin 23, Atmel PC0/ADC0
//CONSTANTS
// BaselineVoltage = x*(5/1023) where x = the baseline voltage
const int BaselineVoltage = 205;// 204 = 0.997067448680352 volts, 205 = 1.0019550342131 volts
const unsigned long belowBaselineVoltageGracePeriod = 30000; // delay in milliseconds for alarm
const unsigned long FastBlinkInterval = 400;// blink interval in milliseconds
const unsigned long SlowBlinkInterval = 1000;// blink interval in milliseconds
//Global Variables
byte belowBaselineFlag = 0;// 0 = no alarm, 1 = grace period, 2 = alarm
byte serialFlag = 0;// 0 = not sent, 1 = sent
unsigned long belowBaselineVoltageTimestamp;
unsigned long blinkLEDTimestamp;
void setup() {
Serial.begin(9600);
pinMode(RelayOnePin, OUTPUT);
digitalWrite(RelayOnePin, LOW);// assuming Arduino is sourcing current
pinMode(LEDPin, OUTPUT);
digitalWrite(LEDPin, LOW);// assuming Arduino is sourcing current
}
void loop() {
if (pollThingOne()) {
blinkLED(FastBlinkInterval);
digitalWrite(RelayOnePin, HIGH);
if (serialFlag == 0) {
Serial.print(millis());
Serial.println(" ALARMED");
serialFlag = 1;
}
}
else {
blinkLED(SlowBlinkInterval);
digitalWrite(RelayOnePin, LOW);
if (serialFlag == 0) {
Serial.print(millis());
Serial.println(" ALL CLEAR");
serialFlag = 1;
}
}
}
bool pollThingOne() {
int ThingOneVoltage = analogRead(ThingOnePin);
if (ThingOneVoltage < BaselineVoltage && belowBaselineFlag <= 0) {
belowBaselineVoltageTimestamp = millis();
belowBaselineFlag = 1;
return false;
}
else if (ThingOneVoltage < BaselineVoltage && belowBaselineFlag == 1) {
if (millis() - belowBaselineVoltageTimestamp >= belowBaselineVoltageGracePeriod) {
belowBaselineFlag = 2;
return true;
serialFlag = 0;
}
else return false;
}
else if (ThingOneVoltage < BaselineVoltage && belowBaselineFlag >= 2) {
return true;
}
else if (ThingOneVoltage >= BaselineVoltage && belowBaselineFlag >= 2) {
belowBaselineFlag = 0;
serialFlag = 0;
return false;
}
else if (ThingOneVoltage >= BaselineVoltage) {
belowBaselineFlag = 0;
return false;
}
}
void blinkLED(unsigned long interval) {
if (millis() - blinkLEDTimestamp >= interval) {
digitalWrite(LEDPin, !digitalRead(LEDPin));
blinkLEDTimestamp = millis();
}
}
Some things to note... I changed many of the ints to bytes as it's a good practice to conserve memory where possible so that it's there when needed in the future. To this same end, I eliminated the unnecessary float math that not only consumes more memory but also processing speed. Since analogRead() returns an int between 0 and 1023, you will only ever have 1024 possible values, so no need to go out to 32 bits and do the decimal stuff. Regarding "ThingOne" the name is intentionally vague to illustrate how vague "sensor" is. It would be better to name it whatever it is so your purpose becomes much more clear. "Relay" is equally vague, and would be better named for the "ThingTwo" it's controlling.
Man, i can not tell you how much of a help this was. I tried your revised code of my mess and it worked with the exception of showing on the serial monitor that it was in alarm. the LED blinked fast (cool BTW) and relay clicked as expected. Because you lay'ed it out so very well it was easy for me to follow and see what flags had to be changed to get the right result as well as it is something i can learn from.
I have been messing with Arduino for about 3 years and have built a few useful things by the old method of find code here and find code there, place it here and learning that way to modify it to suit my needs and only ever done it here or there so i am not exposing myself to it constantly. After seeing how you lay'ed it out I clearly need to focus more and even take some classes to get it stuck in the brain. Free youtube videos isn't cutting the mustard anymore especially when my search is so vague.
Definitely learning a lot more through the forum and your code. Thanks so much.