body:
Many arduino functions return -1 if something 'fails'. Serial.read for example returns -1 or the infamous ÿ when this function is called while the serial buffer is empty.

As embedded C progammer, I am personally a fan of letting functions return data in the form of modifying pointers which points to passed on addresses and return states with the actual return functionality of a function. I am used to return a 0 if a function is 'not done' or 'failed'.

I see no logic in why many arduino functions return an int type which contains -1 instead of just a 0.

Would it not be better to let functions return a boolean type or an unsigned char type in which false or '0' would indicate a 'failed' process and true or '1' would indicate a 'succesful' process?

Also: if I type:
```if(Serial.read()) {/* body */ }  ```
and ``` Serial.read() ``` returns -1 because the buffer is empty. Will the If's body be executed or not?

title: Why do most arduino function return a -1 instead of a 0

Answers: 4

body:
I suspect that this a legacy from Unix command programming, which was first done in C. For commands that only needed to return status and not data, a return value of zero meant success and any other return value indicated some kind of failure. Individual programmers could designate specific non-zero values for specific error types, if desired.

Remember that the return value comes back to the calling function in a register. And these days the term "Arduino" encompasses a broad range of architectures, including 32-bit ARM Cortex-M. Specifying that the return value is a char offers no advantage in this case.

The boolean datatype is a fairly recent addition to the C language, so it's not surprising that you don't see it used much in existing, portable libraries.

Returning an address from a simple function that just needs to indicate success or failure seems like overkill.

If you really want control over the datatypes, include `stdint.h` and use the types defined therein. If you want an unsigned 8-bit value use `uint8_t` and not `unsigned char`. If you want to allow the compiler to choose the best datatype that is at least 8 bits, use `uint_fast8_tf`.

body:
I cannot assert anything for sure, as I was not involved in the design
of the Arduino APIs. However, just like Elliot Alderson, I suspect this
was inspired by the traditional C APIs. The manual page for `getchar()`,
which is a very old function from the standard C library, states:

> **fgetc**(),  **getc**() and **getchar**() return the character read
> as an _unsigned char_ cast to an _int_ or **EOF** on end of file or
> error.

Given that `EOF` is usually defined as `-1`, this is consistent with the
behavior of `Serial.read()`.

Being beginner-friendly is also a _major_ goal of the API. Pointers are
known to be a _huge_ difficulty for beginners.

There may also be some efficiency considerations involved. Arduino
started on the AVR platform. This is a RISC architecture, with a large
number of generic CPU registers (namely 32). The compiler usually
manages to allocate most local variables to registers. The calling
convention ensures that in most cases function parameters and return
values also go through CPU registers. This means we can avoid many RAM
accesses, which are inherently much slower than register access. Using a
return-by-pointer convention defeats these optimizations.

Lastly, it is a good thing that simple things are easy to write. For
example, an interpreter for single-character commands can be very easily
written as:

```c++
switch (Serial.read()) {
case 'a':
    do_command_a();
    break;
case 'b':
    do_command_b();
    break;
// etc...
}
```

with no need to explicitly test for the serial buffer not being empty.
Obviously, a more complex command language will need a full-blown
interpreter, but the focus of Arduino has always been on _simple_
programs being easy to write.

body:
-1 is returned when "0" would be a perfectly valid response.

To take your example of `Serial.read()`: 0 is a valid byte or ASCII character.  -1 isn't.  If you returned 0 for "failure" then there would be no way of differentiating between that and the valid byte value 0.

body:
Arduino API is port of Processing. Processing is Java API to communicate with a MCU running Firmata. Arduino enabled sketches with the same API to run directly on the MCU.

So for example stream functions from Java stream classes were ported to Arduino API. This includes the [read() function][2], to read one byte. Of course Java and Java basic libraries have inspiration in C++.

For other read and write functions, if the return value is count of bytes written or read then 0 is a valid return value and -1 indicates error.

Processing, Wiring and Arduino were created by interactive arts teachers and students, not by embedded systems developers. So you can't wonder about not ideal data types used. Later some things were improved by software developers.

----------

as embedded C developer you should know that:

 - 0 is a valid value to read, so it can't be a value indicating error
 - 'if' executes if the evaluated value is not 0

  [1]: https://www.arduino.cc/en/Guide/HowtoReferences
  [2]: https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html#read--


body:
I have this codes that works correctly!
```c
#include <DFRobot_sim808.h>
#include <SoftwareSerial.h>

#define PIN_TX    7
#define PIN_RX    8
SoftwareSerial mySerial(PIN_TX,PIN_RX);
DFRobot_SIM808 sim808(&mySerial);//Connect RX,TX,PWR,
char http_cmd[] = "GET /index.php?lat=*******&long=******* HTTP/1.0\r\n"
                        "Host: 04d1a36d.ngrok.io\r\n"
                        "\r\n";
char buffer[512];

void setup() {
  mySerial.begin(9600);
  Serial.begin(9600);
    while(!sim808.init())
  {
      Serial.print("Sim808 init error\r\n");
      delay(1000);
  }
  Serial.print("Sim808 init Success\r\n");
  delay(3000);

  //*********** Attempt DHCP *******************
  while(!sim808.join(F("cmnet"))) {
      Serial.println("Sim808 join network error");
      delay(2000);
  }

  //************ Successful DHCP ****************
  Serial.print("IP Address is ");
  Serial.println(sim808.getIPAddress());

  //*********** Establish a TCP connection ************
  while(!sim808.connect(TCP,"39c309ae.ngrok.io", 80)) {
      Serial.println("Connect error");
  }
  Serial.println("Connection success");

  //*********** Send a GET request *****************
  Serial.println("waiting to fetch...");
  sim808.send(http_cmd, sizeof(http_cmd)-1);
  while (true) {
      int ret = sim808.recv(buffer, sizeof(buffer)-1);
      if (ret <= 0){
          Serial.println("fetch over...");
          break;
      }
      buffer[ret] = '\0';
      Serial.print("Recv: ");
      Serial.print(ret);
      Serial.print(" bytes: ");
      Serial.println(buffer);
      break;
  }

  //************* Close TCP or UDP connections **********
  sim808.close();

  //*** Disconnect wireless connection, Close Moving Scene *******
  sim808.disconnect();
  delay(5000);
  }
  void loop(){
  }
```
Actually i want send two numbers instead of ****** in this line:
```c
char http_cmd[] = "GET /index.php?lat=*******&long=******* HTTP/1.0\r\n"
                        "Host: 04d1a36d.ngrok.io\r\n"
                        "\r\n";
```
to 04d1a642.ngrok.io/index.php for inserting in a database.

but when i use

> sprintf

like this:
```c
void setup(){
sprintf( http_cmd, "GET /index.php?lat=%f&long=%f HTTP/1.0\r\n"
                        "Host: 04d1a662.ngrok.io\r\n"
                        "\r\n", 36.423156, 48.526484);
.
.
.
```
The module doesn't fetch to server for get response!

title: Problem in fetching http get request after put float number

Answers: 0


body:
I'm working on a similar project that can be found in this link
https://howtomechatronics.com/projects/arduino-mecanum-wheels-robot/
It's the same build.
To control the 4 steppers (via the NRF24L01), I have built a remote control ( and you can find the project on the same website).
I have modified a few things and kept on testing on each step that I go through.
For now: my remote control sends X, Y from 1 joystick module and X1, Y1 from a second joystick module, besides mapped value from a potentiometer.
Back to the car, I'm receiving the exact same data and all works fine.
I have tested my circuit,
the power supply is fine and all good.
But I'm facing a problem that I could not detect when it comes to making the steppers move after receiving the data from the transmitter.
This is the code I m using for the receiver:
I'm not familiar with this Library and I feel like I'm only missing a small detail.
(As I said the same circuit was tested with a different code and steppers are running just fine).
Hopefully, you can help me out and spot what's wrong.
Thanks a lot guys.

    #include <SPI.h>
    #include <nRF24L01.h>
    #include <RF24.h>
    #include <AccelStepper.h>
     RF24 radio(7, 8);   // nRF24L01 (CE, CSN)
    const byte address[6] = "00001";
    //unsigned long lastReceiveTime = 0;
    //unsigned long currentTime = 0;
    // Define the stepper motors and the pins the will use
    AccelStepper LeftBackWheel(1, 2, 3);   // (Type:driver, STEP, DIR) - Stepper1
    AccelStepper LeftFrontWheel(1, 4, 5);  // Stepper2
    AccelStepper RightBackWheel(1, 9, 10);  // Stepper3
    AccelStepper RightFrontWheel(1, 41, 40); // Stepper4
    int wheelSpeed = 1500;
    // Max size of this struct is 32 bytes - NRF24L01 buffer limit
    struct Data_Package {
      byte j1PotX;
      byte j1PotY;
      byte j2PotX;
      byte j2PotY;
      byte pot1;

    };
    Data_Package data; //Create a variable with the above structure
    void setup() {
      // Set initial seed values for the steppers
      LeftFrontWheel.setMaxSpeed(3000);
      LeftBackWheel.setMaxSpeed(3000);
       RightFrontWheel.setMaxSpeed(3000);
      RightBackWheel.setMaxSpeed(3000);
      radio.begin();
      radio.openReadingPipe(0, address);
      //radio.setAutoAck(false);
      //radio.setDataRate(RF24_250KBPS);
      radio.setPALevel(RF24_PA_LOW);
      radio.startListening(); //  Set the module as receiver
      Serial.begin(9600);
    }
    void loop() {
      // Check whether we keep receving data, or we have a connection between the two modules
      /*currentTime = millis();
        if ( currentTime - lastReceiveTime > 1000 ) { // If current time is more then 1 second since we have recived the last data, that means we have lost connection
        resetData(); // If connection is lost, reset the data. It prevents unwanted behavior, for example if a drone jas a throttle up, if we lose connection it can keep flying away if we dont reset the function
        }*/
      // Check whether there is data to be received
      if (radio.available()) {
        radio.read(&data, sizeof(Data_Package)); // Read the whole data and store it into the 'data' structure
        //lastReceiveTime = millis(); // At this moment we have received the data
      }

      Serial.print("X1= ");
      Serial.print(data.j1PotX);
      Serial.print("  Y1= ");
      Serial.println(data.j1PotY);
      Serial.println();
      Serial.print("X2= ");
      Serial.print(data.j2PotX);
      Serial.print("  Y2= ");
      Serial.println(data.j2PotY);
      Serial.println(" POT1=  ");
      Serial.println(data.pot1);
      Serial.println();
      delay(1000);
      // Set speed - left potentiometer
      wheelSpeed = map(data.pot1, 0, 255, 100, 3000);

      if (data.j1PotX > 150) {
        moveSidewaysLeft();
      }
      else if (data.j1PotX < 100) {
        moveSidewaysRight();
      }
      else if (data.j1PotY > 160) {
        moveForward();
      }
      else if (data.j1PotY < 100) {
        moveBackward();
      }
      else if (data.j2PotX < 100 & data.j2PotY > 160) {
        moveRightForward();
      }
      else if (data.j2PotX > 160 & data.j2PotY > 160) {
        moveLeftForward();
      }
      else if (data.j2PotX < 100 & data.j2PotY < 100) {
        moveRightBackward();
      }
      else if (data.j2PotX > 160 & data.j2PotY < 100) {
        moveLeftBackward();
      }
      else if (data.j2PotX < 100) {
        rotateRight();
      }
      else if (data.j2PotX > 150) {
        rotateLeft();
      }
      else {
        stopMoving();
      }
      // Execute the steps
      LeftFrontWheel.runSpeed();
      LeftBackWheel.runSpeed();
      RightFrontWheel.runSpeed();
      RightBackWheel.runSpeed();
    }
    void moveForward() {
      LeftFrontWheel.setSpeed(wheelSpeed);
      LeftBackWheel.setSpeed(wheelSpeed);
      RightFrontWheel.setSpeed(wheelSpeed);
      RightBackWheel.setSpeed(wheelSpeed);
    }
    void moveBackward() {
      LeftFrontWheel.setSpeed(-wheelSpeed);
      LeftBackWheel.setSpeed(-wheelSpeed);
      RightFrontWheel.setSpeed(-wheelSpeed);
      RightBackWheel.setSpeed(-wheelSpeed);
    }
    void moveSidewaysRight() {
      LeftFrontWheel.setSpeed(wheelSpeed);
      LeftBackWheel.setSpeed(-wheelSpeed);
       RightFrontWheel.setSpeed(-wheelSpeed);
      RightBackWheel.setSpeed(wheelSpeed);
    }
    void moveSidewaysLeft() {
      LeftFrontWheel.setSpeed(-wheelSpeed);
      LeftBackWheel.setSpeed(wheelSpeed);
      RightFrontWheel.setSpeed(wheelSpeed);
      RightBackWheel.setSpeed(-wheelSpeed);
    }
    void rotateLeft() {
      LeftFrontWheel.setSpeed(-wheelSpeed);
      LeftBackWheel.setSpeed(-wheelSpeed);
       RightFrontWheel.setSpeed(wheelSpeed);
      RightBackWheel.setSpeed(wheelSpeed);
    }
    void rotateRight() {
      LeftFrontWheel.setSpeed(wheelSpeed);

      LeftBackWheel.setSpeed(wheelSpeed);
       RightFrontWheel.setSpeed(-wheelSpeed);
      RightBackWheel.setSpeed(-wheelSpeed);
    }
    void moveRightForward() {
      LeftFrontWheel.setSpeed(wheelSpeed);
      LeftBackWheel.setSpeed(0);
      RightFrontWheel.setSpeed(0);
      RightBackWheel.setSpeed(wheelSpeed);
    }
    void moveRightBackward() {
      LeftFrontWheel.setSpeed(0);
      LeftBackWheel.setSpeed(-wheelSpeed);
      RightFrontWheel.setSpeed(-wheelSpeed);
      RightBackWheel.setSpeed(0);
    }
    void moveLeftForward() {
      LeftFrontWheel.setSpeed(0);
      LeftBackWheel.setSpeed(wheelSpeed);
       RightFrontWheel.setSpeed(wheelSpeed);
      RightBackWheel.setSpeed(0);
    }
    void moveLeftBackward() {
      LeftFrontWheel.setSpeed(-wheelSpeed);
      LeftBackWheel.setSpeed(0);
      RightFrontWheel.setSpeed(0);
      RightBackWheel.setSpeed(-wheelSpeed);
    }
    void stopMoving() {
      LeftFrontWheel.setSpeed(0);
      LeftBackWheel.setSpeed(0);
       RightFrontWheel.setSpeed(0);
      RightBackWheel.setSpeed(0);
    }
    void resetData() {
      // Reset the values when there is no radio connection - Set initial default values
      data.j1PotX = 127;
      data.j1PotY = 127;
      data.j2PotX = 127;
      data.j2PotY = 127;
      data.pot1 = 1;
    }

