Make an LED flash at certain voltage

Hello all

I’ve learnt a lot from this forum by just reading but now I am stuck and have registered.

I am a mech eng and relatively new to Arduino and programming. My project is driving a servo from a 2S Li-Ion battery, through an Arduino Nano. There is a 6V UBEC limiting the voltage to the servo.

I have a tri colour LED showing the position of the servo, +90degrees, 0 and -90degrees.

Now to where I’m stuck. I want to monitor the voltage of the battery, making the LED (on which ever colour is illuminated) flash slowly when the battery is at 7V and then flash fast at 6.8V.

I’ve read about making a voltage divider to get a 5V reference on an analogue pin. But from there I haven’t a clue. Read a few threads about this but have never found any code that works for me. All the ones I see are about displaying the voltage on a LCD screen.

Can someone please help me get my LEDS to flash at certain battery voltages?

Thank you!

Start by reading this thread then ask some questions.

https://forum.sparkfun.com/viewtopic.php?f=32&t=38968

Let me ask one upfront … how do “you” know the present position of the servo and how are the LEDs presently controlled ?

OK, mebbe that’s 2 questions. :mrgreen:

Hi, Thanks for the link.

About the servo, on start up, it moves to 0 degrees after being told. Then, contolling it with a three position rocker switch, it moves to +90 or -90 degrees.

“I” know the current position of the servo as I can see it and feel the difference it makes to my mountain bike suspension damping.

The LEDs really only illuminate on the button press, not the actual servo position. I dont need it to be that complicated but could add 3 micro switches but space and weight is at a premium.

Thanks, I’ll read through the link you sent me and report back

Cool, just read the link.

Interesting reading how to do it with hardware but I’d like to keep the number of parts to a minimum and seeing as I have an Arduino working for me already I think its only fair to let it do this too!

Thank you for the code you uploaded on the other thread. I understand whats happening and I’ll be able to adjust it to turn on and blink a single LED. But as I have essentially three different LEDs, one of which is always on, this is where I may need a little guidence.

This code seems different to the code that uses the 1.1V interal reference. Just for my own knowledge, does this code use a reference?

I would like to try and work out how to add your code to mine myself otherwise I’ll never learn. I’ll upload my existing servo code so when I come crawling back for help its here.

       #include <Servo.h>

    Servo myservo; // create servo object to control a servo

    int pos = 0; // variable to store the servo position
    int selectedPos = 2; // sets the selected servo position to middle
    const int buttonPin = 2; //sets pin 2 as button
    const int buttonPin2 = 3; //sets pin 3 as button
    const int ledPin1 = 10; // sets pin 10 as LED for Climb
    const int ledPin2 = 11; // sets pin 11 as LED for Trail
    const int ledPin3 = 12; // sets pin 12 as LED for Descend
    int buttonState = 0; //sets button 1 as off
    int buttonState2 = 0; // sets button 2 as off

    void setup()
    {
    myservo.attach(9); // attaches the servo on pin 9 to the servo object
    pinMode (buttonPin, INPUT); // sets button as input
    pinMode (buttonPin2, INPUT); // sets button as input
    pinMode (ledPin1, OUTPUT); // sets led as output
    pinMode (ledPin2, OUTPUT); // sets led as output
    pinMode (ledPin3, OUTPUT); // sets led as output

    
	digitalWrite(ledPin1, LOW);
    	digitalWrite(ledPin3, LOW);
      digitalWrite(ledPin2, HIGH); // will probably remove this
myservo.write(90); // sets servo to mid trail position and 

    }
  
    void loop()
    {
    
    buttonState = digitalRead(buttonPin);
    buttonState2 = digitalRead(buttonPin2);

    if (buttonState == HIGH && buttonState2 == LOW && selectedPos != 1)	//if button 1 is pushed and servo is not in position 1
    {
      digitalWrite(ledPin2, LOW);
    digitalWrite(ledPin3, LOW);
    digitalWrite(ledPin1, HIGH);
    myservo.write(45);		// servo moves into climb
    selectedPos = 1;
   
    }else if (buttonState2 == HIGH && buttonState == LOW && selectedPos != 3)//if button 2 is pushed and servo is not in the 3rd position
    {
      digitalWrite(ledPin1, LOW);
    digitalWrite(ledPin2, LOW);
    digitalWrite(ledPin3, HIGH);
    myservo.write(135);	// servo moves into descend
    selectedPos = 3;
   
    }else if (buttonState == LOW && buttonState2 == LOW && selectedPos != 2)//if button is in middle position and servo is not in middle position
    {
    digitalWrite(ledPin1, LOW);
    digitalWrite(ledPin3, LOW);
      digitalWrite(ledPin2, HIGH);
    myservo.write(90);		// servo moves into trail
    selectedPos = 2;
    
    }else{
      //digitalWrite(ledPin, LOW);
    }
    }

I’m open to any pointers!

Thank you for your time so far

Cheers

