text:
Weird behaviour with BearSSL on GPIO ESP8266
I use GPIO 5 to trigger a relay. My code also connects with a secure MQTT connection for which I have to use the BearSSL certificate definitions.
Without the BearSSL certificates, when the ESP restarts it does not re-trigger the relay, and the GPIO maintains its state between reboots, but when I use the bearSSL certificates the behavior changes, and GPIO 5 goes low on restart. Any explanation why and how to mitigate it?
I am 100% sure it is because of the import, because I removed components from my code until I could find the piece of code that caused this, and it was because of the declarations.
#include <WiFiClientSecure.h>

static const char AWS_CERT_CA[] PROGMEM = R"EOF(aws root)EOF";
static const char AWS_CERT_CRT[] PROGMEM = R"KEY(device cert)KEY";
static const char AWS_CERT_KEY[] PROGMEM = R"KEY(device key)KEY";

BearSSL::X509List cert(AWS_CERT_CA);
BearSSL::X509List client_crt(AWS_CERT_CRT);
BearSSL::PrivateKey key(AWS_CERT_KEY);

WiFiClientSecure espClient;

void setup() {
  pinMode(5, OUTPUT);
  delay(2000);
  digitalWrite(5, HIGH);
  delay(2000);
  ESP.restart();
}

void loop() {}

Without the following three lines the LED on GPIO 5 does not flicker on restarts, but adding these lines makes them flicker:
BearSSL::X509List cert(AWS_CERT_CA);
BearSSL::X509List client_crt(AWS_CERT_CRT);
BearSSL::PrivateKey key(AWS_CERT_KEY);

Any solution or suggestion towards a solution for this problem will be really helpful.

What worked for me was to move the BearSSL declaration and usage after the pinMode setting of the GPIO.
I had to make the certificate and keys local variables and wrap the entire setting up of WiFi, connecting to it, setting up and connecting to the AWS core in a single function after setting up the GPIO pins.
void setupWiFiAndConnectAWS() {
  BearSSL::X509List cert(AWS_CERT_CA);
  BearSSL::X509List client_crt(AWS_CERT_CRT);
  BearSSL::PrivateKey key(AWS_CERT_KEY);
  WiFi.persistent(false);
  DEBUG_MSG("[setupWiFi] Setting host name\n");
  WiFi.hostname(deviceId);
  DEBUG_MSG("[setupWiFi] Setting station mode\n");
  WiFi.mode(WIFI_STA);

  if (WiFi.getMode() & WIFI_AP) {
    WiFi.softAPdisconnect(true);
  }

  WiFi.persistent(false);
  DEBUG_MSG("[setupWiFi] Loading certificates\n");
  net.setTrustAnchors(&cert);
  net.setClientRSACert(&client_crt, &key);
  loadCredentials();
  connectWiFi();
  attachInputInterrupts(false);
  setupNTP();
  connectAWS();
}

Although this is a workaround, I still don't understand the core problem and would like to understand it.


text:
Is it possible to know how long an ESP8266 was in deep sleep?
I'm working on a low power device that implements an ESP8266 MCU and uses it's deep sleep feature. The firmware uses the Arduino C++ library.
Part of the functionality requires knowing the time. To do this, I am using configTime to get the time (i.e. NTP). But, to reduce power consumption, I only connect to WiFi every 24 hours. The ESP8266 wakes every hour (to decide if it should do something or go back to sleep). To keep time, I record the last known unix timestamp to RTC memory and upon waking add the amount of time that the device was told to deep sleep (i.e. 1 hour).
The flaw in this design: Part of the requirement is that the user needs to be able to wake the device manually with a button press and interrupt the normal sleep pattern, but if the device is woken with the reset button, it adds an hour to the time and the time becomes completely inaccurate (because an hour was added, even though it could be seconds since deep sleep started).
Is there a way, using the ESP8266 API, to tell how long the device was actually in deep sleep? That way, on wake, instead of blindly adding 1 hour to the RTC-saved unix timestamp, I can add the amount of time that the MCU was in deep sleep. The datasheet seems to only mention the RTC a few times in not much detail.
If no firmware solution exists, what hardware solution could I use?
Thinking out loud: I think a compromise could be to detect if the reset button was pressed (latch/flip flop/register, maybe?). In this case I still wouldn't be able to tell how long the MCU was asleep, but at least I'd be able to tell if I should add time. I found that system_get_rst_info is based on how the device went to sleep (i.e. if woken from deep sleep by pressing the reset button, the reason is REANSON_DEEP_SLEEP_AWAKE), so I couldn't see how to make use of that in this case. I suppose I could add an external RTC, negating the need to calculate how long the MCU was in deep sleep, and just use that external IC for time keeping.
Edit: Apparently, rtctime.dsleep() provides time keeping across deep sleep, but it's LUA only so not useful to me. The source is written in C, but I can't see anything that would help.

Time is kept across the deep sleep. I.e. rtctime.get() will keep working (provided time was available before the sleep).

The hardware solution could be a flip/flop or scr or latching bjt thingie that's clamped by a physical button press that also uses a fet to pull down rst. You can then quickly query that one bit of state on boot to determine if a button did it. You then reset the latch/JK/SCR with another GPIO. So, it burns two GPIOs but works well.

@dandavis Good idea, I'll give that a try.

I believe the answer is no (you cannot tell exactly how long an ESP8266 was asleep), given these constraints:

If an external RTC cannot be used.
If the MCU does not connect to Wi-Fi every time it wakes.
If the MCU can be woken arbitrarily by the user pressing the reset button.

In other words, if the ESP8266 does not connect to Wi-Fi every time it wakes, you can only estimate the time based on how long it should have been in deep sleep, but you can't know for sure without either going online or using an external RTC.

save timestamp in NVRAM, the time before sleep. once wakeup, simply subtract the the data saved in NVRAM from the current time.

What if I sleep for 1 hour, but then press the reset button 1 second later? The time would be 59 mins and 59 seconds out, as I mentioned in my question.

I always use unix timestamp in millisecond ie...      gettimeofday(&tv,NULL);
time_stamp[ptr] = (int64_t)(tv.tv_sec*1000LL + tv.tv_usec /(1000LL));

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
How to stop Single Analog Pin Keypad Matrix (Using Resistors) from receiving Interference from Livewire/other Sensors?
I saw a tutorial on linking a keypad using one pin, utilising several resistors:
http://razibshahdat.blogspot.com/2018/05/one-single-analog-pin-keypad-control.html
I have this keypad, a 16x2 LCD, a PIR motion detector, and a DHT11 temperature & humidity sensor attached. Furthermore, I have an additional 5V power supply connected to the breadboard for additional power, although I'm not sure if this is required?
All components work as expected in the current configuration when only loading their relevant Arduino template code, except for the keypad. The keypad worked initially when nothing else was connected, but now the resistance values fed to the serial seem to jump, particularly in the first column. I tried to add some resistance between the first input of the keypad matrix and the live wire, which dampens the fluctuations but does not remove them completely.

I have created a Fritzing sketch to try to make it a bit easier to understand, although I realise that it is still rather chaotic. I am new to Fritzing and Arduino and am still figuring things out.
Here is the isolated code for the keypad, which I am using to find the output values (which, as mentioned, are varying unpredictably), although this was working previously, on a more simple setup:
    // code adapted from: https://www.youtube.com/watch?v=W8ZSeLD90KA
    void setup() {
         Serial.begin(9600);  /* Define baud rate for serial communication */
    }

    void loop() {
      int keyIn;
      int keyVals [16] = {976, 450, 333, 244, 166, 138, 124, 109, 90, 81, 76, 70, 61, 57, 54, 51};
      char keys[16] = {'1','2','3','A','4','5','6','B','7','8','9','C','*','0','#','D'};
      int range = 1;

      keyIn = analogRead(A1);

      String temp = "";

      if (keyIn > 2)
      {
        Serial.print(keyIn);
        for(int i=0; i<=15; i++)
        {
          // The values of the keys changed, that's why the following is commented out
          //if (keyIn >= keyVals[i]-range && keyIn <= keyVals[i]+range)
          //{
          //  temp = keys[i];
          //}
        }
       Serial.print(temp);
       Serial.println("");
       delay(500);
    }

}
Lastly, I intend for this board to be my master. I then intend to connect a slave through I2C with a DC motor, a servo motor, and an RGB LED. Does this seem feasible?
Please assist if you can.
If you have any additional advice, that too would be highly appreciated - thank you in advance!

you do not have a common ground connection between the arduino and the breadboard

Lower the resistance, that will reduce the coupled noise after you make sure all grounds are connected. There are other possibilities but the frizzy picture is useless to me.

Your key values are:
int keyVals [16] = {976, 450, 333, 244, 166, 138, 124, 109, 90, 81, 76, 70, 61, 57, 54, 51};

The formula for the key values given in the OnewireKeypad library is:
float V = (voltage * float( R3 )) / (float(R3) + (float(R1) * float(R)) + (float(R2) * float(C)));
float Vfinal = V * ANALOG_FACTOR;

where:

voltage = 5 V
R1 = 1,000 Ω (the three horizontal ones in the schematic)
R2 = 4,700 Ω
R3 = 1,000 Ω (the pulldown to GND in the schematic)
R = row number 0 to 3
C = column number 0 to 3
ANALOG_FACTOR = 1023 / 5.0;

The keypad schematic given in the blogspot article is:

I put the formula and parameters into an Excel spreadsheet and produced this:

...which is different to your key values.
Have I misunderstood your circuit setup? Are you doing something different?

