Arduino StackArray not global - c

I'm coding a project where I read a byte of serial data, convert it to binary and then print it out to Serial. Currently, I'm using a stack to store the binary. However, when I push the binary numbers to the stack, they appear to be pushed in the method I call push() in, but I cannot pop ints from that array outside of that method because there are no elements to pop. Why, and are there any ways to resolve this problem. I thought stacks were reference variables.
void convertToBinary(byte number, StackArray<int> binaryList){
while(number > 0){
int rem = number % 2;
binaryList.push(rem);
number /= 2;
}
}
It pushes this seemingly fine. However when I try to pop it in another method in which I pass the stack to be popped, no elements are there to be popped.
void printToLED(StackArray<int> list){
//digitalWrite(ledPin, HIGH);
while(!list.isEmpty()){
int ledState = list.pop();
//Serial.println(ledState);
if(ledState == 1){
digitalWrite(ledPin, HIGH);
}
else{
digitalWrite(ledPin, LOW);
}
delay(1000);
transitionFlash();
}
}
Since in the setup I specified serial as the stack printer, it gives me this message when I try to pop an element from the stack.
STACK: can't pop item from stack: stack is empty.
EDIT(Full example):
#include <StackArray.h>
StackArray<int> binary;
int ledPin = 13;
byte data = 0;
void setup() {
Serial.begin(9600);
binary.setPrinter(Serial);
pinMode(ledPin, OUTPUT);
}
void transitionFlash(){
for(int i = 0; i < 20; i++){
digitalWrite(ledPin, LOW);
delay(50);
digitalWrite(ledPin, HIGH);
delay(50);
}
}
void convertToBinary(byte number, StackArray<int> binaryList){
while(number > 0){
int rem = number % 2;
binaryList.push(rem);
number /= 2;
}
}
void printToLED(StackArray<int> list){
while(!list.isEmpty()){
int ledState = list.pop();
if(ledState == 1){
digitalWrite(ledPin, HIGH);
}
else{
digitalWrite(ledPin, LOW);
}
delay(1000);
transitionFlash();
}
}
void blink(int times, int duration){
for(int i = 0; i < times; i++){
digitalWrite(ledPin, HIGH);
delay(duration);
digitalWrite(ledPin, LOW);
delay(duration);
}
}
void loop() {
while(Serial.available()){
data = Serial.read();
convertToBinary(data, binary);
printToLED(binary);
blink(10, 500);
}
}

I've resolved this. In order to pass it as a reference variable, I need to add an ampersand to the front, to notify C that it is in fact a reference variable.

Related

Arduino Teensy array of Bounce not actually updating