I think the simplest way to start is to divide down the voltage you want to measure so it’s max voltage is <= 5V. You can use a 10k potentiometer to do that. Connect the output of the pot to an analog pin. At the bottom of your loop() read the analog voltage and scale it back to it’s real value … as was done in the code I linked to. I think you could use the same blinkState flopping from 0 to 1 to 0 to 1 … as was done in that other code. Enable the blinking based on the voltage read in. Then also at the bottom of your loop() add code to turn on/off the LED to be blinked based on blinkState and selectedPos.

FWIW : none of the coding I’ve seen re: this uses the internal 1.1V reference. That can be done but given the nature of the project I don’t see the need for it. The regulated 5V supply should be good enough. You can always adjust the threshold in software.

Smashing. I’ll have a go at integrating your code at the end of mine. Ok, so instead of turning on the selected LED in my three digitalWrite paragraphs, I turn them on at the end, based on selectedPos? I’ll have a go!

I remember reading about the internal 1.1v of the 328 chip. That seemed to have loads more code that I couldn’t follow compared to yours. Possibly got it confused with something else though.

I’ll have a go tomorrow and get back to you.

Oh, got the voltage divider sorted on a breadboard.

Just worked it out! All the other codes I was reading mulitplied the by the inverse scaleFactor and divided by 1023 further down in their code. All clear now, thanks! Just ignore below

Hi, can you please explain this line to me?

I have a 8.4V battery, through a voltage divider consisting of a 4.05 and 5.95 ohm resistors

The ratio of divided down voltage to battery voltage is 8.4/5=0.595 = scaleFactor

battVolts = (float(analogRead(battPin)) * 5.0 / 1023.0) / scaleFactor;