Thanks you for your detailed response Tim! It consisted of two errors: the one was my ground not being connected between the Arduino and the breadboard, which reduced jumping. Your recommendation of adding the 1 kOhm resistance between the ground and the keypad resistor setup was the finishing touch!

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Having problems compiling this code for NRF24l01 on arduino uno and arduino micro
I have the library RF24 and everything in my arduino library but for some reason it's not compiling.  I don't know why. I posted the code and also the error message that the arduin IDE keeps showing. Please help me figure out whats wrong!
Arduino: 1.6.12 (Windows 7), Board: "Arduino/Genuino Uno"

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::read_register(unsigned char, unsigned char*, unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::read_register(unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::write_register(unsigned char, unsigned char const*, unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::write_register(unsigned char, unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::openReadingPipe(unsigned char, unsigned long long)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::setAutoAck(bool)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::setAutoAck(unsigned char, bool)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::read_payload(void*, unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::flush_rx()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::getDynamicPayloadSize()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::flush_tx()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::get_status()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::available(unsigned char*)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::print_status(unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::print_observe_tx(unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::print_byte_register(char const*, unsigned char, unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::print_address_register(char const*, unsigned char, unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::RF24(unsigned char, unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::RF24(unsigned char, unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::setChannel(unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::setPayloadSize(unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::getPayloadSize()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::stopListening()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::powerDown()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::powerUp()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::write(void const*, unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::available()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::read(void*, unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::whatHappened(bool&, bool&, bool&)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::openWritingPipe(unsigned long long)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::startListening()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::toggle_features()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::enableDynamicPayloads()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::enableAckPayload()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::writeAckPayload(unsigned char, void const*, unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::isAckPayloadAvailable()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::isPVariant()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::testCarrier()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::testRPD()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::getPALevel()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::setDataRate(rf24_datarate_e)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::getDataRate()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::setCRCLength(rf24_crclength_e)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::getCRCLength()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::printDetails()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::disableCRC()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::setRetries(unsigned char, unsigned char)'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\RF24-master\RF24.cpp.o (symbol from plugin): In function `RF24::csn(bool)':

(.text+0x0): multiple definition of `RF24::begin()'

libraries\RF24ArduinoCommunicator-master\RF24.cpp.o (symbol from plugin):(.text+0x0): first defined here

collect2.exe: error: ld returned 1 exit status

Multiple libraries were found for "nRF24L01.h"
 Used: C:\Users\Owner\Documents\Arduino\libraries\RF24ArduinoCommunicator-master
 Not used: C:\Users\Owner\Documents\Arduino\libraries\RF24-master
 Not used: C:\Users\Owner\Documents\Arduino\libraries\RF24-master
 Not used: C:\Users\Owner\Documents\Arduino\libraries\RF24-master
 Not used: C:\Users\Owner\Documents\Arduino\libraries\RF24-master
exit status 1
Error compiling for board Arduino/Genuino Uno.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Example I tried to compile:
/*
 Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 version 2 as published by the Free Software Foundation.
 */

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"

//
// Hardware configuration
//

// Set up nRF24L01 radio on SPI bus plus pins 9 & 10

RF24 radio(9,10);

//
// Topology
//

// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

//
// Role management
//
// Set up role.  This sketch uses the same software for all the nodes
// in this system.  Doing so greatly simplifies testing.
//

// The various roles supported by this sketch
typedef enum { role_ping_out = 1, role_pong_back } role_e;

// The debug-friendly names of those roles
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};

// The role of the current running sketch
role_e role = role_pong_back;

void setup(void)
{
  //
  // Print preamble
  //

  Serial.begin(57600);
  printf_begin();
  printf("\n\rRF24/examples/GettingStarted/\n\r");
  printf("ROLE: %s\n\r",role_friendly_name[role]);
  printf("*** PRESS 'T' to begin transmitting to the other node\n\r");

  //
  // Setup and configure rf radio
  //

  radio.begin();

  // optionally, increase the delay between retries & # of retries
  radio.setRetries(15,15);

  // optionally, reduce the payload size.  seems to
  // improve reliability
  radio.setPayloadSize(8);

  //
  // Open pipes to other nodes for communication
  //

  // This simple sketch opens two pipes for these two nodes to communicate
  // back and forth.
  // Open 'our' pipe for writing
  // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)

  if ( role == role_ping_out )
  {
    radio.openWritingPipe(pipes[0]);
    radio.openReadingPipe(1,pipes[1]);
  }
  else
  {
    radio.openWritingPipe(pipes[1]);
    radio.openReadingPipe(1,pipes[0]);
  }

  //
  // Start listening
  //

  radio.startListening();

  //
  // Dump the configuration of the rf unit for debugging
  //

  radio.printDetails();
}

void loop(void)
{
  //
  // Ping out role.  Repeatedly send the current time
  //

  if (role == role_ping_out)
  {
    // First, stop listening so we can talk.
    radio.stopListening();

    // Take the time, and send it.  This will block until complete
    unsigned long time = millis();
    printf("Now sending %lu...",time);
    bool ok = radio.write( &time, sizeof(unsigned long) );

    if (ok)
      printf("ok...");
    else
      printf("failed.\n\r");

    // Now, continue listening
    radio.startListening();

    // Wait here until we get a response, or timeout (250ms)
    unsigned long started_waiting_at = millis();
    bool timeout = false;
    while ( ! radio.available() && ! timeout )
      if (millis() - started_waiting_at > 200 )
        timeout = true;

    // Describe the results
    if ( timeout )
    {
      printf("Failed, response timed out.\n\r");
    }
    else
    {
      // Grab the response, compare, and send to debugging spew
      unsigned long got_time;
      radio.read( &got_time, sizeof(unsigned long) );

      // Spew it
      printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time);
    }

    // Try again 1s later
    delay(1000);
  }

  //
  // Pong back role.  Receive each packet, dump it out, and send it back
  //

  if ( role == role_pong_back )
  {
    // if there is data ready
    if ( radio.available() )
    {
      // Dump the payloads until we've gotten everything
      unsigned long got_time;
      bool done = false;
      while (!done)
      {
        // Fetch the payload, and see if this was the last one.
        done = radio.read( &got_time, sizeof(unsigned long) );

        // Spew it
        printf("Got payload %lu...",got_time);

        // Delay just a little bit to let the other unit
        // make the transition to receiver
        delay(20);
      }

      // First, stop listening so we can talk
      radio.stopListening();

      // Send the final one back.
      radio.write( &got_time, sizeof(unsigned long) );
      printf("Sent response.\n\r");

      // Now, resume listening so we catch the next packets.
      radio.startListening();
    }
  }

  //
  // Change roles
  //

  if ( Serial.available() )
  {
    char c = toupper(Serial.read());
    if ( c == 'T' && role == role_pong_back )
    {
      printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r");

      // Become the primary transmitter (ping out)
      role = role_ping_out;
      radio.openWritingPipe(pipes[0]);
      radio.openReadingPipe(1,pipes[1]);
    }
    else if ( c == 'R' && role == role_ping_out )
    {
      printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");

      // Become the primary receiver (pong back)
      role = role_pong_back;
      radio.openWritingPipe(pipes[1]);
      radio.openReadingPipe(1,pipes[0]);
    }
  }
}

You have multiple copies of the library.
Delete the folder located at:
C:\Users\Owner\Documents\Arduino\libraries\RF24ArduinoCommunicator-master

ok I deleted that file now it says "void value not ignore as it out to be" and then the line "done = radio.read( &got_time, sizeof(unsigned long) );" is highlighted. Is there something that I missed?

You can't assign nothing (void) to something (boolean "done"). Use radio.available() instead to see if there's something in the buffer waiting to be read.

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
16 X 2 LCD display blank with Arduino Uno
So I am following this tutorial to make my arduino display hello world and millis(), I got it to work for a minute, but then it stopped updating the milliseconds, and when I pushed the reset button it went blank. since then, It has been blank but I have double, triple, and qaudruple checked checked my wiring, and it is flawless. I tried it with both of my 16 segment displays, but to no avail. I have redone the wiring, but it is still blank. Does anybody know what I could be doing wrong?
I followed this diagram
this is my code:
// include the library code:
#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("hello, world!");
}

void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 1);
  // print the number of seconds since reset:
  lcd.print(millis() / 1000);
}

This is the result (the screen is lit up, but there is no text even when turning the potentiometer)

i'm having trouble scrolling down in your code listing .....  lol .... please list the text of the complete sketch .....remove the picture of the code

that is not a 16 segment display .... this is http://www.embeddedadventures.com/images/uploaded_images/DSP_16S04H_2_600.jpg

Please do not post images of code, paste the code itself, select it all and then press {} to properly format it. Also this display is 16x2 character one, not a segment one.

ok, I didn't have it formatted right, my code is in text now

I have no idea what I did, i added a serial println to see if for some reason the program wasn't getting into the loop, and it started working :) EDIT: then I removed the println and it is still working... I guess it was a problem with the compiler or something... but I also checked the code so many times, and it was perfect

Sorry for all the notifs, I fixed my code, and thanks for informing me that the display isn't a 16 segment display. Do any of you have an idea as to what may have been wrong?

I suspect that you wiggled a loose Dupont wire back to it's place. They're quite flimsy. In addition to that, please post your best theory as the answer and click on the check mark button to mark it as the correct answer, adding (SOLVED) to the title is not how Arduino SE works.

Alright, I will do

It won't let me accept my own answer for two days, but I will check it then.

Do any of you have an idea as to what may have been wrong?  ..... perhaps the upload was failing and you did not see the error messages for some reason .... so you were re-running the same sketch over and over

I rewrote the sketch twice, I think it had to do with hardware, if you look at my answer below

It is most likely that I wasn't providing enough power to the arduino, and or had the potentiometer set to the wrong point. according to this post, you shouldn't run the arduino and display off of USB, because it may not actually be providing 5 volts. So I plugged it into the wall using a DC adapter. It now works.

If it solved your problem, you can accept your own answer to mark the question as answered.

It won't let me accept it until tomorrow


text:
Difference between Arduino IDE giving me headaches
For some time now I've been playing around with the latest version of Arduino IDE and my UNO and ATTiny with simple 433 RF links with the Manchester Library. It all worked fine, but for my next project I want to take the step up and use a better wireless thingy... like the nRF24l01 or the nfm12b.
And then starts the pain. Attiny does not have hardware serial, but people seems to have solved this by implementing software-serial. But then they have to use some other boards for ATTiny, because when I try to run the examples I get error messages that it could not find  and so on. I use the ATTiny boards I found over at google code.
Regarding the RFM12B I got something to compile. If I went back and downloaded Arduino IDE 1.5.0 (no other!) it actually work with the JeeLib - hurray! Why is this, why can't I use the latest version of the Arduino IDE?
Regarding the NRF24 chip this case is unresolved. I have not found the correct combination of boards, IDE and library versions. Could anyone point me in the right direction?
What are the difference between the Arduino IDE's? Why can I get stuff to work on 1.5.0 but not the latest 1.6.x?

To get RF24 working:

Download the latest IDE (not 1.0*)
Use the library manager to download the
latest RF24.
See https://github.com/TMRh20/RF24/issues/236#issuecomment-205354077
about what core to use.
Don't forget to define ATTiny in the sketch
Ex: #define __AVR_ATtiny84__
(84, 44, 24 are the choices)

ATTiny* do not have SPI, that's why it can't find SPI.h (SPI library).

As far as I know, there was an internal dispute in the Arduino company. So now there are two companies selling under the Arduino name.
www.arduino.cc 's latest ide is 1.5.x and that has more features than www.arduino.org 's ide 1.6.x. So make sure you use arduino.cc's version only because they do the major development of the IDE.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
RF24 + High speed pwd
I'm using the arduino to generate a 100kHz pwd using timer 1
void setup() {
  // put your setup code here, to run once:

   // Timer 1 Fast PWM mode *toggling* OC1A at 50kHz with *two* OCR1A counts
   // And 7.32 bits 0-159 PWM on OC1B at 100kHz
   // Output on OC1B
   // Set at TOP, Clear at OCR1B
   // WGM =15 0b1111

   DDRB |= bit(DDB1) | bit(DDB2);  // atmega168/UNO OC1A and OC1B (Tested by OP/Luis)

   TCCR1A =  bit(WGM11) | bit(WGM10) | bit(COM1A0) | bit(COM1B1)  ; // Toggle OC1A, Clear on OC1B
   TCCR1B =  bit(WGM13) | bit(WGM12) | bit(CS10);  // Set /1 prescaler
   OCR1A  = 159 ;//79;    // Set TOP count to 16000000/(2*PreScaler*Ftoggle)
                          // or 16000000/(PreScaler *Ftimer)
   OCR1B  = 10;           // 10/160 duty cycle
   TCNT1 = 0 ;
}

void loop() {
  // put your main code here, to run repeatedly:
  OCR1B = 160/4 -1 ; // 25% duty cycle.
}

I used this to test the modules:
Receiver
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
int msg[1];
RF24 radio(9,10);
const uint64_t pipe = 0xE8E8F0F0E1LL;
int LED1 = 3;

void setup(void){
 Serial.begin(9600);
 radio.begin();
 radio.openReadingPipe(1,pipe);
 radio.startListening();
 pinMode(LED1, OUTPUT);}

void loop(void){
 if (radio.available()){
   bool done = false;
   while (!done){
     done = radio.read(msg, 1);
     Serial.println(msg[0]);
     if (msg[0] == 111){delay(10);digitalWrite(LED1, HIGH);}
     else {digitalWrite(LED1, LOW);}
     delay(100);}}
 else{Serial.println("No radio available");}}

Transmitter
#include  <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
int msg[1];
RF24 radio(9,10);
const uint64_t pipe = 0xE8E8F0F0E1LL;
int SW1 = 7;

void setup(void){
 Serial.begin(9600);
 radio.begin();
 radio.openWritingPipe(pipe);}

void loop(void){
 if (digitalRead(SW1) == HIGH){
 msg[0] = 111;
 radio.write(msg, 1);}}

I'm using this library
https://github.com/TMRh20/RF24
And it works ok, now first issue is that both, RF24 and the pwm
are using the pin 10 but the library allows you  to change it, so now I'm using pin 7 instead. I tested it again and still works fine.
But when I add the lines at the setup to use the pwd  the communication doesn't work
   DDRB |= bit(DDB1) | bit(DDB2);  // atmega168/UNO OC1A

   TCCR1A =  bit(WGM11) | bit(WGM10) | bit(COM1A0) | bit(COM1B1)  ; // Toggle OC1A, Clear on OC1B
   TCCR1B =  bit(WGM13) | bit(WGM12) | bit(CS10);  // Set /1 prescaler
   OCR1A  = 159 ;//79;    // Set TOP count to 16000000/(2*PreScaler*Ftoggle)
                          // or 16000000/(PreScaler *Ftimer)
   OCR1B  = 10;           // 10/160 duty cycle
   TCNT1 = 0 ;

I try line by line and the issue is here:
TCCR1B =  bit(WGM13) | bit(WGM12) | bit(CS10);  // Set /1 prescaler
When setting the prescaler at 1.
Which is the dependency of the RF24 on this timer? and which options to I have to make it work
EDIT.
Now I'm using pins 6 and 7 for CE and CS
Also removed  "| bit(COM1A0) " form the register  setting
Still doesn't work
I've this
void setup(void)
{

  /// RF settings

  Serial.begin(9600);
 radio.begin();
 //radio.openReadingPipe(1,pipe);
 //radio.startListening();
 pinMode(LED1, OUTPUT);

 /// end RF settings

  //// pwd settings
 DDRB |= bit(DDB1) | bit(DDB2);
   OCR1A  = max_count;       // 16000000/(PreScaler *Ftimer)
   OCR1B  = 10;
   TCCR1A =  bit(WGM11) | bit(WGM10) |  bit(COM1B1); // bit(COM1A0) | Toggle OC1A, Clear on OC1B
   TCCR1B =  bit(WGM13) | bit(WGM12) | bit(CS10);  // Set /1 prescaler
   TCNT1 = 0 ;

  ////
 }

If I put the settings for the PWM before the settings for the RF24 then the PWM doesn't work, the RF settings at first the the communications doesn't work.
radio.begin() must be overwriting the registers but I haven't found how.

The "TCCR1A =  bit(WGM11) | bit(WGM10) | bit(COM1A0) | bit(COM1B1)  ; // Toggle OC1A, Clear on OC1B"    line set up the PWM to control both the OC1A and OC1B pins, which are 9 and 10 on an Arduino Uno,  Is Pin 9 interfering with the RF24 per the "RF24 radio(9,10\7);" line?    If so, you could take out the " | bit(COM1A0)" portion to free up pin 9 for digital IO rather than PWM.

Maybe the fact that you have pin 10 as PWM is messing up the SPI module that requires pin 10 to be set to output for SPI to operate?

@DaveX I try it, still doesn't work

@Majenko if the RF24 doesn't need to use pin 10 how can I check if the SPI library is causing the issue

The nRF doesn't need pin 10 but the SPI does. It's a hardware thing. If you can run the pwm without pun 10 it may prove or disprove it.

Maybe doing 100kHz PWM with timer2 instead of timer1 would be good.  The registers look similar to timer1, but they are only 8 bit, so you can't go bigger than 255 in the compare and count registers. The prescaler would be the same, and the timer controlled pins would be D11 and D3:
  //// pwm settings for 100kHz on Timer 2
  //// Toggle OC2A/D11/PB3 at 50kHz, PWM OC2B/D3/PD3 at 100kHz:
   DDRB |= bit(DDB3); //Enable output
   DDRD |= bit(DDD3); //Enable output
   // WGM2x=0b111 for fast PWM with TOP=OCR2A
   // COM2Ax=0b01 for toggle OC2A at OCR2A
   // COM2Bx=0b10 for set@bottom-clear@match_OCR2B PWM
   TCCR2A =   bit(WGM21)  | bit(WGM20)
            | bit(COM2B1)  // PWM on OC2B
            | bit(COM2A0); // Toggle OC2A
   TCCR2B =   bit(WGM22) | bit(CS20);  // Set /1 prescaler
   OCR2A  = 159;       // 16000000/(PreScaler *Ftimer)-1
   OCR2B  = 10;        // 6.25% PWM
   TCNT2 = 0 ;

I haven't tested this on an Uno/Atmega328P, but it looks reasonable per the datasheet (p153-157).
If you don't want both the 50kHz toggle and 100kHz PWM outputs, (as in your posted code,) you could disable one or the other and adjust the frequency as needed.


text:
Why adding a LED between Pin 3 and Ground causes LCD display not to show text?
For a project of mine I am programming an Arduino UNO to show information I get from some sensors on an LCD display.
As a first step I setup Arduino to show "Hello, world!" on the LCD, which worked.

For "decorative" reasons I wanted to add some LEDs between the resistors that I placed in series between PIN 3 (V0) of the LCD and ground (about 1.5K Ohm total resistance).
I first of all added one LED between the last resistor and ground. To my surprise this causes the LCD display not to show "Hello, world!" any more.
As you can see the current is flowing (the LED is lit), but I can't understand why the LCD does not show the text.

Can you help me understand what's going on? I know very little of electronics and I am learning it by doing, so I would appreciate an answer that is good for a beginner!

In a typical 1602 LCD pinout, pin 3 or V0 is the contrast setting for the display.  It usually is set to a voltage near ground, often by using a 10K pot with ends connected to Vdd and Vss with wiper to V0.
By putting an LED in series with your resistors (that apparently go to ground) you've either disconnected V0 from ground or have raised its voltage by the LED voltage.  This reduces contrast to the point that characters aren't visible even though they are on the display.
The LED backlight remains on and at the same brightness as before because it is driven via pins 15 and 16, independent of all other display settings.
Edit 1: I haven't duplicated your circuit to take measurements, so at the moment don't know for sure; but (in resistors-only case) V0 from pin 3 on the 1602 LCD board apparently sources some small current through your 1500 Ω to ground.  When you add an LED it can disconnect V0 from ground or can raise its voltage by the LED voltage, as follows:  firstly, if the LED cathode faces V0 and V0 is positive, no current will flow through the diode, thus disconnecting V0.  Secondly, if the LED anode faces V0 and V0 is positive, current will flow through the LED.  If the LED lights at all, most of its Vf characteristic voltage (typically between 3 and 4 volts for a green LED) will appear across it.  Thus, V0 sits at close to Vf plus whatever drops across the resistors.
*The same as for other diodes, LED forward current increases exponentially with voltage (Ref: wikipedia on LED physics) hence voltage change is tiny over large changes in current when an LED is emitting light.  In other words, if the LED is lighting up, its voltage will be close (ie within a few dozen millivolts) to its characteristic band gap voltage.  See petervis.com's led-resistor-calculator for a "Chart by Colour" that shows characteristic Vf forward voltages.

@jwat7 first of all thanks for the answer but there are still some tgings I don't understand.. How could pitting the led in series disconnect V0 from the ground? And how would adding it could possibly raise the voltage? Thanks again!

@lucacerone See edit 1

Can you help me understand what's going on?

that pin controls the contrast and it needs to be 3.5 - 4.x volt (typical) below Vcc. an led in conduction would drop 2 - 3v, depending on the led, making that pin's potential much closer to Vcc -> minimum contrast so you cannot see the text being displayed.

thanks for your answer! In order for the led to cause a drop in voltage shouldn't it's resistance be quite high? I can add a 1k ohm resistor in series and still get enough contrast to read the text. Or are there other ways by which the led can cause the voltage drop?


text:
Deciphering AD7730 outputs
I am currently working with a AD7730 chip for analog-digital conversion. The chip is programmable, and I have been pulling code from GitHub as well as other links.
I am unfamiliar with SPI (the communication protocol it uses), which I believe is most of the problem. I have been using the code pulled from this library on GitHub as well as its wiring diagram.

The wiring diagram above is nearly identical to my wiring with the only exception that the load cell and amplifier have been replaced with a voltage source. Here is the header file for the code:
#ifndef AD7730_h
#define AD7730_h

#include "Arduino.h"
#include "SPI.h"
#include "Math.h"

class AD7730 {
    public:
        AD7730(int resetPin, int readyPin, int chipSelect);
        void reset(); // resets the AD7730 chip. Equivalent to a power down power up.
        void internalCalibrate(); // performs internal zero and full scale calibrations of the chip
        void systemZeroCalibrate(); // performs system zero scale calibration only of the system (sets the intercept to zero in the linear transfer function)
        void systemFullCalibrate(); // performs full scale calibration of the system.
        void waitForReady(); // pause until ready pin goes low
        void offsetDAC(float offset); // Sets the DAC tare offset value. Allowed range is -40 to 40 (mV) in increments of 2.5 mV
        void range(int range); // Sets the voltage range (gain) of the chip. Allowed values are 10, 20, 40, 80. 10mv range is most sensitive
        void vRef(float volts); // Sets the value of the high reference voltage. Allowed values are 2.5, 5 volts
        void channel(int chan); // Sets the input channel (1 or 2)
        void filter(int avg); // Sets the number of samples to be averaged by the smoothing filter. Default is 512. Max smoothing is 4095.
        void continuousConversionMode(); // places the chip in continuous conversion mode (but does not begin continuous reading)
        void unipolar(); // sets the chip in unipolar conversion mode
        void bipolar(); // sets the chip in bipolar conversion mode (default)
        unsigned long read(); // takes a single reading of the raw result from the AD7730 chip using the parameters set above.
        float readVoltage(); // takes a single voltage reading from the chip using the parameters set above and converts to a voltage.
    private:
        int _resetPin;
        int _readyPin;
        int _CS;
};

#endif

Here is the class file:
#include "Arduino.h"
#include "AD7730.h"
#include "SPI.h"
#include "Math.h"

AD7730::AD7730(int resetPin, int readyPin, int chipSelect) {
    SPI.begin();
    SPI.setDataMode(SPI_MODE3);
    SPI.setBitOrder(MSBFIRST);
    SPI.setClockDivider(SPI_CLOCK_DIV128);

    pinMode(resetPin, OUTPUT);
    pinMode(readyPin, INPUT);
    pinMode(chipSelect, OUTPUT);
    pinMode(MISO, INPUT);
    pinMode(MOSI, OUTPUT);
    digitalWrite(resetPin, HIGH);
    digitalWrite(chipSelect, HIGH);

    _resetPin = resetPin;
    _readyPin = readyPin;
    _CS = chipSelect;
}

void AD7730::reset() {
    // perform a hardware reset using the reset pin on the chip
    digitalWrite(_resetPin, LOW);
    delay(200);
    digitalWrite(_resetPin, HIGH);
    delay(200);
}

void AD7730::internalCalibrate() {
    digitalWrite(_CS, LOW);
    SPI.transfer(0x12); // set next operation as single read of Mode register (2 byte register)
    int byte1 = SPI.transfer(0x00); // read first byte
    int byte2 = SPI.transfer(0x00); // read second byte

    byte1 = (byte1 & 0x1f) | (0x4 << 5); // update byte1 to write internal zero scale calibration to chip

    SPI.transfer(0x02); // set next operation as single write to Mode register
    SPI.transfer(byte1); // write first byte
    SPI.transfer(byte2); // write updated second byte
    digitalWrite(_CS, HIGH);

    waitForReady(); // wait for internal zero scale calibration to complete

    byte1 = (byte1 & 0x1f) | (0x5 << 5); // update byte1 to write internal full scale calibration to chip

    digitalWrite(_CS, LOW);
    SPI.transfer(0x02); // set next operation as single write to Mode register
    SPI.transfer(byte1); // write first byte
    SPI.transfer(byte2); // write updated second byte
    digitalWrite(_CS, HIGH);

    waitForReady(); // wait for internal full scale calibration to complete
}

void AD7730::systemZeroCalibrate() {
    digitalWrite(_CS, LOW);
    SPI.transfer(0x12); // set next operation as single read of Mode register (2 byte register)
    int byte1 = SPI.transfer(0x00); // read first byte
    int byte2 = SPI.transfer(0x00); // read second byte

    byte1 = (byte1 & 0x1f) | (0x6 << 5); // update byte1 to write system zero scale calibration to chip

    SPI.transfer(0x02); // set next operation as single write to Mode register
    SPI.transfer(byte1); // write first byte
    SPI.transfer(byte2); // write updated second byte
    digitalWrite(_CS, HIGH);

    waitForReady(); // wait for system zero scale calibration to complete
}

void AD7730::systemFullCalibrate() {

    digitalWrite(_CS, LOW);
    SPI.transfer(0x12); // set next operation as single read of Mode register (2 byte register)
    int byte1 = SPI.transfer(0x00); // read first byte
    int byte2 = SPI.transfer(0x00); // read second byte

    byte1 = (byte1 & 0x1f) | (0x7 << 5); // update byte1 to write system zero scale calibration to chip

    SPI.transfer(0x02); // set next operation as single write to Mode register
    SPI.transfer(byte1); // write first byte
    SPI.transfer(byte2); // write updated second byte
    digitalWrite(_CS, HIGH);

    waitForReady(); // wait for system zero scale calibration to complete
}

void AD7730::waitForReady() {
    while(digitalRead(_readyPin)) {
        // keep waiting as long as ready pin remains HIGH
    }
}

void AD7730::offsetDAC(float offset) {
    int index = (int)(offset/2.5);
    int sign = 0;
    if (index < 0) {
        sign = 1;
        index *= -1;
    }
    int toSend = (sign << 5 | index); // format offset setting as byte to send to DAC register

    digitalWrite(_CS, LOW);
    SPI.transfer(0x04); // set next operation as single write to the DAC register
    SPI.transfer(toSend); // write data to DAC register
    digitalWrite(_CS, HIGH);
}

void AD7730::range(int range) {
    // format range setting is 2 bits to write to Mode register
    int bits;
    if (range <= 10) {
        bits = 0;
    } else if(range <= 20) {
        bits = 1;
    } else if(range <= 40) {
        bits = 2;
    } else {
        bits = 3;
    }

    digitalWrite(_CS, LOW);
    SPI.transfer(0x12); // set next operation as single read of Mode register (16 bit register)
    int byte1 = SPI.transfer(0xff); // read first byte
    int byte2 = SPI.transfer(0xff); // read second byte

    byte2 = (0xcf & byte2) | (bits << 4); // replace current range bits with specified bits

    SPI.transfer(0x02); // set next operation as single write to Mode register
    SPI.transfer(byte1); // write first byte
    SPI.transfer(byte2); // write updated second byte
    digitalWrite(_CS, HIGH);
}

void AD7730::vRef(float volts) {
    int bit;
    if(volts <= 2.5) {
        bit = 0;
    } else {
        bit = 1;
    }

    digitalWrite(_CS, LOW);
    SPI.transfer(0x12); // set next operation as single read of Mode register (16 bit register)
    int byte1 = SPI.transfer(0x00); // read first byte
    int byte2 = SPI.transfer(0x00); // read second byte

    byte2 = (0x7f & byte2) | (bit << 7); // replace current range bits with specified bits

    SPI.transfer(0x02); // set next operation as single write to Mode register
    SPI.transfer(byte1); // write first byte
    SPI.transfer(byte2); // write updated second byte
    digitalWrite(_CS, HIGH);
}

void AD7730::channel(int chan) {
    int bits;
    if (chan==1) {
        bits = 0;
    } else {
        bits = 1;
    }

    digitalWrite(_CS, LOW);
    SPI.transfer(0x12); // set next operation as single read of Mode register (16 bit register)
    int byte1 = SPI.transfer(0x00); // read first byte
    int byte2 = SPI.transfer(0x00); // read second byte

    byte2 = (0xfc & byte2) | bits; // replace current channel bits with specified bits

    SPI.transfer(0x02); // set next operation as single write to Mode register
    SPI.transfer(byte1); // write first byte
    SPI.transfer(byte2); // write updated second byte
    digitalWrite(_CS, HIGH);
}

void AD7730::filter(int avg) {
    digitalWrite(_CS, LOW);
    SPI.transfer(0x13); // set next operation as single read of Filter register (24 bit register)
    int byte1 = SPI.transfer(0x00); // read first byte
    int byte2 = SPI.transfer(0x00); // read second byte
    int byte3 = SPI.transfer(0x00); // read third byte

    // trim input parameter to 12 bits
    if (avg > 4095) {
        avg = 4095;
    }
    byte1 = avg >> 4; // fill byte1 with 8 most signicant bits of avg
    byte2 = (byte2 & 0xf) | avg << 8; // 4 least significant bits of avg spill over to byte2

    SPI.transfer(0x03); // set next operation as single write to Filter register
    SPI.transfer(byte1);
    SPI.transfer(byte2);
    SPI.transfer(byte3);
    digitalWrite(_CS, HIGH);
}

void AD7730::unipolar() {

    digitalWrite(_CS, LOW);
    SPI.transfer(0x12); // set next operation as single read of Mode register (16 bit register)
    int byte1 = SPI.transfer(0x00); // read first byte
    int byte2 = SPI.transfer(0x00); // read second byte

    byte1 = (byte1 & 0xef) | 0x10; // configure unipolar conversion mode

    SPI.transfer(0x02); // set next operation as single write to Mode register
    SPI.transfer(byte1); // write first byte
    SPI.transfer(byte2); // write second byte
    digitalWrite(_CS, HIGH);
}

void AD7730::bipolar() {

    digitalWrite(_CS, LOW);
    SPI.transfer(0x12); // set next operation as single read of Mode register (16 bit register)
    int byte1 = SPI.transfer(0x00); // read first byte
    int byte2 = SPI.transfer(0x00); // read second byte

    byte1 = (byte1 & 0xef); // configure bipolar conversion mode

    SPI.transfer(0x02); // set next operation as single write to Mode register
    SPI.transfer(byte1); // write first byte
    SPI.transfer(byte2); // write second byte
    digitalWrite(_CS, HIGH);
}

void AD7730::continuousConversionMode() {
    digitalWrite(_CS, LOW);
    SPI.transfer(0x12); // set next operation as single read of Mode register (16 bit register)
    int byte1 = SPI.transfer(0x00); // read first byte
    int byte2 = SPI.transfer(0x00); // read second byte

    byte1 = (byte1 & 0x1f) | (0x01 << 5); // configure for continuous conversion mode

    SPI.transfer(0x02); // set next operation as single write to Mode register
    SPI.transfer(byte1); // write first byte
    SPI.transfer(byte2); // write second byte
    digitalWrite(_CS, HIGH);
}

unsigned long AD7730::read() {
    // use when chip is in continuous conversion mode. This function takes a single reading so should be used in a loop.
    unsigned long result;

    digitalWrite(_CS, LOW);
    SPI.transfer(0x11); // set next operation as single read from Data register (24 bit register assuming the chip is used in 24 bit mode)
    digitalWrite(_CS, HIGH);

    waitForReady();

    digitalWrite(_CS, LOW);
    int byte1 = SPI.transfer(0xff);
    int byte2 = SPI.transfer(0xff);
    int byte3 = SPI.transfer(0xff);
    digitalWrite(_CS, HIGH);

    result = byte1*256L*256L + byte2*256L + byte3;
    return result;
}

float AD7730::readVoltage() {
    digitalWrite(_CS, LOW);
    SPI.transfer(0x12); // set next operation as single read of Mode register (16 bit register)
    int byte1 = SPI.transfer(0x00); // read first byte
    int byte2 = SPI.transfer(0x00); // read second byte
    digitalWrite(_CS, HIGH);

    unsigned long raw = read();
    int unipolar = (byte1 & 0xe0) >> 4; // mask out and shift polarity bit; 0 is bipolar, 1 is unipolar
    float mV;

    int range = (byte2 & 0xc0) >> 4; // mask out and shift range bits
    if (range == 0) {
        range = 10;
    } else if (range == 1) {
        range = 20;
    } else if (range == 2) {
        range = 40;
    } else {
        range = 80;
    }

    if (!unipolar) {
        mV = (float)range*((float)raw - (float)8388608)/(float)8388608;
        return mV;
    } else {
        mV = (float)range*(float)raw/(float)16777216;
        return mV;
    }
}

And here is the Arduino file that uses these two library files:
#include <AD7730.h>

AD7730 adc(8,9,10); // create new instance with reset pin = 8, ready pin = 9, chip select pin = 10

void setup() {
  Serial.begin(9600);
  adc.reset();          // reset the AD7730 chip
  adc.filter(512);      // set digital filter to 512 samples (This setting provides good filtering of 50 hz and 60 hz noise)
  adc.range(10);        // set voltage range to 10 millivolts (this sets the gain of the internal amplifier)
  adc.offsetDAC(0);     // use this function to correct for a wheatstone bridge circuit whose resistors aren't perfectly balanced
  adc.unipolar();       // set chip to unipolar mode
  adc.internalCalibrate();          // run internal calibration of chip before reading voltages
  adc.continuousConversionMode();   // place chip in continuous conversion mode
}

long result;            // declare variable to hold conversion results. Since the AD7730 is a 24bit ADC, the 16bit int data type will not work for this.

void loop() {
  result = adc.read();              // take a single conversion result from the chip
  Serial.println(result);           // print conversion result to the serial monitor
}

Running the above Arduino code produces output, albeit not correct. Putting the chip in its unipolar 10 mV range mode somehow outputs values of 40 mV when the analog signal is set to 0.00 mV. As the signal is increased or decreased in voltage, the output responds correspondingly but not according to the prescribed gain on the data sheet and sometimes it appears to change non-linearly. This happens with all voltage ranges and both the unipolar and bipolar modes: the output signals do not match the input signals to any degree.
I am wondering if this has to do with the conversion to mV at the bottom of the class file. Specifically,
if (!unipolar) {
    mV = (float)range*((float)raw - (float)8388608)/(float)8388608;
    return mV;
} else {
    mV = (float)range*(float)raw/(float)16777216;
    return mV;
}

However, given that the ADC is reading with 24 bits, the 8388608 and 16777216 are accurate. Any help would be appreciated. I have been trying to troubleshoot this for about a month with no success.

The conversion seems legit. Did you change anything to the library or to the provided example? If not, you may want to collect more precise data and file an issue on the library's GitHub project.

Nothing has been changed from the library or the provided example. The only difference is that I am using a voltage supply for my ADC signal rather than some sort of load cell.

If the circuit is build out from breadboard, I would want to check if the crystal really oscillate, the tray capacitance plus the 22pf capacitors might not match the load capacitance of the crystal that you purchased.

Are you sure there is nothing wrong with your calibration process?


text:
I can't get my interrupt to control my project
I'm building a programmable resin pump for my resin printer. The goal is to enable the ability to set a print volume and print time provided by the printer. The pump would then pump at full speed to cover the build plate, then continue at a lower speed to continue filling until the print is complete. Other features would be added as needed.
The problem that I'm having is that I can control everything by typing the commands on the keyboard, but the interrupt is not working as expected. Only the Left and Right commands work, but Up and Enter do nothing, and Down freezes the Arduino. The other buttons aren't connected yet.
When commands are issued via keyboard or button successfully, the command is printed to the serial terminal, e.g. #CMD# UP.
When using the buttons, Up and Enter (center) do nothing. Left and Right function properly, but Down begins to return the command and freezes the Arduino at #C so that even the keyboard commands do nothing.
I've tried changing the byte values of Up, Down, Left, Right, and Enter to a number of different values, but no change was noted.
What is going wrong?
Sketch
/*
 Sub Menu

 https://lcdmenu.forntoh.dev/examples/submenu

*/

#include <ItemSubMenu.h>
#include <ItemInput.h>
#include <LcdMenu.h>
#include <utils/commandProccesors.h>

// #define is an alternate way of declaring a const
#define LCD_ROWS 4
#define LCD_COLS 20

#define COMMONPIN 2
const byte BUTTONPINS[] = {4,5,6,7,8,9,10,11};

// Define commands as
#define UP 56        // NUMPAD 8
#define DOWN 50      // NUMPAD 2
#define LEFT 52      // NUMPAD 4
#define RIGHT 54     // NUMPAD 6
#define ENTER 53     // NUMPAD 5
#define BACK 55      // NUMPAD 7
#define BACKSPACE 8  // BACKSPACE
#define CLEAR 46     // NUMPAD .

// Assigned based on the hardware directional buttons
const byte commandOrder[8] = {UP,DOWN,LEFT,RIGHT,ENTER,BACK,BACKSPACE,CLEAR};

unsigned long lastFire = 0;

extern MenuItem* autofillMenu[];
extern MenuItem* semiautofillMenu[];
extern MenuItem* manualfillMenu[];
extern MenuItem* selfcleanMenu[];
extern MenuItem* settingsMenu[];

#define CHARSET_SIZE 10
// Charset used for entering values
char charset[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
// Active index of the charset
int8_t charsetPosition = -1;

// Declare the call back functions
void setVolumeCallback(char* value);
void setTimeCallback(char* value);

// Define the main menu
MAIN_MENU(
  ITEM_BASIC("   *Resin Pump*"),
  ITEM_SUBMENU("Auto Fill", autofillMenu),
  ITEM_SUBMENU("Semi-Auto Fill", semiautofillMenu),
  ITEM_SUBMENU("Manual Pump", manualfillMenu),
  ITEM_SUBMENU("Self-Clean", selfcleanMenu),
  ITEM_SUBMENU("Settings", settingsMenu));
// Auto-Fill
SUB_MENU(autofillMenu, mainMenu,
         ITEM_BASIC("   *Auto Fill*"),
         ITEM_INPUT("Set Vol. (ml)", "200", setVolumeCallback),  // defalt to 200 ml (create a variable)
         ITEM_INPUT("Set Time", "hh:mm", setTimeCallback),       // default to 0's (create a variable)
         ITEM_BASIC("Start")                                     // Execute the command to fill the vat over the specified time span.
);
// Semi-Auto Fill
SUB_MENU(semiautofillMenu, mainMenu,
         ITEM_BASIC(" *Semi-Auto Fill*"),
         ITEM_INPUT("Set Vol. (ml)", "200", setVolumeCallback),  // defalt to 200 ml (create a variable)
         ITEM_BASIC("Start")                                     // Execute the command to fill the vat immediately.
);
// Manual Control
SUB_MENU(manualfillMenu, mainMenu,
         ITEM_BASIC(" *Manual Control*"),
         ITEM_BASIC("Fill (out)"),  // Execute the command to pump out,
         ITEM_BASIC("Empty (in)"),  // Execute the command to pump in,
         ITEM_BASIC("Stop")         // Execute the command to stop pumping.
);
// Self-Clean
SUB_MENU(selfcleanMenu, mainMenu,
         ITEM_BASIC("   *Self-Clean*"),
         ITEM_BASIC("Start"));
// Settings
SUB_MENU(settingsMenu, mainMenu,
         ITEM_BASIC("    *Settings*"),
         ITEM_BASIC("Max Volume of Vat"),
         ITEM_BASIC("Default Volume"),
         ITEM_BASIC("Resin Amount"),
         ITEM_BASIC("Resin Overhead"),
         ITEM_BASIC("Pump Flow Rate"),
         ITEM_BASIC("Default Pump Speed"),
         ITEM_BASIC("Print Start Delay"));

LcdMenu menu(LCD_ROWS, LCD_COLS);

void setup() {
  Serial.begin(9600);
  configureCommon();

  menu.setupLcdWithMenu(0x27, mainMenu);
  attachInterrupt(digitalPinToInterrupt(COMMONPIN), pressInterrupt,  FALLING);
}

void loop() {
  // TODO: Remove check for serial and Serial.read, these will be replaced
  // by physical buttons and an interrupt.
  if (!Serial.available())
    return;
  char command = Serial.read();
  processMenuCommand(menu, command, charsetPosition, charset, CHARSET_SIZE, UP, DOWN, ENTER, BACK, CLEAR, BACKSPACE, LEFT, RIGHT);
}
/**
 * Define callbacks
 */
// setVolume is share with both Auto Fill and Semi-Auto Fill

void setVolumeCallback(char* value) {
  // Do stuff with value
  Serial.print(F("# "));
  Serial.println(value);
}

void setTimeCallback(char* value) {
  // Do stuff with value
  Serial.print(F("# "));
  Serial.println(value);
}

/*** Begin Button Interrupt Watching ***/

void pressInterrupt() { // ISR
  if (millis() - lastFire < 200) { // Debounce
    return;
  }
  lastFire = millis();

  configureDistinct(); // Setup pins for testing individual buttons

  for (int i = 0; i < sizeof(BUTTONPINS) / sizeof(int); i++) { // Test each button for press
    if (!digitalRead(BUTTONPINS[i])) {
      execCommand(i);
    }
  }
  configureCommon(); // Return to original state
}

void configureCommon() {
  pinMode(COMMONPIN, INPUT_PULLUP);
  for (int i = 0; i < sizeof(BUTTONPINS) / sizeof(int); i++) {
    pinMode(BUTTONPINS[i], OUTPUT);
    digitalWrite(BUTTONPINS[i], LOW);
  }
}

void configureDistinct() {
  pinMode(COMMONPIN, OUTPUT);
  digitalWrite(COMMONPIN, LOW);
  for (int i = 0; i < sizeof(BUTTONPINS) / sizeof(int); i++) {
    pinMode(BUTTONPINS[i], INPUT_PULLUP);
  }
}

void execCommand(int buttonIndex) {
  byte command =  commandOrder[buttonIndex];

  processMenuCommand(menu, command, charsetPosition, charset, CHARSET_SIZE, UP, DOWN, ENTER, BACK, CLEAR, BACKSPACE, LEFT, RIGHT);
}

Schematic

Welcome to SE/Arduino! Please take the [tour] to learn how this site works, and you might want to read "[ask]" (again). You forgot to ask an answerable specific question... Please [edit] your post to add that, the schematic of your design, and what you already tried to debug. You might want to reduce your code to a minimal, complete and reproducible source, too. My next step would be to use some output pin as debug aid and toggle it in the ISR, to verify the assumptions.

What does processMenuCommand do? I suspect it does too much to be handled in an interrupt.

Human input is slow.  Trying to use an interrupt to catch human input is adding unnecessary complication to your project.  It would be better to ditch the interrupts and just read the buttons normally.

@Nick Gammon I was unaware of limitations in this sense. I did some brief research in responding to your comment and found the following which may be helpful to me. https://www.digikey.com/en/maker/tutorials/2022/the-dos-and-donts-of-using-arduino-interrupts

The BUTTONPINS contains bytes but in the setup loop you are dividing it by sizeof(int). So half of the buttons are left floating and catching radio... Btw you can use for (byte pin : BUTTONPINS) {

I resolved my problem by following the guidance that I linked to from digikey. My solution:
/*
 Sub Menu

 https://lcdmenu.forntoh.dev/examples/submenu

*/

#include <ItemSubMenu.h>
#include <ItemInput.h>
#include <LcdMenu.h>
#include <utils/commandProccesors.h>

// #define is an alternate way of declaring a const
#define LCD_ROWS 4
#define LCD_COLS 20
#define DELAY 100
#define COMMONPIN 2
const byte BUTTONPINS[] = {4,5,6,7,8,9,10,11};
// Used to indicate if the interrupt was triggered
// If not, set to -1.
int8_t interruptTrigger = -1;

// Define commands as
#define UP 56        // NUMPAD 8
#define DOWN 50      // NUMPAD 2
#define LEFT 52      // NUMPAD 4
#define RIGHT 54     // NUMPAD 6
#define ENTER 53     // NUMPAD 5
#define BACK 55      // NUMPAD 7
#define BACKSPACE 8  // BACKSPACE
#define CLEAR 46     // NUMPAD .

// Assigned based on the hardware directional buttons
const byte commandOrder[] = {UP,DOWN,LEFT,RIGHT,ENTER,BACK,CLEAR,BACKSPACE};

unsigned long lastFire = 0;

extern MenuItem* autofillMenu[];
extern MenuItem* semiautofillMenu[];
extern MenuItem* manualfillMenu[];
extern MenuItem* selfcleanMenu[];
extern MenuItem* settingsMenu[];

#define CHARSET_SIZE 10
// Charset used for entering values
char charset[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
// Active index of the charset
int8_t charsetPosition = -1;

// Declare the call back functions
void setVolumeCallback(char* value);
void setTimeCallback(char* value);

// Define the main menu
MAIN_MENU(
  ITEM_BASIC("   *Resin Pump*"),
  ITEM_SUBMENU("Auto Fill", autofillMenu),
  ITEM_SUBMENU("Semi-Auto Fill", semiautofillMenu),
  ITEM_SUBMENU("Manual Pump", manualfillMenu),
  ITEM_SUBMENU("Self-Clean", selfcleanMenu),
  ITEM_SUBMENU("Settings", settingsMenu));
// Auto-Fill
SUB_MENU(autofillMenu, mainMenu,
         ITEM_BASIC("   *Auto Fill*"),
         ITEM_INPUT("Set Vol. (ml)", "200", setVolumeCallback),  // defalt to 200 ml (create a variable)
         ITEM_INPUT("Set Time", "hh:mm", setTimeCallback),       // default to 0's (create a variable)
         ITEM_BASIC("Start")                                     // Execute the command to fill the vat over the specified time span.
);
// Semi-Auto Fill
SUB_MENU(semiautofillMenu, mainMenu,
         ITEM_BASIC(" *Semi-Auto Fill*"),
         ITEM_INPUT("Set Vol. (ml)", "200", setVolumeCallback),  // defalt to 200 ml (create a variable)
         ITEM_BASIC("Start")                                     // Execute the command to fill the vat immediately.
);
// Manual Control
SUB_MENU(manualfillMenu, mainMenu,
         ITEM_BASIC(" *Manual Control*"),
         ITEM_BASIC("Fill (out)"),  // Execute the command to pump out,
         ITEM_BASIC("Empty (in)"),  // Execute the command to pump in,
         ITEM_BASIC("Stop")         // Execute the command to stop pumping.
);
// Self-Clean
SUB_MENU(selfcleanMenu, mainMenu,
         ITEM_BASIC("   *Self-Clean*"),
         ITEM_BASIC("Start"));
// Settings
SUB_MENU(settingsMenu, mainMenu,
         ITEM_BASIC("    *Settings*"),
         ITEM_BASIC("Max Volume of Vat"),
         ITEM_BASIC("Default Volume"),
         ITEM_BASIC("Resin Amount"),
         ITEM_BASIC("Resin Overhead"),
         ITEM_BASIC("Pump Flow Rate"),
         ITEM_BASIC("Default Pump Speed"),
         ITEM_BASIC("Print Start Delay"));

LcdMenu menu(LCD_ROWS, LCD_COLS);

void setup() {
  Serial.begin(9600);
  configureCommon();

  menu.setupLcdWithMenu(0x27, mainMenu);
  attachInterrupt(digitalPinToInterrupt(COMMONPIN), pressInterrupt,  FALLING);
}

void loop() {
  // TODO: Remove check for serial and Serial.read, these will be replaced
  //       by physical buttons and an interrupt.
  //if (!Serial.available()) return;
  //char command = Serial.read();

  // If the trigger was set, ignore the serial command and redefine command to use the button command
  if (interruptTrigger > -1) {
    char command = commandOrder[interruptTrigger];
    processMenuCommand(menu, command, charsetPosition, charset, CHARSET_SIZE,
                      UP, DOWN, ENTER, BACK, CLEAR, BACKSPACE, LEFT, RIGHT);
    interruptTrigger = -1;  // Now that the trigger has been read, reset the trigger
  }

}
/**
 * Define callbacks
 */
// setVolume is share with both Auto Fill and Semi-Auto Fill
void setVolumeCallback(char* value) {
  // Do stuff with value
  Serial.print(F("# "));
  Serial.println(value);
}
void setTimeCallback(char* value) {
  // Do stuff with value
  Serial.print(F("# "));
  Serial.println(value);
}

/*** Begin Button Interrupt Watching ***/

void pressInterrupt()
{ // ISR
  if (millis() - lastFire < DELAY) { // Debounce
    return;
  }
  lastFire = millis();

  configureDistinct(); // Setup pins for testing individual buttons
  for (int i = 0; i < sizeof(BUTTONPINS); i++)
  { // Test each button for press
    if (!digitalRead(BUTTONPINS[i]))
    {
      interruptTrigger = i; // Set the interrupt trigger (reset elsewhere)
      /* NOT PICKING UP 4 (ENTER) */
    }
  }
  configureCommon(); // Return to original state
}

void configureCommon()
{
  pinMode(COMMONPIN, INPUT_PULLUP);
  for (int i = 0; i < sizeof(BUTTONPINS); i++)
  {
    pinMode(BUTTONPINS[i], OUTPUT);
    digitalWrite(BUTTONPINS[i], LOW);
  }
}

void configureDistinct()
{
  pinMode(COMMONPIN, OUTPUT);
  digitalWrite(COMMONPIN, LOW);
  for (int i = 0; i < sizeof(BUTTONPINS); i++)
  {
    pinMode(BUTTONPINS[i], INPUT_PULLUP);
  }
}

I also had to adjust my loops which were only allowing me to check 4 inputs. by excluding / sizeof(int) I was able to detect all of the button presses. I'm sharing in case someone else runs into a similar situation.

interruptTrigger should be declared volatile. Otherwise the compiler may optimize away any changes to it.

Thank you! I missed this!

You are probably doing too much in your interrupt routine (ISR). See my answer here about using interrupts.
I also have material on my web site which may be helpful.
A comment you linked to https://www.digikey.com/en/maker/tutorials/2022/the-dos-and-donts-of-using-arduino-interrupts which sensibly suggests merely setting a flag in the interrupt routine, and then doing something in your main loop if the flag is set.
Alternatively, as another comment suggested, just detect button presses in the main loop. You will iterate through it fast enough that this should be sufficient.


text:
HID keyboard: send modifier keys only
I want to send modifier keys like shift, alt, ctrl, etc. without any other key.
It should be theoretically possible due to the fact that it works for my normal keyboard (tested it with Xoutput and games).
For now I have to send dummy keystrokes like scroll lock (0xCF) to send the modifiers.
I'm using Arduino core for the ESP32 with the ESP32S3 Dev Module.
#include "USBHIDKeyboard.h"
USBHIDKeyboard Keyboard;
Keyboard.press(KEY_LEFT_CTRL); Keyboard.write(0xCF); Keyboard.write(0xCF);
delay(1000);
Keyboard.release(KEY_LEFT_CTRL); Keyboard.write(0xCF); Keyboard.write(0xCF);

This works, but it's realy ugly: sometimes the scroll lock LED flashes and in games the settings sometimes see the scroll lock and complain.
Any ideas?

You can use Keyboard.pressRaw(), 0xE0 - 0xE8 should be the modifiers.
size_t USBHIDKeyboard::pressRaw(uint8_t k) {
  uint8_t i;
  if (k >= 0xE0 && k < 0xE8) {
    // it's a modifier key
    _keyReport.modifiers |= (1<<(k-0x80));
  } else if (k && k < 0xA5) {
    // Add k to the key report only if it's not already present
    // and if there is an empty slot.
    if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && _keyReport.keys[2] != k && _keyReport.keys[3] != k && _keyReport.keys[4] != k && _keyReport.keys[5] != k) {
      for (i=0; i<6; i++) {
        if (_keyReport.keys[i] == 0x00) {
           _keyReport.keys[i] = k;
           break;
        }
      }
      if (i == 6) {
        return 0;
      }
    }
  } else {
    // not a modifier and not a key
    return 0;
  }
  sendReport(&_keyReport);
  return 1;
}

USBHIDKeyboard.cpp


text:
PulseIN not recognised
I have included the library for the HCSR04 echo sounder, but pulseIN is not recognised; it never goes orange either.
I have tried multiple libraries, and closing down the IDE and opening it back up.

There is no pulseIN() in the Arduino core. The function you are looking for is named pulseIn(). It's in the core library: you do not need to load anything extra. Beware that the language is case-sensitive.

What a simple mistake to make thankyou for giving me the answer.


text:
ATTiny watchdog and interrupt
I'm trying to control an Arduino Barebone from an arduino with relays.
Basically when the attiny starts it should switch on the arduino for 4 seconds.
The Arduino sends a signal back to a digital pin of the attiny and as long as it is set to high the attiny should leave it working.
If it is low the attiny should switch the relay of.
the problem is some changes to the code make the interrupt reset the attiny (which would switch of the arduino) othertimes- in this case.
the interrupt doesn't work at all.
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

int pinBoard = 0;
bool boardOn = false;
bool startBoard_flag = false;
int pinBoardReturn = 3;

volatile boolean f_wdt = 1;

void setup() {
  cli();//disable interrupts during setup
  pinMode(pinBoard, OUTPUT);
  pinMode(pinBoardReturn, INPUT);
  setup_watchdog(9);
  cbi(ADCSRA, ADEN);                   // switch Analog to Digitalconverter OFF
  // cli();//disable interrupts during setup
  for (int i = 0; i < 10; i++) {
    digitalWrite(pinBoard, HIGH);
    delay(100);
    digitalWrite(pinBoard, LOW);
    delay(100);
  }

  PCMSK |= (1 << PCINT1); //sbi(PCMSK,INTERRUPTPIN) also works but I think this is more clear // tell pin change mask to listen to pin2 /pb3 //SBI
  GIMSK |= (1 << PCIE);   // enable PCINT interrupt in the general interrupt mask //SBI

  startBoard();

  DDRB &= ~(1 << DDB1); //cbi(DDRB, DATADIRECTIONPIN);//  set up as input  - pin2 clear bit  - set to zero
  PORTB |= (1 << PB1); //cbi(PORTB, PORTPIN);// disable pull-up. hook up pulldown resistor. - set to zero
}

void startBoard() {
  digitalWrite(pinBoard, HIGH);
  boardOn = true;
  startBoard_flag = false;
  cli();                                  // Disable interrupts
  delay(4000);
}

void shutdownBoard() {
  digitalWrite(pinBoard, LOW);
  boardOn = false;
}

void loop() {
  if (f_wdt == 1) { // wait for timed out watchdog / flag is set when a watchdog timeout occurs
    f_wdt = 0;     // reset flag
    if (startBoard_flag) {
      startBoard();
    }
    bool boardReturn = digitalRead(pinBoardReturn);
    if (boardOn && !boardReturn) {
      shutdownBoard();
    }
    system_sleep();
  }
}

//****************************************************************
// set system into the sleep state
// system wakes up when wtchdog is timed out
void system_sleep() {

  // GIMSK |= _BV(PCIE);                     // Enable Pin Change Interrupts
  // PCMSK |= _BV(PCINT3);                   // Use PB3 as interrupt pin

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // replaces above statement
  sleep_enable();                         // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
  sleep_cpu();                            // sleep

  // PCMSK &= ~_BV(PCINT3);                  // Turn off PB3 as interrupt pin
  sleep_disable();                        // Clear SE bit

  // sei();                                  // Enable interrupts
}

//****************************************************************
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(int ii) {

  byte bb;
  int ww;
  if (ii > 9 ) ii = 9;
  bb = ii & 7;
  if (ii > 7) bb |= (1 << 5);
  bb |= (1 << WDCE);
  ww = bb;

  MCUSR &= ~(1 << WDRF);
  // start timed sequence
  WDTCR  |= (1 << WDCE) | (1 << WDE);
  // set new watchdog timeout value
  WDTCR  = bb;
  WDTCR  |= _BV(WDIE);
}
//****************************************************************
// Watchdog Interrupt Service / is executed when  watchdog timed out
ISR(WDT_vect) {
  f_wdt = 1; // set global flag
}

ISR(PCINT_VECTOR) {
  for (int i = 0; i < 4; i++) {
    digitalWrite(pinBoard, HIGH);
    delay(1000);
    digitalWrite(pinBoard, LOW);
    delay(1000);
  }
  startBoard_flag = true;
  f_wdt = 1; // set global flag
}

Sequence like "cli(); delay(...);" is not a very good idea as delay() depends on Timer interrupts.

@MikaelPatel Is it? I believe it's just a loop with "NOP" instructions?
Wait, this: http://forum.arduino.cc/index.php?topic=46452.0 - tells me it uses milis, which does use a timer I believe! (AVR delay functions didn't use timers).

@Paul Might a well check the source code. Do you have a link to the ATtiny core that you are using? Let's check delay().

So i would rather have a counter for the watchdog in order to wait for the specified time?

Disassembling the delay code indicates it uses micros which needs interrupts on to work.
void delay(unsigned long ms)
{
 27a:   cf 92           push    r12
 27c:   df 92           push    r13
 27e:   ef 92           push    r14
 280:   ff 92           push    r15
 282:   cf 93           push    r28
 284:   df 93           push    r29
 286:   6b 01           movw    r12, r22
 288:   7c 01           movw    r14, r24
    uint16_t start = (uint16_t)micros();
 28a:   d3 df           rcall   .-90        ; 0x232 <micros>
 28c:   eb 01           movw    r28, r22

    while (ms > 0) {
 28e:   c1 14           cp  r12, r1
 290:   d1 04           cpc r13, r1
 292:   e1 04           cpc r14, r1
 294:   f1 04           cpc r15, r1
 296:   79 f0           breq    .+30        ; 0x2b6 <delay+0x3c>
        yield();
 298:   ea d0           rcall   .+468       ; 0x46e <yield>
        if (((uint16_t)micros() - start) >= 1000) {
 29a:   cb df           rcall   .-106       ; 0x232 <micros>
 29c:   6c 1b           sub r22, r28
 29e:   7d 0b           sbc r23, r29
 2a0:   68 3e           cpi r22, 0xE8   ; 232
 2a2:   73 40           sbci    r23, 0x03   ; 3
 2a4:   a0 f3           brcs    .-24        ; 0x28e <delay+0x14>
            ms--;
 2a6:   81 e0           ldi r24, 0x01   ; 1
 2a8:   c8 1a           sub r12, r24
 2aa:   d1 08           sbc r13, r1
 2ac:   e1 08           sbc r14, r1
 2ae:   f1 08           sbc r15, r1
            start += 1000;
 2b0:   c8 51           subi    r28, 0x18   ; 24
 2b2:   dc 4f           sbci    r29, 0xFC   ; 252
 2b4:   ec cf           rjmp    .-40        ; 0x28e <delay+0x14>
        }
    }
}
 2b6:   df 91           pop r29
 2b8:   cf 91           pop r28
 2ba:   ff 90           pop r15
 2bc:   ef 90           pop r14
 2be:   df 90           pop r13
 2c0:   cf 90           pop r12
 2c2:   08 95           ret

That appears to confirm that the code in wiring.c is indeed what is being used on the ATtiny85 core:
void delay(unsigned long ms)
{
    uint16_t start = (uint16_t)micros();

    while (ms > 0) {
        yield();
        if (((uint16_t)micros() - start) >= 1000) {
            ms--;
            start += 1000;
        }
    }
}

Turning interrupts off and then doing a delay is a Bad IdeaTM.

So i would rather have a counter for the watchdog in order to wait for the specified time?

Using the watchdog timer is certainly one way of waiting for 4 seconds.

Excellent effort and description.

+1 for the Bad Idea(TM). I like it! The rest of the answer deserves it too of course.


text:
ESP8266 NodeMCU v3 basic questions
Can somebody please tell me what is the operating voltage of ESP8266?
What is the A0 voltage range?
I am powering it up from USB (5v) and have a sensor that comes back with Analog value, to calculate it correctly I am asked to provide "Logical Voltage" value that is either 3300 or 5000 (3.3v or 5v). Sensor is connected to 3.3V port as there is no 5v port on the board.
What do I choose here 3300 or 5000 for NodeMCU V3?
Thank you.

The subtle clue is in the voltage that is available. That is, the only voltage provided on the board is 3.3v. That's a slight hint that the board might run at 3.3v. And you would be right in that assumption.
The ESP8266 chips, as are most modern MCUs more powerful than 8-bit, 3.3v devices.
So you would choose 3300 as your "Logical Voltage" value.  Or better still, measure the 3.3V and find exactly what it is and use that value x 1000 (for example 3317 or 3295).

Thank you @Majenko, this was really helpfull. Do you know by a chance what is the Range of voltage that this board can take on AD0?

0v to 3.3v since 3.3v is the supply voltage.

Thank you very much Majenko! You saved my project with this :)


text:
Distance sensor
I am adding a distance sensor to existing project that uses Arduino due, do I connect the trigger pin and the echo pin of the HC-SR04 ultrasonic sensor directly to  Arduino due which uses 3.3V   while HC-SR04 ultrasonic sensor uses 5V or do I need to use a voltage divider?

Could you tell us a bit more about the thickness sensor?

Reading the datasheet for the sensor will get you the output voltage range of the sensor.

@user17339 Thank you for adding information about what sensor you were writing about.

@Avamander I was just advising OP to read the sensor datasheet.

@ChetanBhargava I mixed up the @.

As suggested in previous answers, you can directly use a Due output to drive the HC-SR04's Trig pin; according to the HC-SR04 spec sheet, that pin operates at TTL levels.  It will see 0 V as a 0-input and will see 3.3 V as a 1-input since it exceeds 2.4 V.  Also see  3.3v input to Arduino digital pin in electronics.stackexchange.
However, the Due's inputs are not 5 V tolerant, so you will need to use a voltage divider between the Echo pin and a Due input.  See second paragraph of arduino.cc's ArduinoBoardDue article:

Warning: Unlike most Arduino boards, the Arduino Due board runs at 3.3V. The maximum voltage that the I/O pins can tolerate is 3.3V. Applying voltages higher than 3.3V to any I/O pin could damage the board.

Well, it depends on the sensor itself. Some sensors run on both 5V and 3.3V. There's a similar question here on StackExchange: How to connect 5V sensors to 3.3V digital input (Due)?
But, in short, if the sensor can't operate in 3.3V, you'll need a level converter /shifter.

The trigger pin is an input, so you can connect that directly to the Due.
The echo pin will however output 5v. You could use a voltage divider to bring that down to 3.3v or a bit lower.


text:
How do I install the latest Arduino IDE on Ubuntu 14.04LTS?
What I've tried:

I downloaded the package for 1.6.7 on Ubuntu 14.04 LTS but when I open it no matter what I try it will not start.
I installed 1.0.5 from the Ubuntu Software Center. I tried to update it but found no solution.

UPDATE: I found my answer in talamaki's answer on that other question linked above.

You say that you downloaded it, have you actually installed it? What command did you use? Where was it installed to (updatedb;locate arduino)? What happens it you try to run it from the command line? Is it in your path (echo $PATH)? You may need to update, or manually fix, the desktop shortcut, which is currently pointing to 1.0.5. Please edit, and expand upon, your original post with more details.

@LinuxAut2115 did you run the install script inside the tar file? Usually it replaces any arduino.desktop launcher present

If you download 1.6.7 from the Arduino Downloads page, un-archive it, and then  double-click the "Arduino" file inside the download, you will get 1.6.7. That's exactly how I use it. I'm going to close this as a duplicate of a similar question. The answer there has more details.

Follow the following step to download, install and run Arduino IDE on Ubuntu

First Download the Tar (tar-bal) from this link http://arduino.cc/en/Main/Software (download the correct 32 / 64 bit linux version ) depends upon your Ubuntu version.
Then goto download folder using terminal (shell) or the folder where you downloaded the tar and unpacked that tar using the following commands
like
cd /Downloads
tar -zxvf arduino-1.6.7-linux32.tgz
where 1.6.7 is the version of ide
you also need java runtime environment for arduino IDE download and install it using the following command
   sudo apt-get install openjdk-7-jre
you also need to provide the UART permissions for your hardware using following commands
sudo chmod a+rw /dev/ttyACM0
where ACM0 is the port number if you are using multiple or many arduinos just give permissions using the above commands by replacing the ACM0 to ACM1 to ACMN

then create a shortcut of arduino ide from the folder where you extract the tar
cd ~/Desktop
ln -s /Downloads/arduino-1.6.7/arduino

and then double click the shortcut to run arduino if it gives permission error then right click the shortcut and in file preferences gives permissions to the shortcut


text:
Arduino Prototype on Breadboard: "avrdude: stk500_recv(): programmer is not responding"
I have created an arduino prototype using the exact instructions found on this page:
https://www.arduino.cc/en/Main/Standalone
However, when I plug in the micro USB power supply and try to upload a program, here's the error I get:
avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0xe0

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0xe0

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0xe0

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0xe0

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0xe0

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0xe0

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0xe0

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0xe0

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0xe0

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0xe0

I have tried the following solutions, to no avail:
1) press the restart button (in a variety of ways and lengths of time)
2) Enable verbose output
3) trying the different board types in the Arduino IDE
4) Checking the COM port
I have no idea what to do I've basically tried everything I could find, on this website and others.
I hope you guys can help! Thanks very much :)

Those instructions do seem to lack one vital bit: the connection between DTR on the USB board, through a 100nF capacitor, to the reset pin of the ATMega328P.

Thank you. So how would I make this connection, given that the reset pin of the ATMega is already connected to a momentary switch?

Just like I said. There's more than one hole in the breadboard...

I will give it a go, thanks. Just to confirm: 100nF = 100 x 10^-9 F?

Yes, but what does that matter? 100nF is 100nF or 0.1uF. No one works in F it is too big.

Either you don't have serial communication, your ATmega is not powered, fused, and clocked correctly, or it does not yet contain a bootloader of compatible configuration.

Check for Baudrate, the Arduino Serial Terminal, and serial port terminal should exactly match.
Or either check your Rx and Tx pins for respective voltages
Either there may be problem related to power supply.
It is better you also mention the code

Remove the pins connected to Tx and Rx while uploading the code , it worrked for me.
also include all the libraries currently used in your program.
Good luck!!


text:
Multiple I2C devices connected to one Arduino Uno?
Is it possible to connect more than one I2C device to an Arduino Uno? I know that the SCL and SDA pins are on analog pins A4 and A5 respectively, but there are also two pins labeled SCL and SDA located next to the AREF pin on the other side of the board. Does that mean I can connect multiple devices to the same board and, if so, how?
For context, I'm currently working on creating a robotic arm that matches its movements to the movements of my arm (I believe this is called a telepresence robot). To do so, I wanted to use a couple of IMUs (specifically the MPU-6050) to record the movements of my wrist and shoulder. Using the TinyMPU6050 library by Gabriel Milan, I've already been able to establish communication with one IMU, but I'm struggling with the second one. I'm already communicating with the arm via the Uno's SPI interface so I can't use that to communicate with a second IMU, although I know it's possible.
I know that similar questions have been asked before, but none of the questions I could find had the exact answers that I needed, so I thought I would ask anyway. This code that I currently have works for one IMU, but I don't know where to begin to add a second one (if it's even possible). Any help that I can get would be greatly appreciated. Cheers!
#include <TinyMPU6050.h>

MPU6050 IMU_1(Wire);

void setup() {
  Serial.begin(9600);

  //initializing and calibrating `IMU_1`
  IMU_1.Initialize();
  Serial.println("Calibrating...");
  IMU_1.Calibrate();
  Serial.println("Calibrated");

  while (!Serial) {
    //empty while loop
  }
}

void loop() {
  IMU_1.execute();
  Serial.println();
  Serial.print("X angle = ");
  Serial.println(IMU_1.GetAngX());
  Serial.print("Y angle = ");
  Serial.println(IMU_1.GetAngY());
  Serial.print("Z angle = ");
  Serial.println(IMU_1.GetAngZ());

  delay(1000);
}

I2C is a multi-drop bus. That means that one set of I2C pins are designed to have multiple devices on it as long as each device has a unique address.
On an Uno the discrete I2C pins and the A4/A5 I2C pins are the same pins. The discrete pins are an attempt to provide a cross-platform standard location for the I2C signals for shields.

So, since I don't have a way of connecting multiple devices to the A4/A5 pins, does that mean that I can connect one IMU to the A4/A5 pins and one to the discrete pins and have it still function as long as I give them different addresses? Thanks for your help!

Yep. Except you don't normally "give" I2C devices addresses (unless you're making them yourself) - you usually are able to select between a couple of addresses using special pins on the I2C devices. If you can't select different addresses then you have the option of an "I2C multiplexer" to select between them.

Adding on to Majenko, you might find A1, A2, A3 on your I2C device, usually these are not connected, by soldering them (individually) you can change the address of your device, which you can then change in your code