Issues creating light sequence with pause button ARDUINO - c++

So I am trying to create a program that runs various light sequences using an Arduino board. I am not very familiar with C++ so I feel that my lack of syntax knowledge is preventing me from accomplishing my goal.
My idea is to have various light sequences that are played depending on what button is pressed on an infrared remote. The amount of time that a light is on or off may or may not be the same as that of another light. Unfortunately, the sequences do not seem to be working which indicates that the issue is likely with the toggleLight function.
I also wanted there to be a button that allows the user to pause the sequence (no matter where along the sequence it is). And once the button is pressed again, then the sequence continues where it left off. I read something about an interrupter and sleep mode using C++ but I am unfamiliar with this so it is not included in my code.
The rest of my goals I have included within my code. I created an object "light" because I was trying to create the sequence without using the delay function as the interrupt does not work well with the delay function (as far as I am aware). Then I am able to call the function toggleLight on the specific light object. However, as I previously stated the sequences are not working.
I am more familiar with OOP languages so perhaps creating an object is not the best for Arduino. If anyone has any ideas for how I can accomplish my goal it would be much appreciated.
unsigned long previousMillis = 0;
unsigned long currentMillis = millis();
//sets up the Infrared receiver for the remote controller
const int RECV_PIN = 1;
IRrecv irrecv(RECV_PIN);
decode_results results;
//Sets up the LED's pin number and light status
class light{
private:
int _pinNumber;
byte _Lstatus;
public:
//function that creates the objects with the parameters
light(int pinNum, byte Lstat){
_pinNumber = pinNum;
_Lstatus = Lstat;}
void toggleLight(long interval){
//ensures that the "interval" amount of time has passed between the last LED blink
if ((currentMillis - previousMillis) >= interval) {
// if the LED is off turn it on and vice-versa:
if (_Lstatus == LOW) {
_Lstatus = HIGH;
} else if (_Lstatus == HIGH) {
_Lstatus = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(_pinNumber, _Lstatus);
// save the last time you blinked the LED
previousMillis = currentMillis;
}
}
};
//creating four light objects with the pins and initial status of off.
light J1(13, LOW);
light J2(11, LOW);
light P1(12, LOW);
light P2(10, LOW);
void setup()
{
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);
pinMode(10, OUTPUT);
}
//Sequence 1 is a mock sequence. It will probably be longer and the intervals would not all be 1000
void seq1(){
currentMillis = millis();
J1.toggleLight(1000);
P1.toggleLight(1000);
J1.toggleLight(1000);
P1.toggleLight(1000);
J2.toggleLight(1000);
P2.toggleLight(1000);
}
void seq2(){
currentMillis = millis(); //I found that placing currentMillis = millis() here allows the lights to at least turn on
J1.toggleLight(2000);
J1.toggleLight(10);
P1.toggleLight(1000);
P1.toggleLight(0);
J2.toggleLight(1500);
J2.toggleLight(1);
P2.toggleLight(2000);
P2.toggleLight(1);
}
void loop()
{
/* So once i get the sequences working, my idea is to have different sequences play
depending on what button on the remote is pressed. However, first I want to get the sequences and
interrupter
For now I have just tried running sequence #2 but it does not work.. Neither does Sequence #1. */
seq2();
//I MADE THESE LINES OF CODE COMMENTS FOR NOW. UNTIL I GET THE REST OF THE PROGRAM WORKING
/*if (irrecv.decode(&results))
{
switch (results.value) {
case : 0xf00000 // When button #1 sequence one plays
seq1();
break;
case : 0xf00000 // when button #2 is pressed, sequence two plays
seq2();
break;
*/
}