So say the battery is full, float(analogRead(battPin) should be 5 because of my volt divider?

And should battVolts be calculated to be 8.4v?

I am unsure of what figures to use for the scaleFactor. I’m probably over complicating this but thought I’d ask.

Thanks

Well I had a quiet day at work and think I have sussed it!

I Think I may have repeated myself a lot (or left out a lot) in my last three paragraphs.I’m not sure.

Here it is in its entirety

// Rev 0 of Servo with battery monitoring
#include <Servo.h>

Servo myservo; // create servo object to control a servo

int pos = 0; // variable to store the servo position
int selectedPos = 2; // sets the selected servo position to middle
const int buttonPin = 2; //sets pin 2 as button
const int buttonPin2 = 3; //sets pin 3 as button
const int ledPin1 = 10; // sets pin 10 as LED for Climb
const int ledPin2 = 11; // sets pin 11 as LED for Trail
const int ledPin3 = 12; // sets pin 12 as LED for Descend
int buttonState = 0; //sets button 1 as off
int buttonState2 = 0; // sets button 2 as off
//declare the constants used
const float tripVolts1 = 7.4; //above this voltage the LEDs are always on
const float tripVolts2 = 6.9; //above this voltage the LEDs blink at rate 1
const float tripVolts3 = 6.6; //above this voltage the LEDs blink at rate 2
const float scaleFactor = 0.595; //ratio of divided down voltage to battery voltage
const int blinkRate1 = 1; //blink rate1 in Hz (blinks/sec)
const int blinkRate2 = 2; //blink rate2 in Hz (blinks/sec)
const int blinkRate3 = 4; //blink rate4 in Hz (blinks/sec)
//const int FETpin = 13; //number of digital pin used to control FET
const int battPin = A0; //number of analog pin used to measure battery voltage
//declare the variables used
boolean blinkState = false; //variable to control LEDs on or off
unsigned long blinkPeriod = 0; //period in msec of blinking
unsigned long blinkTime = millis(); //variable to store when blink state was last changed
float battVolts = 0; //battery voltage



void setup()
{
  myservo.attach(9); // attaches the servo on pin 9 to the servo object
  pinMode (buttonPin, INPUT); // sets button as input
  pinMode (buttonPin2, INPUT); // sets button as input
  pinMode (ledPin1, OUTPUT); // sets led as output
  pinMode (ledPin2, OUTPUT); // sets led as output
  pinMode (ledPin3, OUTPUT); // sets led as output


  digitalWrite(ledPin1, LOW);
  digitalWrite(ledPin3, LOW);
  digitalWrite(ledPin2, HIGH); // will probably remove this
  myservo.write(90); // sets servo to mid trail position

  //setup digital pin used to control FET
//  pinMode(FETpin, OUTPUT); //set pin to be an output
//  digitalWrite(FETpin, LOW); //turn FET off
}

void loop()
{

  buttonState = digitalRead(buttonPin);
  buttonState2 = digitalRead(buttonPin2);

  if (buttonState == HIGH && buttonState2 == LOW && selectedPos != 1)   //if button 1 is pushed and servo is not in position 1
  {
    digitalWrite(ledPin2, LOW);
    digitalWrite(ledPin3, LOW);
    digitalWrite(ledPin1, HIGH);
    myservo.write(45);      // servo moves into climb
    selectedPos = 1;

  }
  else if (buttonState2 == HIGH && buttonState == LOW && selectedPos != 3)//if button 2 is pushed and servo is not in the 3rd position
  {
    digitalWrite(ledPin1, LOW);
    digitalWrite(ledPin2, LOW);
    digitalWrite(ledPin3, HIGH);
    myservo.write(135);   // servo moves into descend
    selectedPos = 3;

  }
  else if (buttonState == LOW && buttonState2 == LOW && selectedPos != 2)//if button is in middle position and servo is not in middle position
  {
    digitalWrite(ledPin1, LOW);
    digitalWrite(ledPin3, LOW);
    digitalWrite(ledPin2, HIGH);
    myservo.write(90);      // servo moves into trail
    selectedPos = 2;

  }
  
  //measure the divided down voltage and convert back into battery voltage
  battVolts = (float(analogRead(battPin)) * 5.0 / 1023.0) / scaleFactor;
  if (battVolts > tripVolts1) { //check voltage above or below high trip point
    blinkPeriod = 0; //voltage above, special condition for no blinking
  } 
  else if (battVolts > tripVolts2) { //check voltage above or below 2nd trip point
    blinkPeriod = (1000 / blinkRate1); //voltage above, blink at rate1
  } 
  else if (battVolts > tripVolts3) { //check voltage above or below 3rd trip point
    blinkPeriod = (1000 / blinkRate2); //voltage above, blink at rate2
  } 
  else {
    blinkPeriod = (1000 / blinkRate3); //voltage below, blink at rate3
  }
  //now blink the LEDs if conditions are correct
  if (blinkPeriod == 0) { //special condition means no blinking
    //digitalWrite(FETpin, HIGH); //turn FET on
  } 
  else {
    //blink the LEDs on and off
    //check is blinkTime/2 has passed since last on/off change
    //if true change on to off or off to on
    if (millis() - blinkTime >= (blinkPeriod / 2)) {
      blinkState = ~blinkState; //change blinkState
      blinkTime = millis(); //reset blinkTime
    }
    //digitalWrite(FETpin, blinkState); //turn FET on or off per blinkState
  }
  delay(blinkPeriod/10);
  
  
  
  

if (selectedPos == 1 && blinkPeriod == 0)
{  digitalWrite(ledPin1, HIGH); //turn constant ON
}
else {
    //blink the LEDs on and off
    //check is blinkTime/2 has passed since last on/off change
    //if true change on to off or off to on
    if (millis() - blinkTime >= (blinkPeriod / 2)) {
      blinkState = ~blinkState; //change blinkState
      blinkTime = millis(); //reset blinkTime
    }
    digitalWrite(ledPin1, blinkState); //turn LED1 on or off per blinkState
  }
  delay(blinkPeriod/10);
  
  


if (selectedPos == 2 && blinkPeriod == 0)
{  digitalWrite(ledPin1, HIGH); //turn constant ON
}
else {
    //blink the LEDs on and off
    //check is blinkTime/2 has passed since last on/off change
    //if true change on to off or off to on
    if (millis() - blinkTime >= (blinkPeriod / 2)) {
      blinkState = ~blinkState; //change blinkState
      blinkTime = millis(); //reset blinkTime
    }
    digitalWrite(ledPin2, blinkState); //turn LED2 on or off per blinkState
  }
  delay(blinkPeriod/10);
  
  
  

if (selectedPos == 3 && blinkPeriod == 0)
{  digitalWrite(ledPin1, HIGH); //turn constant ON
}
else {
    //blink the LEDs on and off
    //check is blinkTime/2 has passed since last on/off change
    //if true change on to off or off to on
    if (millis() - blinkTime >= (blinkPeriod / 2)) {
      blinkState = ~blinkState; //change blinkState
      blinkTime = millis(); //reset blinkTime
    }
    digitalWrite(ledPin3, blinkState); //turn LED3 on or off per blinkState
  }
  delay(blinkPeriod/10);



}

I only have one instance of the blinkPeriod, is that correct? Below is just a short piece copied from the main part above…

//now blink the LEDs if conditions are correct

  if (blinkPeriod == 0) { //special condition means no blinking
    //digitalWrite(FETpin, HIGH); //turn FET on
  } 
  else {
    //blink the LEDs on and off
    //check is blinkTime/2 has passed since last on/off change
    //if true change on to off or off to on
    if (millis() - blinkTime >= (blinkPeriod / 2)) {
      blinkState = ~blinkState; //change blinkState
      blinkTime = millis(); //reset blinkTime
    }
    //digitalWrite(FETpin, blinkState); //turn FET on or off per blinkState
  }
  delay(blinkPeriod/10);

Should I have the above piece of code in each of the last three paragraphs? And instead of fetPin, the ledPin to be addressed.

Thanks for your help yet again!!

piesoup:
Well I had a quiet day at work and think I have sussed it!

OK, I'll give your code a look-over when I get a chance this weekend. It's a holiday on this side of the pond. :mrgreen:

Enjoy your holiday!!

The led is having a party, flashing as many colours as it can. Will look into that and get back.

Have a great weekend and thanks for your help as far!

I’ve done it!

I’ll upload the working code tomorrow. So don’t waste your time going through what I posted earlier.

Enjoy Labor Day, I’ll be back on Tuesday with some questions!

/* 	Rev 1.0 of iCTD with battery monitoring, by ASF
	01/09/2014



*/ 


#include <Servo.h>

Servo myservo; 			// create servo object to control a servo

int pos = 0; 			// variable to store the servo position
int selectedPos = 2; 		// sets the selected servo position to middle
const int buttonPin = 2; 	//sets pin 2 as button
const int buttonPin2 = 3; 	//sets pin 3 as button
const int ledPin1 = 10; 	// sets pin 10 as LED for Climb Blue
const int ledPin2 = 11; 	// sets pin 11 as LED for Trail Green
const int ledPin3 = 12; 	// sets pin 12 as LED for Descend Red
int buttonState = 0; 		//sets button 1 as off
int buttonState2 = 0; 		// sets button 2 as off

//declare the constants used
const float tripVolts1 = 8; 	//above this voltage the LEDs are always on
const float tripVolts2 = 7.0; 	//above this voltage the LEDs blink at rate 1
const float tripVolts3 = 6.6; 	//above this voltage the LEDs blink at rate 2
const float scaleFactor = 0.595;//ratio of divided down voltage to battery voltage
const int blinkRate1 = 1; 	//blink rate1 in Hz (blinks/sec)
const int blinkRate2 = 2; 	//blink rate2 in Hz (blinks/sec)
const int blinkRate3 = 4; 	//blink rate4 in Hz (blinks/sec)
const int battPin = A0; 	//number of analog pin used to measure battery voltage

//declare the variables used
boolean blinkState = false; 	//variable to control LEDs on or off
unsigned long blinkPeriod = 0; 	//period in msec of blinking
unsigned long blinkTime = millis(); //variable to store when blink state was last changed
float battVolts = 0; 		//battery voltage



void setup()
{
  myservo.attach(9); 		// attaches the servo on pin 9 to the servo object
  pinMode (buttonPin, INPUT); 	// sets button as input
  pinMode (buttonPin2, INPUT);	// sets button as input
  pinMode (ledPin1, OUTPUT); 	// sets led as output
  pinMode (ledPin2, OUTPUT); 	// sets led as output
  pinMode (ledPin3, OUTPUT); 	// sets led as output


  digitalWrite(ledPin1, LOW);
  digitalWrite(ledPin3, LOW);
  digitalWrite(ledPin2, HIGH); 	// will probably remove this
  myservo.write(90); 		// sets servo to mid trail position

  }

void loop()
{

  buttonState = digitalRead(buttonPin);
  buttonState2 = digitalRead(buttonPin2);

  if (buttonState == HIGH && buttonState2 == LOW && selectedPos != 1)   //if button 1 is pushed and servo is not in position 1
  {
    digitalWrite(ledPin2, LOW);
    digitalWrite(ledPin3, LOW);
//    digitalWrite(ledPin1, HIGH);
    myservo.write(45);      		// servo moves into climb blue
    selectedPos = 1;

  }
  else if (buttonState2 == HIGH && buttonState == LOW && selectedPos != 3)//if button 2 is pushed and servo is not in the 3rd position
  {
    digitalWrite(ledPin1, LOW);
    digitalWrite(ledPin2, LOW);
//    digitalWrite(ledPin3, HIGH);
    myservo.write(135);   		// servo moves into descend red
    selectedPos = 3;

  }
  else if (buttonState == LOW && buttonState2 == LOW && selectedPos != 2)//if button is in middle position and servo is not in middle position
  {
    digitalWrite(ledPin1, LOW);
    digitalWrite(ledPin3, LOW);
//    digitalWrite(ledPin2, HIGH);
    myservo.write(90);      		// servo moves into trail
    selectedPos = 2;
  }


 //_________________________________________________________________________---


  
 if (selectedPos == 1) 				// climb
  {
   
     //measure the divided down voltage and convert back into battery voltage
  battVolts = (float(analogRead(battPin)) * 5.0 / 1023.0) / scaleFactor;
  if (battVolts > tripVolts1) { 		//check voltage above or below high trip point
    blinkPeriod = 0; 				//voltage above, special condition for no blinking
  } 
//  else if (battVolts > tripVolts2) { 		//check voltage above or below 2nd trip point
//    blinkPeriod = (1000 / blinkRate1); 	//voltage above, blink at rate1
//  } 
//  else if (battVolts > tripVolts3) { 		//check voltage above or below 3rd trip point
//    blinkPeriod = (1000 / blinkRate2); 	//voltage above, blink at rate2
//  } 
//  else {
//    blinkPeriod = (1000 / blinkRate3); 	//voltage below, blink at rate3
//  }
  //now blink the LEDs if conditions are correct
  if (blinkPeriod == 0) { //special condition means no blinking
    digitalWrite(ledPin1, HIGH); 		//turn led on
  } 
  else {
    //blink the LEDs on and off
    //check is blinkTime/2 has passed since last on/off change
    //if true change on to off or off to on
    if (millis() - blinkTime >= (blinkPeriod / 2)) {
      blinkState = ~blinkState; 		//change blinkState
      blinkTime = millis(); 			//reset blinkTime
    }
    digitalWrite(ledPin1, blinkState); 		//turn led on or off per blinkState
  }
    delay(blinkPeriod/10);
  }
 //_________________________________________________________________________---

 else if (selectedPos == 2 ) 			//trail
 {
  //measure the divided down voltage and convert back into battery voltage
   battVolts = (float(analogRead(battPin)) * 5.0 / 1023.0) / scaleFactor;
  if (battVolts > tripVolts1) { 		//check voltage above or below high trip point
    blinkPeriod = 0; //voltage above, special condition for no blinking
  } 
  else if (battVolts > tripVolts2) { 		//check voltage above or below 2nd trip point
    blinkPeriod = (1000 / blinkRate1); 		//voltage above, blink at rate1
  } 
  else if (battVolts > tripVolts3) { 		//check voltage above or below 3rd trip point
    blinkPeriod = (1000 / blinkRate2); 		//voltage above, blink at rate2
  } 		
  else {
    blinkPeriod = (1000 / blinkRate3); 		//voltage below, blink at rate3
  }
  //now blink the LEDs if conditions are correct
  if (blinkPeriod == 0) { 			//special condition means no blinking
    digitalWrite(ledPin2, HIGH); 		//turn led on
  } 
  else {
    //blink the LEDs on and off
    //check is blinkTime/2 has passed since last on/off change
    //if true change on to off or off to on
    if (millis() - blinkTime >= (blinkPeriod / 2)) {
      blinkState = ~blinkState; 		//change blinkState
      blinkTime = millis(); 			//reset blinkTime
    }
    digitalWrite(ledPin2, blinkState); 		//turn led on or off per blinkState
  }
  delay(blinkPeriod/10);
 }
 
 //_________________________________________________________________________---

 else if (selectedPos == 3 ) 			//descend
 {
  //measure the divided down voltage and convert back into battery voltage
   battVolts = (float(analogRead(battPin)) * 5.0 / 1023.0) / scaleFactor;
  if (battVolts > tripVolts1) { //check voltage above or below high trip point
    blinkPeriod = 0; 				//voltage above, special condition for no blinking
  } 
//  else if (battVolts > tripVolts2) { 		//check voltage above or below 2nd trip point
//    blinkPeriod = (1000 / blinkRate1); 	//voltage above, blink at rate1
//  } 
//  else if (battVolts > tripVolts3) { 		//check voltage above or below 3rd trip point
//    blinkPeriod = (1000 / blinkRate2); 	//voltage above, blink at rate2
//  } 
//  else {
//    blinkPeriod = (1000 / blinkRate3); 	//voltage below, blink at rate3
//  }
  //now blink the LEDs if conditions are correct
  if (blinkPeriod == 0) { //special condition means no blinking
    digitalWrite(ledPin3, HIGH); //turn led on
  } 
  else {
    //blink the LEDs on and off
    //check is blinkTime/2 has passed since last on/off change
    //if true change on to off or off to on
    if (millis() - blinkTime >= (blinkPeriod / 2)) {
      blinkState = ~blinkState; 		//change blinkState
      blinkTime = millis(); 			//reset blinkTime
    }
    digitalWrite(ledPin3, blinkState); 		//turn led on or off per blinkState
  }	
  delay(blinkPeriod/10);
 }
 
 }

So here it is. This works, not sure if its the correct way of going about things though!

As you can see, I’ve had to comment out a few lines in the Climb and Descend parts

//  else if (battVolts > tripVolts2) { 		//check voltage above or below 2nd trip point
//    blinkPeriod = (1000 / blinkRate1); 	//voltage above, blink at rate1
//  } 
//  else if (battVolts > tripVolts3) { 		//check voltage above or below 3rd trip point
//    blinkPeriod = (1000 / blinkRate2); 	//voltage above, blink at rate2
//  } 
//  else {
//    blinkPeriod = (1000 / blinkRate3); 	//voltage below, blink at rate3
//  }

The program only likes it if this is mentioned once, in the Trail ‘else if’. I haven’t tried moving the remaining code in Trail to the top, under ‘void loop()’

Also,it didnt work if I made the led HIGH in the buttonState paragraph. I had to comment it out and turn it HIGH in your blink code.

if (buttonState == HIGH && buttonState2 == LOW && selectedPos != 1)   //if button 1 is pushed and servo is not in position 1
  {
    digitalWrite(ledPin2, LOW);
    digitalWrite(ledPin3, LOW);
//    digitalWrite(ledPin1, HIGH);
    myservo.write(45);      		// servo moves into climb blue
    selectedPos = 1;

  }

Are you able to explain this bit to me please. I can’t follow it 100%

{
    //blink the LEDs on and off
    //check is blinkTime/2 has passed since last on/off change
    //if true change on to off or off to on
    if (millis() - blinkTime >= (blinkPeriod / 2)) {
      blinkState = ~blinkState; 		//change blinkState
      blinkTime = millis(); 			//reset blinkTime
    }
    digitalWrite(ledPin1, blinkState); 		//turn led on or off per blinkState
  }
    delay(blinkPeriod/10);

Thanks again for your help!

piesoup:
Are you able to explain this bit to me please. I can’t follow it 100%

{
//blink the LEDs on and off
//check is blinkTime/2 has passed since last on/off change
//if true change on to off or off to on
if (millis() - blinkTime >= (blinkPeriod / 2)) {
  blinkState = ~blinkState; 		//change blinkState
  blinkTime = millis(); 			//reset blinkTime
}
digitalWrite(ledPin1, blinkState); 		//turn led on or off per blinkState

}
delay(blinkPeriod/10);




Thanks again for your help!
Let me start with the above.

The idea was to come up with code that would blink the LED on and off at a 50% duty cycle, that is equal times on and off, regardless of the actual on and off times (which were to be set elsewhere in the program). To that end the variable blinkPeriod was set elsewhere and so the LED should be on for 1/2 of blinkPeriod and off for 1/2 of blinkPeriod. Now … how to do that ?

Well when the LED is to be turned on for the 1’st time, why not record the “time of day” that happened. Then, as time goes by (loop iteration by loop iteration), ask if 1/2 of blinkPeriod has transpired since the LED was turn on. If not, leave it on. If yes, turn it off and record that time. Then ask if 1/2 of blinkPeriod has transpired since the LED was turned off. Wash, rinse, repeat. The Arduino function millis() provides a count of how many msecs have gone by since the last reset/power on … and so serves as a “time of day” clock. The boolean variable blinkState stores whether the LED is on or off. The statement …

blinkState = ~blinkState; //change blinkState

… simply changes the state from 0 to 1 or 1 to 0, whichever was the case. The delay was set to make sure the on/off question was asked often enough to not noticeably delay the change in the LED’s state.

http://arduino.cc/en/Reference/Millis

http://arduino.cc/en/Reference/BitwiseXorNot

piesoup:

/* 	Rev 1.0 of iCTD with battery monitoring, by ASF
01/09/2014

*/

#include <Servo.h>

Servo myservo; // create servo object to control a servo

int pos = 0; // variable to store the servo position
int selectedPos = 2; // sets the selected servo position to middle
const int buttonPin = 2; //sets pin 2 as button
const int buttonPin2 = 3; //sets pin 3 as button
const int ledPin1 = 10; // sets pin 10 as LED for Climb Blue
const int ledPin2 = 11; // sets pin 11 as LED for Trail Green
const int ledPin3 = 12; // sets pin 12 as LED for Descend Red
int buttonState = 0; //sets button 1 as off
int buttonState2 = 0; // sets button 2 as off

//declare the constants used
const float tripVolts1 = 8; //above this voltage the LEDs are always on
const float tripVolts2 = 7.0; //above this voltage the LEDs blink at rate 1
const float tripVolts3 = 6.6; //above this voltage the LEDs blink at rate 2
const float scaleFactor = 0.595;//ratio of divided down voltage to battery voltage
const int blinkRate1 = 1; //blink rate1 in Hz (blinks/sec)
const int blinkRate2 = 2; //blink rate2 in Hz (blinks/sec)
const int blinkRate3 = 4; //blink rate4 in Hz (blinks/sec)
const int battPin = A0; //number of analog pin used to measure battery voltage

//declare the variables used
boolean blinkState = false; //variable to control LEDs on or off
unsigned long blinkPeriod = 0; //period in msec of blinking
unsigned long blinkTime = millis(); //variable to store when blink state was last changed
float battVolts = 0; //battery voltage

void setup()
{
myservo.attach(9); // attaches the servo on pin 9 to the servo object
pinMode (buttonPin, INPUT); // sets button as input
pinMode (buttonPin2, INPUT); // sets button as input
pinMode (ledPin1, OUTPUT); // sets led as output
pinMode (ledPin2, OUTPUT); // sets led as output
pinMode (ledPin3, OUTPUT); // sets led as output

digitalWrite(ledPin1, LOW);
digitalWrite(ledPin3, LOW);
digitalWrite(ledPin2, HIGH); // will probably remove this
myservo.write(90); // sets servo to mid trail position

}

void loop()
{

buttonState = digitalRead(buttonPin);
buttonState2 = digitalRead(buttonPin2);

if (buttonState == HIGH && buttonState2 == LOW && selectedPos != 1) //if button 1 is pushed and servo is not in position 1
{
digitalWrite(ledPin2, LOW);
digitalWrite(ledPin3, LOW);
// digitalWrite(ledPin1, HIGH);
myservo.write(45); // servo moves into climb blue
selectedPos = 1;

}
else if (buttonState2 == HIGH && buttonState == LOW && selectedPos != 3)//if button 2 is pushed and servo is not in the 3rd position
{
digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, LOW);
// digitalWrite(ledPin3, HIGH);
myservo.write(135); // servo moves into descend red
selectedPos = 3;

}
else if (buttonState == LOW && buttonState2 == LOW && selectedPos != 2)//if button is in middle position and servo is not in middle position
{
digitalWrite(ledPin1, LOW);
digitalWrite(ledPin3, LOW);
// digitalWrite(ledPin2, HIGH);
myservo.write(90); // servo moves into trail
selectedPos = 2;
}

//_________________________________________________________________________—

if (selectedPos == 1) // climb
{

 //measure the divided down voltage and convert back into battery voltage

battVolts = (float(analogRead(battPin)) * 5.0 / 1023.0) / scaleFactor;
if (battVolts > tripVolts1) { //check voltage above or below high trip point
blinkPeriod = 0; //voltage above, special condition for no blinking
}
// else if (battVolts > tripVolts2) { //check voltage above or below 2nd trip point
// blinkPeriod = (1000 / blinkRate1); //voltage above, blink at rate1
// }
// else if (battVolts > tripVolts3) { //check voltage above or below 3rd trip point
// blinkPeriod = (1000 / blinkRate2); //voltage above, blink at rate2
// }
// else {
// blinkPeriod = (1000 / blinkRate3); //voltage below, blink at rate3
// }
//now blink the LEDs if conditions are correct
if (blinkPeriod == 0) { //special condition means no blinking
digitalWrite(ledPin1, HIGH); //turn led on
}
else {
//blink the LEDs on and off
//check is blinkTime/2 has passed since last on/off change
//if true change on to off or off to on
if (millis() - blinkTime >= (blinkPeriod / 2)) {
blinkState = ~blinkState; //change blinkState
blinkTime = millis(); //reset blinkTime
}
digitalWrite(ledPin1, blinkState); //turn led on or off per blinkState
}
delay(blinkPeriod/10);
}
//_________________________________________________________________________—

else if (selectedPos == 2 ) //trail
{
//measure the divided down voltage and convert back into battery voltage
battVolts = (float(analogRead(battPin)) * 5.0 / 1023.0) / scaleFactor;
if (battVolts > tripVolts1) { //check voltage above or below high trip point
blinkPeriod = 0; //voltage above, special condition for no blinking
}
else if (battVolts > tripVolts2) { //check voltage above or below 2nd trip point
blinkPeriod = (1000 / blinkRate1); //voltage above, blink at rate1
}
else if (battVolts > tripVolts3) { //check voltage above or below 3rd trip point
blinkPeriod = (1000 / blinkRate2); //voltage above, blink at rate2
}
else {
blinkPeriod = (1000 / blinkRate3); //voltage below, blink at rate3
}
//now blink the LEDs if conditions are correct
if (blinkPeriod == 0) { //special condition means no blinking
digitalWrite(ledPin2, HIGH); //turn led on
}
else {
//blink the LEDs on and off
//check is blinkTime/2 has passed since last on/off change
//if true change on to off or off to on
if (millis() - blinkTime >= (blinkPeriod / 2)) {
blinkState = ~blinkState; //change blinkState
blinkTime = millis(); //reset blinkTime
}
digitalWrite(ledPin2, blinkState); //turn led on or off per blinkState
}
delay(blinkPeriod/10);
}

//_________________________________________________________________________—

else if (selectedPos == 3 ) //descend
{
//measure the divided down voltage and convert back into battery voltage
battVolts = (float(analogRead(battPin)) * 5.0 / 1023.0) / scaleFactor;
if (battVolts > tripVolts1) { //check voltage above or below high trip point
blinkPeriod = 0; //voltage above, special condition for no blinking
}
// else if (battVolts > tripVolts2) { //check voltage above or below 2nd trip point
// blinkPeriod = (1000 / blinkRate1); //voltage above, blink at rate1
// }
// else if (battVolts > tripVolts3) { //check voltage above or below 3rd trip point
// blinkPeriod = (1000 / blinkRate2); //voltage above, blink at rate2
// }
// else {
// blinkPeriod = (1000 / blinkRate3); //voltage below, blink at rate3
// }
//now blink the LEDs if conditions are correct
if (blinkPeriod == 0) { //special condition means no blinking
digitalWrite(ledPin3, HIGH); //turn led on
}
else {
//blink the LEDs on and off
//check is blinkTime/2 has passed since last on/off change
//if true change on to off or off to on
if (millis() - blinkTime >= (blinkPeriod / 2)) {
blinkState = ~blinkState; //change blinkState
blinkTime = millis(); //reset blinkTime
}
digitalWrite(ledPin3, blinkState); //turn led on or off per blinkState
}
delay(blinkPeriod/10);
}

}




