message:
Attiny timer interrupt does not make an interrupt every 1000ms

I'm making a stopwatch using an attiny85, the idea was to use the timer interrupts to count the seconds
my theory was: since I set the Attiny85 to run at 1Mhz, I can use a presale of 1024; 1000000 / 1024 = 976.5625 hz, 976.5625hz = 1.024ms, 125ms / 1.024ms = 122.07, so that I need to count to 122 to get a 125ms interrupt, then in the ISR function I can count to 8 to get around 1 second, ( 122 * 1.024 ) * 8 = 999.424ms

What is the problem? well, the problem is that I'm not getting something close to 999.424ms, I compere it with my phone's stopwatch and the attiny seems to start well, but then it gets about 2-3 slower than my phone's stopwatch

```cpp
#include <TM1637Display.h>

#define CLK 4
#define DIO 3
#define button 1

TM1637Display display (CLK, DIO);
int intr_count = 0;
byte dots = 0b01000000;

volatile int seg;
volatile int min;
volatile bool start = false;

void setup() {
  display.setBrightness(5);
  display.clear();
  pinMode(button, INPUT);

  cli();

  TCCR0A  = 0;
  TCCR0B  = 0;
  TCCR0B |= B00000101;
  TIMSK  |= B00010000;

  OCR0A   = 122;

  sei();
}

void start_counting(){
  if (digitalRead(button) == HIGH){
    start = !start;
    if(start == false){
//    display.clear();
      seg = 0;
      min = 0;
    }
    while(digitalRead(button) == HIGH);
  }
}

void loop() {
  start_counting();
  display.showNumberDecEx(min, dots, true, 2, 0);
  display.showNumberDec(seg, true, 2, 2);

}

ISR(TIMER0_COMPA_vect) {
  TCNT0 = 0;
  if(start == true){

    if (intr_count == 8) {

      seg++;

      if(seg == 60){
        min++;
        min = min % 60;
      }

      seg = seg % 60;

      intr_count = 0;
    } else {
      intr_count++;
    }
  }
}
```

body:
I see three issues with this approach.

The first is that you are using a very low quality, uncalibrated time
source. The frequency of the internal RC oscillator is good to within a
few percent only. It is also very unstable, and hugely dependent on
temperature. Using an external 16 Mhz ceramic oscillator should
give you a frequency that is no worse than 0.5% off, with a typical
error about 0.1%. It is still somewhat unstable though. If you instead
are using a _crystal_ oscillator, then you can expect an error about ten
times smaller (in the range of 100 ppm), and a very good stability.
Depending on you quality requirements, 100 ppm may still not be
good enough, in which case you still have the option to measure the
drift rate and calibrate it out (see below).

The second problem, which has already been raised by 6v6g, is that your
timer is counting from zero to 122 inclusive, which gives a period of
123 timer clock cycles. Take a look at the timing diagrams in the
datasheet if you need to convince yourself of this. If you want a period
of 122, you should set OCR0A to 121.

The third problem is that you are resetting the timer with the ISR. This
may work in this program, but it is a very fragile approach worth
avoiding. The problem is that everything the microcontroller does takes
time, and your ISR may even get delayed by another interrupt. If the
timer is incremented after rising the interrupt flag but before you
reset it, you are missing one count. If you want to have a continuous
time scale, _never_ reset your timer. You can either:

* let it run continuously, undisturbed (and do `OCR0A += 122` within the
  ISR),

* or let it reset itself by using the appropriate waveform generation
  mode (CTC or fast PWM).

Lastly, here is a trick you may use to calibrate your stop watch.
Instead of counting the interrupts until the counter reaches 8
(which assumes an interrupt period of exactly 1/8 s), increment a
nanosecond counter within the ISR, and count one second once you have
one billion nanoseconds:

```c++
const uint32_t nanoseconds_per_interrupt = 124928000;

ISR(TIMER0_COMPA_vect) {
    static uint32_t nanoseconds;
    nanoseconds += nanoseconds_per_interrupt;
    if (nanoseconds >= 1000000) {
        nanoseconds -= 1000000;
        seconds++;
        // then update minutes, hours... if needed
    }
}
```

This will increment the seconds every eight interrupts... most of the
time. From time to time, however, it will take nine interrupts. This
adds a little bit of jitter, but prevents the timing errors from
accumulating and making the clock drift. If the jitter is visible, you
can reduce it by shortening the interrupt period.

The value 124928000 I wrote above assumes the ISR is called every
122×1024 cycles of a 1 MHz clock. You can change it to fit a
different clock frequency or a different OCR0A setting. The trick is:
once you measure the drift rate of your stop watch, you can tweak this
number to remove that drift. For example, if you measure the stopwatch
and find it is running 0.04% too slow, then you increase that number by
0.04% (that would give 124977971) and the drift is gone.

**Edit**: In a comment, 6v6gt pointed out a fourth issue in your code,
which is likely the biggest issue. Your logic for counting interrupts
is:

```c++
if (intr_count == 8) {
    intr_count = 0;
} else {
    intr_count++;
}
```

This is counting from 0 to 8 _inclusive_, and looping with a period of
9 interrupts. A safer idiom for looping with a period of 8
would be:

```c++
if (++intr_count >= 8) {
    intr_count = 0;
}
```

Although I would still recommend counting nanoseconds if you want the
ability to calibrate your clock.


sender: user

message:
ESP32-CAM rst:0x8 TG1WDT_SYS_RESET bootloop

I have ESP32-CAM that I plan to use as a simple security camera. I tested the software and it was working perfectly. I programmed it using FTDI programming board with 5V. After testing everything I decided to power it with an old adapter (5V 160mA) I had for some time but when I powered with adapter the power started flickering. When I noticed it I immediately unplugged the adapter but since then I started getting stuck in bootloop. Here is the output I get:

    12:56:10.663 -> ets Jul 29 2019 12:21:46
    12:56:10.667 ->
    12:56:10.667 -> rst:0x1 (POWERON_RESET),boot:0x3 (DOWNLOAD_BOOT(UART0/UART1/SDIO_REI_REO_V2))
    12:56:10.667 -> waiting for download
    12:56:49.327 -> ets Jul 29 2019 12:21:46
    12:56:49.327 ->
    12:56:49.327 -> rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
    12:56:49.327 -> configsip: 0, SPIWP:0xee
    12:56:49.327 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
    12:56:49.327 -> mode:DIO, clock div:2
    12:56:49.327 -> load:0x3fff0030,len:1344
    12:56:49.327 -> load:0x40078000,len:13836
    12:56:49.327 -> load:0x40080400,len:3608
    12:56:49.327 -> entry 0x400805f0
    12:56:50.707 -> ets Jul 29 2019 12:21:46
    12:56:50.707 ->
    12:56:50.707 -> rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
    12:56:50.707 -> configsip: 0, SPIWP:0xee
    12:56:50.707 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
    12:56:50.707 -> mode:DIO, clock div:2
    12:56:50.707 -> load:0x3fff0030,len:1344
    12:56:50.707 -> load:0x40078000,len:13836
    12:56:50.707 -> load:0x40080400,len:3608
    12:56:50.707 -> entry 0x400805f0
    12:56:52.086 -> ets Jul 29 2019 12:21:46
    12:56:52.086 ->
    12:56:52.086 -> rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
    12:56:52.086 -> configsip: 0, SPIWP:0xee
    12:56:52.086 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
    12:56:52.086 -> mode:DIO, clock div:2
    12:56:52.086 -> load:0x3fff0030,len:1344
    12:56:52.086 -> load:0x40078000,len:13836
    12:56:52.086 -> load:0x40080400,len:3608
    12:56:52.086 -> entry 0x400805f0
It keeps going like this. I can upload new code without any problems but every code I upload gets stuck in this exact bootloop. Load and entry adresses does not change. I also tried programming with arduino nano instead of ftdi but nothing changed.

I am using Arduino IDE 2.0.0 on Linux Mint 21 OS. I also tried it on Windows 10 but the results didn't change. I am quite new to ESP32 so I don't know how to debug it either.

Thanks in advance.

##############

UPDATE 25/10/2022

After timemage's comment I tried a few more codes and one of arduino ide's example codes ran once with error. I couldn't get the error log but there was something like "PSRAM ID Read error 0xffffff" and another log pointing to a corrupted address.

After that I tried uploading another sketch without PSRAM with following settings:

 - Board: ESP32 Dev Module
 - CPU frequency: 240MHz(WiFi/BT)
 - Events run on: Core 1
 - Flash frequency: 80MHz
 - Flash mode: QIO
 - Flash size: 4MB(32Mb)
 - Arduino runs on: Core 1
 - PSRAM: Disabled
 - Partition scheme: Huge
   APP(3MB No OTA/1MB SPIFFS)
 - Upload speed: 115200

and it worked. But I need PSRAM for my project. So my question is: can it be a hardware problem ? If not, how can I fix it ?

Thanks again.

sender: assistant

body:
1. Is your esp32_cam comes with PSRAM?  I had a program running on esp32 wrover with PSRAM, the same code could not run on esp32 wroom.  After checking, the esp32 wroom does not come with PSRAM.

2. Say that the esp32_cam does come with PSRAM, how do you initilize it?

3. My code has ISR to force shutdown after 15min of wakeup from deep sleep, I will get the same error with reset when there is a while loop or for loop, and i missed these 2 line of codes.
    vTaskDelay( 3 / portTICK_PERIOD_MS );
    esp_task_wdt_reset();

hopefully, this helps.


body:
I got the same "rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)" and crash when using the M5stack-Timer-Camera after doing a "SerialM.setDebugOutput(true);" then starting the camera with "camera_init()" and then doing an "EEPROM.commit".

When I remove the "SerialM.setDebugOutput(true);" the error/crash goes away and instead I just get a (Serial-Terminal) warning of "cam_hal: EV-EOF-OVF" when doing an "EEPROM.commit".

So in my case I suspect that the "SerialM.setDebugOutput(true)" was causing the "cam_hal: EV-EOF-OVF" error message to crash during the "EEPROM.commit".


body:
From my personal experience working with the ESP-CAM's ESP32-s3 chip, the particular error is the result of an invalid line of code.

The best way to address this is to look very closely at the code that you've written, for some of the errors you may introduce through the arduino ide may not be caught in the compilation process.

For example, I was building out a UART shell using the same processor.

My code was producing the same error because of this code here:

    private:
        size_t commandsLen = 1;
        string commands[1]{
            "lcdcam"
        };

I was able to fix the reset loop by correcting the syntax in my string array. Which was missing an equals sign.

The following modification fixed my particular issue, and odds are that your problem is syntax related like mine.

    private:
        size_t commandsLen = 1;
        string commands[1] = {
            "lcdcam"
        };

Edit:
Upon further inspection, there was an additional issue that also caused this error.

Take the following code into consideration:

    public:
        bool commandSwitch(Uart uart, BosCommand cmd){
            if(cmd.getCommandLength() <= 0){
                sendOutput(uart, "Failed to find commands.\n\r");
                return false;
            }
            string target = cmd.getCommandArg(0);

            if(target == "lcdcam"){
                BosCommandSwitch targetCmd;
                targetCmd.init(uart, cmd);
                return targetCmd.process();
            }else{
               // removed
            }
            return false;
        }

The issue is that the processor doesn't like it when I declare the BosCommandSwitch class inside the if logic. Not only did fixing the string array correct the reset bug, but moving the declaration of the class object up into the private section of my class allowed all my code to run without the automated reset.

    private:
        BosCommandSwitch targetCmd;
    public:
        bool commandSwitch(Uart uart, BosCommand cmd){
            if(cmd.getCommandLength() <= 0){
                sendOutput(uart, "Failed to find commands.\n\r");
                return false;
            }
            string target = cmd.getCommandArg(0);

            if(target == "lcdcam"){
                targetCmd.init(uart, cmd);
                return targetCmd.process();
            }else{
               // removed
            }
            return false;
        }