I can see that you haven't yet got around to understanding the flow of code inside the Arduino. Here's a quick tutorial to get you up and running.
Basically, your code is not being processed sequentially. So when the processor is moving through seq() and gets to the first if statement in 'J1.toggleLight(2000);' and finds that the condition is not met (i.e. the 2000 milliseconds have not yet passed,) it immediately moves on to the second line in seq(). The issue with this is that when it does meet the condition at the second line it will reset the 'previousMillis' value which all the lights depend on.
Thus you should dedicate a clock for each light by moving in 'previousMillis' into the class as a member.
class light{
private:
int _pinNumber;
byte _Lstatus;
unsigned long previousMillis = 0;
This way each light will be able to keep track of its own time without conflicting with the other lights. This will lead to your lights flickering at a frequency of 1/interval which I doubt is what you want.(it wont even do that with each light getting toggled twice in the seq() functions. Try removing the second calls and see hat happens) This brings me to the second issue.
The second issue is with the way you set up your sequences. Since you want to the lights to operate sequentially you'll need to find the accumulated time which crosses out the chance of using a class, unless you're willing to implement a scheduling mechanism that takes account the interval and arrangement of each instance. Seems a bit impractical imo.
I think you should ditch the class and use a simple function that that accepts the eight values that each sequence requires. Then you could utilize if statements to manipulate the states of the lights.
I hope the answer made some sense.
Good luck.

Related

How to read a rotary encoder with interrupts on ESP32 and global flags

When using interrupts, any kind of digitalRead should be obsolete, or so i think. Let me explain my understanding of this to show my problem:
Say, a quadrature incremental rotary encoder (RE) is pulled up on both signal pins and is therefore idle HIGH. If i configure an interrupt service routine (ISR) on the falling edge on both pins and have the ISR for pin B do nothing more than set the flag "flag_B" to false (representing the logic state at the pin) and the ISR for pin A sets or resets a flag "flag_clockwise" depending on the state of flag_B during A's ISR, then i should get the right direction for every turning step, right? My only task is to then set the state of pin B to high again after the ISRs and my code should be ready for the next interrupt. But that doesn't work, with many random cases of the wrong direction being displayed or showing counter clockwise on the first half of the turning step when you can feel a little "bump" while turning the knob and then going clockwise on the second half, when the shaft has completed a single step, basically performing two opposite actions while only turning one step. Is my logic flawed?
All signals are debounced in hardware and look like expected on the oscilloscope.
ISRs:
//re-CLK signal
void IRAM_ATTR reCLK_ISR(void){
if(myFlags->pinBstate){
//this means the first interrupt of a turning step comes from the clock, not data
myFlags->direction = CCW;
}
else{
//this means the interrupt of a turning step occured from data first
myFlags->direction = CW;
}
}
//re-DATA signal
void IRAM_ATTR reDATA_ISR(void){
myFlags->pinDATAstate = false;
}
further processing:
//some function
//scroll = CW / CCW
if((myFlags->direction) != STOP){
if(myFlags->direction == CW){
//DEBUG
digitalWrite(PIN_LED_DEBUG, LOW);
}
}
if(myFlags->direction == CCW){
//DEBUG
digitalWrite(PIN_LED_DEBUG, HIGH);
}
myFlags->pinDATAstate = true;
myFlags->direction = STOP; //direction has 3 states: CW, CCW and STOP
}
the last 2 statements should restore all affected flags to the state before the encoder was touched, meaning ready for the next turn. The LED is just a replacement for different calculations which should be performed depending on the turning direction.
Even if the pin is assigned as interrupt, you can still use digitalRead() to determine the direction. For example:
const uint8_t pinA = 25;
const uint8_t pinB = 26;
volatile int counter;
void IRAM_ATTR isr(){
if(digitalRead(pinA) == digitalRead(pinB)) {
//Clockwise
counter++;
} else {
//Counter Clockwise
counter--;
}
}
You don't even need another ISR to determine the direction. I used this method to determine both the speed and the direction;

how to create an interrupt or return value for servo motor?