So here it is. This works, not sure if its the correct way of going about things though!
I'll have to look at this tomorrow. Right now my brain is much mush. Simple quantum physics questions I can handle, code ... not so much. :mrgreen:

Haha!! No rush!

piesoup:
Haha!! No rush!

I looked at the code and I think it'll work but I am confused and I think the coding could be made simpler. But I have to understand something first. It seems that only when in the "trail" condition that the blinkPeriod is set to a non-zero value. When climbing or descending the only change allowed is to have the blinking go back to a steady on (due to a "high/normal" battery voltage). Have I understood that correctly ?

Hi Mac, thanks for looking at it for me.

Yes, on my limited knowledge, it’s confused me too! I had to comment out the blink rate parts for climb and descend for it to work. If I left them in, the LED wouldn’t flash, they just stayed steady. But as the code is, it blinks on all three positions, with the different Vin.

It does look like it can be condensed. Should I try placing my last three if statements into the buttonState statements in the first part of the loop()?

Also, I don’t really need the two blink rates. If (battVolts > tripVolts3), I’m going to make it move to Trail, then not allow any more user inputs. The bike will be hard to ride if it failed in Climb or Descend! I’m pretty sure I can make that happen.

One I’m having more trouble with is a momentary push button, that when pushed, moves the servo to Climb, and when released, moves back to the original selectedPos. But that’s for another day!