title: A small problem that I cannot detect, My steppers are not moving for some reason ...?

Answers: 0


body:
I have a similar problem than the discussed here : https://arduino.stackexchange.com/questions/17766/how-to-display-variables-on-0-96-oled-with-u8glib-library/17773#17773

I'd like to know how can I show float variables in place of int variables. What should i modify in this part of my code ?

    char buf[9];
    sprintf (buf, "%d", a);
    u8g.drawStr(18, 3, buf);

    } while( u8g.nextPage() );

    delay(200);

    }

Thanks in advance =D

title: How to display float variables on oled display (0.96'')

Answers: 2

body:
The printf group of functions in the Arduino library don't implement float and double conversions. For those, you need the function

    char *dtostrf(double dval, int8_t width, uint8_t prec, char *buf);
      Convert the double value passed in dval into an ASCII string stored in
      buf. Conversion is done as "[-]d.ddd". The minimum field width of the output
      string (including the '.' and the possible sign for negative values) is given
      in width, and prec determines the number of digits after the decimal. width
      is signed, negative for left adjustment.
      Returns buf.

, which you'll need to call for each float you want to convert.

Note that you could convert several floats into strings, upfront, each into its own character buffer, then use sprintf to format the final buffer - remembering that in `sprintf`'s format string, those buffers contain character strings, which you'll need to specify with '%s' format-specs.

body:
The u8glib library [provides the Arduino's standard `print()`
method][print]. You can the write:

```c++
u8g.setPrintPos(18, 3);
u8g.print(a);
```

and it should work for mostly any type of `a`.

[print]: https://github.com/olikraus/u8glib/wiki/userreference#print


body:
In my use case I have multiple devices connected to the serial ports of an arduino. Currently I write to them using `Serial1.write()`, `Serial2.write()`, etc.

How can I choose the port programmatically, for example:
```
for(int i = 0; i < numDevices; i++){
  Serial[i].write();
}
```

title: How can I use a variable to choose which Serial port to interact with?

Answers: 1

body:
You may use an array of pointers to the actual serial ports. For
example, on an Arduino Mega:

```c++
const size_t PORTS_COUNT = 4;
const HardwareSerial *ports[PORTS_COUNT] = {
    &Serial, &Serial1, &Serial2, &Serial3
};

void setup() {
    for (size_t i = 0; i < PORTS_COUNT; i++)
        ports[i]->begin(9600);
}
```


body:
I'm trying to make the qMenuSystem to work with my I2C Monochrome OLED display but without any luck.
To summarize all here's what's with it :
- the qMenuSystem is using a library called : DigoleSerial but has the things set as SPI connection
- the library itself can work with I2C but i'm receiving some strange errors like this :
```arduino

Arduino: 1.8.9 (Mac OS X), Board: "Arduino/Genuino Uno"

TestMenu:25:42: error: expected primary-expression before '_disp'
 DigoleSerialDisp mydisp=DigoleSerialDisp _disp(&Wire,'\x3C');
                                          ^
exit status 1
expected primary-expression before '_disp'

```
Here is the video of what i'm trying to display:

https://www.youtube.com/watch?v=rjON_enuOGs (I already tried what's suggested in the comments)

Here's the code so far:

```arduino
#define _Digole_Serial_I2C_
#include <DigoleSerial.h>
#include <Wire.h>

#include <qMenuDisplay.h>
#include <qMenuSystem.h>

#include "TestMenu.h"

//DigoleSerialDisp mydisp=DigoleSerialDisp(8,9,10);
//DigoleSerialDisp _disp(&Wire,'\x3C');

DigoleSerialDisp mydisp=DigoleSerialDisp _disp(&Wire,'\x3C');
qMenuSystem menu=qMenuSystem(mydisp);

void setup()
{
  menu.InitMenu(mnuRoot,cntRoot,1);
  Serial.begin(9600);
}

void loop()
{
  int keycode=0;
  int clickedItem=0;

  if (Serial.available()>0)
  {
    switch(Serial.read())
    {
      case 97:
        menu.ProcessMenu(ACTION_DOWN);
        break;
      case 113:
        menu.ProcessMenu(ACTION_UP);
        break;
      case 115:
        clickedItem=menu.ProcessMenu(ACTION_SELECT);
        break;
    }
  }

  if (clickedItem>0)
  {
    // Logic for Root menu
    if (menu.CurrentMenu==mnuRoot)
      switch (clickedItem)
      {
        case 1:
          menu.InitMenu(mnuSubmenu1,cntSubmenu1,1);
          break;
        case 2:
          menu.InitMenu(mnuSubmenu2,cntSubmenu2,1);
          break;
        case 3:
          menu.InitMenu(mnuSubmenu3,cntSubmenu3,1);
          break;
        case 4:
          menu.MessageBox("Some message!");
          break;
      }
    // Logic for Submenu 1
    else if (menu.CurrentMenu==mnuSubmenu1)
      switch (clickedItem)
      {
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
          menu.MessageBox("Item clicked");
          break;
        case 6:
          menu.InitMenu(mnuRoot,cntRoot,1);
          break;
      }
    // Logic for Submenu 2
    else if (menu.CurrentMenu==mnuSubmenu2)
      switch (clickedItem)
      {
        case 1:
          menu.MessageBox("On");
          break;
        case 2:
          menu.MessageBox("Off");
          break;
        case 3:
          menu.InitMenu(mnuRoot,cntRoot,2);
          break;
      }
    // Logic for Submenu 3
    else if (menu.CurrentMenu==mnuSubmenu3)
      switch (clickedItem)
      {
        case 1:
          menu.MessageBox("Enabled");
          break;
        case 2:
          menu.MessageBox("Disabled");
          break;
        case 3:
          menu.InitMenu(mnuRoot,cntRoot,3);
          break;
      }

  }
}
```

and the progmem part :

```
// required for "prog_char" and "PROGMEM"
#define _PROG_TYPES_COMPAT_
#include <avr/pgmspace.h>

// texts for menus

const char itmBack[] PROGMEM = "< Back";
const char itmOn[] PROGMEM = "On";
const char itmOff[] PROGMEM = "Off";
const char itmEnabled[] PROGMEM = "Enabled";
const char itmDisabled[] PROGMEM = "Disabled";

const char itmRoot[] PROGMEM = "Root menu";
const char itmSubmenu1[] PROGMEM = "Submenu 1";
const char itmSubmenu2[] PROGMEM = "Submenu 2";
const char itmSubmenu3[] PROGMEM = "Submenu 3";
const char itmMessageBox[] PROGMEM = "Message box";
const char itmItem1[] PROGMEM = "Item 1";
const char itmItem2[] PROGMEM = "Item 2";
const char itmItem3[] PROGMEM = "Item 3";
const char itmItem4[] PROGMEM = "Item 4";
const char itmItem5[] PROGMEM = "Item 5";

////////////////////////////////////////////////////////////////
// menus - first item is menu title and it does not count toward cnt

const char* mnuRoot[] = {
  itmRoot,
  itmSubmenu1,itmSubmenu2,itmSubmenu3,itmMessageBox};
const int cntRoot = 4;

const char* mnuSubmenu1[] = {
  itmSubmenu1,
  itmItem1,itmItem2,itmItem3,itmItem4,itmItem5,itmBack};
const int cntSubmenu1 = 6;

const char* mnuSubmenu2[] = {
  itmSubmenu2,
  itmOn,itmOff,itmBack};
const int cntSubmenu2 = 3;

const char* mnuSubmenu3[] = {
  itmSubmenu3,
  itmEnabled,itmDisabled,itmBack};
const int cntSubmenu3 = 3;
```

I'm kinda new and I have no idea how can I make it work. Can anyone please help me figure it out what's wrong ?

Thank you for your time reading all of this.

title: qMenuSystem Oled I2C can't make it work

Answers: 1

body:
As the compiler is indicating, the line

    DigoleSerialDisp mydisp=DigoleSerialDisp _disp(&Wire,'\x3C');

is broken.

This part:

    DigoleSerialDisp _disp(&Wire,'\x3C')

declares and constructs an object named `_disp` of class `DigoleSerialDisp`.

You're trying to assign that to another variable, `mydisp` - that's not valid C++ - you can assign another variable, but you'd need to declare and construct it first, not in the assignment. There's also no need to construct it, name it `_disp` and then assign it to another variable.

Just do this:

    DigoleSerialDisp mydisp(&Wire,'\x3C');

You'll probably want to rewrite

    qMenuSystem menu=qMenuSystem(mydisp);

as

    qMenuSystem menu(mydisp);

as well.


body:
I have a 24v servo motor coupled to a 2,000 segment optical encoder that runs on 5v.