I believe that the issue is related to memory allocation. Once you get deep into logic, you reduce the amount of available memory in a particular region. Though this is just speculation on my part.


message:
Does the bootloader use some SRAM?

I want to use all SRAM of an Arduino by writing the code in assembly. But does the bootloader use some SRAM while the program is running, and if the answer is _yes_ would changing that data lead to failure or does the data stored there get corrupted? Thanks for reaching out.

body:
You did not specify what type of Arduino you are using. My answer is for
the AVR-based ones.

The bootloader does use RAM _while it is running_. However, once it
handles control to your program, the microcontroller is all yours: you
are free to use all the RAM.

Id did not check with optiboot but, it is possible that the bootloader
leaves some stuff in the stack. The C runtime of the avr-libc takes care
of this: one of the first things it does is to reset the stack pointer.
If you link with the avr-libc, you will find the stack empty. If you
don't, I suggest you set the stack pointer to RAMEND at the beginning of
your program, just in case.


message:
Array of Functions

I'm new to C++. How to make a menu without `if() {} else {}` & `switch() case`?
I made a menu on an array, but for some reason it doesn't compile. How to correct it?

    typedef void (*cbd)(uint8_t, uint8_t);
    typedef void (*cbt)(uint8_t, uint8_t);
    typedef void (*cba)(uint8_t, uint8_t);
    typedef void (*MenuFunction) (int8_t);

    class Menu {
    public:
     Menu() {
            updownFns[5] = {updownNone, updownAlarmHours, updownAlarmMinutes, updownTimeHours, updownTimeMinutes};
        }

     static void Setup(cbd display, cbt setTime, cba setAlarm, uint8_t alarmHours, uint8_t alarmMinutes) {
            cbDisplay = display;
      cbSetTime = setTime;
      cbSetAlarms = setAlarm;
            alarmHours = alarmHours;
            alarmMinutes = alarmMinutes;
            cbSetAlarms(alarmHours, alarmMinutes);
        }
        // Used for menu.UpDown(dir) callback
     static void UpDown(int8_t direction) {
            updownFn(direction);
     }
        // Used for menu.Tab() callback
        static void Tab() {
            updownFnNum++;
            updownFn = updownFns[updownFnNum % 5];
     }

    private:

        static void updownNone(int8_t direction) { }

        static void updownAlarmHours(int8_t direction) {
            alarmHours += direction;
            cbDisplay(alarmHours, alarmMinutes);
            cbSetAlarms(alarmHours, alarmMinutes);
        }

        static void updownAlarmMinutes(int8_t direction) {
            alarmMinutes += direction;
            cbDisplay(alarmHours, alarmMinutes);
            cbSetAlarms(alarmHours, alarmMinutes);
        }

        static void updownTimeHours(int8_t direction) {
            timeHours += direction;
            cbSetTime(timeHours, timeMinutes);
            cbDisplay(timeHours, timeMinutes);
        }

        static void updownTimeMinutes(int8_t direction) {
            timeMinutes += direction;
            cbSetTime(timeHours, timeMinutes);
            cbDisplay(timeHours, timeMinutes);
        }

        static uint8_t alarmHours, alarmMinutes, timeHours, timeMinutes;
        static uint8_t updownFnNum; // 0-None, 1-AlarmH, 2-AlarmM, 3-TimeH, 4-TimeM
        static cbd cbDisplay;
     static cbt cbSetTime;
     static cba cbSetAlarms;
     static MenuFunction updownFns[5];
     static MenuFunction updownFn;
    };

    uint8_t Menu::alarmHours = 0;
    uint8_t Menu::alarmMinutes = 0;
    uint8_t Menu::timeHours = 0;
    uint8_t Menu::timeMinutes = 0;
    uint8_t Menu::updownFnNum = 0;
    cbd Menu::cbDisplay = NULL;
    cbt Menu::cbSetTime = NULL;
    cba Menu::cbSetAlarms = NULL;
    MenuFunction Menu::updownFn = NULL;

Output:

    In file included from app.ino:7:0:
    menu.h: In constructor 'Menu::Menu()':
    menu.h:9:109: error: cannot convert '<brace-enclosed initializer list>' to 'MenuFunction {aka void (*)(signed char)}' in assignment
    updownFns[5] = {updownNone, updownAlarmHours, updownAlarmMinutes, updownTimeHours, updownTimeMinutes};

Thank you!

body:
First, your `updownFns[5]` can be contain 5 variable. And the last variable index can be 4 not 5 because of array index starts from 0.

Here is the code :

    typedef void (*cbd)(uint8_t, uint8_t);
    typedef void (*cbt)(uint8_t, uint8_t);
    typedef void (*cba)(uint8_t, uint8_t, uint8_t);
    typedef void (*MenuFunction) (int8_t);

    class Menu {
    public:
        Menu() {
            updownFns[0] = updownNone;
            updownFns[1] = updownAlarmHours;
            updownFns[2] = updownAlarmMinutes;
            updownFns[3] = updownTimeHours;
            updownFns[4] = updownTimeMinutes;
        }

        static void Setup(cbd display, cbt setTime, cba setAlarm, uint8_t alarmHours, uint8_t alarmMinutes) {
            cbDisplay = display;
            cbSetTime = setTime;
            cbSetAlarms = setAlarm;
            alarmHours = alarmHours;
            alarmMinutes = alarmMinutes;
            cbSetAlarms(alarmHours, alarmMinutes);
        }
        // Used for menu.UpDown(dir) callback
        static void UpDown(int8_t direction) {
            updownFn(direction);
        }
        // Used for menu.Tab() callback
        static void Tab() {
            updownFnNum++;
            updownFn = updownFns[updownFnNum % 5];
        }

    private:

        static void updownNone(int8_t direction) { }

        static void updownAlarmHours(int8_t direction) {
            alarmHours += direction;
            cbDisplay(alarmHours, alarmMinutes);
            cbSetAlarms(alarmHours, alarmMinutes);
        }

        static void updownAlarmMinutes(int8_t direction) {
            alarmMinutes += direction;
            cbDisplay(alarmHours, alarmMinutes);
            cbSetAlarms(alarmHours, alarmMinutes);
        }

        static void updownTimeHours(int8_t direction) {
            timeHours += direction;
            cbSetTime(timeHours, timeMinutes);
            cbDisplay(timeHours, timeMinutes);
        }

        static void updownTimeMinutes(int8_t direction) {
            timeMinutes += direction;
            cbSetTime(timeHours, timeMinutes);
            cbDisplay(timeHours, timeMinutes);
        }

        static uint8_t alarmHours, alarmMinutes, timeHours, timeMinutes;
        static uint8_t updownFnNum; // 0-None, 1-AlarmH, 2-AlarmM, 3-TimeH, 4-TimeM
        static cbd cbDisplay;
        static cbt cbSetTime;
        static cba cbSetAlarms;
        static MenuFunction updownFns[5];
        static MenuFunction updownFn;
    };

    uint8_t Menu::alarmHours = 0;
    uint8_t Menu::alarmMinutes = 0;
    uint8_t Menu::timeHours = 0;
    uint8_t Menu::timeMinutes = 0;
    uint8_t Menu::updownFnNum = 0;
    cbd Menu::cbDisplay = NULL;
    cbt Menu::cbSetTime = NULL;
    cba Menu::cbSetAlarms = NULL;
    MenuFunction Menu::updownFn = NULL;
    // MenuFunction Menu::updownFns = {};

But still code is not correct. if you look at the signature of this definition

    typedef void (*cba)(uint8_t, uint8_t, uint8_t);
it takes 3 parameters. But inside the code, you give 2 parameter to the function

    cbSetAlarms(alarmHours, alarmMinutes)


body:
The C++ language makes a distinction between an _initialization_ and an
_assignment_. An initialization is the initial value you give to a
variable at the point where you are defining it. An assignment is the
use of the `=` operator anywhere else. Also, the language does not allow
assigning the contents of an array as a whole. You can initialize an
array though.

This:

```c++
Menu() {
    updownFns[5] = {updownNone, updownAlarmHours, updownAlarmMinutes,
        updownTimeHours, updownTimeMinutes};
}
```

is an attempt to assign a whole array. It cannot work. If you want to
initialize the array, do it at the point where it is being defined,
outside of the class definition:

```c++
MenuFunction Menu::updownFns[5] = {updownNone, updownAlarmHours,
    updownAlarmMinutes, updownTimeHours, updownTimeMinutes};
```


message:
Problem with character concatenation algorithm in matrix led

good afternoon, I am making a 7x10 led matrix in which I use a CD4017 to handle the 7 rows and 2 cascaded shift registers to handle the 10 columns.
 I first tried a programming to turn on my entire led matrix and it worked fine. Then, I tried to make a character appear statically and it worked fine. Next, I tried to make that character sweep from right to left and it worked fine. But, what I am having a hard time with is sweeping the message from right to left smoothly with a column of character to character spacing.

 What I originally thought is that if I wanted to move a character from right to left, I have to shift the column values for all the rows by an appropriate amount (shift step) and once the character has been shifted enough, I start feeding the column values of the next character in the message for which, the formula that would create the right to left shift effect is:
(current_char<scroll) | (next_char>>(8-shift_step)-scroll)
 But I don't get the expected result, the message scrolls from right to left but it doesn't do it with a column of separation between character and character and it doesn't do it in a fluid way either. In addition to that at the end of sweeping the message appears something strange that should not be there.

 I recorded a video showing what I am saying: https://drive.google.com/file/d/1ebO5zassWY060mvWACPhcSLeOi5JmZAC/view