Im quite new to Arduino and C itself, but I can't figure out why the array does not work, while the sanity check does.
It seems to me that both should operate fine. I'm guessing I'm missing some small bit of crucial info with regards to how arrays in C work.
The entirity of the code:
#include <Bounce2.h>
#define BUTTON_AMOUNT 1
#define DEBOUNCE_INTERVAL 25
const int ledPin = LED_BUILTIN;
//Bounce *buttons[BUTTON_AMOUNT];
Bounce buttons[BUTTON_AMOUNT];
Bounce b1 = Bounce();
void setup() {
Serial.begin(31250);
pinMode(ledPin, OUTPUT);
for (int i = 0; i < BUTTON_AMOUNT; i++) {
Bounce b = Bounce();
b.attach(i, INPUT_PULLUP);
b.interval(DEBOUNCE_INTERVAL);
buttons[i] = b;
// buttons[i] = new Bounce();
// (*buttons[i]).attach(i, INPUT_PULLUP);
// (*buttons[i]).interval(DEBOUNCE_INTERVAL);
}
b1.attach(0, INPUT_PULLUP);
b1.interval(25);
}
void loop () {
for (int i = 0; i < BUTTON_AMOUNT; i++) {
// Serial.println("looping ...");
Bounce b = buttons[i];
b.update();
if (b.rose()) {
// Serial.println("rising edge");
digitalWrite(ledPin, LOW);
}
if (b.fell()) {
// Serial.println("falling edge");
digitalWrite(ledPin, HIGH);
}
}
// sanity check
b1.update();
if (b1.rose()) {
Serial.println("B1 - rising edge");
digitalWrite(ledPin, LOW);
}
if (b1.fell()) {
Serial.println("B1 - falling edge");
digitalWrite(ledPin, HIGH);
}
}
Your are copying Bounce objects into and out of the button array. E.g.
...
for (int i = 0; i < BUTTON_AMOUNT; i++) {
Bounce b = Bounce();
b.attach(i, INPUT_PULLUP);
b.interval(DEBOUNCE_INTERVAL);
buttons[i] = b; // <- bitwise copy
...
However, since Bounce doesn't implement means for copying objects buttons[i] = b simply copies b bitwise into the array which won't work.
Instead of copying the elements out of / into the array you can simply access them. Here working code showing how to do that.
#include "Bounce2.h"
constexpr int BUTTON_AMOUNT = 5;
constexpr int DEBOUNCE_INTERVAL = 25;
constexpr int ledPin = LED_BUILTIN;
Bounce buttons[BUTTON_AMOUNT]; // this already constructs the buttons in the array, you can use them directly
void setup() {
pinMode(ledPin, OUTPUT);
for (int i = 0; i < BUTTON_AMOUNT; i++) {
buttons[i].attach(i, INPUT_PULLUP); // directly access the Bounce objects in the array
buttons[i].interval(DEBOUNCE_INTERVAL);
}
}
void loop () {
for (int i = 0; i < BUTTON_AMOUNT; i++) {
buttons[i].update();
if (buttons[i].rose()) {
Serial.printf("rising edge B%u\n", i);
digitalWrite(ledPin, LOW);
}
if (buttons[i].fell()) {
Serial.printf("falling edge B%u\n", i);
digitalWrite(ledPin, HIGH);
}
}
}

Stopping and starting loops in arduino

I need a motor to cycle forward, then backward when the user pushes a once. the problem is, the arduino will run in loops after it is presses and wont stop.
How can i make it only cycle through once each time the button is pushed?
Ive tried exit(0), stop_it, etc, but those just exit the loop instead of starting back up when the button is pressed another time.
const int pwm_pin = 9;
const int dir_1a_pin = 8;
const int dir_2a_pin = 7;
int buttonPin = 2;
boolean on=false;
int buttonState = 0;
void setup() {
pinMode(buttonPin, INPUT);
pinMode(pwm_pin, OUTPUT);
pinMode(dir_1a_pin, OUTPUT);
pinMode(dir_2a_pin, OUTPUT);
}
void loop() {
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH){
if (on==true){
on=false;
} else{
on=true;
}
}
if(on == true){
digitalWrite(dir_1a_pin, HIGH);
digitalWrite(dir_2a_pin, LOW);
analogWrite(pwm_pin, 255);
delay (8000);
digitalWrite(dir_1a_pin, LOW);
digitalWrite(dir_2a_pin, HIGH);
analogWrite(pwm_pin, 255);
delay (12000);
}
}
You are making the logic too much complicated. Just read the button state in your loop and if it was HIGH do your motorcycle job. The next time loop runs as you haven't pressed the button it would become LOW and won't go into if statement.
const int pwm_pin = 9;
const int dir_1a_pin = 8;
const int dir_2a_pin = 7;
int buttonPin = 2;
void MotorCycle()
{
digitalWrite(dir_1a_pin, HIGH);
digitalWrite(dir_2a_pin, LOW);
analogWrite(pwm_pin, 255);
delay(8000);
digitalWrite(dir_1a_pin, LOW);
digitalWrite(dir_2a_pin, HIGH);
analogWrite(pwm_pin, 255);
delay(12000);
}
void setup()
{
pinMode(buttonPin, INPUT);
pinMode(pwm_pin, OUTPUT);
pinMode(dir_1a_pin, OUTPUT);
pinMode(dir_2a_pin, OUTPUT);
}
void loop()
{
// if button pressed
if (digitalRead(buttonPin) == HIGH)
{
MotorCycle();
}
}
I assume that the part you want to run once is in the section at the end in the if(on == true) section. If you don't want that to repeat, then how about setting on to false in that section. Then next time loop repeats it won't go into that section.

Arduino: detecting buttons pressed inside a while loop

I have been trying to write a code to basically add points to a score whenever I pressed a button while a certain amount of time is running down. The problem I am finding is that it doesn't detect when the button is pressed while the time is decreasing, in fact it can only detect when the time starts to decrease and then it doesn't matter at which state the button is it will continue to add to the score. Anyway here is the main code:
void loop() {
buttonState01 = digitalRead(button01);
buttonState02 = digitalRead(button02);
buttonState03 = digitalRead(button03);
if (buttonState01){
time = 3000;
while(time > 0){
if (buttonState02){
score += 10;
Serial.println(score);
}
time--;
Serial.println(time);
}
}
}
And here is the full code if needed:
int button01 = 4;
int button02 = 3;
int button03 = 2;
int buttonState01 = 0;
int buttonState02 = 0;
int buttonState03 = 0;
float time;
int score;
void setup() {
score = 0;
time = 0;
pinMode(button01, INPUT);
pinMode(button02, INPUT);
pinMode(button03, INPUT);
Serial.begin(9600);
}
void loop() {
buttonState01 = digitalRead(button01);
buttonState02 = digitalRead(button02);
buttonState03 = digitalRead(button03);
if (buttonState01){
time = 3000;
while(time > 0){
if (buttonState02){
Serial.println("Points");
}
time--;
Serial.println(time);
}
}
}
You should read the status of a button inside the while loop. Like this:
while(time > 0)
{
buttonState02 = digitalRead(button02);
if (buttonState02){
Serial.println("Points");
}
time--;
Serial.println(time);
}
And in your code, there is no logic to add points to the score.
A hardware interrupt would do exactly what you need.
Attach an interrupt routine to the pin your button is linked to, and get it to set the 'score' variable. Make sure you introduce some sort of timeout to avoid button-bounce (I.e. set LastTimeIncremented when you increase the score, and only increment score if LastTimeIncremented is more than 1 second ago)
This way the score will always be set regardless of what else the program may be doing.
Information on this can be found in the Arduino https://www.arduino.cc/en/Reference/attachInterrupt
The example on that page would do exactly what you want, just replace 'blink' with 'incrementScore' and you're pretty much done
const byte ledPin = 13;
const byte interruptPin = 2;
int score = 0;
int increment = 1;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), incScore, RISING);
}
void loop() {
digitalWrite(ledPin, state);
}
void incScore() {
score = score+increment;
// add anti-bounce functionality here
}