That's 2,000 "ticks" per revolution at it's base resolution. (Full quad reading allows 8,000 ticks per revolution, which I have no idea how a person could really USE! Egads that's tiny slices of a circle.)

It ALSO has a 'full-circle' index, a "Z" line.

That Z ***SEEMS*** to be coincident with A. Meaning that the clear slot in the rotor seems to be in the same place for both ONE of the A ticks and the only Z tick. I do not have an oscilliscope to verify this, but timestamping two different interrupts makes it seem like they do line up (one on A one on Z).

The motor runs at max 1075 RPM. So if I did the maths correctly that means there are 2,150,000 ticks per minute on the A/B lines plus 1075 ticks per minute on the Z line.

35,833.33-ish ticks per second on the A line.

17.9166-ish ticks per second on the Z line.

____________________________

I have used sample code from a number of sources on both a Nano v3 and an Uno r3. I can't get counting to be accurate on either device, both lose ticks counting the A trigger and the coincidence of the A and Z ticks makes the interrupts 'stack' (both trigger almost instantaneously, but whichever was first gets processed and THEN the other gets processed...)

I do know that I can get IC's that will count for me, but there are MANY models and I do not have the ability to determine which would suit this situation the best.

Despite reading a great number of posts about encoders and the Arduino code to read them I still don't understand if the Nano or Uno COULD do this on their own at this speed.

GOAL:
-----

 1. Accurately track all 2000 pulses per revolution at 1075 RPM.
 2. Accurately track FULL rotation pulses at 1075 RPM.
 3. Use full rotations as error-checking against the 2000 count.
 4. Provide error-checked count as an absolute count to external device.
 5. Provide resettable zero-point to external device (remotely reset the count).

So please, if you would, inform me about or direct me to *proven methods* and resources for achieving the above goals?

title: Best approaches to reading a high-count quadrature encoder?

Answers: 0


body:
I am a performing musician and quite new to the Arduino community.  Just learning as I go.  I am interested in using a momentary touch sensor with Adafruit's MP3 shield or Wave Shield.  I have successfully connected a touch sensor to the MusicMaker MP3 shield (which is sitting on the Adafruit Metro).  I combined some code from two independently working code sequences: one, to play MP3s and, two, to trigger with the sensor.  This works successfully except that the music starts but does not stop when I lift my finger off the sensor.  I want the music to stop when the touch sensor is not being touched.  When the sensor is touched again, I want the music file to start again from the beginning.  I'm printing the code IDE is running below and attaching an image of the touch sensor I am using.  I appreciate any advice on the code!  Thank you.

    /*
      AnalogReadSerial

      Reads an analog input on pin 0, prints the result to the Serial Monitor.
      Graphical representation is available using Serial Plotter (Tools > Serial Plotter menu).
      Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

      This example code is in the public domain.

      http://www.arduino.cc/en/Tutorial/AnalogReadSerial
    */

    // include SPI, MP3 and SD libraries
    #include <SPI.h>
    #include <Adafruit_VS1053.h>
    #include <SD.h>

    // define the pins used
    //#define CLK 13       // SPI Clock, shared with SD card
    //#define MISO 12      // Input data, from VS1053/SD card
    //#define MOSI 11      // Output data, to VS1053/SD card
    // Connect CLK, MISO and MOSI to hardware SPI pins.
    // See http://arduino.cc/en/Reference/SPI "Connections"

    // These are the pins used for the breakout example
    #define BREAKOUT_RESET  9      // VS1053 reset pin (output)
    #define BREAKOUT_CS     10     // VS1053 chip select pin (output)
    #define BREAKOUT_DCS    8      // VS1053 Data/command select pin (output)
    // These are the pins used for the music maker shield
    #define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
    #define SHIELD_CS     7      // VS1053 chip select pin (output)
    #define SHIELD_DCS    6      // VS1053 Data/command select pin (output)

    // These are common pins between breakout and shield
    #define CARDCS 4     // Card chip select pin
    // DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
    #define DREQ 3       // VS1053 Data request, ideally an Interrupt pin

    Adafruit_VS1053_FilePlayer musicPlayer =
      // create breakout-example object!
      //Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
      // create shield-example object!
      Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

    // the setup routine runs once when you press reset:
    void setup() {
      // initialize serial communication at 9600 bits per second:
      Serial.begin(9600);
      Serial.println("Adafruit VS1053 Simple Test");

      if (! musicPlayer.begin()) { // initialise the music player
         Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
         while (1);
      }
      Serial.println(F("VS1053 found"));

       if (!SD.begin(CARDCS)) {
        Serial.println(F("SD failed, or not present"));
        while (1);  // don't do anything more
      }

      // Set volume for left, right channels. lower numbers == louder volume!
      musicPlayer.setVolume(20,20);
    }

    // the loop routine runs over and over again forever:
    void loop() {
      // read the input on analog pin 0:
      int sensorValue = analogRead(A0);
      // print out the value you read:
      Serial.println(sensorValue);
      if(sensorValue > 100) {
        Serial.println(F("Playing track 001"));
      musicPlayer.playFullFile("/track001.mp3");
      }
     else(sensorValue < 100); {
        Serial.println(F("Paused"));
      musicPlayer.pausePlaying("/track001.mp3");
     }      }

title: How do I code the release of a momentary touch sensor in IDE?

Answers: 2

body:
You have a semicolon that doesn't belong in your code. Your current code (With the indentation cleaned up a little)

    void loop() {
      // read the input on analog pin 0:
      int sensorValue = analogRead(A0);
      // print out the value you read:
      Serial.println(sensorValue);
      if(sensorValue > 100) {
        Serial.println(F("Playing track 001"));
        musicPlayer.playFullFile("/track001.mp3");
      }
      else(sensorValue < 100); { // <<<--semicolon does not belong here.
        Serial.println(F("Paused"));
        musicPlayer.pausePlaying("/track001.mp3");
      }
    }

Should be:

    void loop() {
      // read the input on analog pin 0:
      int sensorValue = analogRead(A0);
      // print out the value you read:
      Serial.println(sensorValue);
      if(sensorValue > 100) {
        Serial.println(F("Playing track 001"));
        musicPlayer.playFullFile("/track001.mp3");
      }
      else(sensorValue < 100) { // <<<--semicolon removed from this line
        Serial.println(F("Paused"));
        musicPlayer.pausePlaying("/track001.mp3");
      }
    }

With the semicolon after the else, your code reads "...else do nothing" and then I would expect it to execute the pause logic no matter what value is in `sensorValue`.

You should pick an indentation style and then be absolutely consistent with it. Most C/C++ programmers use K&R style, which is what I used in my edit. (Opening braces are on the same line as the if statement/function that begins the scope, code inside braces is indented, and closing brace is at the same indentation level as the line that contains the opening brace.)

body:
As Sim Son have pointed it out, you need to use the proper function.
According to your library's [documentation][1]:

boolean playFullFile(char *trackname) - Play the complete file. This function will not return until the playback is complete.

You want to check your touch sensor, so this won't be enough for you.

boolean startPlayingFile(char *trackname) - Begin playing the specified file from the SD card using interrupt-driven playback. This allows your program to perform other tasks as the file is playing.

That documentation missed it, but in the source there is a function that stops your music:

void stopPlaying(void);

You can find this within your Arduino folder: Arduino/libraries/Adafruit_VS1053_Library's Adafruit_VS1053.h and Adafruit_VS1053.cpp files.

  [1]: https://learn.adafruit.com/adafruit-vs1053-mp3-aac-ogg-midi-wav-play-and-record-codec-tutorial/library-reference


body:
Can I simplify the code in arduino where it doesn't promote any error.
Example:

    Int led =13;
    Blink = digitalWrite(led, HiGH);
                 delay(1000);
                 digitalWrite(led, LOW);
                 delay(1000);

    void setup(){
    pinMode(led, OUTPUT);
    }

    void loop(){
    Blink
    }

title: Can I do something like this to simplify the code for arduino?

Answers: 4

body:
There are indeed some errors.

First, you cannot assign a function body to a variable.

So you have to rewrite the Blink function:

    void blink()
    {
        digitalWrite(led, HIGH);
        delay(1000);
        digitalWrite(led, LOW);
        delay(1000);
    }

Also for calling a function, even without parameters, you should use ( and ):

    void loop()
    {
        blink();
    }

Also you need to use the correct capitals or not:

    int led = 13;

You can make it constant since it does not change:

    static const int led = 13;

So all together you get:

    static const int led = 13;

    void setup()
    {
        pinMode(led, OUTPUT);
    }

    void loop()
    {
        blink();
    }

    void blink()
    {
        digitalWrite(led, HIGH);
        delay(1000);
        digitalWrite(led, LOW);
        delay(1000);
    }

I suggest you read a book about C or C++ to get used to the syntax.

Also, note that int is written as int, not Int. Case matters.

body:
And this should be byte, vs int, to save on memory:

    static const int led = 13;

HiGH should be HIGH, all caps.

body:
Your code

    Blink = digitalWrite(led, HiGH);
             delay(1000);
             digitalWrite(led, LOW);
             delay(1000);

Is attempting to define a function `Blink` that you can call later. You don't do that with an assignment (`=`)

You want to define a function. I'd suggest naming it `blink()`, not `Blink`. (all lower case.

Functions have parentheses after the name, which is where you put parameters if your function has any parameters. If not you still need the parentheses. The basic syntax of a function definition is:

    return_type function_name(param_type param_name)

If your function doesn't return a value, use the type `void` which means "no type."

So for a function `foo` that doesn't take any parameters and doesn't return any value, you'd use:

    void foo () {
       //Code for function foo()
    }

Michael's excellent answer (voted!) shows you what changes you need to make to your code to make it work. The above explains in a little more detail WHY you need to make those changes.

body:
Of course C++ has nice things.

For fun ad learn a working Arduino sketch based on the code from the Question:

    int led =13;

    auto Blink = []() { digitalWrite(led, HIGH);
                 delay(1000);
                 digitalWrite(led, LOW);
                 delay(1000);
    };

    void setup(){
    pinMode(led, OUTPUT);
    }

    void loop(){
    Blink();
    }

Note: use normal functions in your sketches and save lambdas for special occasions.


body:
I have an Arduino Leonardo (master) and a Polulu A-star 328 PB(slave). I intend to use the slave to actuate some servos. I've modified the code from https://www.arduino.cc/en/Tutorial/MasterWriter to also blink the builtin led of the slave and it hangs after a few loops. **Without the blink, it works fine. With blink, it hangs after a few loops.**

Master:
<!-- language-all: lang-cpp -->

    #include <Wire.h>

    void setup() {
      Wire.begin(); // join i2c bus (address optional for master)
    }

    byte x = 0;

    void loop() {
      Wire.beginTransmission(8); // transmit to device #8
      Wire.write("x is ");        // sends five bytes
      Wire.write(x);              // sends one byte
      Wire.endTransmission();    // stop transmitting
      x++;
      delay(2000);
    }

Slave:

    #include <Wire.h>

    void setup() {
    pinMode(LED_BUILTIN, OUTPUT);
    Wire.begin(8);                // join i2c bus with address #8
    Wire.onReceive(receiveEvent); // register event
    Serial.begin(9600);           // start serial for output
    }

    void loop() {
    delay(100);
    }

    void receiveEvent(int howMany) {
    while (1 < Wire.available()) {
      char c = Wire.read();
      Serial.print(c);
    }
    int x = Wire.read();
    Serial.println(x);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
    }

Serial monitor:

    x is 16
    x is 17
    x is 18
    x

Any idea what's causing it and what can I do to further debug it or fix it?
Thank you!

title: Arduino I2C Wire.onReceive hangs after a few loops

Answers: 2

body: After a bit of tinkering, I noticed that removing the delay() call in the slave fixed it and there were no more hangs. Also, when using the Servo library to move a servo instead of blinking the led, Servo.write() hangs while Servo.writeMicroseconds() doesn't. I'd mark the answer that has an explanation for this strange behavior.

body:
The `onReceive` callback get's called from an ISR (interrupt service routine). During the execution of this ISR, the MCU cannot react to other interrupts, since interrupts get automatically turned off at the start of an ISR.

Some functions like `delay()` and `millis()` rely on interrupts to work correctly, since the timekeeping in the Arduino framework is done via a timer interrupt. This means, that you cannot use `delay()` inside of an ISR. It will block forever, waiting for the internal time increment from the pointer, which will never come.

You can also get a problem with big `Serial.print()`s. These `Serial` functions fill the libraries internal buffer, and  the library will use interrupts to actually transmitt the data. If interrupts are turned off (like in an ISR), the buffer get's filled, until it is full. If you then again call `Serial.print()` or one of it's siblings, the library will block the execution, until there is enough space in the buffer, which will never happen. (You don't have this problem here, since you are only printing a few characters, but you should know this)

Generally ISR's should be as short as possible to prevent, that the Arduino misses an interrupt (which may mean data loss). Instead doing the blink in the ISR, you should simply set a flag variable, which you check in your `loop()` function and execute the blink correspondingly. That looks about like this:

    volatile byte flag=0;

    void loop(){
        if(flag){
            // Execute blink here
        }
    }

    void receiveEvent(int howMany) {
        // Do receiving here
        flag=1; //Set flag to a non-zero value to activate the corresponding code in loop()
    }


body:
I know a global JsonObject shouldn't be used, but I have my reasons.

I have a JsonObject* functions and I want him to save the content of a file.
With
<!-- language-all: lang-cpp -->

    functions=new JsonObject(jsonBuffer.as<JsonObject>());

I can access the JsonObject, but not when I leave the method. Can someone help me to understand why?
(Don't give me a solution like: copy into a struct, I need a JsonObject ready to be read in all my code.

Full code:

    JsonObject* functions;

    void loadFunctions() {
      File file = SPIFFS.open("/functions.json", "r");
      if (!file) {
        Serial.println("Failed to open the file");
      }else{
        size_t size = file.size();
        if (size > 512) {
          Serial.println("File size is too large");
        }else{
          std::unique_ptr<char[]> buf(new char[size]);
          file.readBytes(buf.get(), size);
          DynamicJsonDocument jsonBuffer(256);
          DeserializationError error = deserializeJson(jsonBuffer, buf.get());
          if (error) {
            Serial.println("Failed to parse file ");
          } else {
            functions=new JsonObject(jsonBuffer.as<JsonObject>());
            Serial.println((*functions)["test"].as<String>()); //this doesn't work in another method
          }
        }
      }
    }

title: Global JsonObject (ArduinoJson)

Answers: 1

body:
`jsonBuffer` is local to the function. When you leave the function the contents of `jsonBuffer` are lost.

`functions` just points to the internals of `jsonBuffer` to get its data (to save memory).

You can either:

* Make the `jsonBuffer` global so it sticks around all the time, or
* Have a secondary `DynamicJsonDocument` or `StaticJsonDocument` that is global to which you copy your objects once read from `jsonBuffer`.


body:
I am trying to understand the following code snippet from the Espressif OTABasic example for the ESP32 wireless/BT module (see [this repository][1] for the full code).

     ArduinoOTA
    .onStart([]() {
      String type;
      if (ArduinoOTA.getCommand() == U_FLASH)
        type = "sketch";
      else // U_SPIFFS
        type = "filesystem";

      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
      Serial.println("Start updating " + type);
    })
    .onEnd([]() {
      Serial.println("\nEnd");
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .onError([](ota_error_t error) {
      Serial.printf("Error[%u]: ", error);
      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
      else if (error == OTA_END_ERROR) Serial.println("End Failed");
    });

The initial 'ArduinoOTA' looks kinda like an implied 'with ArduinoOTA' statement, but I can't find anything like that in the reference documents.  I know it has something to do with the way the function templates in 'ArduinoOTA.h', but it's beyond me to untangle the syntax.

May I buy a clue, please?

TIA,

Frank

  [1]: https://github.com/espressif/arduino-esp32/blob/master/libraries/ArduinoOTA/examples/BasicOTA/BasicOTA.ino

Thanks to all for the clues; I'm an old-time c/c++ programmer, but must have slept through the 'lambda function' class ;-).

To help my somewhat calcified brain, is it functionally equivalent (if more clunky) to write the above snippet as shown below with the handler functions 'unchained'?

     ArduinoOTA.onStart
 ([]() //lambda function
  {
   String type;
   if (ArduinoOTA.getCommand() == U_FLASH)
    type = "sketch";
   else // U_SPIFFS
    type = "filesystem";

   // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
   Serial.println("Start updating " + type);
  }
 );

 ArduinoOTA.onEnd
 ([]() //lambda function
  {
   Serial.println("\nEnd");
  }
 );

 ArduinoOTA.onProgress
 ([](unsigned int progress, unsigned int total) //lambda func with arguments
  {
   Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  }
 );

 ArduinoOTA.onError
 ([](ota_error_t error) //lambda func with arguments
  {
   Serial.printf("Error[%u]: ", error);
   if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
   else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
   else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
   else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
   else if (error == OTA_END_ERROR) Serial.println("End Failed");
  }
 );

TIA,

Frank

title: Help with function template syntax

Answers: 1

body:
This is called (by me, anyway) "method chaining".

It's nothing special, really.  ArduinoOTA is just an instance of the class ArduinoOTAClass.

Each method of that class does what it needs to do, then returns a reference to the object that the method is within.  Which means that you can then call a method on that returned reference ... and so on.

All the rest of it is "lambda" functions - that is, functions that are embedded within the parameters of the functions being called.

The basic result is something like:

    A.foo().bar().baz();

Where A.foo() returns A. A.bar() returns A. A.baz() returns A.

You can do the same with:

    A.foo();
    A.bar();
    A.baz();


body:
Why is it that when i use this code for http request on DFRobot_sim808 , I get 'fetch over' message, that means that no data is being returned?

char strings:
```c
char http_cmd[] = " HTTP/1.0\r\n"
                        "Host: 5ac80719.ngrok.io\r\n"
                        "\r\n";
char first[] = "GET /index.php?lat=";

char requestion[100];
```

functions to join them:
```c

void setup() {
  float lat = 32.685362, lon = 48.411512;
  char char_coor[10];

  mySerial.begin(9600);
  Serial.begin(9600);

// Set Http Cmd
  strcpy(requestion,first);
// For Convert latitude float to char
  dtostrf(lat, 4, 6, char_coor);
  strcat(requestion,char_coor);
// For Convert longitude float to char
  dtostrf(lon, 4, 6, char_coor);
  strcat(requestion,"&long=");
  strcat(requestion,char_coor);
  strcat(requestion,http_cmd);

.
.
.
```

and fetching:
```c
sim808.send(requestion, strlen(requestion)-1);
  while (true) {
      int ret = sim808.recv(buffer, sizeof(buffer)-1);
      if (ret <= 0){
          Serial.println("fetch over...");
          break;
      }

/*
The program stops at above
*/

      buffer[ret] = '\0';
      Serial.print("Recv: ");
      Serial.print(ret);
      Serial.print(" bytes: ");
      Serial.println(buffer);
      break;
  }
```

thanks

title: Why doesn't data return when I use Sim808 http request

Answers: 1

body:
One problem I can see is the `while` loop has a `break` statement in it that "exits" the `while` loop before printing the data. Removing that `break` and printing the data out where the `break` "was" may help. Here's an example of what I'm trying to say:

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

    void loop(){

      while(true){
        int ret = 0;
        if(ret <= 0){
          Serial.println("fetch over...");
          // Print out the received data here...
          Serial.print("Recv: ");
          Serial.print(ret);
          break;
        }
      }

    }


body:
Newbie question here.

I have bought a 5V, 40A power supply to externally power up some LED strips (WS2812B). The Arduino Nano is powered by a standard USB wall charger (5V).
So far I have tested with 4 LED strips (each of about 25 LED's). Each of the strips is connected to an individual data pin on the Arduino in addition to the power supply (5V and ground).

So, to the problem. For each LED strip that gets powered it seems that the brightness of the LED's decreases. Using for example "white color", all the LED's shows a "yellow"-ish color when all the LED strips are powered. If only one or two is powered it looks fine.
The Arduino by the way shares the same ground as the power supply.
What could the cause to this issue be? The power supple should be more than sufficient for the task. Is it the data pins that can't handle it?

Thanks for any help!

EDIT:

I more detail, each LED strip has 3 pins (1 for 5V, 1 for data input, and 1 for ground). Each for the LED strips 5V pin are connected to the + rail on a breadboard where the power supplies + is also connected. The same goes for the ground pin of the LED strips (they are connected to a ground rail on the same breadboard where also the ground of the power supply is connected).
The data pin on the LED strips are connected to 4 (when all are connected) different data pins on the Arduino Nano (A1,A2,A3 and A4).

The ground pin on the Arduino Nano is connected to the same breadboard ground rail as the rest. When I didn't do this the LED's had weird behaviour.
The wires going from the LED strips into the breadboard are standard 24 AWG stranded wires (each of about 50 - 80 cm in length).

Power supply used is "AC 110V-220V TO DC 5V 40A" from ebay.
https://www.ebay.com/itm/AC-110V-220V-TO-DC-5V-12V-24V-Switch-Power-Supply-Driver-Adapter-LED-Strip-Light/152134115704

LED strips that are used "5M WS2812B 5050 RGB, 150LEDS ip65 Waterproof"
https://www.ebay.com/itm/5M-WS2812B-Strip-LED-Lights-5050-RGB-30-60-LED-M-IC-Individual-Addressable-DC5V/113117301639?

title: LED strip brightness decreases when using multiple strips

Answers: 1

body:
40 amps is a LOT of current.

24 AWG wire can't handle anywhere near 20A of current, nevermind 40A. (After a little googling, it looks like 24 AWG wire is limited to about 3.5A.)

Think about it. In the US, 15 amp branch circuits require 14 AWG wire. 20 amp circuits require 12 AWG wire. It looks like 40 amps requires 8 AWG, from the googling I did. (Voltage doesn't really matter when considering current carrying capacity.) So if you want to drive 40 amps, you need 8-gauge wire on both the +5 leg and the ground leg to your LED strip.

As I said in my comment, I found some 144 WS2812B LED strips on Amazon that draw 20A just for one strip. You say your strips have 150 WS2812B LEDs on them. Assuming it's 150 vs 144 of the same LEDS, you're going to need almost 21 amps per strip, so 2 strips will slightly exceed the 40A capacity of your power supply, and *VASTLY* exceed the current handling ability of your wiring. As a general rule you should have a power supply that offers a little **MORE** current that your max needs, never less.(When a power supply reaches its current limits its voltage may start to droop, or it may be slower to adjust to rapid changes in load.)

In addition, You're gonna need **BIG, THICK** 5V and ground wires to feed your LED strips, and you should wire the LED stips in parallel. (I suggest 8 AWG wires for 40A. Those are HUGE, but that's what you need for that much current.) You should not connect either the +5V supply or the ground wires through a breadboard.


body:
I am trying to implement a program in assembly code for an Arduino UNO. A potentiometer is used on an ADC pin for variable time (t). LED1 flashes for t seconds, then stays on for t seconds, then goes off and another LED(LED2) goes on for t seconds and then the cycle repeats (t is variable time that comes from potentiometer). I have a working program in c++ but I want to convert it to assembly. I have just started learning assembly and am not very good at it.

The part I am really stuck on is the analogRead() function. I do not know how to implement this on assembly. Anyone know how to do this?

    #define led 3
    #define led2 2

    void setup()

    {

    Serial.begin(9600);

    //initializing pins
    pinMode(led,OUTPUT);

    pinMode(led2,OUTPUT);

    }
    void loop()

    {

    // read the input on analog pin 0:
    int sensorValue = analogRead(A0);

    // Convert the analog reading(which goes from 0 - 1023) to a voltage(0-5V):
    int voltage = sensorValue * (5.0 / 1023.0);

    // print out the value you read:
    Serial.println(voltage);

    for(int i=0;i<2*voltage;i++)

    {

    digitalWrite(led,LOW);

    delay(100);

    digitalWrite(led,HIGH);

    delay(100);

    }

    //red stays on
    digitalWrite(led,HIGH);

    delay(voltage*500);

    digitalWrite(led,LOW);

    //green stays on
    digitalWrite(led2,HIGH);

    delay(voltage*500);

    digitalWrite(led2,LOW);

    }

title: How do I convert this program to assembly from c++

Answers: 1

body:
The obvious solution for converting any program to assembly is... to
compile it! You can disassemble the resulting binary with a command
like:

```shell
avr-objdump -S -C the_program.elf > the_program.lss
```

This will output a listing of the program, with the original source
interspersed with an hex dump of the binary and the corresponding
disassembly.

> The part I am really stuck on is the analogRead() function.

Here it goes:

```lisp
000003a6 <analogRead>:
 3a6: 8e 30        cpi r24, 0x0E ; 14
 3a8: 08 f0        brcs .+2       ; 0x3ac <analogRead+0x6>
 3aa: 8e 50        subi r24, 0x0E ; 14
 3ac: 87 70        andi r24, 0x07 ; 7
 3ae: 20 91 00 01  lds r18, 0x0100 ; 0x800100 <__data_start>
 3b2: 90 e4        ldi r25, 0x40 ; 64
 3b4: 29 9f        mul r18, r25
 3b6: 90 01        movw r18, r0
 3b8: 11 24        eor r1, r1
 3ba: 82 2b        or r24, r18
 3bc: 80 93 7c 00  sts 0x007C, r24 ; 0x80007c <__TEXT_REGION_LENGTH__+0x7e007c>
 3c0: 80 91 7a 00  lds r24, 0x007A ; 0x80007a <__TEXT_REGION_LENGTH__+0x7e007a>
 3c4: 80 64        ori r24, 0x40 ; 64
 3c6: 80 93 7a 00  sts 0x007A, r24 ; 0x80007a <__TEXT_REGION_LENGTH__+0x7e007a>
 3ca: 80 91 7a 00  lds r24, 0x007A ; 0x80007a <__TEXT_REGION_LENGTH__+0x7e007a>
 3ce: 86 fd        sbrc r24, 6
 3d0: fc cf        rjmp .-8       ; 0x3ca <analogRead+0x24>
 3d2: 80 91 78 00  lds r24, 0x0078 ; 0x800078 <__TEXT_REGION_LENGTH__+0x7e0078>
 3d6: 20 91 79 00  lds r18, 0x0079 ; 0x800079 <__TEXT_REGION_LENGTH__+0x7e0079>
 3da: 90 e0        ldi r25, 0x00 ; 0
 3dc: 92 2b        or r25, r18
 3de: 08 95        ret
```

Now, in order to more easily make sense of it, you need to know what all
those magic numbers mean. The command

```shell
avr-nm -nC the_program.elf
```

will dump the symbols associated with every RAM and flash address. In
order to tell those apart, 0x800000 is added to every RAM address. This
will tell you that, in this specific program, the RAM address `0x0100`
is actually the address of the variable `analog_reference` from the
Arduino core library. Thus, you can replace the line

```lisp
 3ae: 20 91 00 01  lds r18, 0x0100 ; 0x800100 <__data_start>
```

by

```lisp
    lds  r18, analog_reference
```

Then you can use the datasheet to get the names of the memory-mapped IO
registers, and the names of the bits from those registers. I have done
all this for you, so here is the cleaned-up disassembly of
`analogRead()`:

```lisp
analogRead:
    cpi  r24, 14
    brcs 1f
    subi r24, 14
1:  andi r24, 0x07
    lds  r18, analog_reference
    ldi  r25, 1<<REFS0
    mul  r18, r25
    movw r18, r0
    clr  r1
    or   r24, r18
    sts  _SFR_MEM_ADDR(ADMUX), r24
    lds  r24, _SFR_MEM_ADDR(ADCSRA)
    ori  r24, 1<<ADSC
    sts  _SFR_MEM_ADDR(ADCSRA), r24
2:  lds  r24, _SFR_MEM_ADDR(ADCSRA)
    sbrc r24, ADSC
    rjmp 2b
    lds  r24, _SFR_MEM_ADDR(ADCL)
    lds  r18, _SFR_MEM_ADDR(ADCH)
    ldi  r25, 0
    or   r25, r18
    ret
```

If you compare this with [the source code of `analogRead()`][source], it
should now make perfect sense.

> I am trying to implement a program in assembly

Now, if you want to write the assembly _yourself_, that's a whole
different story. If you allow yourself the use of the Arduino core, then
you can simply

```lisp
    ldi r24, 14  ; pin A0 is pin 14
    call analogRead
```

If you don't want to rely on external libraries, and really write
everything yourself, it's going to be a lot harder. I suggest you do
this as a two-step process:

**Step 1**: Learn how to program the ATmega328P in plain C, at the
register level, using no library other than the avr-libc. You can start
by reading this short tutorial about [direct port access][direct-port].
But then you should quickly move on to studying [the
datasheet][datasheet] and [the manual of the avr-libc][avr-libc]. Yes,
that's a lot to digest. I hope you didn't expect this to be quick and
easy. But note that, on those documents, you can skip all the chapters
related to functions you are not going to use.

> I am really stuck on is the analogRead() function.

In the specific case of your example program, you don't need a version
of `analogRead()` that can read any pin with any reference. You can
instead write a simpler version that just reads the currently selected
pin using the currently selected reference:

```c
int simple_analog_read(void)
{
    ADCSRA |= 1<<ADSC;                    // start the converion
    while (ADCSRA & (1<<ADSC)) continue;  // wait till it's done
    return ADC;                           // return the reading
}
```

Of course, this assumes you have appropriately initialized the ADC.

> `int voltage = sensorValue * (5.0 / 1023.0);`

You really, _really_ don't want to implement something like this in
assembly. The AVR hardware supports neither floating point nor
divisions. All this is handled by the compiler through supporting
libraries, and _they are not simple_. What you really want is something
like

```c++
int voltage = (sensorValue * 5) >> 10;
```

which is incidentally more correct, as the scaling factor is 5/1024, not
5/1023 (see the datasheet).

**Step 2**: Learn assembly, and rewrite your low-level C code in
assembly. If your C code is low-level enough this should not be too
hard. As a learning aid, you can ask the compiler to do it for you and
then try to make sense of what it did. If you just try to compile the
`simple_analog_read()` function I wrote above you will see the
translation to assembly is almost trivial.

[source]: https://github.com/arduino/ArduinoCore-avr/blob/1.6.23/cores/arduino/wiring_analog.c#L38
[direct-port]: https://www.arduino.cc/en/Reference/PortManipulation
[datasheet]: http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf
[avr-libc]: https://www.nongnu.org/avr-libc/user-manual/index.html


body:
Just like the title says I’m trying to make qMenuSystem to work with my oled display.
Here is what I know so far about my display :

```arduino
- It's a Monochrome OLED 128x64 (Blue) Display
- It's connecting using I2C using the 0x3C address allocated
- It's working well with Adafruit SSD1306 and Adafruit GFX Libraries
- It's looking like this : https://cdn3.volusion.com/btfzd.umflq/v/vspfiles/photos/AD304-2T.jpg?1526038845
```
The library DigoleSerial has the following files :

```arduino
//DigoleSerial.cpp

//Digole Digital Solutions: www.digole.com
#include "DigoleSerial.h"
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Arduino.h"

/*
// Communication set up command
 * "SB":Baud (ascII bytes end with 0x00/0x0A/0x0D) -- set UART Baud Rate
 * "SI2CA":Address(1 byte <127) -- Set I2C address, default address is:0x27
 * "DC":1/0(1byte) -- set config display on/off, if set to 1, displayer will display current commucation setting when power on
// Text Function command
 * "CL": -- Clear screen--OK
 * "CS":1/0 (1 byte)-- Cursor on/off
 * "TP":x(1 byte) y(1 byte) -- set text position
 * "TT":string(bytes) end with 0x00/0x0A/0x0D -- display string under regular mode
// Graphic function command
 * "GP":x(1byte) y(1byte) -- set current graphic position
 * "DM":"C/!/~/&/|/^"(ASCII 1byte) -- set drawing mode--C="Copy",! and ~ = "Not", & = "And", | = "Or", ^ = "Xor"
 * "SC":1/0 (1byte) -- set draw color--only 1 and 0
 * "LN":x0(1byte) y0(1byte) x1(1byte) y2(1byte)--draw line from x0,y0 to x1,y1,set new pot to x1,y1
 * "LT":x(1byte) y(1byte) -- draw line from current pos to x,y
 * "CC":x(1byte) y(1byte) ratio(byte) -- draw circle at x,y with ratio
 * "DP":x(1byte) y(1byte) Color(1byte) -- draw a pixel--OK
 * "DR":x0(1byte) y0(1byte) x1(1byte) y2(1byte)--draw rectangle, top-left:x0,y0; right-bottom:x1,y1
 * "FR":x0(1byte) y0(1byte) x1(1byte) y2(1byte)--draw filled rectangle, top-left:x0,y0; right-bottom:x1,y1
 */

// that resetting the Arduino doesn't reset the LCD, so we
// can't assume that its in that state when a sketch starts (and the
// LiquidCrystal constructor is called).

//UART function

void DigoleSerialDisp::preprint(void) {
    //write((uint8_t)0);
    Print::print("TT");
}

/*----------Functions for Graphic LCD/OLED adapters only---------*/
void DigoleSerialDisp::drawBitmap(unsigned int x, unsigned int y, unsigned int w, unsigned int h, const uint8_t *bitmap) {
    uint8_t i = 0;
    if ((w & 7) != 0)
        i = 1;
    Print::print("DIM");
    writePosition(x); //x;
    writePosition(y);
    writePosition(w);
    writePosition(h);
    for (int j = 0; j < h * ((w >> 3) + i); j++) {
        write(pgm_read_byte_near(bitmap + j));
//        delay(5);
    }
}

void DigoleSerialDisp::setRot90(void) {
    Print::print("SD1");
}

void DigoleSerialDisp::setRot180(void) {
    Print::print("SD2");
}

void DigoleSerialDisp::setRot270(void) {
    Print::print("SD3");
}

void DigoleSerialDisp::undoRotation(void) {
    Print::print("SD0");
}

void DigoleSerialDisp::setRotation(uint8_t d) {
    Print::print("SD");
    write(d);
}

void DigoleSerialDisp::setContrast(uint8_t c) {
    Print::print("CT");
    write(c);
}

void DigoleSerialDisp::drawBox(unsigned int x, unsigned int y, unsigned int w, unsigned int h) {
    Print::print("FR");
    writePosition(x);
    writePosition(y);
    writePosition(x + w);
    writePosition(y + h);
}

void DigoleSerialDisp::drawCircle(unsigned int x, unsigned int y, unsigned int r, uint8_t f) {
    Print::print("CC");
    writePosition(x);
    writePosition(y);
    writePosition(r);
    write(f);
}

void DigoleSerialDisp::drawDisc(unsigned int x, unsigned int y, unsigned int r) {
    drawCircle(x, y, r, 1);
}

void DigoleSerialDisp::drawFrame(unsigned int x, unsigned int y, unsigned int w, unsigned int h) {
    Print::print("DR");
    writePosition(x);
    writePosition(y);
    writePosition(x + w);
    writePosition(y + h);
}

void DigoleSerialDisp::drawPixel(unsigned int x, unsigned int y, uint8_t color) {
    Print::print("DP");
    writePosition(x);
    writePosition(y);
    write(color);
}

void DigoleSerialDisp::drawLine(unsigned int x, unsigned int y, unsigned int x1, unsigned int y1) {
    Print::print("LN");
    writePosition(x);
    writePosition(y);
    writePosition(x1);
    writePosition(y1);
}

void DigoleSerialDisp::drawLineTo(unsigned int x, unsigned int y) {
    Print::print("LT");
    writePosition(x);
    writePosition(y);
}

void DigoleSerialDisp::drawHLine(unsigned int x, unsigned int y, unsigned int w) {
    drawLine(x, y, x + w, y);
}

void DigoleSerialDisp::drawVLine(unsigned int x, unsigned int y, unsigned int h) {
    drawLine(x, y, x, y + h);
}

void DigoleSerialDisp::nextTextLine(void) {
    write((uint8_t) 0);
    Print::print("TRT");
}

void DigoleSerialDisp::setFont(uint8_t font) {
    Print::print("SF");
    write(font);
}

void DigoleSerialDisp::setColor(uint8_t color) {
    Print::print("SC");
    write(color);
}

void DigoleSerialDisp::backLightOn(void) {
    Print::print("BL");
    write((uint8_t) 1);
}

void DigoleSerialDisp::backLightOff(void) {
    Print::print("BL");
    write((uint8_t) 0);
}

void DigoleSerialDisp::directCommand(uint8_t d) {
    Print::print("MCD");
    write(d);
}

void DigoleSerialDisp::directData(uint8_t d) {
    Print::print("MDT");
    write(d);
}

void DigoleSerialDisp::moveArea(unsigned int x0, unsigned int y0, unsigned int w, unsigned int h, char xoffset, char yoffset) {
    Print::print("MA");
    writePosition(x0);
    writePosition(y0);
    writePosition(w);
    writePosition(h);
    write(xoffset);
    write(yoffset);
}

void DigoleSerialDisp::uploadStartScreen(int lon, const unsigned char *data) {
     int j;
     uint8_t c;
    Print::print("SSS");
    write((uint8_t) (lon % 256));
    write((uint8_t) (lon / 256));
    delay(300);
    for (j = 0; j < lon;j++) {
        if((j2)==0)
         delay(50);
         delay(_Comdelay);
        c=pgm_read_byte_near(data+j);
        write(c);
    }
}

void DigoleSerialDisp::uploadUserFont(int lon, const unsigned char *data, uint8_t sect) {
     uint8_t c;
    Print::print("SUF");
    write(sect);
    write((uint8_t) (lon % 256));
    write((uint8_t) (lon / 256));
    for (int j = 0; j < lon; j++) {
        if((j2)==0)
         delay(50);
         delay(_Comdelay);
        c=pgm_read_byte_near(data+j);
        write(c);
    }
}
void DigoleSerialDisp::drawBitmap256(unsigned int x, unsigned int y, unsigned int w, unsigned int h, const uint8_t *bitmap) { //display 256 color image
    uint8_t i = 0;
    Print::print("EDIM1");
    writePosition(x); //x;
    writePosition(y);
    writePosition(w);
    writePosition(h);
    for (int j = 0; j < h * w; j++) {
        write(pgm_read_byte_near(bitmap + j));
//        delay(5);
    }
}
void DigoleSerialDisp::drawBitmap262K(unsigned int x, unsigned int y, unsigned int w, unsigned int h, const uint8_t *bitmap) { //display 256 color image
    uint8_t i = 0;
    Print::print("EDIM3");
    writePosition(x); //x;
    writePosition(y);
    writePosition(w);
    writePosition(h);
    for (int j = 0; (j < h * w *3); j++) {
        write(pgm_read_byte_near(bitmap + j));
//        delay(5);
    }
}
void DigoleSerialDisp::setTrueColor(uint8_t r, uint8_t g, uint8_t b) { //Set true color
    uint8_t i = 0;
    Print::print("ESC");
    write(r);
    write(g);
    write(b);
}
```
```arduino

//DigoleSerial.h

//Digole Digital Solutions: www.digole.com
#ifndef DigoleSerialDisp_h
#define DigoleSerialDisp_h

#include <inttypes.h>
#include "Print.h"
#include <Wire.h>
#include "Arduino.h"

// Communication set up command
// Text function command
// Graph function command

#define Serial_UART 0;
#define Serial_I2C 1;
#define Serial_SPI 2;
#define _TEXT_ 0
#define _GRAPH_ 1

class DigoleSerialDisp : public Print {
public:
#if defined(_Digole_Serial_UART_)

DigoleSerialDisp(HardwareSerial *s, unsigned long baud) //UART set up
    {
        _mySerial = s;
        _Baud = baud;
        _Comdelay=2;
    }

    size_t write(uint8_t value) {
        _mySerial->write(value);
        return 1; // assume sucess
    }

    void begin(void) {
        _mySerial->begin(9600);
        _mySerial->print("SB");
        _mySerial->println(_Baud);
        delay(100);
        _mySerial->begin(_Baud);
    }
#endif
#if defined(_Digole_Serial_I2C_)

void begin(void) {
        _myWire->begin();
    }

    DigoleSerialDisp(TwoWire *s, uint8_t add) //U2C set up
    {
        _myWire = s;
        _I2Caddress = add;
        _Comdelay=6;
    }

    size_t write(uint8_t value) {
        _myWire->beginTransmission(_I2Caddress);
        _myWire->write(value);
        _myWire->endTransmission();
        return 1; // assume sucess
    }
#endif
#if defined(_Digole_Serial_SPI_)

void begin(void) {
    }

    DigoleSerialDisp(uint8_t pin_data, uint8_t pin_clock, uint8_t SS) //spi set up
    {
        _Clockpin = pin_clock;
        _Datapin = pin_data;
        _SSpin = SS;
        pinMode(_Clockpin, OUTPUT);
        pinMode(_Datapin, OUTPUT);
        pinMode(_SSpin, OUTPUT);
        digitalWrite(_SSpin, HIGH);
        digitalWrite(_Clockpin, LOW);
        digitalWrite(_Datapin, LOW);
        _Comdelay=6;
    }

    size_t write(uint8_t value) {
        digitalWrite(_SSpin, LOW);
        digitalWrite(_SSpin, LOW);
        digitalWrite(_SSpin, LOW);
        shiftOut(_Datapin, _Clockpin, MSBFIRST, value);
        digitalWrite(_SSpin, HIGH);
        return 1; // assume sucess
    }
#endif
    //    virtual size_t write(uint8_t);
    //    void begin(void);

        /*---------fucntions for Text and Graphic LCD adapters---------*/
    void writePosition(int p)
    {
 if(p>255)
 {
  write(255);
  p-=255;
 }
 write(p);
    }
    void disableCursor(void) {
        Print::print("CS0");
    }

    void enableCursor(void) {
        Print::print("CS1");
    }

    void drawStr(unsigned int x, unsigned int y, const char *s) {
        Print::print("TP");
 writePosition(x);
 writePosition(y);
        Print::print("TT");
        Print::println(s);
    }

    void setPrintPos(unsigned int x, unsigned int y, uint8_t graph = _TEXT_) {
        if (graph == _TEXT_) {
            Print::print("TP");
            writePosition(x);
            writePosition(y);
        } else {
            Print::print("GP");
            writePosition(x);
            writePosition(y);
        }
    }

    void clearScreen(void) {
        Print::print("CL");
    }

    void setLCDColRow(uint8_t col, uint8_t row) {
        Print::print("STCR");
        write(col);
        write(row);
        Print::print("\x80\xC0\x94\xD4");
    }

    void setI2CAddress(uint8_t add) {
        Print::print("SI2CA");
        write(add);
        _I2Caddress = add;
    }

    void displayConfig(uint8_t v) {
        Print::print("DC");
        write(v);
    }
    //print function

    size_t println(const __FlashStringHelper *v) {
        preprint();
        Print::println(v);
        Print::print("\x0dTRT");
    }

    size_t println(const String &v) {
        preprint();
        Print::println(v);
        Print::println("\x0dTRT");
    }

    size_t println(const char v[]) {
        preprint();
        Print::println(v);
        Print::println("\x0dTRT");
    }

    size_t println(char v) {
        preprint();
        Print::println(v);
        Print::println("\x0dTRT");
    }

    size_t println(unsigned char v, int base = DEC) {
        preprint();
        Print::println(v, base);
        Print::println("\x0dTRT");
    }

    size_t println(int v, int base = DEC) {
        preprint();
        Print::println(v, base);
        Print::println("\x0dTRT");
    }

    size_t println(unsigned int v, int base = DEC) {
        preprint();
        Print::println(v, base);
        Print::println("\x0dTRT");
    }

    size_t println(long v, int base = DEC) {
        preprint();
        Print::println(v, base);
        Print::println("\x0dTRT");
    }

    size_t println(unsigned long v, int base = DEC) {
        preprint();
        Print::println(v, base);
        Print::println("\x0dTRT");
    }

    size_t println(double v, int base = 2) {
        preprint();
        Print::println(v, base);
        Print::println("\x0dTRT");
    }

    size_t println(const Printable& v) {
        preprint();
        Print::println(v);
        Print::println("\x0dTRT");
    }

    size_t println(void) {
        Print::println("\x0dTRT");
    }

    size_t print(const __FlashStringHelper *v) {
        preprint();
        Print::println(v);
    }

    size_t print(const String &v) {
        preprint();
        Print::println(v);
    }

    size_t print(const char v[]) {
        preprint();
        Print::println(v);
    }

    size_t print(char v) {
        preprint();
        Print::println(v);
    }

    size_t print(unsigned char v, int base = DEC) {
        preprint();
        Print::println(v, base);
    }

    size_t print(int v, int base = DEC) {
        preprint();
        Print::println(v, base);
    }

    size_t print(unsigned int v, int base = DEC) {
        preprint();
        Print::println(v, base);
    }

    size_t print(long v, int base = DEC) {
        preprint();
        Print::println(v, base);
    }

    size_t print(unsigned long v, int base = DEC) {
        preprint();
        Print::println(v, base);
    }

    size_t print(double v, int base = 2) {
        preprint();
        Print::println(v, base);
    }

    size_t print(const Printable& v) {
        preprint();
        Print::println(v);
    }
    void preprint(void);
    /*----------Functions for Graphic LCD/OLED adapters only---------*/
    //the functions in this section compatible with u8glib
    void drawBitmap(unsigned int x, unsigned int y, unsigned int w, unsigned int h, const uint8_t *bitmap);
    void drawBitmap256(unsigned int x, unsigned int y, unsigned int w, unsigned int h, const uint8_t *bitmap);
    void drawBitmap262K(unsigned int x, unsigned int y, unsigned int w, unsigned int h, const uint8_t *bitmap);
    void setTrueColor(uint8_t r, uint8_t g, uint8_t b);
    void setRot90(void);
    void setRot180(void);
    void setRot270(void);
    void undoRotation(void);
    void setRotation(uint8_t);
    void setContrast(uint8_t);
    void drawBox(unsigned int x, unsigned int y, unsigned int w, unsigned int h);
    void drawCircle(unsigned int x, unsigned int y, unsigned int r, uint8_t = 0);
    void drawDisc(unsigned int x, unsigned int y, unsigned int r);
    void drawFrame(unsigned int x, unsigned int y, unsigned int w, unsigned int h);
    void drawPixel(unsigned int x, unsigned int y, uint8_t = 1);
    void drawLine(unsigned int x, unsigned int y, unsigned int x1, unsigned int y1);
    void drawLineTo(unsigned int x, unsigned int y);
    void drawHLine(unsigned int x, unsigned int y, unsigned int w);
    void drawVLine(unsigned int x, unsigned int y, unsigned int h);
    //-------------------------------
    //special functions for our adapters
    void setFont(uint8_t font); //set font, availale: 6,10,18,51,120,123, user font: 200-203
    void nextTextLine(void); //got to next text line, depending on the font size
    void setColor(uint8_t); //set color for graphic function
    void backLightOn(void); //Turn on back light
    void backLightOff(void); //Turn off back light
    void directCommand(uint8_t d); //send command to LCD drectly
    void directData(uint8_t d); //send data to LCD drectly
    void moveArea(unsigned int x0, unsigned int y0, unsigned int x1, unsigned int y1, char xoffset, char yoffset); //move a area of screen to another place

    void displayStartScreen(uint8_t m) {
        Print::print("DSS");
        write(m);
    } //display start screen

    void setMode(uint8_t m) {
        Print::print("DM");
        write(m);
    } //set display mode

    void setTextPosBack(void) {
        Print::print("ETB");
    } //set text position back to previous, only one back allowed

    void setTextPosOffset(char xoffset, char yoffset) {
        Print::print("ETO");
        write(xoffset);
        write(yoffset);
    }

    void setTextPosAbs(unsigned int x, unsigned int y) {
        Print::print("ETP");
        writePosition(x);
        writePosition(y);
    }
    void setLinePattern(uint8_t pattern) {
        Print::print("SLP");
        write(pattern);
     }
    void setLCDChip(uint8_t chip) {      //only for universal LCD adapter
        Print::print("SLCD");
        write(chip);
     }
    void uploadStartScreen(int lon, const unsigned char *data); //upload start screen
    void uploadUserFont(int lon, const unsigned char *data, uint8_t sect); //upload user font
    void digitalOutput(uint8_t x) {Print::print("DOUT");write(x);}
private:
    unsigned long _Baud;
    HardwareSerial *_mySerial;
    uint8_t _I2Caddress;
    TwoWire *_myWire;
    uint8_t _Clockpin;
    uint8_t _Datapin;
    uint8_t _SSpin;
    uint8_t _Comdelay;
};

#endif
```
And qMenuSystem has 4 files :

```arduino
qMenuDisplay.cpp
#include "qMenuDisplay.h"
#include <Wire.h>

//DigoleSerialDisp _disp(8,9,10);
DigoleSerialDisp _disp(&Wire,'\x3C');

qMenuDisplay::qMenuDisplay()
{
}

qMenuDisplay::qMenuDisplay(DigoleSerialDisp disp)
{
  _disp=disp;
}

void qMenuDisplay::Start()
{
  _disp.clearScreen();
  _disp.setFont(18);
}

void qMenuDisplay::Finish()
{
}

void qMenuDisplay::Title(const char text[])
{
  _disp.setTextPosAbs(64-strlen(text)*9/2,11);
  _disp.print(text);
  _disp.drawHLine(0,14,128);
}

void qMenuDisplay::Item(int index,const char text[])
{
  _disp.setTextPosAbs(5,(index*14)+32);
  _disp.print(text);
}

void qMenuDisplay::Highlight(int index)
{
  _disp.setMode('~');
  _disp.drawBox(4,(index*14)+20,120,13);
}

void qMenuDisplay::MessageBox(const char text[])
{
  int textWidth=strlen(text)*9;
  int x=64-(textWidth/2);
  int y=32;

  _disp.setMode('&');
  _disp.setColor(0);
  _disp.drawBox(x-5,y-12,textWidth+9,21+3);
  _disp.setMode('~');
  _disp.setColor(1);
  _disp.drawFrame(x-3,y-10,textWidth+5,17+3);

  _disp.setTextPosAbs(x,y+5);
  _disp.print(text);
}
```
```arduino
qMenuDisplay.h

#define _Digole_Serial_I2C_
#include <DigoleSerial.h>
#ifndef qMenuDisplay_h
#define qMenuDisplay_h

class qMenuDisplay
{
  public:
    qMenuDisplay(DigoleSerialDisp disp);
    qMenuDisplay();
    void Start();
    void Finish();
    void Title(const char text[]);
    void Item(int index,const char text[]);
    void Highlight(int index);
    void MessageBox(const char text[]);
  private:
//    char tempBuffer[32];
};

#endif
```
```arduino
qMenuSystem.cpp

/////////////////////
// qMenuSystem
// version: 1.0
// 22.12.2013
// CLASS
/////////////////////
#include <avr/pgmspace.h>
#include "qMenuSystem.h"
#include "qMenuDisplay.h"

//DigoleSerialDisp disp(255,255,255);
//qMenuDisplay qmd;

qMenuSystem::qMenuSystem(DigoleSerialDisp disp)
{
  qmd=qMenuDisplay(disp);
  _selectedIndex=0;
  _itemCount=0;
  _firstVisible=1;
}

void qMenuSystem::InitMenu(const char ** page, int itemCount, int selectedIndex)
{
  CurrentMenu=page;
  _selectedIndex=selectedIndex;
  _itemCount=itemCount;
//  ProcessMenu(ACTION_NONE);
  ShowMenu();
}

int qMenuSystem::ProcessMenu(int action)
{
  if (action==ACTION_DOWN)
    _selectedIndex++;
  if (action==ACTION_UP)
    _selectedIndex--;

  if (_selectedIndex>_itemCount)
    _selectedIndex=1;
  if (_selectedIndex<1)
    _selectedIndex=_itemCount;

  if (action==ACTION_SELECT)
    return _selectedIndex;

  ShowMenu();

  return 0;
}

void qMenuSystem::ShowMenu()
{
  if (_selectedIndex>_firstVisible+2)
    _firstVisible=_selectedIndex-2;
  else if (_selectedIndex<_firstVisible)
    _firstVisible=_selectedIndex;

  qmd.Start();

  // display title
  strcpy_P(tempBuffer, (char*)pgm_read_word(&(CurrentMenu[0])));
  qmd.Title(tempBuffer);

  // display items
  int p = 3;
  if (p > (_itemCount-_firstVisible+1))
    p=_itemCount-_firstVisible+1;
  for (int i=0;i<p;i++)
  {
    strcpy_P(tempBuffer, (char*)pgm_read_word(&(CurrentMenu[i+_firstVisible])));
    qmd.Item(i,tempBuffer);
  }

  // display selection
  qmd.Highlight(_selectedIndex-_firstVisible);

  qmd.Finish();
}
```
```arduino
qMenuSystem.h

/////////////////////
// qMenuSystem
// version: 1.0
// 22.12.2013
// HEADER
/////////////////////
#include "qMenuDisplay.h"

#ifndef qMenuSystem_h
#define qMenuSystem_h

#define ACTION_NONE    0
#define ACTION_UP      1
#define ACTION_DOWN    2
#define ACTION_SELECT  3
#define ACTION_BACK    4

class qMenuSystem
{
  public:
    qMenuSystem(DigoleSerialDisp disp);
    void InitMenu(const char ** page, int itemCount, int selectedIndex);
    int ProcessMenu(int action);
    void ShowMenu();
    void MessageBox(const char text[]) { qmd.MessageBox(text); };

    const char ** CurrentMenu;
  private:
    int _selectedIndex;
    int _itemCount;
    int _firstVisible;

    char tempBuffer[32];
    qMenuDisplay qmd;
};

#endif
```
Here is what it should show on the screen : https://www.youtube.com/watch?v=rjON_enuOGs

The example code that I'm using it this:
```arduino
/*
======================================
qMenuSystem example #1
======================================

1. Connect OLED in SPI mode: DATA=D8, CLOCK=D9, SS=D10
2. Compile & upload
3. Open Serial monitor (Ctrl+Shift+M)
4. Use "q", "a", "s" to move across menu ("q" = up, "a" = down, "s" = select)

*/

#define _Digole_Serial_I2C_
#include <DigoleSerial.h>
#include <Wire.h>

#include <qMenuDisplay.h>
#include <qMenuSystem.h>

#include "TestMenu.h"

//DigoleSerialDisp mydisp=DigoleSerialDisp(8,9,10);
//DigoleSerialDisp _disp(&Wire,'\x3C');

//DigoleSerialDisp mydisp=DigoleSerialDisp _disp(&Wire,'\x3C');
//qMenuSystem menu=qMenuSystem(mydisp);
DigoleSerialDisp _mydisp(&Wire,'\x3C');
qMenuSystem menu(_mydisp);

void setup()
{
  //mydisp.begin();
  //mydisp.clearScreen(); //CLear screen
  menu.InitMenu(mnuRoot,cntRoot,1);
  //mydisp.write(0);
  Serial.begin(9600);
}

void loop()
{
  int keycode=0;
  int clickedItem=0;

  if (Serial.available()>0)
  {
    switch(Serial.read())
    {
      case 97:
        menu.ProcessMenu(ACTION_DOWN);
        break;
      case 113:
        menu.ProcessMenu(ACTION_UP);
        break;
      case 115:
        clickedItem=menu.ProcessMenu(ACTION_SELECT);
        break;
    }
  }

  if (clickedItem>0)
  {
    // Logic for Root menu
    if (menu.CurrentMenu==mnuRoot)
      switch (clickedItem)
      {
        case 1:
          menu.InitMenu(mnuSubmenu1,cntSubmenu1,1);
          break;
        case 2:
          menu.InitMenu(mnuSubmenu2,cntSubmenu2,1);
          break;
        case 3:
          menu.InitMenu(mnuSubmenu3,cntSubmenu3,1);
          break;
        case 4:
          menu.MessageBox("Some message!");
          break;
      }
    // Logic for Submenu 1
    else if (menu.CurrentMenu==mnuSubmenu1)
      switch (clickedItem)
      {
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
          menu.MessageBox("Item clicked");
          break;
        case 6:
          menu.InitMenu(mnuRoot,cntRoot,1);
          break;
      }
    // Logic for Submenu 2
    else if (menu.CurrentMenu==mnuSubmenu2)
      switch (clickedItem)
      {
        case 1:
          menu.MessageBox("On");
          break;
        case 2:
          menu.MessageBox("Off");
          break;
        case 3:
          menu.InitMenu(mnuRoot,cntRoot,2);
          break;
      }
    // Logic for Submenu 3
    else if (menu.CurrentMenu==mnuSubmenu3)
      switch (clickedItem)
      {
        case 1:
          menu.MessageBox("Enabled");
          break;
        case 2:
          menu.MessageBox("Disabled");
          break;
        case 3:
          menu.InitMenu(mnuRoot,cntRoot,3);
          break;
      }

  }
}
```
and with the bundled progmem part :
```arduino
// required for "prog_char" and "PROGMEM"
#define _PROG_TYPES_COMPAT_
#include <avr/pgmspace.h>

// texts for menus

const char itmBack[] PROGMEM = "< Back";
const char itmOn[] PROGMEM = "On";
const char itmOff[] PROGMEM = "Off";
const char itmEnabled[] PROGMEM = "Enabled";
const char itmDisabled[] PROGMEM = "Disabled";

const char itmRoot[] PROGMEM = "Root menu";
const char itmSubmenu1[] PROGMEM = "Submenu 1";
const char itmSubmenu2[] PROGMEM = "Submenu 2";
const char itmSubmenu3[] PROGMEM = "Submenu 3";
const char itmMessageBox[] PROGMEM = "Message box";
const char itmItem1[] PROGMEM = "Item 1";
const char itmItem2[] PROGMEM = "Item 2";
const char itmItem3[] PROGMEM = "Item 3";
const char itmItem4[] PROGMEM = "Item 4";
const char itmItem5[] PROGMEM = "Item 5";

////////////////////////////////////////////////////////////////
// menus - first item is menu title and it does not count toward cnt

const char* mnuRoot[] = {
  itmRoot,
  itmSubmenu1,itmSubmenu2,itmSubmenu3,itmMessageBox};
const int cntRoot = 4;

const char* mnuSubmenu1[] = {
  itmSubmenu1,
  itmItem1,itmItem2,itmItem3,itmItem4,itmItem5,itmBack};
const int cntSubmenu1 = 6;

const char* mnuSubmenu2[] = {
  itmSubmenu2,
  itmOn,itmOff,itmBack};
const int cntSubmenu2 = 3;

const char* mnuSubmenu3[] = {
  itmSubmenu3,
  itmEnabled,itmDisabled,itmBack};
const int cntSubmenu3 = 3;
```

Can somebody please help me figuring out what's wrong that it doesn't show on the screen? (there are no errors on the code while compiling.)
Thank you so much for reading all the code I posted and for your time.

title: qMenuSystem using DigoleSerial library doesn’t work on my I2C Monochrome OLED

Answers: 0


body: For the device I am creating, I am hooking up an apa102 led strip to pins 11 and 13 to control each LED. But I would also like to hookup my NRF receiver to the arduino, but I also use pins 11 and 13. My question is can i hookup both to the same pins and control the inputs and outputs through the MOSI amd MISO pins separately!

title: Using MOSI and MISO pins for multiple devices

Answers: 0


body: I would like to know if there is a way to filter some specific sound using **FFT** on arduino. For instance, there is wind sound frequency in my analysis and I want to take it off. I searched for that a lot, but I didn't find something useful to solve this problem.

title: Using Arduino fix_fft or arduinoFFT library to filter some specific sound?

Answers: 1

body:
FFT is a tool for _analyzing_ sound. It is not very appropriate for
filtering, unless you have loads of computing power to spare. And it is
even less appropriate for _real-time_ filtering, if that is what you are
after.

Attempting to filter-out a noise based on its frequency is a reasonable
strategy for narrow-band noise, i.e. noise that lies in a narrow band of
frequencies. You can hope that, with some luck, removing this narrow
band doesn't affect too much the interesting part of the signal.

Alas, wind noise is very broad band, although it has more weight at low
frequencies:

![wind spectrogram](https://i.stack.imgur.com/N40sx.png)

([image source](https://www.reddit.com/r/askscience/comments/3tkdgg/is_it_possible_to_break_the_sound_of_roaring_wind/)).

If the frequencies that interest you are above ≈ 2 – 4 kHz, you could
try a simple high-pass filter. Something like this should work even on
an Arduino if the sample rate is not too high:

```c++
static uint16_t filter(uint16_t input)
{
    static uint16_t sum;
    uint16_t delta = input - (sum >> SCALE);
    sum += delta;
    return delta
}
```

where `SCALE` is a small constant that determines the cut-off frequency.

**Edit**: The Z-domain transfer function of this filter is

H = (z − 1) / (z − u)

where u = 1 − 2−SCALE. Its cut-off frequency is then
approximately fsamp ÷ (2 π 2SCALE).


body:
I would like to use the interrupt register from the BMA220 accelerometer in order to detect high-g shock. I am using a Mega2560 and the sensor is powered by 3.3 V. I use a voltage divider to convert the 5V from the card to 3.3V because the 5V pin gives more current. The memory map concerning the registers is shown below [![Memory map for registers][1]][1]
In the datasheet the section concerning high-g registers is as followed :
[![High-g detection registers][2]][2]
It is written that whenever a condition is met for the interrupt controller "an interrupt (logic '1') is issued through the INT pin of the sensor."

However after initializing the necessary registers (in I2C):

 - 0xC for high_th
 - 0xA for high_hy and high_dur
 - 0x1C for en_high_x/y/z

I don't get my interrupt working. Using a voltmeter I always get a high value (3.3V) on the INT pin of my accelerometer eventhough it stays still and I wrote a threshold of 2G...

Here is the code I am using :

    #include <BMA220.h>
    #include "SEN0168.h"

    BMA220 bma;
    byte interruptPin = 2;
    byte count = 0;
    const uint8_t HIGH_SET = 0xA;
    const uint8_t HIGH_LOW_TH = 0xC;
    const uint8_t INTERRUPT_REG = 0x18; // to get the bit indicating an interrupt was detected, not used because of the INT pin
    const uint8_t ENABLE = 0x1C;

    void setup() {
       Serial.begin(74880);
       pinMode(interruptPin, INPUT);
       init_SEN0168(R4); // set sensitivity to 4G
       bma.setRegister(ENABLE, 0xF7); // enable high-g-detection, reset interrupt bit control and latch permanently
       bma.setRegister(HIGH_LOW_TH, 0x1); // Threshold of 1G
       bma.setRegister(HIGH_SET, 0x1); // No hysteresis and 2 signals needed to trigger
       attachInterrupt(digitalPinToInterrupt(interruptPin),counter, HIGH);
    }

    void loop() {
        if (count==1){
        Serial.print("x-axis: ");
        Serial.println(accel_range_SEN0168(X,R4));
        Serial.print("y-axis: ");
        Serial.println(accel_range_SEN0168(Y,R4));
        Serial.print("z-axis: ");
        Serial.println(accel_range_SEN0168(Z,R4));
        count =0;
        bma.setRegister(INTRP_RES_REG, 0xF7); // enable high-g-detection, reset interrupt bit control and latch permanently
        }
        else{
          Serial.println("No shock");
          count =0;
        }
    }

    void counter(){
      count +=1;
    }
Am I missing something to clear in one register ? Or maybe since the card is in 5V and the sensor 3.3V logic there is a problem to detect change on the interrupt pin ?  Also I don't know if I understand properly the "logic 1". For me it means it puts the pin to "HIGH".

I use a part of the library written by Sönke Carstens-Behrens to set the registers from here : https://github.com/scbrac/BMA220.

I really need this interrupt pin to work...

Thank you for your help !

  [1]: https://i.stack.imgur.com/zvsT2.png
  [2]: https://i.stack.imgur.com/SFJGJ.png

title: How to manage interrupt from accelerometer BMA220?

Answers: 0


body:
With peak consumption at 2A, the SIM800L needs much more current than can be supplied by an Arduino or NodeMCU.

What is the best strategy to power this module, considering that you have access to a 100-240V outlet?

title: Powering SIM800L

Answers: 3

body:
The cleanest solution is to use separate power supplies for your MCU and your other high power devices. Get a 2.5A supply for the SIM800L, and a more modest supply for the Arduino/NodeMCU.

If you use the same power supply for both, you should use a bigger power supply than your max current needs to minimize "droop" as the load changes. You might also need to add filtering capacitors to the 5V rails of each device fed by the power supply.

## EDIT

I've used this 2A power supply in my projects before: https://www.amazon.com/gp/product/B01G6ZJ6DY/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1

You could use one of those for your SIM800L, and a 0.5A supply for the Arduino (A USB power supply would be fine.) Just be sure to tie the ground lines of the separate power supplies together.

body: I am usually using 12V/1000 mA adapter source to power Arduino and adjustable step-down/buck converter which powers GPS and similar modules. Advantage of this is that these converters usually have big capacitors on input and output, so you do not have to use additional auxiliary capacitors.

body:
I had to design a board for a customer with a built in LTE modem module (similar to a SIM800), and the power circuitry was something that required special consideration.

One requirement of the board was that the modem should be able to be powered on and off to save power, but that powering it on shouldn't ever cause the rest of the board to brownout.

To this end a separate 5V power circuit was built with a "soft start" facility built in.  This was always on, and fed into a number of capacitors to act as a reservoir. From them the power went via a large P-channel MOSFET to switch the power on to the LTE module when needed.  The capacitors provided the extra inrush current the LTE module demanded at powerup, and the soft start of the power supply limited the initial inrush current of charging the capacitors.

The power supply also had a "power good" output on it which was monitored to know when the output voltage had risen to an acceptable level (and hence the capacitors were charged) and the LTE module was able to be safely enabled.

The basic circuit was:

<!-- Begin schematic: In order to preserve an editable schematic, please
     don't edit this section directly.
     Click the "edit" link below the image in the preview instead. -->

![schematic](https://i.stack.imgur.com/KW0eS.png)

<!-- End schematic -->

That is a somewhat overkill probably for your situation though, but you should understand how it's done in the "real world" in a proper device.  However for experimental / prototyping with an Arduino where you aren't wanting to turn the modem on and off, and aren't too worried about the odd brownout, and bulkiness isn't of as much of a concern, then simply using two suitably sized external power supplies is adequate.  One small one to power the MCU (Arduino), and one larger one to power the modem.

<!-- Begin schematic: In order to preserve an editable schematic, please
     don't edit this section directly.
     Click the "edit" link below the image in the preview instead. -->

![schematic](https://i.stack.imgur.com/vI3XP.png)

<!-- End schematic -->

Because the power supplies themselves should have plenty of capacitance, and they are separately powered from a low impedance source (the mains power) there should be no interference between the modem and the MCU.


body:
I am trying to write to a charging IC (BQ24193) and I am trying to figure out how to use I2C to write to a specific register so I can set up the charging IC properly. I have watched a few videos on the communication protocol, but I don't understand how to write to a register directly. Your help would be appreciated. Thanks.

Datasheet: http://www.ti.com/lit/ds/symlink/bq24193.pdf

title: How do you write to a specific register using I2C communcation?

Answers: 1

body:
The Arduino uses the [`Wire.h` library](https://www.arduino.cc/en/reference/wire) to communicate on an I2C bus.

Writing to a register in I2C is usually done by sending two bytes to the correct I2C address.  The first byte is usually the register address, and the second is the value to place into the register:

    #define CHIP_ADDRESS     0x6B
    #define REGISTER_ADDRESS 0x12

    Wire.beginTransmission(CHIP_ADDRESS);
    Wire.write(REGISTER_ADDRESS);
    Wire.write(0x18);
    Wire.endTransmission();

Reading from a register is slightly more tricky, in that first you need to write to the chip to set the register address, then as a separate operation you need to read from that address:

    Wire.beginTransmission(CHIP_ADDRESS);
    Wire.write(REGISTER_ADDRESS);
    Wire.endTransmission();
    Wire.requestFrom(CHIP_ADDRESS, 1); // We want one byte
    uint8_t val = Wire.read();


body:
I'm trying to use a Wemos D1 mini as a smart button that will boot up, perform a task, and then shut back down. I'd like to do this as a true power off as opposed to any sort of sleep mode.

I'm hoping I can do something similar to this post https://www.esp8266.com/viewtopic.php?f=11&t=4458

1. Tie RST pin to a Low GPIO pin so that it doesn't boot
2. Push a button that will run 3.3v to RST pin to make it go high and cause a boot up
3. Flip the GPIO pin that is tied to RST to high so that it stays running when button is no longer pressed
4. Run some code and flip GPIO back to LOW shutting down

Things I've tried:

1. Tie to GPIO15 (D8) - This stops the boot and starts booting when button is pressed but never finishes booting up. I'm assuming I am causing D8 to go high by pressing my button and interfering with the boot, but honestly not sure

2. Tie to GPIO4 or 5 (D2, D1). This doesn't prevent boot.

3. I've also tried #2 with a pull down resistor on the GPIO pin, but that doesn't seem to work either

Any help would be much appreciated.

title: D1 Mini latch button using rst pin

Answers: 3

body:
Try using D8, also follow this for selecting your pins to make sure the code runs as it is attended to work

[![enter image description here][1]][1]

  [1]: https://i.stack.imgur.com/7pkfh.jpg

body:
as far as I know, it's not possible [the way as simple as you said]. here's some notes :

 1. after a reset, GPIOs are set as inputs. if you connect a GPIO to RST and make it low, it resets the chip, but immediately sets the GPIOs as inputs and the RST is released.
 2. if you don't use appropriate resistors, you'll burn the GPIO driver by connecting an output GPIO to a supply line. e.g. when you are trying to connect 3.3v to RST and LOW GPIO which is holding RST down.
 3. sleep modes are very efficient. many times, the battery self discharge is much higher than an slept MCU
 4. if you insist, turn the chip off by cutting off it's supply using an external circuitry. a 555 with a mosfet without any res,cap will do the jb (using only it's internal flip flop)

body:
To do this you would usually use MOSFETs to control the power.

Take the following circuit, for example:

<!-- Begin schematic: In order to preserve an editable schematic, please
     don't edit this section directly.
     Click the "edit" link below the image in the preview instead. -->

![schematic](https://i.stack.imgur.com/K6bzE.png)

<!-- End schematic -->

M1 is normally off, having its gate pulled up by R1.

Pressing SW1 pulls the gate of M1 low, allowing current to flow through it to power the D1.

The D1 boots up, and immediately drives the GPIO high.

This then turns on M2 (which is normally off, having the gate pulled down by R2), which in turn pulls the gate of M1 low.

SW1 can now be released since M2 is doing the same job.

To turn off, simply drive the GPIO low, or allow it to float as an input, in which case R2 will turn off M2, which then turns off M1, which stops the current flowing.


body: While wiring up my new Arduino Uno R3, I accidentally shorted the 5V pin and the GND pin (for less than a sec). It was powered by a 12V 500mAh power supply through the Arduino DC power jack. ![Now the arduino looks like this ](https://i.stack.imgur.com/CvYwI.jpg). The ON, Rx, X1 and L LED's are glowing continuously, and also, pressing the reset button doesn't have any effect on the LED's and arduino doesn't restarts. How can I get my arduino working again?

title: Arduino Uno not working after Short-circuit

Answers: 3

body:
The regualator of that 5V Blew up or the diode you need to read the schemtics of the Arduino Uno and check the circuits.

https://www.arduino.cc/en/uploads/Main/arduino-uno-schematic.pdf

body:
Chances are the cheap Chinese clone board you have has an inferior 5V regulator with no thermal protection.

These are notorious for breaking with a short circuit (over-current = over-temperature = meltdown).  And when they break they "fail short", which means that they end up working like a simple piece of wire - the voltage you put in is the voltage you get out.

That means that 12V has now been sent into the rest of the Arduino, and has destroyed everything - the main MCU, the USB interface chip, etc.

In short: your board is dead.

body: You can tell it's a fake Uno because the USB chip is not an Atmega32U4.


body:
I am trying to learn how to use a Rotary Encoder together with an LCD display where I can use the encoder to choose Letters that will be printed in the LCD.
[![enter image description here][1]][1]

This is the kind of result I should be getting, but instead I am getting this:

1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16

c  d  e  f  0  1  2  3  4  5   6   7   8   9   a   b

10 00 10 00 11 01 11 01 10 00  10  00  11  01  11  01

A:
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0

B:
0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1

Shouldn't I be getting a sort of
001100110
100110011
pattern to be able to tell which way it is rotated?
How can I fix this?
I am using the following connections:
[![enter image description here][2]][2]

  [1]: https://i.stack.imgur.com/yaYUK.png
  [2]: https://i.stack.imgur.com/2jtwX.png

title: Rotary Encoder gives "wrong" patterns?

Answers: 0


body:
My question is quite simple. I am using one external interrupt on the Mega2560 to wake it up with an alarm from the rtc DS3231 and record data from sensors for about 30 seconds and I would like also to use the other external interrupt to wake it up in case of shock detection to measure the signal.

The thing is that I know external interrupts have priority on internal interrupt but is it possible to put, in my case, the shock detection prior to the alarm ? In case the shock occurs during the alarm recording I would prefer to record the shock signal.

Thank you for your help !

title: Is it possible to put priorities between external interrupts?

Answers: 1

body:
Interrupts are not the right place to handle priorities. The interrupt
handlers should be as short as possible. Then the likeliness of two of
them happening at the same time is very low. And even if it happens, the
lowest-priority interrupt will only be delayed by a handful of
microseconds, which should not be a big deal.

In this case, the sensible approach is to have the interrupt handlers
set a global flag and _do nothing else_. Then the main program will
check the flags and do the real work, handling the priorities as needed.

Conceptually, the code could be something along these rough lines:

```c++
// Global flags.
volatile bool alarmDetected;
volatile bool shockDetected;

// Interrupt handlers.
void onAlarmInterrupt() { alarmDetected = true; }
void onShockInterrupt() { shockDetected = true; }

void loop() {
    if (shockDetected) {  // check this first!
        measureShockData();
        if (gotEnoughShockData()) {
            shockDetected = false;
            alarmDetected = false;  // ignore the alarm
            goToSleep();
        }
    } else if (alarmDetected) {
        recordSensorData();
        if (gotEnoughSensorData()) {
            alarmDetected = false;
            goToSleep();
        }
    }
}
```

Note that you can remove the line that ignores the alarm in case of
shock. If you do so, the alarm will be handled _after_ all relevant
shock data has been recorded.