Code:
```arduino
/*
 char_data is a two dimensional constant array that holds the 5-bit column values
 of individual rows for ASCII characters that are to be displayed on a 7x10 matrix.
*/
const byte char_data[95][7]={
    {0, 0, 0, 0, 0, 0, 0}, // space
    {0b100, 0b100, 0b100, 0b100, 0b100, 0, 0b100}, // !
    {0b1010, 0b1010, 0b1010, 0, 0, 0, 0}, // "
    {0b1010, 0b1010, 0b11111, 0b1010, 0b11111, 0b1010, 0b1010}, // #
    {0b100, 0b1111, 0b10100, 0b1110, 0b101, 0b11110, 0b100}, // $
    {0b11000, 0b11001, 0b10, 0b100, 0b1000, 0b10011, 0b11}, // %
    {0b1000, 0b10100, 0b10100, 0b1000, 0b10101, 0b10010, 0b1101}, // &
    {0b100, 0b100, 0b100, 0, 0, 0, 0}, // '
    {0b100, 0b1000, 0b10000, 0b10000, 0b10000, 0b1000, 0b100}, // (
    {0b100, 0b10, 0b1, 0b1, 0b1, 0b10, 0b100}, // )
    {0b100, 0b10101, 0b1110, 0b100, 0b1110, 0b10101, 0b100}, // *
    {0, 0b100, 0b100, 0b11111, 0b100, 0b100, 0}, // +
    {0, 0, 0, 0, 0b100, 0b100, 0b1000}, // ,
    {0, 0, 0, 0b11111, 0, 0, 0}, // -
    {0, 0, 0, 0, 0, 0, 0b100}, // .
    {0, 0b1, 0b10, 0b100, 0b1000, 0b10000, 0}, // /
    {0b1110, 0b10001, 0b10011, 0b10101, 0b11001, 0b10001, 0b1110}, // 0
    {0b110, 0b1100, 0b100, 0b100, 0b100, 0b100, 0b1110}, // 1
    {0b1110, 0b10001, 0b1, 0b110, 0b1000, 0b10000, 0b11111}, // 2
    {0b11111, 0b1, 0b10, 0b110, 0b1, 0b10001, 0b1111}, // 3
    {0b10, 0b110, 0b1010, 0b10010, 0b11111, 0b10, 0b10}, // 4
    {0b11111, 0b10000, 0b11110, 0b1, 0b1, 0b10001, 0b1110}, // 5
    {0b01110, 0b10001, 0b10000, 0b11110, 0b10001, 0b10001, 0b1110}, // 6
    {0b11111, 0b1, 0b10, 0b100, 0b1000, 0b1000, 0b1000}, // 7
    {0b01110, 0b10001, 0b10001, 0b1110, 0b10001, 0b10001, 0b1110}, // 8
    {0b01110, 0b10001, 0b10001, 0b1111, 0b1, 0b10001, 0b1110}, // 9
    {0, 0, 0b100, 0, 0b100, 0, 0}, // :
    {0, 0, 0b100, 0, 0b100, 0b100, 0b1000}, // ;
    {0b10, 0b100, 0b1000, 0b10000, 0b1000, 0b100, 0b10}, // <
    {0, 0, 0b11111, 0, 0b11111, 0, 0}, // =
    {0b1000, 0b100, 0b10, 0b1, 0b10, 0b100, 0b1000}, // >
    {0b1110, 0b10001, 0b1, 0b10, 0b100, 0, 0b100}, // ?
    {0b1110, 0b10001, 0b10111, 0b10101, 0b10110, 0b10000, 0b1111}, // @
    {0b1110, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001}, // A
    {0b11110, 0b10001, 0b10001, 0b11110, 0b10001, 0b10001, 0b11110}, // B
    {0b1110, 0b10001, 0b10000, 0b10000, 0b10000, 0b10001, 0b1110}, // C
    {0b11110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b11110}, // D
    {0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b11111}, // E
    {0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b10000}, // F
    {0b1110, 0b10001, 0b10000, 0b10111, 0b10101, 0b10001, 0b1110}, // G
    {0b10001, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001}, // H
    {0b11111, 0b100, 0b100, 0b100, 0b100, 0b100, 0b11111}, // I
    {0b1, 0b1, 0b1, 0b1, 0b1, 0b10001, 0b1110}, // J
    {0b10001, 0b10001, 0b10010, 0b11100, 0b10010, 0b10001, 0b10001}, // K
    {0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b11111}, // L
    {0b10001, 0b11011, 0b10101, 0b10101, 0b10001, 0b10001, 0b10001}, // M
    {0b10001, 0b10001, 0b11001, 0b10101, 0b10011, 0b10001, 0b10001}, // N
    {0b1110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b1110}, // O
    {0b11110, 0b10001, 0b10001, 0b11110, 0b10000, 0b10000, 0b10000}, // P
    {0b1110, 0b10001, 0b10001, 0b10001, 0b10101, 0b10011, 0b1111}, // Q
    {0b11110, 0b10001, 0b10001, 0b11110, 0b10001, 0b10001, 0b10001}, // R
    {0b1111, 0b10000, 0b10000, 0b1110, 0b1, 0b1, 0b11110}, // S
    {0b11111, 0b100, 0b100, 0b100, 0b100, 0b100, 0b100}, // T
    {0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b1110}, // U
    {0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b1010, 0b100}, // V
    {0b10001, 0b10001, 0b10001, 0b10101, 0b10101, 0b11011, 0b10001}, // W
    {0b10001, 0b10001, 0b1010, 0b100, 0b1010, 0b10001, 0b10001}, // X
    {0b10001, 0b10001, 0b1010, 0b100, 0b100, 0b100, 0b100}, // Y
    {0b11111, 0b1, 0b10, 0b100, 0b1000, 0b10000, 0b11111}, // Z
    {0b1110, 0b1000, 0b1000, 0b1000, 0b1000, 0b1000, 0b1110}, // [
    {0, 0b10000, 0b1000, 0b100, 0b10, 0b1, 0}, // backward slash
    {0b1110, 0b10, 0b10, 0b10, 0b10, 0b10, 0b1110}, // ]
    {0, 0, 0b100, 0b1010, 0b10001, 0, 0}, // ^
    {0, 0, 0, 0, 0, 0, 0b11111}, // _
    {0b1000, 0b100, 0b10, 0, 0, 0, 0}, // `
    {0, 0, 0b1110, 0b1, 0b1111, 0b10001, 0b1111}, // a
    {0b10000, 0b10000, 0b10000, 0b11110, 0b10001, 0b10001, 0b11110}, // b
    {0, 0, 0b1110, 0b10001, 0b10000, 0b10001, 0b1110}, // c
    {0b1, 0b1, 0b1, 0b1111, 0b10001, 0b10001, 0b1111}, // d
    {0, 0, 0b1110, 0b10001, 0b11111, 0b10000, 0b1111}, // e
    {0b1110, 0b1001, 0b11100, 0b1000, 0b1000, 0b1000, 0b1000}, // f
    {0, 0, 0b1110, 0b10001, 0b1111, 0b1, 0b1110}, // g
    {0b10000, 0b10000, 0b10000, 0b11110, 0b10001, 0b10001, 0b10001}, // h
    {0b100, 0, 0b100, 0b100, 0b100, 0b100, 0b1110}, // i
    {0b1, 0, 0b11, 0b1, 0b1, 0b10001, 0b1110}, // j
    {0b10000, 0b10000, 0b10001, 0b10010, 0b11100, 0b10010, 0b10001}, // k
    {0b1100, 0b100, 0b100, 0b100, 0b100, 0b100, 0b1110}, // l
    {0, 0, 0b11110, 0b10101, 0b10101, 0b10101, 0b10101}, // m
    {0, 0, 0b11110, 0b10001, 0b10001, 0b10001, 0b10001}, // n
    {0, 0, 0b1110, 0b10001, 0b10001, 0b10001, 0b1110}, // o
    {0, 0, 0b1111, 0b1001, 0b1110, 0b1000, 0b1000}, // p
    {0, 0, 0b1111, 0b10001, 0b1111, 0b1, 0b1}, // q
    {0, 0, 0b10111, 0b11000, 0b10000, 0b10000, 0b10000}, // r
    {0, 0, 0b1111, 0b10000, 0b1110, 0b1, 0b11110}, // s
    {0b100, 0b100, 0b1110, 0b100, 0b100, 0b100, 0b11}, // t
    {0, 0, 0b10001, 0b10001, 0b10001, 0b10011, 0b1101}, // u
    {0, 0, 0b10001, 0b10001, 0b10001, 0b1010, 0b100}, // v
    {0, 0, 0b10001, 0b10001, 0b10101, 0b11111, 0b10101}, // w
    {0, 0, 0b10001, 0b1010, 0b100, 0b1010, 0b10001}, // x
    {0, 0, 0b10001, 0b10001, 0b1111, 0b1, 0b11110}, // y
    {0, 0, 0b11111, 0b10, 0b100, 0b1000, 0b11111}, // z
    {0b10, 0b100, 0b100, 0b1000, 0b100, 0b100, 0b10}, // {
    {0b100, 0b100, 0b100, 0b100, 0b100, 0b100, 0b100}, // |
    {0b1000, 0b100, 0b100, 0b10, 0b100, 0b100, 0b1000}, // }
    {0, 0, 0, 0b1010, 0b10101, 0, 0} // ~
};
char message[] = "MATRIX LED 7X10 WITH ATMEGA328p";
int string_length = strlen(message);
byte shift_step = 1;

void setup(){
    // PORTB as output.
    // Pin 13: ClockRegister
    // Pin 12: Latch
    // Pin 11: Data
    // Pin 10: Reset
    // Pin 9: Clock4017
    DDRB = 0b111111;
    // Makes sure the 4017 value is 0.
    PORTB |= (1 << PB2);
    PORTB &= ~(1 << PB2);
    Serial.begin(9600);
}

void send_data(uint16_t data){
    uint16_t mask = 1, flag = 0;
    for (byte i=0; i<10; i++){
        flag = data & mask;
        if (flag) PORTB |= (1 << PB3);
        else PORTB &= ~(1 << PB3);
        PORTB |= (1 << PB5);
        PORTB &= ~(1 << PB5);
        mask <<= 1;
    }
    PORTB |= (1 << PB4);
    PORTB &= ~(1 << PB4);
}

void display_pattern(byte loops){
    for (byte c=0; c<string_length; c++){ // For each character
        for (byte scroll=0; scroll<10; scroll++){ // For each column.
            for (byte t=0; t<loops; t++){ // The delay we get with loops.
                for (byte z=0; z<7; z++){ // For each row.
                    // To obtain the position of the current character in the char_data array, subtract 32 from the ASCII value of the character itself.
                    byte index = message[c];
                    byte temp = char_data[index-32][z];
                    byte index_2 = message[c+1];
                    byte temp_2 = char_data[index_2-32][z];
                    send_data((temp<<scroll) | (temp_2>>(8-shift_step)-scroll));
                    delayMicroseconds(800);
                    // Clear the row so we can go on to the next row without smearing.
                    send_data(0);
                    // On to the next row.
                    PORTB |= (1 << PB1);
                    PORTB &= ~(1 << PB1);
                }
                // Select the first row.
                PORTB |= (1 << PB2);
                PORTB &= ~(1 << PB2);
            }
        }
    }
}