Thanks again

If I were you, and now that you’ve gotten your feet wet, I’d take a step back and write in plain English a set of requirements, what functions, you want the device to have and/or accomplish. And just before that I would introduce you to the concept of a State Machine. A lot of software can be written as a SM and it helps clarify what the code does and organize the code in an efficient manner. You can Google State Machine or Finite State Machine (same thing) or perhaps first search these forums, as I know I’ve posted some URLs to help others on the topic. With that in mind let me start w/my thinking on what your device is supposed to do.

The device {insert name here} will be a FSM with 3 states; descending, trailing and climbing. After reset or power-up, the FSM will be initialized to the trailing state. Independent of the present state the {insert name here} will monitor 2 momentary switches, which in turn will control the transition from one state to the next. A press on button A will cause the state to go from descending to trailing or trailing to climbing. A press on button B will cause the state to go from climbing to trailing, or trailing to descending. No other transitions are allowed. [?Do I have that right or does battery voltage also determine state?] The software will also provide some form of debouncing for the switches. Independent of the present state, the {insert name here} will monitor the battery voltage via an analog input to it’s A/D converter. Also independent of the present state the {insert name here} will provide a blink timing function for an LED.
When in the descending state the code will use the monitored battery voltage and if above a threshold, disable the blinking function. It will command a servo to the {descending } position and activate the {descending} LED.
When in the trailing state the code will use the monitored battery voltage to set the blink rate. When above a threshold of XX volts the blinking will be disabled. When between XX and YY volts the blink rate will be set to {some} Hz. Lastly when the battery voltage is less the YY volts the blink rate will be set to {different} Hz. The servo will be commanded to the {trailing} position. The {trailing} LED will be activated.
When in the climbing state the code will use the monitored battery voltage and if above a threshold, disable the blinking function. It will command a servo to the {climbing} position and activate the {climbing} LED.

