Arduino crashing when a button is pressed

I'm making a controller for a drone with an arduino nano and it crashes when I press one specific button. The controller consists of 2 joysticks (each of which contains 2 10k potentiometers), a 16x2 LCD screen, an NRF24L01+PA+LNA and 2 push buttons. Everything works individually but when i put everything into the same script, one of the buttons causes the arduino to freeze. The buttons are used to control the brightness of the LCD screen. The faulty one is the button that increases the brightness and its connected to pin 10.

This is the code:

#include <RF24.h>
#include <LiquidCrystal.h>
#include <Potentiometer.h>

// Transmitter set up
RF24 radio(7, 8); // CE, CSN

const byte address[6] = "00001";

static int channels[4];

// LCD set up
LiquidCrystal lcd(0, 1, 2, 3, 4, 5); // Creates an LCD object. Parameters: (rs, enable, d4, d5, d6, d7) 
int upButton = 9;
int downButton = 10;
int brightness = 80;
int brightnessPin = 6;

int updateRemainingTime;

// Joystick set up
const int leftXPin = A3;
const int leftYPin = A2;
const int rightXPin = A1;
const int rightYPin = A0;

Potentiometer lxPot = Potentiometer(leftXPin);
Potentiometer lyPot = Potentiometer(leftYPin);
Potentiometer rxPot = Potentiometer(rightXPin);
Potentiometer ryPot = Potentiometer(rightYPin);

void setup() {
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_MIN);
  radio.stopListening();

  lcd.begin(16,2); 
  pinMode(brightnessPin, OUTPUT);
  analogWrite(brightnessPin, brightness);
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);

  lxPot.setParameters(502, 10);
  rxPot.setParameters(515, 10);
  ryPot.setParameters(527, 10); 
}

void updateScreen(int battery, int delay){
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Battery:");
  lcd.setCursor(0,1);
  lcd.print((String) battery + "%");
  lcd.setCursor(10,0);
  lcd.print("Delay:");
  lcd.setCursor(10,1);
  lcd.print((String) delay + " ms");
}

void loop() {
  int loopStartTime = millis();

  if(updateRemainingTime < 0){
    //need to ask drone for battery percentage here
    updateScreen(channels[1]/10, 0);
    updateRemainingTime = 200;
    loopStartTime = millis();
  }

  channels[0] = lxPot.getValue();
  channels[1] = lyPot.getValue();
  channels[2] = rxPot.getValue();
  channels[3] = ryPot.getValue();
  
  if(digitalRead(upButton) == LOW){ brightness--; }
  if(digitalRead(downButton) == LOW){ brightness++; }

  if(brightness < 0){brightness = 0; }
  if(brightness > 255){brightness = 255; }

  analogWrite(brightnessPin, brightness);

  radio.write(&channels, sizeof(channels));
  
  delay(20);

  updateRemainingTime -= millis() - loopStartTime;
}

sorry for the distinct lack of comments.

I am exceptionally confused because the button works in all my other tests like this one that just controls the LCD screen:

#include <LiquidCrystal.h> // includes the LiquidCrystal Library 
LiquidCrystal lcd(0, 1, 2, 3, 4, 5); // Creates an LCD object. Parameters: (rs, enable, d4, d5, d6, d7) 
int upButton = 10;
int downButton = 9;
int brightness = 80;
int brightnessPin = 6;

int looptime = 0;
int updateRemainingTime = 1000;

void setup() { 
 lcd.begin(16,2); // Initializes the interface to the LCD screen, and specifies the dimensions (width and height) of the display } 
 pinMode(brightnessPin, OUTPUT);
 analogWrite(brightnessPin, 80);
 pinMode(upButton, INPUT_PULLUP);
 pinMode(downButton, INPUT_PULLUP); 
}

void updateScreen(int battery, int delay){
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Battery:");
  lcd.setCursor(0,1);
  lcd.print((String) battery + "%");
  lcd.setCursor(10,0);
  lcd.print("Delay:");
  lcd.setCursor(10,1);
  lcd.print((String) delay + " ms");
}


void loop() { 
  int loopStartTime = millis();

  if(updateRemainingTime < 0){
    updateScreen(97, 23);
    updateRemainingTime = 1000;
  }

  if(digitalRead(upButton) == LOW){ brightness--; }
  if(digitalRead(downButton) == LOW){ brightness++; }

  if(brightness < 0){brightness = 0; }
  if(brightness > 255){brightness = 255; }

  analogWrite(brightnessPin, brightness);

  delay(20);
  
  updateRemainingTime -= millis() - loopStartTime;
}

Both the buttons are connected in the same way, with a 10k resistor between them and ground.

After a series of tests it seems that the arduino freezes when digitalRead() is called and the value is 0. Sometimes it returns 0 but sometimes it crashes before that.

Thanks for any help.

Sounds like that button is shorting out the power supply, causing a reset. Double check the wiring, and if you still need help, post a close up photo of the setup.