void loop(){
    display_pattern(10);
    delay(100000);
}
```
I appreciate the help.

body:
Here are a few issues that I noticed in this code. I think that, if you
manage to address them, you should get a smooth display:

 1. In the expression `(temp_2>>(8-shift_step)-scroll)`, the amount of
    shift will be negative when `scroll` gets larger than 7. A righ
    shift by a negative amount is not a left shift: it is undefined
    behavior. Judging by the video, it seems the compiler does no shit
    at all in this case.

 2. If you want a one pixel space between the characters, you should
    move to the next character in the string every six pixels, thus the
    scroll variable should count from 0 to 5.

 3. Be aware that there could be up to three characters simultaneously
    (partially) displayed on the screen: when one character is centered,
    you should be able to see the edges of both its neighbors.

 4. As noted by hcheung in a comment, when you get to the last character
    in the string, the expression `message[c+1]` is reading past the end
    of that string.


message:
Connect OLED SSD1306 to Elegoo Uno R3

I'm trying to connect the [OLED SSD1306][1] screen to my Elegoo Uno R3 and display something using Arduino IDE. However, nothing shows up on the screen for some reason.

I have connected every pin in the following way:

 - VCC: 3.3V
 - GND: GND
 - SCL: A5
 - SDA: A4

You can see the setup in the following pictures:

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

[![enter image description here][2]][2]

Then, I'm using the code from [this tutorial][3], that is, [this code][4], to see if the setup is correct, but nothing shows up on the screen. My question is: does anybody know if this is right way to do it? Even though I'm using analog pins and the screen needs digital ones, [I read online][5] that it doesn't matter:

> The analog input pins can be used as digital pins, referred to as A0, A1, etc. The exception is the Arduino Nano, Pro Mini, and Mini’s A6 and A7 pins, which can only be used as analog inputs.

I also saw in [Elegoo Uno R3's guide][6] that the A4 and A5 pins are used for the I2C protocol, which is the one that this OLED screen uses:

[![enter image description here][7]][7]

So as far as I know, from the hardware point of view, everything seems to be correct, right?

  [1]: https://i.stack.imgur.com/yBtYQ.jpg
  [2]: https://i.stack.imgur.com/3IA3T.jpg
  [3]: https://randomnerdtutorials.com/guide-for-oled-display-with-arduino/
  [4]: https://raw.githubusercontent.com/RuiSantosdotme/Random-Nerd-Tutorials/master/Projects/OLED/oled_adafruit_demo.ino
  [5]: https://www.arduino.cc/reference/en/language/functions/digital-io/digitalread/
  [6]: https://epow0.org/~amki/car_kit/Datasheet/ELEGOO UNO R3 Board.pdf
  [7]: https://i.stack.imgur.com/GHsTU.jpg

body:
You are close. Looks like you have a run-of-the-mill, clone [not Adafruit], 128x64 LCD with / I2C interface.

1. Determine the I2C address by flipping it over and seeing which side a 0 ohm resistor or solder blob is on - either 0 or 1. If it is on the '0' side, the address is 0x3C if it is on the '1' side, it is 0x3D.

Here is a photo of the back and with the address of 0x3c.

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

If the back of yours looks very different, locate and run an I2C device scanner to find the address of your display.

2. Do not use the code that you linked.

From the Arduino IDE, install or update the the Adafruit SSD1306 library, Version 2.57 is what I used to test this.

Once the library is in place, load the example SSD1306_128X64_I2C

Locate this line (near the beginning of the code):

#define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32

Change 0x3D to 0x3C if you need to (as determined earlier). I don't think it is an Adafruit screen, so you can ignore the comment.

3. Triple check your 4 connections

Run demo and audibly gasp - "cool".

PS: Mine works on either 3.3V or 5V

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


message:
How to determine the minimum time for a servo to reach its destination?

We all know servos don't move instantly, which is why it is common to put a delay or a millis() loop whenever you issue a servo.write() command to give it time to reach its target before moving on to the next thing.

What irks me though is that this could be inefficient in situations where the last servo position might be close to its target - you might only need a very short delay in those cases, whereas if it has to sweep the full 359 degrees, you might want more time.

I was disappointed that servo.read() is completely useless for this task (why even include it in the library?) as the following code illustrates:

    #include <Adafruit_TiCoServo.h>
    Adafruit_TiCoServo servo;
    const uint8_t PIN_SERVO = 9;

    void setup() {
      servo.attach(PIN_SERVO);
      Serial.begin(9600);

      Serial.println("start");
      servo.write(180);
      delay(1000);

      int pos;
      while(pos != 0){
        pos = servo.read();
        Serial.println(pos); // because it only returns what the last write() operation
                             // was sent, it immediately thinks it's at pos 0 and exits.
        servo.write(0);
      }

      Serial.println("Done");
    }

So that sucks. It seems that my options are:

1. just use a long delay that accommodates the worst-case scenario. I hate this.
2. add a limit switch at the final target position and just read the state of that switch
3. build some kind of elaborate encoder that you can read an absolute angle from or buy a more expensive servo that can tell you this info

For reference the servo I'm playing with is a hobby servo: MG90S

Specifically my question is to confirm that there are no other options available for the MG90S other than what I've listed above.

body:
in this case there is mostly one simple solution, and there are some better ones.

**the problem you faced with the method:**
First of all, the read() function indeed only returns what you send to it, it mostly is useful for if you want to know what position you send it to in some other part of code(for example can be used to plan what way to go first if you need to go to many points, or if you already are going to the desired position).
but since the rc servo has only one signal wire and that wire sends no signals back you don't know what state they are in, rc servo's are mostly for ease of use and not for accuracy and speed, if you need that you can look into a real servo(stepper motor).
so yes that function doesn't return the actual position, it returns the desired position.

**Solution1:** the easy software based method: to do this you can either read the datasheet to read the speed in duration per degree or measure it, and then use that to calculate the time it would take.
*actually here the Servo.read() function really comes in use, so this is a perfect example of why you would actually sometimes need or want it.*

 1. save the duration in miliseconds per degree in a variable.
 2. next just before you write to the servo use Servo.read() to get the current theoretical position and use that combined with the position you want to go to calculate the difference in dergees (for example 100 and 40 results in a difference of 60), then multiply that with the duration per step. and you will have the answer of how long a change would take.

**Example1** *warning, untested, might contain spelling mistakes and such*

        /* tuned delay Sweep
      This example code is in the public domain.
      No warranty

      modified 27 March 2023
      by Daan V.Loon
    */

    #include <Servo.h>
    #define DELAYPERDEGREE 2 //this is the value for the sg90 servo from the datasheet(0,12s(120ms)per 60degrees.
    #define SAFETYMARGIN 110 //this is to add 10% extra time to wait, to make sure it finishes in time even under load.
    //# define is used kind of like a variable that doesn't need to change, purely in code and not in ram
    unsigned long waitDuration=0;//variable that shows how long to wait.

    Servo myservo;

    unsigned long CalcWait(Servo s,int desiredPosition)//method to calculate and return duration to wait in ms 1000ms is 1 s.
    {
      int spos=s.read();
      if(spos>desiredPosition){return (((spos-desiredPosition)*DELAYPERDEGREE)*SAFETYMARGIN)/100;}
      else{ return(((desiredPosition-spos)*DELAYPERDEGREE)*SAFETYMARGIN)/100;}
    }//end of method

    void ServoAndWait(int pos){
      //insert range limiting code here if needed, warning this method doesn't check if you try to use numbers bigger or smaller than your servo or the servo library can actually handle.
      waitDuration=CalcWait(myservo,pos);//call method to update how long to wait, needs to be done before telling the servo to move.
      myservo.write(pos);//tell servo to rotate
      delay(waitDuration);//blocking wait for servo to complete
    }
    void setup() {
      myservo.attach(2);
      ServoAndWait(180);//rotate to 180 degrees and wait until it should be there+10% with the safetymargin of 110
    }

    void loop() {
        ServoAndWait(0);
        ServoAndWait(180);
        //this should reult in the famous sweep example, however then at the max speed of your servo, this way you can test it.
        //to optimize speed use a safetymargin far over 100(like 200 or such) then reduce it until you see it just stop or just not stop anymore at the edges.
        //also make sure to first test if your servo can actually handle 0 and 180 degrees, for example first test if it moves if you tell it to go from 10 to 0 and from 170 to 180, not all servos reach the full 180 degree range.

      }

**Example2:(no comments)**

    /* tuned delay Sweep
      This example code is in the public domain.
      No Warranty

      modified 27 March 2023
      by Daan V.Loon
    */

    #include <Servo.h>
    #define DELAYPERDEGREE 2
    #define SAFETYMARGIN 110
    unsigned long waitDuration = 0;
    Servo myservo;

    unsigned long CalcWait(Servo s, int desiredPosition)
    {
      int spos = s.read();
      if (spos > desiredPosition) {
        return (((spos - desiredPosition) * DELAYPERDEGREE) * SAFETYMARGIN) / 100;
      }
      else {
        return (((desiredPosition - spos) * DELAYPERDEGREE) * SAFETYMARGIN) / 100;
      }
    }

    void ServoAndWait(int pos) {
      waitDuration = CalcWait(myservo, pos);
      myservo.write(pos);
      delay(waitDuration);
    }
    void setup() {
      myservo.attach(2);
      ServoAndWait(180);
    }

    void loop() {
      ServoAndWait(0);
      ServoAndWait(180);
    }
**Example3:** *Shorter and more stack overflow alien themed for people who just copy paste or find this clearer*

    /* tuned delay Sweep
      This example code is in the public domain.
      No Warranty

      modified 27 March 2023
      by Daan V.Loon
    */

    #include <Servo.h>
    #define DELAYPERDEGREE 2
    #define SAFETYMARGIN 110

    Servo myservo;

    unsigned long CalcWait(Servo s, int desiredPosition)
    {
      int spos = s.read();
      return (spos>desiredPosition?((spos - desiredPosition) * DELAYPERDEGREE * SAFETYMARGIN) / 100 : ((desiredPosition - spos) * DELAYPERDEGREE * SAFETYMARGIN) / 100);
    }

    unsigned long waitDuration = 0;
    void ServoAndWait(int pos) {
      waitDuration = CalcWait(myservo, pos);
      myservo.write(pos);
      delay(waitDuration);
    }

    ////---code you would see below, headers and functions and variables above---////
    void setup() {
      myservo.attach(2);
    }

    void loop() {
      ServoAndWait(0);
      ServoAndWait(180);
    }

These above should be fully functional codes that should work for you, they all work the same. I didn't test it with a servo however, but the logic worked when I tested that. also make sure to change the delay per degree to whatever your datasheet says, in this case the datasheet said 0.12s/60 degrees sg90(very common servo for arduino) so I turned seconds into miliseconds and divided it by 60, so 120/60=2, if you have a much faster servo or need more accurate results for different servos you can use the safety margin to tune, or you can use microseconds in the calculations or such, or just multiply the numbers by 10 and then at the end of the calculations divide it by 10 before returning.

**Then here is also the more difficult hardware version**
to do this you can either try to use the servo's buildin hardware and modify the servo with a 4th wire, either add it to the rotation sensor/potentiometer, or add it to the chip if it has a place where you can read it directly, with this you are on your own however since it is very speciffic for every servo.

a more easy way to do this is to use a compactor(or something else that gives you one digital output(typical rc servos will always keep the motor on,and just very rapidly change direction once they are on position, if it actually stops you might just want to read it like a normal digital signal(perhaps do something to protect against motor spikes), and read the wires both standalone instead of comparing them to each other) to compare the voltages on the wires to the motor in the servo, since when it moves one side has a higher voltage than the other side, when it stops, they either are equal or rapidly change to keep position. so you just check for whenever it changes. or if you know the direction you can be even more accurate and fast. this ofcource requires you opening up the servo.

or you can indeed add something like a rotary encoder, no need for a complex one, since you can just count the stripes and if you suddenly don't get changes anymore the servo is also stopped in case you missed some, or you can use something like a small microphone or vibration meter since the servo when it moves, this however may become inaccurate under higher load.
just try to avoid reading it with analog signals, since for what you want to use it for analog signals can be really slow.

**also**
you might want to look into non blocking delays, it won't make the servo's faster, but it allows you to do other things while the servo is moving so you won't have to wait until it is finished.


message:
Conditional assignment of array

I have some really long global variable arrays filled with data.

There is a single function that processes the data. The function works on only one array everytime. This arrays value changes every iteration and gets the value from the global variable arrays.

Since i declare lots of global variable arrays, in order to pass them to the array_to_be_processed_by_the function, the memory is filled up really quickly.

What is the best way to conditionally give values to the array?

For example, there could be a counter in the program, and if the counter is a particular value, the array would be initialized with certain data. Of course, i would also have to call the function, and i would have to keep track of the counter and increase it and zero it at the beginning of the loop, to start from the beginning.

In this approach, only one variable would always be initialized.

    PSEUDOCODE:
    int looper = 0;

    void loop()
    {
      switch(looper)
      {
         case 0:
            my_array[] = {DATA HERE};
            exec_func(myarray);
            looper++;
            continue;
         case 1:
             ......
         case 'last_case':
             ...
             looper = 0;
             break;
      }
    }

However, i am not sure if this approach is the correct one.
Especially for a microcontroller.

One obvious issue, is that the array values are not necessarily the same size.
Therefore, the base array should be destroyed at each `case`?
If this is good approach, should `new/delete` be used on an arduino?

What is the best approach to conditionally initialize an array, so that i don't get out of memory

body:
Let's consider this:

```c++
case 0:
    my_array[] = {DATA HERE};
    exec_func(myarray);
```

This is not quite valid C++, but let's pretend you get the syntax right
to make it work. The problem is: doing this will not help you save
memory. Where do you think the compiler is going to store `{DATA HERE}`?
In memory, right. It will be stored as an _anonymous_ array. Then the
initialization of `my_array` will make a _second copy_ of the data in
memory, this time in a named array.

You can avoid this second copy by naming your arrays of constants, and
passing the correct one to your function:

```c++
// At global scope:
const int my_array_0[] = {...};
const int my_array_1[] = {...};