Arduino millis not work

I have written a huge program for Arduino.
I have tested each function individually, and all go fine except the function where I need millis().
Now carry the code block that I encounter any difficulties.
the variable T contains the number in seconds for this is multiplied by 1000
void onResistance(){
Input = sensors.getTempC(tempSensor);
sensors.requestTemperatures(); // prime the pump for the next one - but don't wait
digitalWrite(RelayPin, HIGH);
//more code
Input = sensors.getTempC(tempSensor);
sensors.requestTemperatures(); // prime the pump for the next one - but don't wait
if(Input<Setpoint){ onResistance(); }
else{ digitalWrite(RelayPin, LOW); istru++; return ; }
return ;
}
void statTemp(){
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > ttemp){
previousMillis = currentMillis;
Input = sensors.getTempC(tempSensor);
sensors.requestTemperatures();
lcd.setCursor(0,1);
lcd.print(F("T. Att.:"));
lcd.print(Input);
lcd.write(1);
lcd.print(F("C"));
if (Input<Setpoint) {
digitalWrite(RelayPin, HIGH);
statTemp();
} else if(Input>Setpoint || Input == Setpoint) {
digitalWrite(RelayPin, LOW);
statTemp(); }
} else if(currentMillis - previousMillis < ttemp) { playShortBeep(); istru++; return; }
return ;
}
void startFan(){
Input = sensors.getTempC(tempSensor);
sensors.requestTemperatures(); // prime the pump for the next one - but don't wait
digitalWrite(FAN_PIN, HIGH);
//more code
Input = sensors.getTempC(tempSensor);
sensors.requestTemperatures(); // prime the pump for the next one - but don't wait
if(Input>Tm){ startFan(); }
else{ digitalWrite(FAN_PIN, LOW); istru++; return ; }
return ;
}
void controll(){
if(!start)
return ;
if(start){
if(istru==0){
onResistance();
}
if(istru==1){
ttemp = (T * 1000) + millis() ;
statTemp();
}
if(istru==2){
startFan();
}
if(istru==3){
start =false;
opState = OFF;
playShortBeep();
playShortBeep();
playShortBeep();
istru=0;
}
}
delay(100);
return ;
}
I need for the time T the function statTemp remains running conducting checks if written in it.
sorry for my bad english
So you want to stay in the function statTemp() until time T has passed?
Then something like this might work
void statTemp(){
unsigned long currentMillis;
unsigned long enteringMillis = millis();
while (((currentMillis = millis()) -enteringMillis) < T)
{
if(currentMillis - previousMillis > ttemp){
etc etc etc....
}
return ;
}
Notice the MIGHT. I don't know if millis is updated at every timer interrupt or just in the loop function; in the latter case, you will be stuck forever in the function.
Consequently i suggest you not to do this, but think at another approach: an FSM which handles the function to be executed. It's a cleaner way to proceed and less error-prone.
Bye
EDIT:
Here is a complete working example. In this example, the function myfunc is executed for 10 seconds; during this time the board performs some actions (in this example serial output). When 10 seconds pass, the program goes on, thus repeating the loop function.
unsigned long previousTime;
void myfunc();
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println("I'm in the loop function");
myfunc();
}
void myfunc()
{
unsigned long currentTime;
unsigned long enteringTime = millis();
while(((currentTime = millis()) - enteringTime) < 10000)
{
if(currentTime - previousTime > 1000)
{
previousTime = currentTime;
Serial.println("I'm in the custom function");
}
}
}
HOWEVER my suggestion is still the same: instead of blocking the execution inside of a function, use a finite state machine; it's much more flexible and easier to understand, implement and edit.

Confusing increment behaviour

int i = 1;
void setup() {
Serial.begin(9600);
}
void loop() {
if(i == 1){
Serial.print(i);
}
i++;
}
This is intended to only print the value of i once. Why does it keep printing 1 forever?
This code works properly only writing i once:
int i = 1;
void setup() {
Serial.begin(9600);
}
void loop() {
if(i == 1){
Serial.print(i);
}
i = 2;
}
Assuming loop() is called in a loop:
i will overflow in the first example.
In the second example it is fixed to the value of 2 after the first iteration.
You may also want to add some delay because sometimes you can miss the first Serial.println();.
Something like that:
int i = 1;
void setup() {
Serial.begin(9600);
delay(1000); //wait for one second
}
Hope it helps!
If you want your first example to work longer. Change "int" to "long".
int can only store 2 bytes. -32,768 to 32,767. You will reach this number really fast.
long can store 4 bytes. -2,147,483,648 to 2,147,483,647. This will take a whiiiile.

Resources