Hint: the best way to wire a button is from the input pin directly to ground (no additional resistor). Use pinMode(pin, INPUT_PULLUP); to safely keep the pin HIGH when the button is not pressed.

It doesn't seem to be resetting because the program doesn't restart, it just freezes. would this happen if it was shorting the power supply?

I will try removing the resistor, thanks for the tip.

Shorting the resistor so the button goes straight to ground did not affect the porblem.

Here is a photo of the wiring

And you changed the software in the setup function, and the logic in the code so that reading a push of the button when you see a zero as a result of a read?

Not much good as you can't tell the wiring of the button from the photograph. Post a picture of the other side of the board, along with a schematic of what you think you have wired up. Also take the first picture with proper lighting so we can clearly see the components.

When using those 4 pin buttons always wire across the diagonal of the switch, and remember not to wire the other diagonal to anything.

Sounds like that to me as well. Classic case of misswiring .

Hi, @bowl_of_petunias

Can you please post a copy of your circuit, a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, power supplies, component names and pin labels.

Reverse engineer your project to make the schematic, you may find your problem.

Do you have a DMM? Digital MultiMeter?

Tom.. :smiley: :+1: :coffee: :australia:

Where do we find that library?

And does it qualify as the worst library in the Arduino universe, on the grounds of what could it possibly do?

Maybe we should start a thread on the most useless library?

Hi @TomGeorge ,

I don't have time to do a full schematic right now but I'll post one in the next few days but before I do that I have two questions:

  1. How could it be a case of misswiring if the button works when other scripts are uploaded?

  2. I deliberately shorted power to ground to see what would happen. This briefly turned off the arduino then caused it to restart the program from the beginning. When the button is pressed the arduino simply freezes. Does this not rule out the possibility of the 5V pin being shorted to ground?

Also here are a few pieces of additional information I did not clarify before:

  1. The potentiometer library is a library I created to map the joysticks I have to a desired range of values with a deadzone in the middle to make them easier to use and to avoid stickdrift. This is the header file:
#ifndef Potentiometer_h
#define Potentiometer_h

#include "Arduino.h"

class Potentiometer {
	int _centre, _deadzone;
	int _pin;

public:
	Potentiometer(int pin);

	void setParameters(int centre, int deadzone);
	void setDeadzone(int d);
	void setCentre(int c);

	int getValue();
	int getValue(int max);
	int getValue(int min, int max);
};

#endif

and this is the other file:

#include "Arduino.h"
#include "Potentiometer.h"

int limit(int x, int min, int max) {
    if (x < min) { return min; }
    if (x > max) { return max; }
    return x;
}

Potentiometer::Potentiometer(int pin) {
    _centre = 511;
    _deadzone = 0;

    _pin = pin;
    pinMode(_pin, INPUT);
}

void Potentiometer::setParameters(int c, int d) {
    setDeadzone(d);
    setCentre(c);
}

void Potentiometer::setDeadzone(int d) {
    _deadzone = d;
}

void Potentiometer::setCentre(int c) {
    _centre = c;
}

int Potentiometer::getValue() {
    return getValue(0, 1000);
}

int Potentiometer::getValue(int max) {
    return getValue(0, max);
}

int Potentiometer::getValue(int min, int max) {
    int val = analogRead(_pin);
    if (val < _centre) {
        val = map(val, 0, _centre, 0, 500 + (_deadzone / 2));
        val = limit(val, 0, 500);
    }
    else if (val >= _centre) {
        val = map(val, _centre, 1023, 500 - (_deadzone / 2), 1000);
        val = limit(val, 500, 1000);
    }
    return val;
}
  1. Yes I do have a DMM and i have checked all the pins near the faulty button and nothing is shorted

Thank you for any help

...

As far as I know, the nRF24 is an SPI device. On your Nano, pin 10 is the SS pin and that pin has a special function when using SPI; it determines if your Nano is an SPI master or an SPI slave.
Move the downButton to A4 or A5, they seem to be free.

Further one advice. Do not use functions that access the hardware in a constructor. Yes, it does not throw errors when compiling, yes, it works on a number of boards but there are boards where e.g. the pinMode setting is wiped by the time the setup() function is executed. Add a begin method to your class where you set the pin mode.

Hi,
I personally would forget a library and make the potentiometer a function the the main code.

Tom... :smiley: :+1: :coffee: :australia:

All that and STILL no code with a setup function in it.

And still no schematic.

That is the third and final request from me. Otherwise I will put you on my banned list and walk away from this thread.

That's fantastic, everything is working perfectly now thank you so much this response has made my day. Is there a reason why the SS pin isn't on the arduino nano pinout?

Thanks for the advice I'll start using begin methods.

Second page of https://docs.arduino.cc/resources/pinouts/A000005-full-pinout.pdf has the SS mentioned.

Don't ask me why it's not on the first page; you can let Arduino know that their pinout is bad (to use a friendly term). https://www.arduino.cc/en/contact-us.