// Within the switch/case:
case 0:
    exec_func(my_array_0);
```

You can even avoid the `switch`/`case` altogether by using an array of
pointers, but that is irrelevant to your current problem.

Your idea of initializing only the array you actually need can work if
you manage to do it _procedurally_, i.e. implementing some recipe with
instructions, rather than copying a set of constant:

```c++
case 0: {
    int my_array[array_size];
    for (int i = 0; i < array_size; i++) {
        my_array[i] = some_expression_to_compute_this_array_item;
    }
    exec_func(myarray);
}
```

This is not always feasible though.

If you really have to store the constants in the program, and you are
using an AVR-based Arduino (like the Uno, Mega, Micro...), then you can
save RAM by storing the arrays of constants in flash memory, and copying
only the one you need to RAM:

```c++
// At global scope:
const int my_array_0[] PROGMEM = {...};
const int array_size_0 = sizeof my_array_0 / sizeof my_array_0[0];
const int my_array_1[] PROGMEM = {...};
const int array_size_1 = sizeof my_array_1 / sizeof my_array_1[0];

// Within the switch/case:
case 0: {
    int my_array[array_size_0];  // array in RAM
    memcpy_P(my_array, my_array_0, sizeof my_array);
    exec_func(my_array);
}
case 1: {
    int my_array[array_size_1];  // array in RAM
    memcpy_P(my_array, my_array_1, sizeof my_array);
    exec_func(my_array);
}
```

Check the documentations of [PROGMEM][] and [`memcpy_P()`][avr-libc] for
the details.

If you go this route, you may consider modifying the function
`exec_func()` so that it expects its parameter to be a pointer to flash
instead of a pointer to RAM. Then you will completely avoid the copy in
RAM.

------------------------------------------------------------------------

**Edit:** expanding on the idea of passing a pointer to flash.

The C++ compiler doesn't really know the difference between a pointer to
RAM and a pointer to flash. If you want to pass a pointer to flash to a
function, you have to write the function in such a way that it expects a
pointer to flash. For example, this function prints out the contents of
a flash-based array:

```c++
// The argument should be a pointer to flash.
void exec_func(const int *data)
{
    for (int i = 0; i < array_size; i++) {
        int number = pgm_read_word(&data[i]);
        Serial.println(number);
    }
}
```

Note that the array is not accessed directly (evaluating `data[i]` would
give garbage). Instead, the address of the element you want (`&data[i]`,
a flash address) is passed to the macro `pgm_read_word()`, which uses
inline assembly to get the relevant data from the flash.

Now you can call this function passing it the address of a `PROGMEM`
array, as in `exec_func(my_array_0);`.

Just for completeness, I will show you how to use an array of pointers
to avoid the `switch`/`case` construct:

```c++
const int my_array_0[] PROGMEM = {...};
const int my_array_1[] PROGMEM = {...};
...

const int *arrays[] = {my_array_0, my_array_1, ...};

int looper = 0;

void loop()
{
    exec_func(arrays[looper]);
    if (++looper == number_of_arrays) looper = 0;
}
```

Note that here `arrays` is a RAM-based array. That's why you can access
the elements directly as `arrays[looper]`. These elements, however, are
pointers to flash-based arrays. If you have so many arrays that `arrays`
gets too big, you might consider putting it also in flash.

[PROGMEM]: https://www.arduino.cc/reference/en/language/variables/utilities/progmem/
[avr-libc]: https://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html#gad92fa2ebe26e65fa424051047d21a0eb


message:
Changing Frequency of PWM Pin on Arduino Uno

I am trying to change the frequency of the PWM output from an Arduino Uno R3 (Been using Pin 9) to 200 Hz with a duty cycle of 20%. This is for an ESC that is connected to a 12V motor, and I know the ESC works as if I input a 200 HZ wave from a waveform generator the motor runs. However, I have been finding it difficult to do the same thing with an Arduino Uno and I believe it is due to the frequency being a default of 490 Hz, so I need a way to change that frequency to 200 Hz. Are there any libraries or specific ways to do so?

Thanks!

body:
If you are prepared to use Timer 2 (Pin D3) this code will do it:

    void setup()
     {
      pinMode (3, OUTPUT);

      TCCR2A = bit (WGM20) | bit (WGM21) | bit (COM2B1); // fast PWM, clear OC2B on compare
      TCCR2B = bit (WGM22) | bit (CS20) | bit (CS21) | bit (CS22); // prescaler of 1024
      OCR2A =  77;    // zero relative
      OCR2B =  15;    // 20% duty cycle
      }  // end of setup

    void loop()
      {
      // do other stuff here
      }

More information on the Atmega328P timers on [my page about timers](http://gammon.com.au/timers).

The figure 77 is obtained from:

    16000000 / 1024 / 78 = 200.32

In other words, the prescaler of 1024 is divided into the clock of 16 MHz, and then we count up to 78, giving a result of just over 200. I actually use 77 because the timer is zero-relative (it counts from 0 to 77, giving 78 counts). This means the frequency is slightly out (it will be 200.32 Hz rather than 200 but that could be close enough).

---

You could also do it with Timer 1 (pin D10) to get slightly more accurate results, like this:

    void setup()
     {
      pinMode (10, OUTPUT);

      // mode 15
      TCCR1A = bit (WGM10) | bit (WGM11) | bit (COM1B1); // fast PWM, clear OC1B on compare
      TCCR1B = bit (WGM12) | bit (WGM13) | bit (CS11);   // fast PWM, prescaler of 8
      OCR1A = 10000 - 1;   // what to count to
      OCR1B = 2000 - 1;    // duty cycle
      }  // end of setup

    void loop()
      {
      // do other stuff here
      }

In this case I have used a prescaler of 8 and a count-up value of 10000, as follows:

    16000000 / 8 / 10000 = 200

In this case the answer is exactly 200, which will be more accurate than the 200.32 obtained from using Timer 2. That is because Timer 1 is a 16-bit timer and has higher resolution.


body:
You can also use my newly-created [**AVR_PWM**](https://github.com/khoih-prog/AVR_PWM) library to shield you from dealing with complex hardware registers

For example

```cpp
#include "AVR_PWM.h"

#if ( PWM_USING_ATMEGA2560 )
  // Pins tested OK in Mega
  //#define pinToUse      12            // Timer1B on Mega
  //#define pinToUse      11            // Timer1A on Mega
  //#define pinToUse       9            // Timer2B on Mega
  //#define pinToUse       2            // Timer3B on Mega
  //#define pinToUse       3            // Timer3C on Mega
  //#define pinToUse       5            // Timer3A on Mega
  //#define pinToUse       6            // Timer4A on Mega
  //#define pinToUse       7            // Timer4B on Mega
  #define pinToUse       8            // Timer4C on Mega
  //#define pinToUse      46            // Timer5A on Mega
  //#define pinToUse      45            // Timer5B on Mega
  //#define pinToUse      44            // Timer5C on Mega

#elif ( PWM_USING_ATMEGA_32U4  )
  // Pins tested OK on 32u4
  //#define pinToUse      5            // Timer3A on 32u4
  #define pinToUse      9            // Timer1A on 32u4
  //#define pinToUse      10            // Timer1B on 32u4

#else

  // Pins tested OK on Nano / UNO
  #define pinToUse      9            // Timer1A on UNO, Nano, etc
  //#define pinToUse     10            // Timer1B on UNO, Nano, etc
  //#define pinToUse      5               // Timer0B on UNO, Nano, e
  //#define pinToUse       3            // Timer2B on UNO, Nano, etc
#endif

//creates pwm instance
AVR_PWM* PWM_Instance;

float frequency;
float dutyCycle;

void setup()
{
  Serial.print(F("\nStarting PWM_Basic on "));
  Serial.println(BOARD_NAME);
  Serial.println(AVR_PWM_VERSION);

  //assigns PWM frequency of 200 Hz and a duty cycle of 0%
  PWM_Instance = new AVR_PWM(pinToUse, 200, 0);
}

void loop()
{
  frequency = 200;
  dutyCycle = 20;

  PWM_Instance->setPWM(pinToUse, frequency, dutyCycle);

  delay(10000);
  dutyCycle = 90;

  PWM_Instance->setPWM(pinToUse, frequency, dutyCycle);

  delay(10000);
}
```


message:
Arduino not recognizing external microcontroller

I've been trying to follow the official [Arduino instructions][1] on how to program and power an external breadboard, and I've gotten a pack of ATmega328p's that may or may not have been preloaded with the bootloader (found [here][2]). From the title, I assumed that they were, in fact, preloaded, but I followed the instructions to "reload it" from a working Arduino (with its original microcontroller), and I did it with the following circuit setup (this is the best image that I have of it, unfortunately, I promise I've checked that the wiring actually is equivalent to the original diagram, just shifted around for convenience on the breadboard):

[![enter image description here][3]][3]

I'm not sure whether I should've kept the original microcontroller in, as the guide ambiguously shows a void in the area where the controller should be in the provided diagram...

[![enter image description here][4]][4]

...but my thinking was that the Arduino basically isn't anything without its attached microcontroller, so attempting to "send" bootloader code to a separate microcontroller would require a plugged in microcontroller, and that was the only way I got it to work.

With all this set up, I tried to test using this new microcontroller, and it worked perfectly when mounted in the provided microcontroller area. However, when I tried to follow this up with the steps detailed in the guide, [found here][5], with the following circuit (slightly better angle):

[![enter image description here][6]][6]

...I was faced with errors of being unable to connect.

[![enter image description here][7]][7]

From what I understand, it seems like the Arduino should automatically detect that no microcontroller is plugged in, hence allowing the stated "FTDI chip can talk to the microcontroller on the breadboard instead" from the guide. However, the error I'm getting seems to be the same as the error I got when I just plainly tried to send code or program without any microcontroller connected, so I'm assuming this implies that it can't find any microcontroller, either internal or standalone.

From googling this error, it seems that others have had this problem with seemingly no solution, and I have absolutely no idea how I could fix this. If there's something I'm missing, would greatly appreciate the help.

side note, when I was idly testing out the program with a tiny test circuit that lights up an LED, after programming it with a program that turns on a GPIO pin, connecting that pin to the LED, it did in fact light up. I'm concluding this means that the setup of the actual microcontroller is functional, but it's unable to be written to. this has also happened with the original microcontroller that I tried to simply program externally.

any help is appreciated, thanks for reading!

  [1]: https://docs.arduino.cc/built-in-examples/arduino-isp/ArduinoToBreadboard
  [2]: https://www.digikey.com/en/products/detail/universal-solder-electronics-ltd/ATMEGA328P-PU-Arduino-Bootloader/16822123
  [3]: https://i.stack.imgur.com/M0l4b.png
  [4]: https://i.stack.imgur.com/qPZNg.png
  [5]: https://docs.arduino.cc/built-in-examples/arduino-isp/ArduinoToBreadboard#uploading-using-an-arduino-board
  [6]: https://i.stack.imgur.com/WtIeI.png
  [7]: https://i.stack.imgur.com/AAoxd.png

body:
In the case of using an Arduino as a USB/UART (FTDI) adapter to upload a sketch onto a barebones Arduino (ATMEGA328P) via its own bootloader,  a reset of that MCU chip must preceed the sketch upload. That is because, immediately following the reset, the bootloader watches the serial traffic to see if this is marked as a sketch upload and, if so, processes it. If this reset operation fails, for example through a bad or missing connection, the sketch upload attempt will also fail.
A good description of the sketch upload process can  be found here: https://www.instructables.com/Overview-the-Arduino-sketch-uploading-process-and-/


message:
Buttons pressed in correct order

I’m trying to figure out the best way of doing this, currently using a bunch messy if-statements which kind of work. I have an IR sensor and three buttons that all need to be activated in the right order. Each sensor/button will activate LEDs and sound effects. First, when sensor1 goes HIGH, button1 can be pressed momentarily, then button2, then button3. If sensor1 is LOW, then nothing should happen when the buttons are pressed. When sensor1 is HIGH then the buttons should be pressed in the right order to progress through the sequence. When sensor1 goes back to LOW it should reset everything and allow the sequence to be run again when HIGH. Should I look into case switches for this?

Thank you

Jason

body:
This is a classic application for a state machine, in which you keep track of where your process currently is in the sequence of events that must take place. The 'state' is just a numeric variable whose value you change whenever a significant event takes place.

You would probably assign 0 - Initial state, waiting for an event (or the first event); 1 - Sensor is high, 2 - button-1 went high, 3 - button-1 went low; ... etc.

It always helps to sketch out your state machine on paper, drawing a circle for each state, and arrows from each state 'x' to whatever the next state should be if an event 'y' happens while in state 'x'. The events are sensors and buttons going HIGH or LOW. In a particular state, no arrow for some event means you want to ignore that event while you are in that state.

Once you have drawn the map you can code the state machine. A common way of coding it is with a `switch`-`case` block, one case per defined state. Inside each `case` block, you test only for those events for which there is an arrow leading from that state to another state.

As you add new conditions, (e.g. "What should happen if the sensor goes low after button-1 has been pressed?"), `switch`-`case` logic will be much easier to modify than if you had used a complex collection of `if`-`then` statements. And you *will* be adding new conditions & removing or fixing wrong ones as you discover ways the device fails or humans do things you didn't anticipate. (Ask me how I know this! :-)

It will be really helpful to be able to go back to your state map to visualize what should (or shouldn't) happen, and what to change (on the map) to make that behavior. From the updated map, it is usually easy to see what code needs to be added, deleted, or fixed in the `switch`-`case` block.


message:
I2C HMC5983 communication issue

I have a really weird problem, when I run the exmple wire (I2C) scanner from Arduino, I get:

**I2C Scanner**
**Scanning...**
**I2C device found at address 0x1E  !**
**done**

However when I try directly to the 0x1E I get the following error code 2:

**received NACK on transmit of address.**

Below is my code that i did only modify the example code:
```
#include <Wire.h>

