Im trying to write code that records LED's when a button is pressed, stores them into an array, and when that array is 5 long, it stops cycling through LED colours and plays the recorded pattern. It sometimes works perfectly, however sometimes it will double record a single button press/led colour. I can't figure out why. If anyone could let me know any possible issues it would be much appreciated :).
Here's the code (C++):
#include "mbed.h"
#include <vector>
// Green LED
DigitalOut led1(LED1);
// Blue LED
DigitalOut led2(LED2);
// Red LED
DigitalOut led3(LED3);
// Button Interrupt
InterruptIn button(USER_BUTTON);
// Initialise counter for button presses (n), and selector for the lit LED (l)
int n = 0;
int l = 1;
// Define sequence length
int sequence_length=5;
// Create vector/list for recorded LED's to go into
int sequence[5];
// Callback function to associate with the press button event
void onButtonPress()
{
led1 = true;
led2 = true;
led3 = true;
// Add corresponding led to 'sequence'
sequence[n] = l;
n = n + 1;
}
// 'Decoding' what LED's should be lit up for different 't' values in main
void select_led(int l)
{
if (l==0) {
led1 = false;
led2 = false;
led3 = false;
}
else if (l==1) {
led1 = true;
led2 = false;
led3 = false;
}
else if (l==2) {
led1 = false;
led2 = true;
led3 = false;
}
else if (l==3) {
led1 = false;
led2 = false;
led3 = true;
}
}
int main() {
// attach the address of the callback function to the rising edge
button.rise(onButtonPress);
while (true) {
while (n >= sequence_length) {
select_led(0);
wait(1);
for (int i = 0; i < n; i++) {
select_led(sequence[i]);
wait(0.5);
select_led(0);
wait(0.5);
}
}
select_led(l);
wait(1);
l = l + 1;
if (l==4) {
l = 1;
}
}
}
I'm not sure if its a logic issue or if its dependent on the length of the button press, or another unconsidered factor.
Your problem probably has to do with the way you press the button. If there is even a little hesitation the button will recognize two presses and not one. Try adding a wait to the end of the onButtonPress function in order to account for this occurrence.
Related
I am getting serial communication and trying to make an led fade effect ,
This is my function for leds which is facing latency issues , obviously the for loop . Can anyone suggest a better logic or solution to approach this without getting latency in leds?
void loop() {
// serial communication
while(Serial.available() > 0 ){
int inByte = Serial.read();
Serial.print(inByte);
if (inByte > 0) {
// if byte is 255, then the next 3 bytes will be new rgb value
if (inByte == 255) {
setColors = true;
colorSetCounter = 0;
} else if (setColors) {
switch (colorSetCounter) {
case 0:
redVal = inByte;
break;
case 1:
greenVal = inByte;
break;
case 2:
blueVal = inByte;
setColors = false;
receiveNotes = true;
fill_solid(leds, NUM_LEDS, CRGB::Black);
FastLED.show();
break;
}
colorSetCounter++;
} else if (receiveNotes) {
controlLeds(inByte);
}
}
}
}
void controlLeds (int note) {
note -= 1;
if (!leds[note]) {
leds[note].red = redVal;
leds[note].green = greenVal;
leds[note].blue = blueVal;
}
else {
for(int i =0; i<=255; i++){
leds[note].fadeToBlackBy(i);
FastLED.show();
if(!leds[note]){
break;
}
}
}
FastLED.show();
}
You need to write non-blocking code as Scheff mentioned. Instead of a global variable, you can use a static variable in a function. It remembers its value for each call of that function.
Here is an example how you could do it, using millis(). My code fades an LED on and off if some serialEvent happens and it does not block the rest of the code:
const int ledPin = 13;
int setValue = 0;
unsigned long lastTime = 0;
const unsigned long refreshTime = 200;
char buffer1[8];
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
if (millis() - lastTime > refreshTime)
{
lastTime = millis();
fadeLED(setValue);
}
}
void fadeLED(int fadeValue)
{
static int currentValue = 0;
if (fadeValue > currentValue) {
currentValue++;
}
if (fadeValue < currentValue) {
currentValue--;
}
analogWrite(ledPin, currentValue);
}
void serialEvent()
{ Serial.readBytesUntil('\n', buffer1, 8);
switch (setValue)
{
case 0:
setValue = 255;
break;
case 255:
setValue = 0;
break;
default:
break;
}
}
I'm modifying decounce code for a push button system, where momentary buttons will be monitored for a short press and a long press to carry out some action. I'm having trouble using the code in Typedef though as it seems to not be working as I expect. Can anyone help explain what I'm missing? Specifically, I'm modifying the code to work for multiple buttons.
In the setup I have 'buttons[i].dimmer = dimmer[i];' using the "buttons[i].dimmer" I thought was established in the typedef but I can't seem to populate it? When I run the code no inputs are read, I'm trying to sort out what may have happened here.
Full code:
// detectButtonPress
// Use millis to detect a short and long button press
// See baldengineer.com/detect-short-long-button-press-using-millis.html for more information
// Created by James Lewis
#define PRESSED LOW
#define NOT_PRESSED HIGH
int value = 0;
const byte numberButtons = 5;
const int debounce = 10;
int pin[numberButtons] = {2, 3, 4, 7, 8}; //not used with multiple buttons?**
int dimmer[numberButtons] = {A0, A1, A0, A0, 0}; //which dimmer is associated with which button
int output[numberButtons] = {10, 10, 11, 11, 0}; //which output pin to send signal
//variables for timing long button press
unsigned long startMillis;
unsigned long currentMillis;
unsigned long timerMillis;
const unsigned long period = 4000; //the value is a number of milliseconds, ie 4000=4 second
int longPressOutput = 0; //which dimmer to monitor with long press
int longPressDimmer = 0; //dimmer pin for long press
const unsigned long shortPress = 100;
const unsigned long longPress = 500;
bool monitorDimmer = false; //whether to monitor dimmer or not
int dimValue = 0; //dimmer value initialized
typedef struct Buttons {
const int debounce = 10;
unsigned long counter=0;
bool prevState = NOT_PRESSED;
bool currentState;
bool lightState = false;
bool prevLightState = false;
int pin[numberButtons] = {2, 3, 4, 7, 8}; //not used with multiple buttons?**
int dimmer[numberButtons] = {A0, A1, A0, A0, 0}; //which dimmer is associated with which button
int output[numberButtons] = {10, 10, 11, 11, 0}; //which output pin to send signal
} Button;
//array of button objects
Buttons buttons[numberButtons];
void setup() {
Serial.begin(9600); //start Serial in case we need to print debugging info
startMillis = millis(); //initial start time
bool monitorDimmer = false; //initial monitorDimmer status
//initialize each button in the array
for (int i = 0; i < numberButtons; i++) {
buttons[i].pin = pin[i]; //initialize pin number for this buttons
buttons[i].dimmer = dimmer[i];
buttons[i].output = output[i]; //this one doesn't work but the above does?
buttons[i].debounce = debounce;
pinMode(buttons[i].pin, INPUT_PULLUP);
//Serial.println(buttons[i].pin);
}
}
void loop() {
timerMillis = millis();
for (int i = 0; i < numberButtons; i++) {
// check the button
buttons[i].currentState = digitalRead(buttons[i].pin);
// has it changed?
if (buttons[i].currentState != buttons[i].prevState) {
delay(buttons[i].debounce);
// update status in case of bounce
buttons[i].currentState = digitalRead(buttons[i].pin);
if (buttons[i].currentState == PRESSED) {
// a new press event occured
// record when button went down
buttons[i].counter = millis();
}
if (buttons[i].currentState == NOT_PRESSED) {
// but no longer pressed, how long was it down?
unsigned long currentMillis = millis();
if ((currentMillis - buttons[i].counter >= shortPress) && !(currentMillis - buttons[i].counter >= longPress)) {
// short press detected.
buttons[i].prevLightState = buttons[i].lightState; //Set prev to current, then change
buttons[i].lightState != buttons[i].lightState; //flip state
if (buttons[i].lightState = true) {
analogWrite(buttons[i].output, 180); //set pin to roughly 70% brightness**
value = 5;
Serial.println(value);
}else {
analogWrite(buttons[i].output, 0);
value = 4;
Serial.println(value);
}
//specifically for off button - above will only turn off pin 10, this gets pin 11
if (i == 4) {
analogWrite(11, 0);
}
}
if ((currentMillis - buttons[i].counter >= longPress)) {
// the long press was detected
analogWrite(buttons[i].pin, 180); //turn light on immediately
longPressDimmer = buttons[i].dimmer; //set monitor value for dimmer pin
longPressOutput = buttons[i].output; //set which output to watch
startMillis = millis();
monitorDimmer = true; //set true so dimmer loop
//handleLongPress(); //go to long press function to monitor dimmer
//specifically for off button - above will only turn off pin 10, this gets pin 11
if (i == 4) {
analogWrite(11, 0); //turn off main
analogWrite(10, 0); //turn off bed
}
}
}
// used to detect when state changes
buttons[i].prevState = buttons[i].currentState;
}
}
if (monitorDimmer == true) {
if (timerMillis - startMillis <= period) { //until period is reached do this
dimValue = analogRead(longPressDimmer);
analogWrite(longPressOutput,dimValue); //set light to value of dimmer
}
else {
monitorDimmer = false; //if time is up, stop checking
}
}
}
You have "numberButtons" buttons each with "numberButtons" outputs. This means you have numberButtons*numberButtons outputs, which sounds wrong. If this is what is intended, you would need a loop like this
for (int b_idx = 0; b_idx < numberButtons; ++b_idx) // once per button
for (int o_idx = 0; o_idx < numberButtons; ++o_idx) // once per button
button[b_idx].output[o_idx] = init_value;
However, from the comments in the code it is entirely more likely your error really is in your structure
struct Button {
const int debounce = 10;
unsigned long counter=0;
bool prevState = NOT_PRESSED;
bool currentState;
bool lightState = false;
bool prevLightState = false;
int pin {-1}; // Each button has only one pin
int dimmer {-1}; // Each button has only one dimmer
int output {-1}; // Each button has only one output
};
//array of button objects
Button buttons[numberButtons];
Now your setup function make sense.
First of, the typedef isn’t need in C++! That’s a C thing. It is allowed but actually doesn’t really have any useful effect.
It seems you are trying to create a class and hope to initialize a global array to reference the elements in the class. That won’t work as C++ is based on values rather than references. You could potentially use pointers in your class to point to the global array to modify these.
constexpr or template
not typedef
// ...
#include <windows.h> // for byte type:
const byte numberButtons = 5;
// ...
int dimValue = 0; //dimmer value initialized
template<byte DIM>
struct Buttons {
const int debounce = 10;
unsigned long counter=0;
bool prevState = NOT_PRESSED;
bool currentState;
bool lightState = false;
bool prevLightState = false;
int pin[DIM] = {2, 3, 4, 7, 8}; //not used with multiple buttons?**
int dimmer[DIM] = {A0, A1, A0, A0, 0}; //which dimmer is associated with which button
int output[DIM] = {10, 10, 11, 11, 0}; //which output pin to send signal
}
typedef Buttons<numberButtons> BUT;
int main ( ) {
//array of button objects
BUT buttons;
for (int i=0; i<15; ++i)
cout<< buttons.pin[i] <<"\n";
}
Here is my code:
#include <SoftwareSerial.h>
#include <Servo.h> // servo library
Servo servo1; // servo control object
Servo servo2;
Servo servo3;
SoftwareSerial bluetooth(5, 6); // RX, TX
int servo1Pin = 11;
int servo2Pin = 10;
int servo3Pin = 9;
int motor1pin = 8;
int flag = 0; //Sets integer for HIGH or LOW LED case
String bdata = "";
char c = ' ';
void setup()
{
bluetooth.begin(9600);
pinMode(motor1pin, OUTPUT);
servo1.attach(servo1Pin);
servo2.attach(servo2Pin);
servo3.attach(servo3Pin);
}
void loop()
{
int position;
while (bluetooth.available()) {
c = bluetooth.read();
bdata += c;
//~~~~~~Servo 1~~~~~~~~
if (bdata == "open1")
{
//Opens Door
for (position = 0; position < 90; position += 1)
{
servo1.write(position); // Move to next position
delay(20); // Short pause to allow it to move
}
}
if (bdata == "close1")
{
//Closes Door
for (position = 90; position >= 0; position -= 1)
{
servo1.write(position); // Move to next position
delay(20); // Short pause to allow it to move
}
}
//~~~~~~Servo 2~~~~~~~~
if (bdata == "open2")
{
//Opens Door
for (position = 0; position < 90; position += 1)
{
servo2.write(position); // Move to next position
delay(20); // Short pause to allow it to move
}
}
if (bdata == "close2")
{
//Closes Door
for (position = 90; position >= 0; position -= 1)
{
servo2.write(position); // Move to next position
delay(20); // Short pause to allow it to move
}
}
//~~~~~~Servo 3~~~~~~~~
if (bdata == "open3")
{
//Opens Door
for (position = 0; position < 90; position += 1)
{
servo3.write(position); // Move to next position
delay(20); // Short pause to allow it to move
}
}
if (bdata == "close3")
{
//Closes Door
for (position = 90; position >= 0; position -= 1)
{
servo3.write(position); // Move to next position
delay(20); // Short pause to allow it to move
}
}
//~~~~~~Motor 1~~~~~~
if (bdata == "on")
{
flag = 1; //Turns LEDs on using a high digital signal
}
if (bdata == "off")
{
flag = 0; //Turns LEDs off using a low digital signal
}
}
digitalWrite(motor1pin, flag);
delay(1000);
bdata = "";
}
It is uploaded to an Arduino Uno where I have the 3 servos and DC Motor connected via breadboard. It is meant to power a 3d printed mechanical arm I have made. when read you can see it is also controlled via Bluetooth using a HC-05 module and phone. I am having trouble with it as the commands for servo 1 are working fine so is 3, but when command for servo 2 is sent from phone servo 3 moves instead and servo 3 command also moves servo 3. I have already tried looking at the variable and the commands on my phone by nothing is sticking out to me. so here I am.
Can anyone help?
My question is very simple but I'm stuck on it for a while now.
I need to make a script that when pushed on a button loop a() is put on pause. And when you press it again it should go from where it ended. But I can't figure out a way to do it.
I hope someone can help me.
This is my code:
int Aan = 1;
int Uit = 0;
int analogPin = A3;
int LED1 = 13;
int LED2 = 12;
int LED3 = 11;
int LED4 = 10;
int val;
bool r = false;
void setup() {
pinMode(analogPin, INPUT_PULLUP);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
pinMode(LED4, OUTPUT);
digitalWrite(LED1, Aan);
digitalWrite(LED2, Aan);
digitalWrite(LED3, Aan);
digitalWrite(LED4, Aan);
}
void loop() {
val = digitalRead(analogPin);
if (val == LOW)
{
if (r == true)
{
r = false;
}
if (r == false)
{
r = true;
}
}
if (r == true)
{
a();
}
}
void a() {
for (int i = 10; i <= 13; i++)
{
pinMode(i, OUTPUT);
digitalWrite(i, Uit);
delay(100);
digitalWrite(i, Aan);
}
for (int i = 13; i >= 10; i--)
{
pinMode(i, OUTPUT);
digitalWrite(i, Uit);
delay(100);
digitalWrite(i, Aan);
}
}
Just to explain whats happening.. Void a() makes 4 different leds light up and go out. The pattern thats used is Knight Rider (If you don't know the tv show just google the car of him)
I will assume you want the "Knight Rider" pattern to constantly run.
I've made a couple of changes. First, I added a function to run the led sequence one way. Second, I added a while loop that will always run once, and will continue to run while the button is pushed.
bool paused = false;
int buttonState = HIGH;
void loop() {
a();
}
// This only works if leds ports are consecutive
void runSequence(int ledStart, int ledEnd)
{
int direction = ledStart < ledEnd ? 1 : -1;
for (int i = ledStart; i != ledEnd + direction; i += direction) {
digitalWrite(i, Uit);
do {
delay(100);
} while (LOW == digitalRead(analogPin)); // Check button state
digitalWrite(i, Aan);
}
}
void a() {
runSequence(LED4, LED1);
runSequence(LED1, LED4);
}
EDIT Changes based on comment
bool paused = false;
int buttonState = HIGH;
int currentLED = LED1;
int currentDirection = -1;
void loop() {
checkButton();
if (!paused) {
// Flash the led
digitalWrite(currentLED, Uit);
delay(100);
digitalWrite(currentLED, Aan);
// Change direction?
if (LED1 == currentLED || LED4 == currentLED) {
currentDirection *= -1;
}
// Setup for next iteration
currentLED += currentDirection;
}
}
void checkButton() {
int state = digitalRead(analogPin);
// Check if button state has changed
if (state != buttonState) {
buttonState = state;
// Change paused state when button is released
if (state == HIGH) {
paused = !paused;
}
}
}
Inside your a() function put another while loop which becomes false when the button is Up.
Like:
while(digitalRead(analogPin) == LOW)
{
}
As long as the button is pressed down the loop will continue. When you release the button the program will exit the loop and continue execution of your code.
Need to break the Stepper motor operation within "for loop". But the code that I have written breaks the operation after the completion of the loop, it does not break the operation between the loop. Please chek the code and tell me any possible way to stop the loop in between..
Code:
#include <Stepper.h>
int in1Pin = 8;
int in2Pin = 9;
int in3Pin = 10;
int in4Pin = 12;
bool entry = false;
int j;
Stepper motor(200, in1Pin, in2Pin, in3Pin, in4Pin);
void setup() {
pinMode(in1Pin, OUTPUT);
pinMode(in2Pin, OUTPUT);
pinMode(in3Pin, OUTPUT);
pinMode(in4Pin, OUTPUT);
while (!Serial);
Serial.begin(9600);
motor.setSpeed(300);
Serial.println("Type in your selection");
entry = false;
}
void loop() {
if (Serial.available() > 0){
switch(Serial.read()){
case 'a':
entry = true;
break;
case 'b':
entry = false;
break;
default:break;
}
}
if(entry == true){
for(j = -20; j <= 20; j++){
motor.step(j/0.176);
}
}
else if(entry == false){
digitalWrite(in1Pin,LOW);
digitalWrite(in2Pin,LOW);
digitalWrite(in3Pin,LOW);
digitalWrite(in4Pin,LOW);
}
}
From Comments: when i send 'a' through serial monitor, the stepper starts rotating, when i send 'b' through serial it should break stepper motor rotation, but its breaking only after the completion of loop (not within the loop)
If you don't give a chance to Arduino to parse the serial input in-between the execution of the for loop, then obviously is not going to work as you want.
You should do something similar to this:
...
void loop() {
static int j;
if (Serial.available() > 0){
switch(Serial.read()){
case 'a':
entry = true;
/**
* replace next 3 lines with `j = -20` if you want to start
* the loop from scratch each time `a` is received,
* instead of resuming from where you stopped.
*/
if (j >= 20) {
j = -20;
}
break;
case 'b':
entry = false;
break;
default:break;
}
}
if (entry) {
if (j <= 20) {
motor.step(j/0.176);
++j;
}
} else {
digitalWrite(in1Pin, LOW);
digitalWrite(in2Pin, LOW);
digitalWrite(in3Pin, LOW);
digitalWrite(in4Pin, LOW);
}
}
In this code, I let Arduino parse a new character after each call to motor.step(). Note that this approach introduces a tiny delay among sub-sequent calls to motor.step() wrt. your original solution, but it should be negligible in practice.
If you send multiple a in a row to Arduino using this code, but Arduino did not complete the for loop yet, then with this code the additional a will be ignored. If you want to handle them as additional for request, then you should add a counter to keep track of the number of pending (full) iterations of the for loop that you want to perform.