Now I may have missed some stuff and got some parts wrong but it’s a start. You can correct the above and fill in the {blanks}. You no doubt have noticed that your code is already written as a FSM, w/the state variable being selectedPos. Given you only have 3 states, you can get away with

if (state == 1)
 do state 1 stuff;
if (state == 2)
 do state 2 stuff;
if (state == 3)
 do state 3 stuff;

but I’d like to introduce you to a neater form of the above, it’s the switch…case conditional. Read here …

http://arduino.cc/en/Reference/SwitchCase

Using it will tend to make SM type code easier to read and comprehend.

Based on the above I might jot down some pseudo-code (not real code language) just to organize my thoughts.

loop()
 - reading in and store battery voltage
 - check on blink timing, flip blinkState (on/off) according to timing if enabled
 - read switches, debounce, set state variable accordingly
 - switch(state variable)
   -- case(descending)
       -- command servo
       -- choose/activate LED if blinkState = 1
       -- check if voltage > threshold, disable blinking if true
   -- case(trailing)
       -- command servo
       -- choose/activate LED if blinkState = 1
       -- check if voltage vs thresholds, set blink rate (or period), enable/disable blinking. 
   -- case(climbing)
       -- command servo
       -- choose/activate LED if blinkState = 1
       -- check if voltage > threshold, disable blinking if true

I’ve got a better way to combine the blinking and choosing of the LED but the above is enough for now. There’s also some timing issues to be resolved but for the moment I’m not sure I’ve correctly understood all the code is supposed to do. So I’ll leave some details sketchy for now.

Wow, thank you !

I understand what you have typed and I will write out what I want my machine to do in the format above. I’ll read over the items you described this weekend so I fully understand them.

I’ll write down what the machine currently does, then write down what I would like it to do.

Thanks for your time so far, have a great weekend!

I haven’t forgotten Mac, unfortunately work is getting the way of my hobbies!