void setup() {
  Wire.begin();

  Serial.begin(9600);
  while (!Serial); // Leonardo: wait for Serial Monitor
  Serial.println("\nI2C Scanner");
}

void loop() {

  Serial.println("Scanning...");

  byte address = 0x1E;

  Wire.beginTransmission(address);
  byte error = Wire.endTransmission();

  if (error == 0) {
    Serial.print("I2C device found at address 0x1E");
  } else if (error == 1) {
      Serial.print("data too long to fit in transmit buffer.");
  }
  else if (error == 2) {
      Serial.print("received NACK on transmit of address.");
  }
  else if (error == 3) {
      Serial.print("received NACK on transmit of data.");
  }
  else if (error == 4) {
      Serial.print("Unknown error at address 0x");
  }

  delay(5000); // Wait 5 seconds for next scan
}
```

body:
There are certain situations where the device can send a nack after a valid address is sent - search "received NACK on transmit of address". Nothing I read applies specifically to your situation.

I see nothing in the HMC5983 datasheet (https://www.farnell.com/datasheets/1509871.pdf?_ga=2.219060057.1318745487.1555987311-293789508.1555987311) that could account for what you are seeing.

I don't have an HMC5983 on a GY282 module (you mentioned the module in a different forum) as you do, but I have it's predecessor, HMC5883 which I think is largely comparable, but slower.

I tested your code and I DID NOT get the NACK error - it simply reported finding the the device.

Then, I tested the leanest HMC5883 code I could find and I saw systematic output, which changed as I moved the device.

Then I tested similar code for the HMC5983 (see https://wiki.eprolabs.com/index.php?title=GY-282_HMC5983_Module#Hardware_Connections). That code worked on my slower HMC5883 board (e.g., systematic output).

I suggest the following - double check the solder blobs on the board to make sure I2C/SPI is jumpered properly - also the 3v3 CS blobs - a picture would be helpful.

I would also suggest that you try to run the HMC5983 code that I linked and see what you get.

Hope it helps.


message:
Connecting the MKR GPS shield by cable or as a shield

I have an MKR WiFi 1010 and an MKR GPS Shield. When I connect my GPS Shield using the I2C cable, it works fine.

This works perfectly (the bottom is the MKR Motor Carrier):

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

However, when I use it as a shield (hat?) using the pins, it doesn't.

This doesn't work. The code blocks somewhere (I suspect `GPS.available()`):

[![enter image description here][2]][2]

My question, should it work the same whether it is cabled or put on with the pins? Or should I change my code somehow?

  [1]: https://i.stack.imgur.com/kcKGu.jpg
  [2]: https://i.stack.imgur.com/S5wPC.jpg

body:
From [the shop page][1]:
> It interfaces with Arduino boards either through a serial interface, when used with headers and put on top of a MKR board, or through an I2C interface and a dedicated ESLOV cable supplied as bundle.

From Arduino_MKRGPS library [reference][2]:

`begin()` Parameters:
* GPS_MODE_I2C to use the MKR GPS with the I2C cable (default setting),
* GPS_MODE_SHIELD if using the MKR GPS as a shield.

  [1]: https://store.arduino.cc/collections/shields/products/arduino-mkr-gps-shield
  [2]: https://www.arduino.cc/reference/en/libraries/arduino_mkrgps/begin/


message:
How to reduce codes numbers

I am new in Arduino projects, i made a digital counter that counts from 00 to 99.
Here is my code below

```void setup()
void setup()
{
pinMode(0,OUTPUT);
  pinMode(1,OUTPUT);
  pinMode(2,OUTPUT);
  pinMode(3,OUTPUT);
  pinMode(4,OUTPUT);
  pinMode(5,OUTPUT);
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);
}