It's been a frustrating day of learning from Arduino tuts.
I'm working on setting up a servo motor. I troubleshooted why I couldn't get it to receive data and now I got it reading through the serial port and turning to appropriate degrees. But now it seems every time it loops through it tries to reset it's value to 0 degrees. I haven't assigned the variable to be 0 and the while loop is supposed to act like an interrupt while it waits for user input. So I don't understand why it's doing this.
I've also tried to return the value pos to keep from changing/resetting values during each loop but keep getting compiling errors. I got one saying that pos returns void. And then I got another one when trying to declare the int pos as a method within the loop and nesting the rest of the code inside the int method.
Also interesting side note: when you launch the serial port window in the IDE it'll rotate the motor by a small amount despite no input being given. After an given input is entered, it'll go to those degrees then it resets as described before.
Code:
#include <Servo.h> //Including the Servo code library
int servoPin = 6;
int servoDelay = 25;
int pos;
Servo myPointer; // Create a Servo object called myPointer
void setup() {
Serial.begin(9600);
//pinMode (servoPin, OUTPUT);
myPointer.attach(servoPin);
Serial.println("Hello");
}
void loop() {
Serial.println ("Where would you like the servo to point?");
while (Serial.available()==0){
}
pos = Serial.parseInt();
Serial.println (pos);
myPointer.write(pos);
}
The servo is running off the 5V power supply on the Arduino and receives instructions OK. It does not reset the position when running through void setup() so this must be the loop causing this. I just don't know why or how to fix it.
You have ensure the entire message is received before you start to parse it. Either set a the inter character gap with Serial.setTimeout() (default 1s) to a larger value before use:
Serial.setTimeout(2000);
while (Serial.available() == 0) {}
duration = Serial.parseInt();
Or add a delay between Serial.available() and Serial.parseInt() if the above does not solve all your problems.
while (Serial.available() == 0) {}
delay(4000);
duration = Serial.parseInt();
Serial.available() would fall thru on the first character received. So:
Setting the inter character timeout would extend the time before parsing by waiting after each new character to see if any further characters would be received.
A delay before parsing would ensure that the entire message is received before you try and parse it.
Additional characters like \n or \r could also be present triggering the parse but without there being sensible data. Serial.parseInt() returns 0 if it fails to convert a number. So:
Do a range check for 1 to 360 degrees to catch these without losing much range of turning.
Check if your terminal appends \n or \r.
After parsing empty the receive buffers with Serial.flush() to get rid of any remaining \n or \r characters.

Run two delays at once C++

I want to make a program in which there are two dots blinking (with a break of 10ms) simultaneously, but one with delay 200ms and other with delay of 300ms. How can I play these two dots simultaneously from beginning? Is there a better way to that from following:
for(int i=1;i<100;i++)
{
if (i%2==0)
circle(10,10,2);
if (i%3==0)
circle(20,10,2);
delay(10);
cleardevice();
delay(100);
}
I would do something like this instead:
int t0=0,t1=0,t=0,s0=0,s1=0,render=1;
for (;;)
{
if (some stop condition like keyboard hit ...) break;
// update time, state
if (t>=t0) { render=1; s0=!s0; if (s0) t0+=10; else t0+=200; }
if (t>=t1) { render=1; s1=!s1; if (s1) t1+=10; else t1+=300; }
// render
if (render)
{
render=0;
cleardevice();
if (s0) circle(10,10,2);
if (s1) circle(20,10,2);
}
// update main time
delay(10); // Sleep(10) would be better but I am not sure it is present in TC++
t+=10;
if (t>10000) // make sure overflow is not an issue
{
t -=10000;
t0-=10000;
t1-=10000;
}
}
Beware the code is untested as I wrote it directly in here (so there might be syntax errors or typos).
The basic idea is having one global time t with small enough granularity (10ms). And for each object have time of event (t0,t1) state of object (s0,s1) and periods (10/200 , 10/300).
If main time reach the event time swap the state on/off and update event time to next state swap time.
This way you can have any number of objects just make sure your main time step is small enough.
The render flag just ensures that the scene is rendered on change only.
To improve timing you can use RDTSC instead of t+=10 and actually measure how much time has passed with CPU frequency accuracy.
To display the two circles simultaneously in the first round, you have to satisfy both conditions i%2==0 and i%3==0 at once. You can achieve it by simply changing
for(int i=1;i<100;i++)
to
for(int i=0;i<100;i++)
// ↑ zero here

