Hello Guys!!
I am working on my first 'permanent' project. And I could use a little help.
But first, a little back story:
I got two sets of those el cheapo LED light bars off of ebay for free. I got them installed on my truck and was very disappointed with the flash patterns. A normal person would have just got a different flash box off of Amazon, but of course I opt to do things the hard way. I have an Arduino (UNO R3) laying around and in a moment of pure genius decided I should make my own flasher. Since the LED's run off the 12v straight from the car battery, I have a bank of 12 MOSFETs to switch the ground on and off for them. Hopefully that was a good choice. The plan is to have the 12v going into the Vin on the Arduino. Is that ok or should I through in a 5v voltage regulator? Then I bought on of the VKey Voltage Keypad off of SF and am planning on using that so that I can select from 12 different flash patterns.
Here's the problem:
How do I have a flash pattern running while checking to see if the user is pressing one of the other buttons to change the flash pattern?
I am a little stumped here. I hope I don't have to have two Arduino to do this, one monitoring the keypad while the other controls the flash pattern.
Any help/direction is greatly appreciated! Thanks
Blenderite
Here's the specs on the UNO:
So yes, powering the UNO off 12V is fine. Car batteries are not the most stable supply, but it's probably OK.
The answer to your flash problem, is you need to use millis() to time things. It does not wait, just checks if the time period has been met yet, and moves on.
Have a read of this:
and then add your button code to change the blink pattern.
How do I have a flash pattern running while checking to see if the user is pressing one of the other buttons to change the flash pattern?
Don't use delay() in your flash pattern code as it blocks operation of the code until the delay() is finished. If you have delay()s inside for loops or while loops then you make the problem worse.
Use millis() instead of delay()
Save the millis() value at the time that the start action happens, perhaps turning an LED on. Then, each time through loop(), check whether the required wait period has elapsed by subtracting the start time from the millis() value now. If the period has elapsed then act accordingly and maybe save the start time for the next activity, maybe another LED. If not, then go round loop() again, perhaps taking other actions and/or reading inputs, but don't block the free running of loop().
Read up on state machines. It sounds scary but isn't. At any time the program will be in one of several states, perhaps with an LED on for a period, then, when the period ends (timed using millis()) you turn LED(s) on/off and move to a new state and start timing again.
Because the code is free running you can read inputs each time through loop() and react to them.
#include <VKey.h>
// Global declaration of the VKey class
// Initialized with analog pin number and supply voltage
VKey keypad(A1, VKey::FIVE );
const int ledPin = 13;
int ledState = LOW;
unsigned long previousMillis = 0;
unsigned long previousRefresh = 0;
const long interval = 1000;
const long refreshRate = 50;
void setup()
{
// Initialize serial port for text output
Serial.begin(9600);
Serial.println("Welcome to VKey example");
pinMode(ledPin, OUTPUT);
// No VKey specific initialization required.
}
void loop()
{
VKey::eKeynum k; // Variable to receive the key indication
/* CheckKeys will always return the current key in parameter k.
The boolean return value indicates whether that value is different than
the previous value.
*/
unsigned long currentMillis = millis();
int newKey;
if(currentMillis - previousRefresh >= refreshRate){
previousRefresh = currentMillis;
if(keypad.checkKeys(k))
{
// Only print when value has changed
Serial.print("Got key: ");
Serial.println(k);
if(k != 0){
if(k != newKey){
newKey = k;
Serial.print("New Key: ");
Serial.println(newKey);
}
}
}
}
}
Alright so this is the code that I have put together so far. The problem is that if I run that code, it always prints the New Key when I press the same button I just pressed. Is it resetting newKey to 0 somewhere and I am just missing it? Here is a screenshot of Serial Monitor.
UKHeliBob:
int newKey;
Its always something simple right under my nose. Thanks!
Alright, so I got this going:
class Flasher
{
// Class Member Variables
// These are initialized at startup
int ledPin; // the number of the LED pin
long OnTime; // milliseconds of on-time
long OffTime; // milliseconds of off-time
// These maintain the current state
int ledState; // ledState used to set the LED
unsigned long previousMillis; // will store last time LED was updated
// Constructor - creates a Flasher
// and initializes the member variables and state
public:
Flasher(int pin, long on, long off)
{
ledPin = pin;
pinMode(ledPin, OUTPUT);
OnTime = on;
OffTime = off;
ledState = LOW;
previousMillis = 0;
}
void Update()
{
// check to see if it's time to change the state of the LED
unsigned long currentMillis = millis();
if((ledState == HIGH) && (currentMillis - previousMillis >= OnTime))
{
ledState = LOW; // Turn it off
previousMillis = currentMillis; // Remember the time
digitalWrite(ledPin, ledState); // Update the actual LED
}
else if ((ledState == LOW) && (currentMillis - previousMillis >= OffTime))
{
ledState = HIGH; // turn it on
previousMillis = currentMillis; // Remember the time
digitalWrite(ledPin, ledState); // Update the actual LED
}
}
};
//---Definitions---//
#include <VKey.h>
VKey keypad(A1, VKey::FIVE );
unsigned long previousMillis = 0;
unsigned long previousRefresh = 0;
const long interval = 1000;
const long refreshRate = 50;
int newKey;
void setup()
{
// Initialize serial port for text output
Serial.begin(9600);
Serial.println("Welcome to VKey example");
// No VKey specific initialization required.
}
Flasher led5(6, 200, 300);
Flasher led1(2, 333, 300);
Flasher led3(4, 200, 300);
Flasher led7(8, 333, 300);
Flasher led9(10, 200, 300);
Flasher led11(12, 333, 300);
Flasher led2(3, 200, 300);
Flasher led4(5, 333, 300);
Flasher led6(7, 200, 300);
Flasher led8(9, 333, 300);
Flasher led10(11, 200, 300);
Flasher led12(13, 333, 300);
void loop()
{
VKey::eKeynum k; // Variable to receive the key indication
/* CheckKeys will always return the current key in parameter k.
The boolean return value indicates whether that value is different than
the previous value.
*/
unsigned long currentMillis = millis();
if(currentMillis - previousRefresh >= refreshRate){
previousRefresh = currentMillis;
if(keypad.checkKeys(k))
{
// Only print when value has changed
Serial.print("Got key: ");
Serial.println(k);
if(k != 0){
if(k != newKey){
newKey = k;
Serial.print("New Key: ");
Serial.println(newKey);
}
}
}
}
if(newKey == 1){
led1.Update();
}
if(newKey == 2){
led2.Update();
}
if(newKey == 3){
led3.Update();
}
if(newKey == 4){
led4.Update();
}
if(newKey == 5){
led5.Update();
}
if(newKey == 6){
led6.Update();
}
if(newKey == 7){
led7.Update();
}
if(newKey == 8){
led8.Update();
}
if(newKey == 9){
led9.Update();
}
if(newKey == 10){
led10.Update();
}
if(newKey == 11){
led11.Update();
}
if(newKey == 12){
led12.Update();
}
}
It turns the correct light on for each key, but it isn't turning the previous LED off. If I understood the code correctly, I thought it was supposed to not have the LED on if the correlating led**.Update() wasn't running.
Am I misunderstanding how that is supposed to work? I got that code from here.
Is there a way to select patterns that would be easier than using a keypad like the one I got? At this point, I have spent so much time on this, if there is a better way, I am more than happy to entertain any ideas.
Thanks!