Arduino the void loop() function isn't looping - loops

I'm new to Arduino and I wrote the beginning a code that is supposed to play games read stories and more on an LCD display.
Here's my code
#include <LiquidCrystal.h>
// Arduino pins number
const int SW_pin = 2; // digital pin connected to switch output
const int X_pin = 0; // analog pin connected to X output
const int Y_pin = 1; // analog pin connected to Y output
const int LCD_RS = 7;
const int LCD_Enable = 8;
const int LCD_D4 = 9;
const int LCD_D5 = 10;
const int LCD_D6 = 11;
const int LCD_D7 = 12;
LiquidCrystal lcd(LCD_RS, LCD_Enable, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
// Basic vars
int none = 0;
String Apps[2] = {"App selector","Credits"};
int CurrentApp = 0;
int Yaxis = 1;
int Xaxis = 1;
int HiCh = 0;
int button;
int JXaxis;
int JYaxis;
void Credits() { // CREDITS
Serial.print("- Credits app loading \n");
lcd.clear();
lcd.setCursor(3,0);
lcd.print("Credits app");
lcd.setCursor(0,1);
Serial.print("- Credits app loaded \n");
}
void setup() { // SETUP
Serial.begin(9600);
Serial.print("[2J");
Serial.print(" Serial Monitor opened \n \n");
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("App selector");
Serial.print("- App selector menu \n");
pinMode(SW_pin, INPUT);
digitalWrite(SW_pin, HIGH);
lcd.setCursor(0,1);
lcd.print(Apps[0]);
}
void SelectApp() { // SELECTAPP
switch (HiCh) {
case (1):
CurrentApp = 1;
Credits();
break;
default:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Error");
Serial.print("- App loading error \n");
}
}
void loop() { // LOOP
while (none == 0) {
button = digitalRead(SW_pin);
int JYaxis = analogRead(Y_pin) / 128;
int JXaxis = analogRead(X_pin) / 128;
if (CurrentApp == 0) {
for (;;) {
if (button == 0) {
SelectApp();
}
if (JYaxis <= 1) {
if (HiCh != 0) {
HiCh = HiCh - 1;
delay(300);
}
}
if (JYaxis >= 7) {
HiCh = HiCh + 1;
delay(300);
}
}
}
}
}
I am only using one joystick as the controller and I have an Arduino UNO R3 board
I know a lot of other people have written about this and a lot of people have fixed the issue too but I cannot find the problem in my code...
I'm sure it's an error during the execution of the script that blocks the rest but I can't find where it is.
Thank you in advance!
If you need any specifications ask them to me and I'll try to answer them.

That code has a couple of issues.
In the loop() function you wouldn't normally make an infinite loop, you just put one run of your loop. That is, remove the while.
On the other hand, using delay() is not a great idea, as the processing loop will stop there and continue after specified time. The behavior you're trying to achieve is better implemented using timer interrupts.

Related

Is this the right way to interact with the button/joystick?

I am currently trying to create memory game with leds, but it becomes humiliating struggle. It would be more logical to start with idea. The idea is that with the help of two diodes some sequence is played and you have to repeat it with the joystick. My program should look something like this...
void main() {
generateNewGame();
blinkLeds();
for (uint8_t index = 0; i < Game_Length; index++) {
if(waitForPress() != GameArray[index])
blinkFail();
return;
}
}
blinkSuccess();
}
This two functions are working fine.
generateNewGame();
blinkLeds();
I have a problem with this function
waitForPress()
My "GameArray" is filled with ones and zeros.
I want to make it so that if I turn the joystick let's say to the left, then the function "waitForPress()" will return 1 and in the main i want to compare this 1 with my "GameArray", and if this is true, check the next element. Comparison with the "Game" array does not work for me. In addition, for some reason,my left led is constantly on, and the joystick does not respond. I hope my words make sense, I am ready to supplement the question if you have any questions.
My code at the moment
#define F_CPU 2000000UL
#include <avr/io.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
// Global
uint8_t Game[8];
int i;
const uint16_t n = 500;
void delay(uint16_t n) {
for(uint16_t i = 0; i < n ; i++) {
for(uint16_t j = 0; j < 200 ; j++) {
asm volatile ("NOP");
}
}
}
// Function for filling the game array with ones and zeros
void RandomNumber() {
srand((unsigned int)time(NULL));
for(unsigned int i = 0; i < sizeof(Game)/sizeof(Game[0]); i++) {
int v = rand() % 2;
Game[i] = v;
}
}
// Function for flashing the Game array sequence
void PlayDemo() {
int i;
for(i = 0; i <= 8; i++) {
if(Game[i] == 1) {
PORTA = 0x80;
delay(n);
PORTA = 0x00;
delay(n);
}
else if (Game[i] == 0) {
PORTA = 0x01;
delay(n);
PORTA = 0x00;
delay(n);
}
else {
PORTA = 0x00;
}
}
}
int waitForPress() {
uint8_t x = PINF;
// Until the button is off, do nothing
while(!(x & 0x20) && !(x & 0x08)) {
x = PINF;
}
// Check if we press to the left
if(x & 0x20) {
// Last LED ON
PORTA = 0x80;
// Wait ( Debouncing )
delay(n);
return 1;
}
// Check if we press to the right side
if(x & 0x08) {
// First LED ON
PORTA = 0x01;
// Wait ( Debouncing )
delay(n);
return 0;
}
return 0;
}
int main(void) {
MCUCR |= 0x80;
MCUCR |= 0x80;
DDRA = 0xFF;
PORTF = 0x20;
RandomNumber();
PlayDemo();
while(1)
{
// Check all elements of the "Game" array
for(uint8_t index = 0; index < 8; index++) {
// If the output of the function "waitForPress()" is not equal to "Game" array element
if(waitForPress() != Game[index]) {
// End the game
break;
} else if(waitForPress() == Game[index]) {
// Turn all led ON
PORTA = 0xFF;
// Wait
delay(n);
// Turn all led OFF
PORTA = 0x00;
// Wait
delay(n);
}
}
}
}
There might be multiple issues with your program:
(1) First of all: In the FOR-loop in which you are comparing the user input with your Game-Array, you are calling waitForPress() two times when the user entered the correct answer. This is not what you want, your code should look like this:
//...
if (waitForPress() != Game[index])
{
//...
break;
}
else
{
//... (correct answer)
}
//...
Or you could do:
//...
int userInput = waitForPress();
if (userInput != Game[index])
{
//...
break;
}
else
{
//... (correct answer)
}
//...
(2) Assuming the corrected code in (1), I think another main issue is the way you are processing the user input in general. Let me illustrate the problem:
Starting off, nothing is pressed. Your main program called waitForPress() and is "stuck" in the WHILE-loop, waiting for the user to push the joystick.
When the user finally pushes the joystick, the function returns 1 or 0.
In your main program, this return value is processed according to your IF-statements inside the FOR-loop (see (1)).
Shortly after this, waitForPress() is called again (in the case of a wrong input almost immediately; in the case of a correct input after your delays; I'm assuming this is meant to be something like a short "flash" of all LEDs lasting maybe a few hundred milliseconds).
Because the button is still pressed (humans are slow!), waitForPress() returns immediately. Now, your program thinks you made the same input again although you didn't even make a second input by your understanding.
To solve this, you want to detect a signal edge. The easiest way to do this is to make sure that the joystick is released before waiting until one button comes on. You may modify waitForPress() like:
int waitForPress() {
uint8_t x = PINF;
// Make sure that the user released the joystick
while((x & 0x20) || (x & 0x08)) {
x = PINF;
}
// Until one button comes on, do nothing
while(!(x & 0x20) && !(x & 0x08)) {
x = PINF;
}
//...
Additionally, you might want to add mechanisms for dealing with bouncing.
(3) You never exit the WHILE-loop in your main() function. Therefore, your program always remains in the state of expecting user input.
(4) In your function PlayDemo(), you are accessing a "non-existing" Game-array element (Game[8]) because the condition of your FOR-loop is i <= 8 and not i < 8.
Additionally, there might be hardware or hardware configuration problems. Such problems might be hard to find over StackOverflow because I don't have or know your exact setup. You could run test programs to check if your hardware is working fine.

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 Magnetometer state change

I currently have a Arduino connected with magnetometer. When metal is detected it shows a 1 but when there is no metal it is a 0. I currently want a count to detect when there is a change in state but ONLY when it goes from a 0 to 1 not a 11 or 10. I have a last state variable set up to capture the previous state and on the next loop back it compares with the current state. Then from there it will send a "2" to my raspberry pi which I have connected. But for some reason the state detect doesn't work. The last State keeps changing with the current state. Can anyone help check out my code.
/* Intialize Variables */
byte data[32]= {0}; //Data buffer for testing data transfer speeds
int k=0;
float headingdegrees;
boolean VehicleDetected;
float high;
float low;
float Average;
float Sum = 0;
unsigned int Counter = 0; //number of attempted transmissions
unsigned int fail_counter = 0; //number of failed transmissions
unsigned int success_counter = 0; //number of successful transmissions
unsigned long rxTimer; //Counter and timer for keeping track transfer info
unsigned long startTime, stopTime;
bool TX=1,RX=0,role=0;
bool car_detected = 0;
int inPin_on = 4; // pushbutton connected to digital pin 4
int inPin_off = 5;
int val = 0; // variable to store the
int fsrPin = 0; // the FSR and 10K pulldown are connected to a0
int fsrReading; // the analog reading from the FSR resistor divider
int fsrVoltage; // the analog reading converted to voltage
unsigned long fsrResistance; // The voltage converted to resistance, can be very big so make "long"
unsigned long fsrConductance;
long fsrForce; // Finally, the resistance converted to force
unsigned int percentage_Transmission = 100;
const unsigned int reset_counter = 5; //number of transmissions before reset
unsigned int arr_transmission_percentage[reset_counter] = {0};
unsigned int arr_index = 0; //To be used for indexing through percentage array
unsigned int i = 0;
unsigned int temp = 0;
float TxRxAve = 100; //Average Transmission percentage
uint32_t displayTimer = 0;
int changeDetected = 0;
int lastState = 0;
int sendChange = 2;
if ( headingdegrees > high ){
VehicleDetected = 1;
}
else if(headingdegrees < low){
VehicleDetected =1;
}
else{
VehicleDetected = 0;
}
//Detect the state change
delay(100);
if(lastState == 0 && VehicleDetected == 1){
changeDetected = 1;
}
else{
changeDetected = 0;
}
//store the current state
// lastState = VehicleDetected;
/***** Sending Data****/
mesh.update();
// Send to the master node every 5 second
if (millis() - displayTimer >= 5000) {
displayTimer = millis();
//if changeDetected = 1 then send a 2 to the raspberry pi
// Send an 'M' type message containing the current millis()
if (changeDetected == 1){
if (!mesh.write(&sendChange, 'M', sizeof(sendChange))) {
// If a write fails, check connectivity to the mesh network
if ( ! mesh.checkConnection() ) {
//refresh the network address
Serial.println("Renewing Address");
mesh.renewAddress();
} else {
Serial.println("Send fail, Test OK");
}
} else {
Serial.print("Begin \n");
Serial.print("Average:"); Serial.println(Average);
Serial.print("Heading (degrees): "); Serial.println(headingdegrees);
Serial.print("Sending Count: "); Serial.println(sendChange);
Serial.print("Last State: "); Serial.println(lastState);
Serial.print("Change: "); Serial.println(changeDetected);
//Serial.print("Data: ");
//Serial.println(data[0]);
Serial.print("Send OK: "); Serial.println(displayTimer);
Serial.print("End \n\n\n");
;
}
}
//if changeDetected = 0 then simplay send the vehicledDetected
else{
if (!mesh.write(&VehicleDetected, 'M', sizeof(VehicleDetected))) {
// If a write fails, check connectivity to the mesh network
if ( ! mesh.checkConnection() ) {
//refresh the network address
Serial.println("Renewing Address");
mesh.renewAddress();
} else {
Serial.println("Send fail, Test OK");
}
} else {
Serial.print("Begin \n");
Serial.print("Average:"); Serial.println(Average);
Serial.print("Heading (degrees): "); Serial.println(headingdegrees);
Serial.print("Vehicle Detected:"); Serial.println(VehicleDetected);
Serial.print("Last State: "); Serial.println(lastState);
Serial.print("Change: "); Serial.println(changeDetected);
//Serial.print("Data: ");
//Serial.println(data[0]);
Serial.print("Send OK: "); Serial.println(displayTimer);
Serial.print("End \n\n\n");
;
}
}
}
while (network.available()) {
RF24NetworkHeader header;
payload_t payload;
network.read(header, &payload, sizeof(payload));
Serial.print("Received packet #");
Serial.print(payload.counter);
Serial.print(" at ");
Serial.println(payload.ms);
delay(500);
}
lastState = VehicleDetected;
}

Arduino - Reading Serial Data while performing for loop

I just got my arduino the other day. I am currently making a program in java to control my arduino using serial communication. So far, I only have the program turn it on or off. But I ran into an issue. I have my arduino fade two rgb leds, looping through every color. I run into my issue here. When I press the button to turn it off(java program), it doesn't turn off until its ran through every color(complete the for loops). I want it to instantly shut off. Is there any way I can read serial data in the for loops, or is there any possible way I can turn it off instantly, not having to wait for the for loops to complete? Here is the code:
const int redPins[] = {11,6};
const int greenPins[] = {10,5};
const int bluePins[] = {9, 3};
const int pinCountPerColor = 2;
const int sensorPin = 0;
int lightLevel;
int val = 0;
boolean isOn;
void setup() {
Serial.begin(9600);
setColourRgb(0,0,0);
isOn = true;
}
void loop() {
if(isOn) {
unsigned int rgbColour[3];
lightLevel = analogRead(sensorPin);
if(lightLevel >= 400) {
rgbColour[0] = 255;
rgbColour[1] = 0;
rgbColour[2] = 0;
for (int decColour = 0; decColour < 3; decColour += 1) {
int incColour = decColour == 2 ? 0 : decColour + 1;
for(int i = 0; i < 255; i += 1) {
lightLevel = analogRead(sensorPin);
if(lightLevel <= 400) {
setColourRgb(255, 255, 255);
} else {
rgbColour[decColour] -= 1;
rgbColour[incColour] += 1;
setColourRgb(rgbColour[0], rgbColour[1], rgbColour[2]);
delay(5);
}
}
}
} else {
setColourRgb(255, 255, 255);
}
}
}
void setColourRgb(unsigned int red, unsigned int green, unsigned int blue) {
for(int r = 0; r < pinCountPerColor; r++) {
analogWrite(redPins[r], red);
}
for(int g = 0; g < pinCountPerColor; g++) {
analogWrite(greenPins[g], green);
}
for(int b = 0; b < pinCountPerColor; b++) {
analogWrite(bluePins[b], blue);
}
}
void serialEvent()
{
while (Serial.available())
{
val = Serial.parseInt();
if(val == 1)
{
isOn = true;
//do nothing
}
else if(val == 0)
{
setColourRgb(255, 255, 255);
isOn = false;
}
}
Serial.println("Succesfully received.");
}
It is best to create a state machine for the colors, that does not have any blocking for loops, to dwell in. Especially loops with delays. So that each cycle through the loop changes the color and polls the Serial.
This is the art to writing real time code, or simply non-blocking code.
Note it is possible to create a timer interrupt to better schedule RGB updates. See Answer about Timer Interrupts to write precision updates.
#mpflaga answered your question correctly.
I would add that if you projects get bigger than just two leds fading, you might want to use something more reliable than a hand-made state machine.
That is called a Real Time Operating System (RTOS) and it allows you to have different threads running at different frequencies.
I personally use ChibiOS/RT for my robot project. There is a port for Arduino you can download here, it's very well documented and I'd say pretty easy to use once you get the basics. The nice thing to do is to add a higher level layer to manage the threads.
Here is a page with describing it and other solutions : Arduino rtoslibs
And here are some tutorials on real time and ChibiOS for Arduino:
It’s time for real-time
Blinking in real-time
ChibiOS for the Arduino IDE
Hope it helps! :)