C++ buzzer to play piano notes for an Arduino

unsigned long t;
boolean isHigh;
#define BUZZER_PIN 3
void setup() {
// put your setup code here, to run once:
pinMode(BUZZER_PIN, OUTPUT);
isHigh = false;
t = micros();
}
void loop() {
playNote('c');
}
void playNote(char note) {
unsigned long timeToWait;
unsigned long timeToPlayTheNote = millis();
while (timeToPlayTheNote - millis() < 1000) {
if (note == 'c') {
timeToWait = 1911;
}
if (micros() - t > timeToWait) {
if (!isHigh) {
digitalWrite(BUZZER_PIN, HIGH);
isHigh = true;
} else {
digitalWrite(BUZZER_PIN, LOW);
isHigh = false;
}
t = micros();
}
}
}
I don't know why this won't work. I used to play a frequency every 1,000 microseconds but is there any way to make this simpler as well? Also, with this method I have to do (1/f)/2 and then convert that value from seconds to microseconds and use that as the value for timeToWait.
Initialization of ˋtimeToWait` should obviously be outside of the loop.
An array could be used for timing data.
ˋt` should probably be initialized inside ˋplayNoteˋ
Alternatively, you might use an enum for delay associated to a note.
enum class notes
{
C = 1911
};
Well, all suggestion assume that you don't want to compensate for drifting offsets.
Buzzers have a fixed frequency. They don't work like speakers at all. You will get better results with a real speaker. Don't forget to put a capacitor in series with it so the speaker sees an AC signal, you can fry a speaker quite easily if you feed it a DC signal..
For best results, you should use 2 x 47uF to 100uF electrolytic capacitors back to back, with the negative poles joined together, one positive to the 'duino and the other positive pole connected to the speaker. With higher capacitance, you'll get more bass.
Why don't you use a PWM at 50% (128) and change the PWM frequency to generate the sound? You could use the Timer1 or Timer3 library for that. Letting the hardware do the work would be more presise and would free your application for other tasks, such as reading a keyboard.
https://playground.arduino.cc/Code/Timer1
Setting the PWM at 0% with an analogWrite() would cut the sound.

Arduino timed void draw() loops

I have an Arduino Uno set up to sense the light level and draw to a text file via Processing when it gets dark. I'd like to modify the Processing code to interrupt the draw loop for five seconds and then restart the draw loop. This will continuously write and overwrite the .txt file but that's not important right now.
The purpose of this excercise is to understand how to insert a break into the endless draw loop. I'm still very much a newbie to programming and am trying to wrap my head around how commands interact with eath other. Can anyone help me understand how to make this work? Eample code would be great but I'd also be happy with a conceptual description of how it's supposed to work...learn by doing and all.
I've tried putting the void draw() loop within a void loop() but it erred out. Am I on the right path?
<setup...mySerial and createWriter to path/file.txt>{
}
void draw() { //this is what needs to terminate & restart
if (mySerial.available() > 0 ) {
String value = mySerial.readString();
if ( value != null ) {
output.println( value );
}
}
}
void keyPressed and end
I believe what you're looking for is called a "state machine".
Make a variable that you can use to store a time value, then compare that to the current time to see if 5s have passed.
uint32_t last_trigger = 0; // millis() returns an unsigned, 32-bit integer
void setup()
{
Serial.begin(9600);
}
void loop()
{
if (millis() - last_trigger > 5000) { // 5000 milliseconds
last_trigger = millis(); // update last_trigger
Serial.print("last triggered at "); // report findings
Serial.print(last_trigger);
Serial.println(" milliseconds");
}
}
http://www.arduino.cc/en/Reference/Millis
If you aren't worried about really tight timing, the easy solution is to use the delay function. http://www.arduino.cc/en/Reference/Delay
The following might be a simple sketch that would do what you want. Adjust it as needed.
void setup()
{
Serial.begin(9600); // initialize serial routines
}
void loop()
{
int a = analogRead(0); // read the value of lightness
Serial.println(a); // tell processing what the value is
delay(5000); // wait for a 5 seconds
}