void loop()
{
/* segment starts from 00*/
digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(3,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(0,LOW);
digitalWrite(1,HIGH);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(2,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(1,HIGH);
digitalWrite(0,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(3,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(2,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(4,HIGH);
digitalWrite(0,LOW);
digitalWrite(3,LOW);
/* segment will now be 10, the 0 will continue counting up to 1*/

digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(3,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(0,LOW);
digitalWrite(1,HIGH);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(2,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(1,HIGH);
digitalWrite(0,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(3,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(2,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(5,HIGH);
digitalWrite(4,LOW);
/* the segment will now be 20 */

digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(3,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(0,LOW);
digitalWrite(1,HIGH);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(2,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(1,HIGH);
digitalWrite(0,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(3,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(2,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(4,HIGH);
digitalWrite(5,HIGH);

digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(3,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(0,LOW);
digitalWrite(1,HIGH);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(2,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(1,HIGH);
digitalWrite(0,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(3,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(2,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(4,LOW);
digitalWrite(6,HIGH);
digitalWrite(5,LOW);

digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(3,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(0,LOW);
digitalWrite(1,HIGH);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(2,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(1,HIGH);
digitalWrite(0,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(3,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(2,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(4,HIGH);
digitalWrite(6,HIGH);

digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(3,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(0,LOW);
digitalWrite(1,HIGH);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(2,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(1,HIGH);
digitalWrite(0,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(3,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(2,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(5,HIGH);
digitalWrite(4,LOW);

digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(3,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(0,LOW);
digitalWrite(1,HIGH);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(2,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(1,HIGH);
digitalWrite(0,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(3,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(2,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(4,HIGH);

digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(3,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(0,LOW);
digitalWrite(1,HIGH);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(2,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(1,HIGH);
digitalWrite(0,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(3,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(2,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(4,LOW);
digitalWrite(7,HIGH);
digitalWrite(6,LOW);
digitalWrite(5,LOW);

digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(3,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(0,LOW);
digitalWrite(1,HIGH);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(2,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(1,HIGH);
digitalWrite(0,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(3,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(2,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(4,HIGH);
/* the segment will now be 9 0 */

digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(3,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(0,LOW);
digitalWrite(1,HIGH);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(2,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(1,HIGH);
digitalWrite(0,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(3,HIGH);
digitalWrite(0,LOW);
digitalWrite(1,LOW);
digitalWrite(2,LOW);
delay(500);
digitalWrite(0,HIGH);
delay(500);
digitalWrite(4,LOW);
digitalWrite(7,LOW);
/* when it gets here the segment resets to 00*/
}
```
[![arduino counter][1]][1]
It works pretty fine but the problem i have is the code is too long, is there a method i can use to reduce the length of the codes?

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

body:
What you are writing here is some sort of binary counter: a BCD
(binary-coded decimal) counter to be precise. It turns out that the
processor inside the Arduino already works in binary. It's its native
language, so you do not have to tell it how to do binary. You just have
to know what operators to use in order to access the individual bits.

My approach would be to write a function that can display any number `n`
between 0 and 99. The first step is to do the decimal decomposition:
divide by 10, and take the quotient (first digit) and the remainder
(second digit). These digits will be represented in binary within the
machine. The next step is to access the individual bits. This is a two
step process:

1. Shift the bits of the number to the right until the bit you want is
   at the far right. This is accomplished with the right-shift operator.

2. Compute the bitwise AND with the number 1 (0000000000000001 in
   binary). This will clear all the bits but the one you want, and
   result in either 0 (the same as `LOW`) or 1 (i.e. `HIGH`).

For example, if you want to get bit 1 of the number 7, you do

```text
0000000000000111 = 7  initial number
0000000000000011 = 3  shifted one potion to the right
0000000000000001 = 1  bitwise AND-ed with 1
```

In code:

```c++
void display(int n)
{
    int digit0 = n % 10;
    int digit1 = n / 10;
    digitalWrite(0, (digit0 >> 0) & 1);
    digitalWrite(1, (digit0 >> 1) & 1);
    digitalWrite(2, (digit0 >> 2) & 1);
    digitalWrite(3, (digit0 >> 3) & 1);
    digitalWrite(4, (digit1 >> 0) & 1);
    digitalWrite(5, (digit1 >> 1) & 1);
    digitalWrite(6, (digit1 >> 2) & 1);
    digitalWrite(7, (digit1 >> 3) & 1);
}
```

**Edit**: If you need more that 2 digits, you have to successively
divide by 10:

1. Divide the number to be displayed by 10: the rest of the division is
   the rightmost digit

2. replace the original number by the quotient of the division

3. divide again by 10: the rest of the division is the second rightmost
   digit

4. replace the original number by the quotient of the division

5. etc.

For example, for three decimal digits:

```c++
void display(int n)
{
    int digits[3];  // digits[0] is the rightmost digit
    digits[0] = n % 10;
    n /= 10;
    digits[1] = n % 10;
    n /= 10;
    digits[2] = n % 10;

    // Now make sure that n < 10 (otherwise we are missing digits),
    // then display digits[0], digits[1] and digits[2].
}
```

The main program now only has to loop through the numbers 0 to 99, and
display each one in turn:

```c++
void loop()
{
    for (int n = 0; n < 100; n++) {
        display(n);
        delay(500);
    }
}
```


body:
I suggest you look up how to do loops in a C or C++ programming tutorial. For example you can replace:

    void setup()
    {
      pinMode(0,OUTPUT);
      pinMode(1,OUTPUT);
      pinMode(2,OUTPUT);
      pinMode(3,OUTPUT);
      pinMode(4,OUTPUT);
      pinMode(5,OUTPUT);
      pinMode(6,OUTPUT);
      pinMode(7,OUTPUT);
      pinMode(8,OUTPUT);
      pinMode(9,OUTPUT);
    }

with:

    void setup()
    {
      for (int i = 0; i <= 9; i++)
        pinMode(i,OUTPUT);
    }


message:
Cannot read LED state

I am running into a problem on a very basic functionality.

I want to read the state of an LED.
I have confirmed that under the specified circumstances, the LED receives 1.9V.

I try to read its state with this code:

    #define LED_1  5

    void setup()
    {
    pinMode(LED_1, INPUT);
    }

    void loop()
    {
     int led_state = 0;
     if ( digitalRead(LED_1) ) led_state = 1;
     Serial.println("LED State is: ");
     Serial.println(led_state);
    }

However, most of the time, the `led_state` is `0`. Sometimes, it goes to `1`, but then quickly goes back to `0`.

Is it because the voltage is low?

EDIT: I am hooking power directly to one pin of the LED, and the other pin goes to GND (from the same DC power supply).
Also, the power pin from the LED enters inside Arduino Digital Pin 5.

body:
A digital input on the Arduino Uno is guaranteed to read `LOW` if the
input voltage is less than 1.5 V. It is guaranteed to read `HIGH`
if that voltage is above 3.0 V. For any voltage in between, you
have no guarantees.

That being said, the datasheet of the microcontroller shows some
“typical” characteristics. According to those, the input should switch
to `HIGH` when the input voltage goes above 2.6 V, and switch to
`LOW` when it goes below 2.1 V. There is an hysteretic range in
between.

Note, however, that there is no guarantee that your input will behave
like in the typical characteristics. The only guarantees are for
voltages below 1.5 V and above 3.0 V.


body:
For the CMOS logic the treshold is usually 1/2 Vcc, therefore you might get lucky with arduino 3.3V Arduinos, but it's still in undefined area. That usual threshold can also change with operating temperature (like 5V WS2812 stopped working in the winter if you were using 3V3 mcu as a driver)

So what are the possible solutions?

1) route it to the Ax pin and use analogRead + condition (basically software comparator)

2) if the previous is too slow, you can use AC module on the mega328p (Analog Comparator), but you'll most likely have to dig into the datasheet and use specific pin or pins (compare it against internal 1V1 reference or external one set by potentiometer)

3) external OpAmp/Comparator (this one can be used with the original pin, note comparator needs pullup, opamp doesn't)

4) NPN transistor (1k or bigger between base and Anode of the LED, internal pullup or external one between Vcc and Collector, Emmiter to the ground)


body:
On my understanding, this is what you made
[![my understanding][1]][1]

But i think you should do it this way

[![how i think][2]][2]

  [1]: https://i.stack.imgur.com/eJdC3.jpg
  [2]: https://i.stack.imgur.com/QtDNP.jpg

Here is the code

```

int value;
float input;
int delaytime=500;

void setup() {
pinMode(value,INPUT);
Serial.begin(9600); //serial bud rate
}

void loop() {

value=analogRead(A2);
input=(value*5.0)/1022.0;
Serial.println(value);
Serial.println("LED state is: ");
Serial.println(input);
delay(delaytime);

}
```


message:
The same button with one click and double click

i hope to get some help with my code.

I am trying to distinguish between a single press and a quick double press of the button with debouncing.

I am making some silly mistake in my code and i can't find out the problem. If I double press the button, both 'single' and 'double' gets printed on the serial monitor.

Thanks in advance for some help.

```
const int buttonPin = 5;
unsigned long lastPressTime;
int buttonState = 0;
int singlePress = 0;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);

  lastPressTime = millis();
  Serial.begin(9600);
}

void loop() {
  if (!digitalRead(buttonPin) == HIGH && buttonState == 0) {
    unsigned long currentPressTime = millis();

    //two presses within 500ms
    if (currentPressTime - lastPressTime < 500) {
      singlePress = 0;
      //Do double press action
      Serial.println("double");
    } else {
      singlePress = 1;
    }

    //update the last pressed time
    lastPressTime = currentPressTime;
    buttonState = 1;
  } else if (!digitalRead(buttonPin) == LOW) {
    buttonState = 0;
  }

  //check if 500ms have passed with no second button press
  if (singlePress == 1 && lastPressTime  - millis() > 500) {
    singlePress = 0;
    //DO single press stuff
    Serial.println("single");
  }
}

```

body:
The problem is this statement:

    lastPressTime  - millis() > 500

Because time is stored as an unsigned long, this test as it is written now is always true.

You want to measure the time since the last press, so you should subtract the timestamp of the last press from the current time. Replace it with:

    millis() - lastPressTime > 500

And the code will run fine.


body:
Thank you all for your help...

Definitely the problem in my code, to get the one click and double click working like @mhopeng wrote, was this statement:

 ```
lastPressTime  - millis() > 500
 ```
changing it to this

 ```
millis() - lastPressTime > 500
 ```
maked it work.

But what i realize is that my approach is not enough responsive.
Using the approach of @6v6gt is much better than mine.
The reaction is much more responsive and smoother.

 ```
// note the simulation speed is about one third of real time
// adjust timings if using on real hardware.

const int buttonPin = 5;
unsigned long inStateAtMs = millis() ;
int buttonState ;  // 0 = waiting for press, 1= waiting for release 2= differentiate single or double 3= wait button release (double)

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {

  if ( buttonState == 0 ) {
    // wait for button press
    if ( millis() - inStateAtMs > 100 ) {
      if (!digitalRead(buttonPin)) {
        buttonState = 1 ;
        inStateAtMs = millis();
      }
    }
  }
  else if ( buttonState == 1 ) {
    // wait for stable button release 1
    if ( millis() - inStateAtMs > 100 && digitalRead(buttonPin) ) {
      buttonState = 2 ;
      inStateAtMs = millis();
    }
  }
  else if ( buttonState == 2 ) {
    // differentiate between single and double press
    if ( millis() - inStateAtMs > 400 ) {
      // timeout - is a single press
      Serial.println("single");
      buttonState = 0 ;
      inStateAtMs = millis() ;
    }
    else if (  ( ! digitalRead(buttonPin) ) && (millis() - inStateAtMs > 100 ) ) {
      // got second press within timeout - double
      Serial.println("double");
      buttonState = 3 ;
      inStateAtMs = millis() ;
    }
  }
  else if ( buttonState == 3 ) {
    // wait for stable button release 2
    if ( millis() - inStateAtMs > 100 && digitalRead(buttonPin) ) {
      buttonState = 0 ;
      inStateAtMs = millis();
    }
  }
}

 ```

Thanks again all of you for the help


message:
Adafruit_SSD1306.cpp fatal error: pgmspace.h: No such file or directory using SSD1306 on Arduino Nano RP2040

I am currently trying to get a SBC-OLED01 display to run under my Arduino Nano RP2040. I use the [official example from Adafruit][1], attached is the code.

    /**************************************************************************
     This is an example for our Monochrome OLEDs based on SSD1306 drivers

     Pick one up today in the adafruit shop!
     ------> http://www.adafruit.com/category/63_98

     This example is for a 128x64 pixel display using I2C to communicate
     3 pins are required to interface (two I2C and one reset).

     Adafruit invests time and resources providing this open
     source code, please support Adafruit and open-source
     hardware by purchasing products from Adafruit!

     Written by Limor Fried/Ladyada for Adafruit Industries,
     with contributions from the open source community.
     BSD license, check license.txt for more information
     All text above, and the splash screen below must be
     included in any redistribution.
     **************************************************************************/

    #include <SPI.h>
    #include <Wire.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306.h>

    #define SCREEN_WIDTH 128 // OLED display width, in pixels
    #define SCREEN_HEIGHT 64 // OLED display height, in pixels

    // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
    // The pins for I2C are defined by the Wire-library.
    // On an arduino UNO:       A4(SDA), A5(SCL)
    // On an arduino MEGA 2560: 20(SDA), 21(SCL)
    // On an arduino LEONARDO:   2(SDA),  3(SCL), ...
    #define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
    #define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
    Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

    #define NUMFLAKES     10 // Number of snowflakes in the animation example

    #define LOGO_HEIGHT   16
    #define LOGO_WIDTH    16
    static const unsigned char PROGMEM logo_bmp[] =
    { 0b00000000, 0b11000000,
      0b00000001, 0b11000000,
      0b00000001, 0b11000000,
      0b00000011, 0b11100000,
      0b11110011, 0b11100000,
      0b11111110, 0b11111000,
      0b01111110, 0b11111111,
      0b00110011, 0b10011111,
      0b00011111, 0b11111100,
      0b00001101, 0b01110000,
      0b00011011, 0b10100000,
      0b00111111, 0b11100000,
      0b00111111, 0b11110000,
      0b01111100, 0b11110000,
      0b01110000, 0b01110000,
      0b00000000, 0b00110000 };

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

      // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
      if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
        Serial.println(F("SSD1306 allocation failed"));
        for(;;); // Don't proceed, loop forever
      }

      // Show initial display buffer contents on the screen --
      // the library initializes this with an Adafruit splash screen.
      display.display();
      delay(2000); // Pause for 2 seconds

      // Clear the buffer
      display.clearDisplay();

      // Draw a single pixel in white
      display.drawPixel(10, 10, SSD1306_WHITE);

      // Show the display buffer on the screen. You MUST call display() after
      // drawing commands to make them visible on screen!
      display.display();
      delay(2000);
      // display.display() is NOT necessary after every single drawing command,
      // unless that's what you want...rather, you can batch up a bunch of
      // drawing operations and then update the screen all at once by calling
      // display.display(). These examples demonstrate both approaches...

      testdrawline();      // Draw many lines

      testdrawrect();      // Draw rectangles (outlines)

      testfillrect();      // Draw rectangles (filled)

      testdrawcircle();    // Draw circles (outlines)

      testfillcircle();    // Draw circles (filled)

      testdrawroundrect(); // Draw rounded rectangles (outlines)

      testfillroundrect(); // Draw rounded rectangles (filled)

      testdrawtriangle();  // Draw triangles (outlines)

      testfilltriangle();  // Draw triangles (filled)

      testdrawchar();      // Draw characters of the default font

      testdrawstyles();    // Draw 'stylized' characters

      testscrolltext();    // Draw scrolling text

      testdrawbitmap();    // Draw a small bitmap image

      // Invert and restore display, pausing in-between
      display.invertDisplay(true);
      delay(1000);
      display.invertDisplay(false);
      delay(1000);

      testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps
    }

    void loop() {
    }

    void testdrawline() {
      int16_t i;

      display.clearDisplay(); // Clear display buffer

      for(i=0; i<display.width(); i+=4) {
        display.drawLine(0, 0, i, display.height()-1, SSD1306_WHITE);
        display.display(); // Update screen with each newly-drawn line
        delay(1);
      }
      for(i=0; i<display.height(); i+=4) {
        display.drawLine(0, 0, display.width()-1, i, SSD1306_WHITE);
        display.display();
        delay(1);
      }
      delay(250);

      display.clearDisplay();

      for(i=0; i<display.width(); i+=4) {
        display.drawLine(0, display.height()-1, i, 0, SSD1306_WHITE);
        display.display();
        delay(1);
      }
      for(i=display.height()-1; i>=0; i-=4) {
        display.drawLine(0, display.height()-1, display.width()-1, i, SSD1306_WHITE);
        display.display();
        delay(1);
      }
      delay(250);

      display.clearDisplay();

      for(i=display.width()-1; i>=0; i-=4) {
        display.drawLine(display.width()-1, display.height()-1, i, 0, SSD1306_WHITE);
        display.display();
        delay(1);
      }
      for(i=display.height()-1; i>=0; i-=4) {
        display.drawLine(display.width()-1, display.height()-1, 0, i, SSD1306_WHITE);
        display.display();
        delay(1);
      }
      delay(250);

      display.clearDisplay();

      for(i=0; i<display.height(); i+=4) {
        display.drawLine(display.width()-1, 0, 0, i, SSD1306_WHITE);
        display.display();
        delay(1);
      }
      for(i=0; i<display.width(); i+=4) {
        display.drawLine(display.width()-1, 0, i, display.height()-1, SSD1306_WHITE);
        display.display();
        delay(1);
      }

      delay(2000); // Pause for 2 seconds
    }

    void testdrawrect(void) {
      display.clearDisplay();

      for(int16_t i=0; i<display.height()/2; i+=2) {
        display.drawRect(i, i, display.width()-2*i, display.height()-2*i, SSD1306_WHITE);
        display.display(); // Update screen with each newly-drawn rectangle
        delay(1);
      }

      delay(2000);
    }

    void testfillrect(void) {
      display.clearDisplay();

      for(int16_t i=0; i<display.height()/2; i+=3) {
        // The INVERSE color is used so rectangles alternate white/black
        display.fillRect(i, i, display.width()-i*2, display.height()-i*2, SSD1306_INVERSE);
        display.display(); // Update screen with each newly-drawn rectangle
        delay(1);
      }

      delay(2000);
    }

    void testdrawcircle(void) {
      display.clearDisplay();

      for(int16_t i=0; i<max(display.width(),display.height())/2; i+=2) {
        display.drawCircle(display.width()/2, display.height()/2, i, SSD1306_WHITE);
        display.display();
        delay(1);
      }

      delay(2000);
    }

    void testfillcircle(void) {
      display.clearDisplay();

      for(int16_t i=max(display.width(),display.height())/2; i>0; i-=3) {
        // The INVERSE color is used so circles alternate white/black
        display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE);
        display.display(); // Update screen with each newly-drawn circle
        delay(1);
      }

      delay(2000);
    }

    void testdrawroundrect(void) {
      display.clearDisplay();

      for(int16_t i=0; i<display.height()/2-2; i+=2) {
        display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i,
          display.height()/4, SSD1306_WHITE);
        display.display();
        delay(1);
      }

      delay(2000);
    }

    void testfillroundrect(void) {
      display.clearDisplay();

      for(int16_t i=0; i<display.height()/2-2; i+=2) {
        // The INVERSE color is used so round-rects alternate white/black
        display.fillRoundRect(i, i, display.width()-2*i, display.height()-2*i,
          display.height()/4, SSD1306_INVERSE);
        display.display();
        delay(1);
      }

      delay(2000);
    }

    void testdrawtriangle(void) {
      display.clearDisplay();

      for(int16_t i=0; i<max(display.width(),display.height())/2; i+=5) {
        display.drawTriangle(
          display.width()/2  , display.height()/2-i,
          display.width()/2-i, display.height()/2+i,
          display.width()/2+i, display.height()/2+i, SSD1306_WHITE);
        display.display();
        delay(1);
      }

      delay(2000);
    }

    void testfilltriangle(void) {
      display.clearDisplay();

      for(int16_t i=max(display.width(),display.height())/2; i>0; i-=5) {
        // The INVERSE color is used so triangles alternate white/black
        display.fillTriangle(
          display.width()/2  , display.height()/2-i,
          display.width()/2-i, display.height()/2+i,
          display.width()/2+i, display.height()/2+i, SSD1306_INVERSE);
        display.display();
        delay(1);
      }

      delay(2000);
    }

    void testdrawchar(void) {
      display.clearDisplay();

      display.setTextSize(1);      // Normal 1:1 pixel scale
      display.setTextColor(SSD1306_WHITE); // Draw white text
      display.setCursor(0, 0);     // Start at top-left corner
      display.cp437(true);         // Use full 256 char 'Code Page 437' font

      // Not all the characters will fit on the display. This is normal.
      // Library will draw what it can and the rest will be clipped.
      for(int16_t i=0; i<256; i++) {
        if(i == '\n') display.write(' ');
        else          display.write(i);
      }

      display.display();
      delay(2000);
    }

    void testdrawstyles(void) {
      display.clearDisplay();

      display.setTextSize(1);             // Normal 1:1 pixel scale
      display.setTextColor(SSD1306_WHITE);        // Draw white text
      display.setCursor(0,0);             // Start at top-left corner
      display.println(F("Hello, world!"));

      display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text
      display.println(3.141592);

      display.setTextSize(2);             // Draw 2X-scale text
      display.setTextColor(SSD1306_WHITE);
      display.print(F("0x")); display.println(0xDEADBEEF, HEX);

      display.display();
      delay(2000);
    }

    void testscrolltext(void) {
      display.clearDisplay();

      display.setTextSize(2); // Draw 2X-scale text
      display.setTextColor(SSD1306_WHITE);
      display.setCursor(10, 0);
      display.println(F("scroll"));
      display.display();      // Show initial text
      delay(100);

      // Scroll in various directions, pausing in-between:
      display.startscrollright(0x00, 0x0F);
      delay(2000);
      display.stopscroll();
      delay(1000);
      display.startscrollleft(0x00, 0x0F);
      delay(2000);
      display.stopscroll();
      delay(1000);
      display.startscrolldiagright(0x00, 0x07);
      delay(2000);
      display.startscrolldiagleft(0x00, 0x07);
      delay(2000);
      display.stopscroll();
      delay(1000);
    }

    void testdrawbitmap(void) {
      display.clearDisplay();

      display.drawBitmap(
        (display.width()  - LOGO_WIDTH ) / 2,
        (display.height() - LOGO_HEIGHT) / 2,
        logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
      display.display();
      delay(1000);
    }

    #define XPOS   0 // Indexes into the 'icons' array in function below
    #define YPOS   1
    #define DELTAY 2

    void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) {
      int8_t f, icons[NUMFLAKES][3];

      // Initialize 'snowflake' positions
      for(f=0; f< NUMFLAKES; f++) {
        icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
        icons[f][YPOS]   = -LOGO_HEIGHT;
        icons[f][DELTAY] = random(1, 6);
        Serial.print(F("x: "));
        Serial.print(icons[f][XPOS], DEC);
        Serial.print(F(" y: "));
        Serial.print(icons[f][YPOS], DEC);
        Serial.print(F(" dy: "));
        Serial.println(icons[f][DELTAY], DEC);
      }

      for(;;) { // Loop forever...
        display.clearDisplay(); // Clear the display buffer

        // Draw each snowflake:
        for(f=0; f< NUMFLAKES; f++) {
          display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE);
        }

        display.display(); // Show the display buffer on the screen
        delay(200);        // Pause for 1/10 second

        // Then update coordinates of each flake...
        for(f=0; f< NUMFLAKES; f++) {
          icons[f][YPOS] += icons[f][DELTAY];
          // If snowflake is off the bottom of the screen...
          if (icons[f][YPOS] >= display.height()) {
            // Reinitialize to a random position, just off the top
            icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
            icons[f][YPOS]   = -LOGO_HEIGHT;
            icons[f][DELTAY] = random(1, 6);
          }
        }
      }
    }

I downloaded the optimized Adafruit GFX library from [github][2] and installed it as described. As board I use Arduino Nano RP2040 from Arduino Mbed OS in V3.4.1.

Now when I compile the code, I get the following error:

    [...]Arduino\libraries\Adafruit_SSD1306\Adafruit_SSD1306.cpp:42:10: fatal error: pgmspace.h: No such file or directory
    #include <pgmspace.h>
              ^~~~~~~~~~~~
    compilation terminated.

    exit status 1

    Compilation error: exit status 1

Unfortunately, I have not found a solution on the net how to solve the problem, which is why I have now written this question. I tried the "normal" GFX library from the package manager instead of the optimized one, with the same result. I guess the error is in the Adafruit_SSD1306 library, so it doesn't make any difference anyway.

  [1]: https://learn.adafruit.com/monochrome-oled-breakouts/arduino-library-and-examples#run-demo-1757237
  [2]: https://github.com/Bodmer/Adafruit-GFX-Library

body:
What is happening is, in the library you have included, another library is included. There are 2 solutions: delete the `#include pgmspace.h` within one of those libraries or just get `pgmspace.h`.
Hope this helps!


message:
How to find the correct navigation course by gps navigation with Arduino?

I have a problem for about days ago and here it is :

I have an RC plane and wanna make it autonomous via GPS navigation by Arduino

I have an Arduino Mage 2560 onboard connected to a GPS Ublox-Neo-M8N (GPS module) and there is the problem

I want my RC-Plane to read it's position and go to waypoints

The Coordinates of  two waypoints  are defined before on a matrix variable like this example :

    a [1] [3] =
    {
        {38.884675, -116.671035,
         245}
    };

    b [1] [3] =
    {
        {38.725019, -116.580951,
         1180}
    };

    ( 1st is Latitude, 2nd is Longitude and 3rd is height)

So i want my Arduino to read it's current position from gps module's data and calculate the correct Azimuth (correct horizontal angle) and the correct pitch angle (vertical angle) to navigate my plane to the waypoints

and remember, when it reaches to the waypoint "a" with a few error (miss distance = 4 meters), it should be able to ignore navigation to the waypoint of variable "a" and then, navigate to waypoint "b"

I WAND THE EXACT COMMAND FROM ANY LIBRARY TO CALCULATE THOSE TWO ANGLE FOR NAVIGATION (azimuth direction angle and pitch angle to navigate RC-Plane from everywhere o the waypoints

body:
The computation is not difficult. Since your drone is unlikely to travel
for thousands of kilometers, you can assume the Earth is locally flat,
and the latitude and longitude are an orthogonal coordinate system.
First, compute the vector to the next waypoint in Cartesian coordinates
(dx, dy, dz):

```c++
// Defined at global scope.
const float radians_per_degree = M_PI / 180;
const float degrees_per_radians = 180 / M_PI;
const float meters_per_degree = 1e7 / 90;

// For every reading of the GPS:
float dx = (waypoint.longitude - current.longitude) * meters_per_degree
         * cos(current.latitude * radians_per_degree);
float dy = (waypoint.latitude - current.latitude) * meters_per_degree;
float dz = waypoint.height - current.height;
```

Then, from this vector you can get the required angles:

```c++
float azimuth = atan2(dx, dy) * degrees_per_radians;
float pitch_angle = atan(dz/sqrt(dx*dx + dy*dy)) * degrees_per_radians;
```

Note that the approximation breaks down if the drone has to travel for a
distance that is a significant fraction of the distance to the closest
pole. Note also that the approximation errors are inconsequential if you
periodically update your estimate of azimuth and pitch angle: the errors
will be corrected along the way as the drone gets closer and closer to
the waypoint.

**Edit**: timemage posted a very interesting comment, and I would want
to further expand on the precision issue. The AVR floating point support
is indeed limited to single precision. For latitudes and longitudes in
the range shown in the question, the numerical resolution (formally, the
[unit in the last place][ulp]) is (3.81×10−6)° for the latitude
and (7.63×10−6)° for the longitude. This translates to about
42 cm and 66 cm respectively on the surface of the Earth. It
may be just good enough to hit the waypoint to within 4 m.

You could increase the resolution by storing the latitude and longitude
in microdegrees, as 32-bit integers. This should be easy if the GPS
always gives 6 digits after the decimal point: just ignore that
decimal point. Then, once the quantities
`waypoint.longitude - current.longitude`
and `waypoint.latitude - current.latitude` are computed, you can safely
use floating point for the rest of the computations.

[ulp]: https://en.wikipedia.org/wiki/Unit_in_the_last_place