Arduino won't read the buttons

This program is intended to count the number of button1 presses and then break out of the loop with the button2 press. The button2 is like an enter key.
If I run what is inside the do while statement by itself without the do while it will count up each button push. I used this to verify that I have constructed my circuit correctly. but for some unknown reason if I put the same code into a do while or just a while then it does not read the pins. It will loop inside the do while but never exit to that done statement at the end. If I start the arduino as I press down either of the two buttons then it will register that a button is being pressed, but as soon as I let go then it will do nothing again. Please tell me what I am doing wrong.
My code
int ledpin = 11;
int button1pin = 7;
int button2pin = 2;
int button1counter = 0;
int button1state = 0;
int lastButton1state = 0;
int button2state = 0;
int lastButton2state = 0;
int button2counter = 0;
void setup() {
// initialize the digital pin as an output.
pinMode(button1pin, INPUT);
pinMode(button2pin, INPUT);
Serial.begin(9600);
}
void loop() {
button1state = digitalRead(button1pin);
button2state = digitalRead(button2pin);
do {
if (button1state != lastButton1state) {
if (button1state == HIGH) {
button1counter++;
Serial.print("number of button 1 pushes: ");
Serial.println(button1counter);
}
lastButton1state = button1state;
}
} while(button2state == LOW);
Serial.println("done");
}
Thanks I changed it and of course your right. However, I can't quite understand why your right. Let me comment the code with my understanding and please correct me if I'm wrong.
void setup() {
pinMode(button1pin, INPUT);//tells comp to make button 1 input
pinMode(button2pin, INPUT);//tells comp to make button 2 input
Serial.begin(9600);
}
void loop() {
button1state = digitalRead(button1pin);//tells comp to begin reading pin? but for how long?
button2state = digitalRead(button2pin);
do {
You read your button state outside of your while loop, so your button1state and button2state are never updated, that is why you enter in an infinite loop just do that little change:
void loop() {
do {
button1state = digitalRead(button1pin);
button2state = digitalRead(button2pin);
if (button1state != lastButton1state) {
if (button1state == HIGH) {
button1counter++;
Serial.print("number of button 1 pushes: ");
Serial.println(button1counter);
}
lastButton1state = button1state;
}
} while(button2state == LOW);
Serial.println("done");
}

Resources