message:
New code results in audio noise

I am working on a circuit that can record audio to an SD when a switch is HIGH and stop recording when the switch is LOW. I am using the TMRpcm library. I previously had an issue solved on these two forums[Recording Audio - Film Name Error][1]and [Trying to save .wav files with new name every loop][2]. These solutions solved my problem but have left me with a new one. Currently the audio recorded on the new code (which I have pasted below) results is a very noisy and muffled audio quality; while the audio recorded on the old code (also posted below) is very clear. Could this be a physical issue and if so what should I do about it? Or is it an issue I am missing in the code?

OLD CODE - provides good quality audio

    //////////////////////////////////////// SD CARD
    #include <SD.h>
    #include <SPI.h>
    #include <TMRpcm.h>
    #define SD_ChipSelectPin 10
    TMRpcm audio;
    //////////////////////////////////////// SWITCH CASE
    int audiofile = 0;     // # of recording
    unsigned long i = 0;
    bool recmode = 0;      // recording state
    //////////////////////////////////////// SWITCH
    int inPin = 2;         // input Switch Pin
    int state = HIGH;      // the current state switch
    int reading;           // the current reading from the switch

    void setup() {
      Serial.begin(9600);
      pinMode(A0, INPUT);  // Microphone
      pinMode(inPin, INPUT_PULLUP); // Switch
      //////////////////////////////////////// SD CARD
      SD.begin(SD_ChipSelectPin);
      audio.CSPin = SD_ChipSelectPin;
    }

    void loop() {

      reading = digitalRead(inPin);
      ////////////////////////////////////////
      while (i < 300000) {
        i++;
      }
      i = 0;
      ////////////////////////////////////////
      if (reading == LOW) {
        if (recmode == 0) {
          recmode = 1;

          Serial.println("Recording");

          audiofile++; // To move case
          switch (audiofile) {
            case 1: audio.startRecording("1.wav", 16000, A0); break;
            case 2: audio.startRecording("2.wav", 16000, A0); break;
            case 3: audio.startRecording("3.wav", 16000, A0); break;
            case 4: audio.startRecording("4.wav", 16000, A0); break;
            case 5: audio.startRecording("5.wav", 16000, A0); break;
            case 6: audio.startRecording("6.wav", 16000, A0); break;
            case 7: audio.startRecording("7.wav", 16000, A0); break;
            case 8: audio.startRecording("8.wav", 16000, A0); break;
            case 9: audio.startRecording("9.wav", 16000, A0); break;
            case 10: audio.startRecording("10.wav", 16000, A0); break;
          }
        }
      }
      ////////////////////////////////////////
      else if (reading == HIGH) {
        recmode = 0;

        Serial.println("Hung-Up");
        switch (audiofile) {
          case 1: audio.stopRecording("1.wav"); break;
          case 2: audio.stopRecording("2.wav"); break;
          case 3: audio.stopRecording("3.wav"); break;
          case 4: audio.stopRecording("4.wav"); break;
          case 5: audio.stopRecording("5.wav"); break;
          case 6: audio.stopRecording("6.wav"); break;
          case 7: audio.stopRecording("7.wav"); break;
          case 8: audio.stopRecording("8.wav"); break;
          case 9: audio.stopRecording("9.wav"); break;
          case 10: audio.stopRecording("10.wav"); break;
        }
      }
    }

NEW CODE - poor quality audio

    //////////////////////////////////////// SD CARD
    #include <SD.h>
    #include <SPI.h>
    #include <TMRpcm.h>
    #define SD_ChipSelectPin 10
    TMRpcm audio;
    //////////////////////////////////////// SWITCH CASE
    unsigned int i = 0;     // # of recording
    unsigned long d = 0;
    bool recmode = 0;      // recording state
    //////////////////////////////////////// SWITCH
    int inPin = 2;         // input Switch Pin
    int state = HIGH;      // the current state switch
    int reading;           // the current reading from the switch

    void setup() {
      //Serial.begin(9600);
      pinMode(A0, INPUT);  // Microphone
      pinMode(inPin, INPUT_PULLUP); // Switch
      //////////////////////////////////////// SD CARD
      SD.begin(SD_ChipSelectPin);
      audio.CSPin = SD_ChipSelectPin;
    }

    void loop() {
      char buffer[50];
      sprintf(buffer, "%i.wav", i++);
      reading = digitalRead(inPin);
      ////////////////////////////////////////
      while (d < 300000) {
        d++;
      }
      d = 0;
      ////////////////////////////////////////
      if (reading == LOW) {
        if (recmode == 0) {
          recmode = 1;

          //Serial.println("Recording");

          audio.startRecording(buffer, 1600, A0);
          //Serial.println(buffer);
        }
      }
      ////////////////////////////////////////
      else if (reading == HIGH) {
        recmode = 0;

        //Serial.println("Hung-Up");

        audio.stopRecording(buffer);
      }
    }

  [1]: https://forum.arduino.cc/index.php?topic=587263.0
  [2]: https://arduino.stackexchange.com/questions/60046/trying-to-save-wav-files-with-new-name-every-loop

body:
Old code:

    audio.startRecording("1.wav", 16000, A0);

New code:

    audio.startRecording(buffer, 1600, A0);

Spot the typo?


sender: user

message:
comprehensive list of common library methods that do not work in interrupt service routines

Where is a comprehensive and authoritative list of commonly used library or built-in methods (functions) that do not work properly in Arduino interrupt service routines?

I am aware of the following:

* do not use delay()
* do not use Serial print methods

which are part of Nick Gammon's advice [linked here][1]. His TLDR summary is:

> TL;DR :
>
> When writing an Interrupt Service Routine (ISR):
>
>
>     Keep it short
>     Don't use delay ()
>     Don't do serial prints
>     Make variables shared with the main code volatile
>     Variables shared with main code may need to be
>                 protected by "critical sections" (see below)
>     Don't try to turn interrupts off or on

however, I am looking for, as I said, a list that is more comprehensive and authoritative.

  [1]: https://gammon.com.au/interrupts

sender: assistant

body:
The basic rule is quite simple, but the list is practically impossible to produce.

The rule is:

* You cannot use anything that relies on an interrupt to function from within an interrupt service routine.

AVR chips only have one interrupt priority. Only one interrupt routine can function at a time. If an interrupt fires whilst an ISR is currently executing that interrupt will be delayed until the ISR finishes.  If that ISR relies on a function that itself needs an ISR to fire (such as `millis()`, or serial transmission), then it will never get to finish.

A partial list of things to know:

* You cannot transmit serial more than there is room in the TX buffer for, or it blocks.
* The time generated by `millis()` (which `delay()` relies on) never changes.
* Servo motors cannot be controlled and will *jitter* if an interrupt routine takes too long.
* `tone()` generated sounds will also jitter since the ISR is delayed while another ISR is executing

And basically anything else that uses interrupts.


body:
> ... that do not work properly in Arduino interrupt service routines ...

A much safer approach would be to ask what **does** work properly in an ISR. Considering that my advice was to "keep it short" that would tend to exclude calling *any* functions except ones which are known to be OK. For example, calling `millis()` or `micros()` to find out the current timer values would be OK (bearing in mind that the figures returned by `millis()` will not increment).

Anything complex enough to be placed in a library would tend to be excluded simply based on that, in my opinion, unless *specifically documented otherwise*.

So, I wouldn't try to write files, do serial output, do I2C output, drive motors, etc.

Really, what an ISR should be doing is one or more of:

 * Setting a flag (eg. "key has been pressed")
 * Note the time (eg. "Pulse received at this moment")
 * Retrieve some value (eg. what number is in a timer register)

Then the main code, not in an ISR, does something lengthier with that data.

The other thing to be concerned about is: *Is a function re-entrant?*

Just as an example, if you are doing `strcpy` in an ISR, is the `strcpy` function coded to be re-entered? (I don't know the answer just now). If it is not re-entrant, and you happen to be doing a `strcpy` in the main code, and the ISR also does a `strcpy` then one of them will be corrupted.

---

In terms of getting a comprehensive list, that would be almost impossible. Some libraries are no longer maintained. Others might be maintained but change from one month to the next, and the change might affect how they work inside an ISR. This is like the question people ask about "which libraries use which timers or pins?". These questions are difficult or impossible to adequately answer.


message:
avrdude: stk500_recv(): programmer is not responding: lilypad arduino

i realise this is probably the most common error that is asked about on this forum, but it is a major issue for me. i have an arduino lilypad main board (with the ATMega328P, boot loader already burned), and a generic FTDI serial to usb adapter plugged into my windows 10 laptop. When i try to upload the Blink program from the Arduino IDE, it fails with the error:

`avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0xfe`

i am using a windows 10 laptop, the Arduino IDE from the windows store. this is a new lilypad, and i have never been able to upload to it. take note that when i reset the board, the pin13 light does flash (but  not the way the Blink program specifies, obviously.

i have already tried:

 - Rebooting my computer
 - Restarting the IDE
 - Turning the COM port on and off
 - Taking out the RX/TX wires from the FTDI converter
 - Pressing the reset button right before uploading (or during uploading)
 - Changing which board it is set as in the IDE
 - Unplugging and re-plugging the USB-Serial converter

[![my wiring, the USB end goes in to the laptop of course][1]][1]

if you have any other possible solutions they would be appreciated, thanks

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

body:
Last time I bought one of the Lilypads, it did not have a bootloader. I had to buy a SMD programmer adapter that presses down over the 328P chip to bootload it as the board did not break out the ICSP pins to any pads.  [![enter image description here][1]][1]

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

I think I got mine here https://hobbyking.com/en_us/atmel-atmega-socket-firmware-flashing-tool.html but I haven't seen them in stock for a while.  Very handy tool tho. Another option is to tack wires to the appropriate uC pins and, connected to a 2x3 header that your Programmer can connect to. Remove the wires when done.


message:
How can I reduce the memory usage on my code?

I wrote this code to control my christmas tree. It takes up the majority of the memory on my Arduino Uno:

    Sketch uses 31822 bytes (98%) of program storage space. Maximum is 32256 bytes.
    Global variables use 1882 bytes (91%) of dynamic memory, leaving 166 bytes for local variables. Maximum is 2048 bytes.
    Low memory available, stability problems may occur.

Does anyone know how I can reduce the memory usage?

Code:

    #include <SPI.h>
    #include <SdFat.h>
    #include <SdFatUtil.h>
    #include <SFEMP3Shield.h>

    #define TREEONE 3
    #define TREETWO 4
    #define TREETHREE 5
    #define TREEFOUR 10

    SdFat sd;
    SFEMP3Shield MP3player;

    const uint8_t volume = 10; // MP3 Player volume 0=max, 255=lowest (off)
    //10 for basement 50 for testing

    const uint16_t monoMode = 1;

    int song = 3;
    int num = 0;
    int count = 0;

    //put arrays here
    byte arrayTree[] = {17,16,9,8,3,2,5,4,17,16,9,8,3, ...etc };

    void setup() {
      initSD();
      initMP3Player();

      pinMode(TREEONE, OUTPUT);
      pinMode(TREETWO, OUTPUT);
      pinMode(TREETHREE, OUTPUT);
      pinMode(TREEFOUR, OUTPUT);

      digitalWrite(TREEONE, HIGH);
      digitalWrite(TREETWO, HIGH);
      digitalWrite(TREETHREE, HIGH);
      digitalWrite(TREEFOUR, HIGH);
    }

    void loop() {
      if(!MP3player.isPlaying()){
        MP3player.playTrack(song);
        MetallicaChristmas();
      }
    }

    void initSD() {
      if(!sd.begin(SD_SEL, SPI_HALF_SPEED))
        sd.initErrorHalt();
      if(!sd.chdir("/"))
        sd.errorHalt("sd.chdir");
    }

    void initMP3Player() {
      uint8_t result = MP3player.begin();
      MP3player.setVolume(volume, volume);
      MP3player.setMonoMode(monoMode);
    }

    void treeFunc() {
        //delay(arrayTimes[i]);
        num = arrayTree[count];

        //TREEONE
        if(num>15){
          if((num%2)==0){
            digitalWrite(TREEONE,HIGH);
          }else{
            digitalWrite(TREEONE,LOW);
          }
        }
        //TREETWO
        if((num)>7){
          if((num%2)==0){
            digitalWrite(TREETWO,HIGH);
          }else{
            digitalWrite(TREETWO,LOW);
          }
        }
        //TREETHREE
        if((num%8)>3){
          if((num%2)==0){
            digitalWrite(TREETHREE,HIGH);
          }else{
            digitalWrite(TREETHREE,LOW);
          }
        }
        //TREEFOUR
        if((num%4)>1){
          if((num%2)==0){
            digitalWrite(TREEFOUR,HIGH);
          }else{
            digitalWrite(TREEFOUR,LOW);
          }
        }
      count = count + 1;
    }

    void MetallicaChristmas()
    {
      //event 1
      delay(670);
      treeFunc();
      delay(248);
      treeFunc();
      //event 2
      delay(116);
      treeFunc();
      delay(248);
      treeFunc();
      //event 3
      delay(100);
      treeFunc();
      delay(248);
      treeFunc();
      //event 4
      delay(132);
      treeFunc();
      delay(248);
      treeFunc();
      //event 5
      delay(125);
      treeFunc();
      delay(248);
      treeFunc();
      //event 6

      ...etc.

body:
As well as `PROGMEM` (as described in the comments), there are a couple of other efficiencies that you can make:

* A function call is expensive (takes a lot of code space), and you are performing a LOT of them!

  * The repetitious calls to `delay()` followed by `treeFunc()` are wasteful. Your commented-out line

            //delay(arrayTimes[i]);

     looks like you were going to do the right thing, so I’d restore that (use `count` instead of `i`) and put the `delay()` numbers in a new `int arrayTimes[]` array.

     `PROGMEM` this array too, of course!

  * Once you’ve done this, you can remove all the calls to `delay()`. You’ll be left with nothing but repeated calls to `treefunc()`, which you can replace with a single loop:

            for (count=0;count<sizeof(arrayTree);++count) {
               treeFunc();
            } // for
      Don’t forget to get rid of the `count = count + 1;` line from `treeFunc()` - it’s now in the `for` loop.

* Also expensive is calling the same function twice except with different parameters in both sides of the `if` in `treeFunc()`. Instead of:

        if (<condition>) {
           Function(1);
        } // if
        else {
           Function(0);
        } // else

 you can instead do:

        Function(<condition>);

 For this to work, you need to know that `HIGH` has the value `1` and `LOW` has the value `0` - and that a `true` condition has the value `1` and a `false` condition has the value `0`.

 So, you need to change the `if ()` slightly:

        digitalWrite(THREEONE, (num%2)>0);

* Finally, the mod `%` operator itself is very expensive, since it is effectively a division, and the Arduino chip doesn’t know how to divide - so the code to do so is large. But the code you’ve written is using binary arithmetic, which the Arduino can do instantly - you just have to write it as such.

 * Instead of `(num%2)>0` use `num & B0001`.
 * Instead of `(num%4)>1` use `num & B0010`.
 * Instead of `(num%8)>3` use `num & B0100`.
 * Instead of `(num)>7` use `num & B1000`.

You’ve probably copied the guts of this code from somewhere else, and while it works it isn’t very efficient. Writing the code as above will greatly reduce your code size, exchanging repeated calls for much smaller `PROGMEM` arrays.


message:
Arduino: incorrect calculation of long integer

I'm doing a simple calculation with integers (on Arduino with ESP8266 12E), but I can't get the expected result and can't find the error. Can someone guide me?

    #define A      200
    #define B      A * 62
    #define C      500

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

       unsigned long aux = 0;

       aux = (B * 500) / C;    // (12400 * 500) / 500 = 12400
       Serial.printf("aux = %d\n", aux);
       aux = aux * C;          // 12400 * 500 = 6200000
       Serial.printf("aux = %d\n", aux);

       // ERROR: Should result in "500", but is resulting in "1922000"
       aux = aux / B;          // 6200000 / 12400 = 500

       Serial.printf("aux = %d\n", aux); // It's printing "1922000"
    }

body:
In your #define of B you missed parenthesis (). Change your definition to:

    #define B      (A * 62)

Without parenthesis you first divide 6200000 by 200 and then multiply result by 62, which is not what you intend.


body:
Fully-parenthesizing macros (as noted in [answer by dmz](https://electronics.stackexchange.com/a/414154/5185)) solves one class of problem.

Another thing you should do is, in any arithmetic expression which involves literal constants, use the `L` suffix on at least one of the constants involved if there's any chance the result will exceed 32767 (the maximum guaranteed-representable value for `int`). The type of an arithmetic operation in C is based on the types of the operands of that operation only; the type of the variable to which the result is assigned is irrelevant.

(edit)
For example:

    long q, r;
    unsigned char v = 231;
    unsigned char w = 197;

    q = v * w * 5;
    r = v * w * 5L;

`q` might contain 30927, since after the Usual Arithmetic Conversions (6.3.1.8) [in this case, the Integer Promotions (6.3.1.1-2)] all operands are of type `int` and it's possible for `INT_MAX` to be 32767 in which case each operation would be performed modulo 32768.

`r` will contain 227535, since the constant `5L` is of type `long` and thus all operations in this expression will be performed on values of type `long`.


body:
As explained in previous answers, fully parenthesizing the macros is the
standard solution to this problem in C. However, on Arduino you are
programming in C++, and in C++ it is considered good practice to replace
this usage of `#define` by explicit constants:

<!-- language: lang-c++ -->

    const int A = 200;
    const int B = A * 62;
    const int C = 500;

Not only this makes the initial problem go away, it also provides some
type safety: you can choose to give these constants other types (e.g.
`long`) if appropriate.


message:
Problem with ESP8266, wrong voltage?

I recently bought a new ESP8266 because I'm pretty sure I used 5V instead of 3.3V on my old one.
But it seems the new one behaves the same as the old one.

I'm using the sketch:

https://i.stack.imgur.com/BZRd4.jpg

When I open up the serial monitor and type [b]AT [/b]I get not response (on the 115200 baud).
If I boot up the power supply while the device is connected I get this in the serial monitor:

    load 0x40100000, len 1856, room 16
    tail 0
    chksum 0x63
    load 0x3ffe8000, len 776, room 8
    tail 0
    chksum 0x02
    load 0x3ffe8310, len 552, room 8
    tail 0
    chksum 0x79
    csum 0x79

    2nd boot version : 1.5
      SPI Speed      : 40MHz
      SPI Mode       : DOUT
      SPI Flash Size & Map: 8Mbit(512KB+512KB)
    jump to run user1 @ 1000

    Fatal exception 0(IllegalInstructionCause):
    epc1=0x40215021, epc2=0x00000000, epc3=0x00000000, excvaddr=0x00000000, depc=0x00000000

When I googled the log it seems to be related to the voltage. Could it be the same problem again? If so, what did I do wrong?

body:
The ESP8266 has a relatively high peak current requirement compared to general microcontrollers. This is rarely fully understood. There is a lot of information on the Internet that says the current requirements is about 70mA. But that is a long term operational average. The peak current requirements can be as high as 1/2 an Amp.

When the ESP8266 starts one of the first things it does is an analog calibration. This is where it draws more current. If the power supply can not maintain the minimum required voltage at that current the voltage dip will cause a failure. The duration of this dip can be very short. A digital scope needed to see the fault.

I tend to recommend the use of ESP8266 modules that have an onboard regulator. Modules like the Wemos and Nodemcu type boards.

Using modules like the ESP-01 or the ESP-12 type modules (no regulators) are a lot more touchy. What you need to do is keep the 3.3v regulator as close as possible to those modules, and short solid connections. It also helps to have some additional capacitance across the 3.3v connections at the module.

Breadboards are convenient to use but they also can be the source of poor connections.

Consider what I have wrote here, how it applies to your setup. You may also want to solder an additional capacitor on the module. Vcc to ground. Something like 200-470uF, right onto the top of the module.


message:
Weight Measurement System using arduino and load cell

I want to use a load cell (Capable of measuring up to 1 ton) connected to a arduino board.
I am a beginner, my questions are as follows :
1. How to calculate the current generated by the load cell ?
2. If current is too high, how will We make the arduino use the current to display weight ?

p.s If you know some helpful articles that might help me learn, please suggest.

body:
You need to use a load cell amplifier between the Arduino and the load cell. Load cells are around 350 Ohms. Four wire. And the signal that needs to be measured are very small.

The current will not be too high. The question indicates that you don't understand the application. (and therefore you are looking for help)

Here are some useful links.

https://www.hackster.io/MOHAN_CHANDALURU/hx711-load-cell-amplifier-interface-with-arduino-fa47f3

https://circuits4you.com/2016/11/25/hx711-arduino-load-cell/

A typical load cell has an output of 2 millivolts per volt of excitation voltage at the full rated weight. For example, if 5 volts were used for the excitation voltage, and the output is 2 mV/volt, then the voltage out would be 10mV at full scale. The voltage difference (compared to the unloaded load cell) is what is measure.

If the excitation voltage (just a technical name for applied voltage) were 5 volts, the voltage at the output terminals, measured from the negative terminal, would be 2.5 volts, half of the applied voltage. But this 2.5 volts is not the measured output. What is measured is the difference between the +signal and the -signal wires.


body:
My suggestion would be to make a spreadsheet with some items of known weights. Generally while using scales you’ll have a 5lb calibration weight that has a very tight tolerance. You can find the output voltage changes and map it from 0-1023.

This should mean for every 2.2lbs you will get another increment. Not extremely accurate but fine when measuring at the ton scale


body: That makes sense, most of my experience is with Mettler Toledo but I have never used the voltage for reference. A lot of the time hacking something together on Arduino requires mapping to values it likes. I had a few ultrasonic distance sensors that were just slightly different in the way they responded so I spent a while getting them just right.


body:
Get a multimeter and check the max output. That would be the best way to find it. If you actually have items around that weigh a literal ton that’d be the best way to find out the max current. Once that’s done you can split the current with a few resistors. If I recall correctly twice as much current would flow through a resistor with twice the value of the other. Make a y and pick the end that outputs the value you like. If you need 1/4 you should have a resistor for example with 47k and 3 together would be 141k. Connect to the 3 to get 1/4 the output current

Wikipedia has a pretty good article on <b> Current Dividers </b> if the output current is too high.


message:
Problem with MP3 Shield and function calling combination

I wrote this code to control my Christmas tree. It plays the Holy Night Code perfectly but never transitions to the next song. In addition, it plays random notes after the song is finished. Does anyone know what the error is?

    #include <SPI.h>
    #include <SdFat.h>
    #include <SdFatUtil.h>
    #include <SFEMP3Shield.h>

    #define TREEONE 3
    #define TREETWO 4
    #define TREETHREE 5
    #define TREEFOUR 10

    SdFat sd;
    SFEMP3Shield MP3player;

    const uint8_t volume = 10; // MP3 Player volume 0=max, 255=lowest (off)
    //10 for basement 50 for testing

    const uint16_t monoMode = 1;

    byte song = 1;
    byte totalsongs = 10;
    int num = 0;
    int i;

    //put arrays here
    const PROGMEM uint16_t arrayTimesMC[] = {670, 249, 116, 249, 100, 249, 132, 249, 125, 249, 102, 249, 116, 249, 82, 249, 130, 249, 118, 249, 94, 249, 125, 249, 100, 249, 110, 249, 95, 249, 134, 249, 156, 249, 125, 249, 107, 249, 142, 249, 110, 249, 73, 249, 96, 249, 119, 249, 115, 249, 83, 249, 101, 249, 168, 249, 120, 249, 111, 249, 108, 249, 102, 249, 104, 249, 106, 249, 115, 249, 122, 249, 136, 249, 100, 249, 99, 249, 136, 249, 138, 249, 113, 249, 111, 249, 117, 249, 148, 249, 115, 249, 102, 249, 100, 249, 108, 249, 140, 249, 115, 249, 93, 249, 148, 249, 119, 249, 91, 249, 136, 249, 84, 249, 185, 249, 104, 249, 126, 249, 148, 249, 83, 249, 74, 249, 97, 249, 105, 249, 166, 249, 128, 249, 95, 249, 158, 249, 122, 249, 220, 249, 42, 249, 66, 249, 180, 249, 387, 249, 236, 249, 350, 249, 3571, 249, 622, 249, 744, 249, 711, 249, 707, 249, 727, 249, 691, 249, 682, 249, 570, 198, 0, 249, 333, 249, 67, 249, 401, 249, 103, 249, 355, 249, 107, 249, 712, 249, 687, 249, 749, 249, 688, 249, 424, 249, 53, 249, 371, 249, 92, 249, 330, 249, 112, 249, 387, 249, 98, 249, 709, 249, 704, 249, 702, 249, 693, 249, 785, 249, 33, 147, 0, 171, 0, 249, 93, 249, 64, 124, 0, 165, 0, 249, 100, 249, 82, 149, 0, 137, 0, 249, 56, 249, 66, 148, 0, 142, 0, 249, 124, 249, 59, 216, 0, 190, 0, 249, 87, 249, 14, 171, 0, 105, 0, 74, 0, 249, 46, 249, 38, 150, 0, 183, 0, 249, 67, 249, 46, 152, 0, 192, 0, 249, 55, 249, 30, 182, 0, 136, 0, 172, 0, 166, 0, 249, 73, 162, 0, 160, 0, 175, 0, 141, 0, 249, 56, 179, 0, 158, 0, 155, 0, 160, 0, 249, 54, 249, 58, 249, 91, 119, 0, 112, 0, 162, 0, 200, 0, 136, 0, 152, 0, 181, 0, 199, 0, 249, 59, 249, 64, 122, 0, 142, 0, 156, 0, 216, 0, 154, 0, 130, 0, 160, 0, 209, 0, 249, 49, 249, 102, 125, 0, 132, 0, 205, 0, 224, 0, 158, 0, 164, 0, 162, 0, 172, 0, 174, 0, 139, 0, 173, 0, 148, 0, 169, 0, 170, 0, 113, 0, 178, 0, 170, 0, 108, 0, 124, 0, 249, 10, 144, 0, 100, 0, 208, 0, 138, 0, 249, 225, 215, 0, 249, 59, 249, 4, 249, 77, 249, 84, 249, 32, 249, 90, 249, 54, 249, 89, 249, 20, 89, 0, 249, 43, 249, 50, 249, 69, 249, 58, 249, 89, 249, 67, 249, 48, 249, 50, 249, 88, 249, 58, 249, 59, 249, 108, 249, 157, 239, 0, 249, 78, 249, 74, 249, 25, 249, 104, 249, 111, 249, 32, 249, 56, 249, 76, 249, 42, 249, 104, 249, 36, 249, 58, 249, 88, 249, 48, 249, 73, 249, 73, 249, 78, 249, 39, 249, 94, 249, 124, 249, 67, 249, 92, 249, 60, 249, 47, 150, 0, 169, 0, 249, 101, 249, 5, 166, 0, 144, 0, 249, 102, 249, 22, 196, 0, 173, 0, 249, 81, 249, 12, 136, 0, 209, 0, 249, 69, 249, 325, 249, 77, 249, 303, 249, 142, 249, 373, 249, 124, 249, 365, 249, 122, 249, 354, 249, 34, 249, 367, 249, 104, 249, 402, 249, 86, 249, 404, 249, 110, 249, 332, 249, 51, 249, 381, 249, 92, 249, 402, 249, 76, 249, 406, 249, 38, 249, 404, 249, 48, 249, 420, 249, 64, 249, 418, 249, 82, 249, 369, 249, 63, 249, 442, 249, 11, 249, 362, 249, 92, 249, 423, 249, 70, 249, 380, 249, 57, 249, 369, 249, 104, 249, 354, 249, 98, 249, 410, 249, 72, 249, 424, 249, 50, 249, 768, 249, 61, 170, 0, 131, 0, 153, 0, 206, 0, 249, 40, 129, 0, 162, 0, 146, 0, 184, 0, 249, 103, 129, 0, 156, 0, 131, 0, 186, 0, 249, 79, 176, 0, 131, 0, 141, 0, 194, 0, 249, 60, 146, 0, 154, 0, 135, 0, 201, 0, 249, 67, 147, 0, 155, 0, 143, 0, 194, 0, 249, 220, 102, 0, 104, 0, 249, 55, 249, 56, 249, 374, 249, 725, 249, 723, 249, 673, 249, 689, 249, 711, 249, 744, 249, 751, 249, 617, 249, 753, 249, 698, 249, 760, 249, 74, 161, 0, 212, 0, 249, 17, 249, 50, 132, 0, 172, 0, 249, 64, 249, 34, 149, 0, 191, 0, 249, 94, 249, 96, 124, 0, 151, 0, 249, 66, 249, 18, 203, 0, 146, 0, 228, 0, 132, 0, 249, 62, 162, 0, 170, 0, 175, 0, 162, 0, 249, 79, 164, 0, 218, 0, 166, 0, 148, 0, 249, 38, 249, 37, 249, 66, 123, 0, 138, 0, 166, 0, 194, 0, 166, 0, 155, 0, 165, 0, 165, 0, 249, 23, 249, 100, 142, 0, 162, 0, 150, 0, 172, 0, 142, 0, 136, 0, 168, 0, 249, 10, 249, 14, 249, 114, 151, 0, 249, 41, 162, 0, 249, 118, 249, 16, 163, 0, 152, 0, 249, 90, 249, 30, 167, 0, 167, 0, 249, 121, 249, 16, 192, 0, 168, 0, 249, 71, 249, 74, 123, 0, 163, 0, 249, 115, 249, 32, 155, 0, 166, 0, 249, 90, 249, 45, 139, 0, 149, 0, 249, 117, 249, 62, 182, 0, 189, 0, 249, 42, 249, 39, 142, 0, 173, 0, 145, 0, 156, 0, 249, 60, 183, 0, 141, 0, 155, 0, 182, 0, 249, 39, 175, 0, 170, 0, 155, 0, 149, 0, 249, 103, 249, 42, 249, 118, 118, 0, 132, 0, 136, 0, 222, 0, 134, 0, 136, 0, 162, 0, 184, 0, 249, 36, 249, 106, 142, 0, 120, 0, 140, 0, 232, 0, 184, 0, 139, 0, 158, 0, 214, 0, 239, 0, 249, 156, 110, 0, 112, 0, 228, 0, 192, 0, 168, 0, 146, 0, 176, 0, 172, 0, 163, 0, 112, 0, 173, 0, 239, 0, 120, 0, 172, 0, 146, 0, 173, 0, 140, 0, 136, 0, 191, 0, 92, 0, 125, 0, 165, 0, 162, 0, 216, 0, 249, 55, 158, 0, 128, 0, 249, 95, 249, 60, 221, 0, 127, 0, 249, 102, 249, 24, 148, 0, 155, 0, 249, 74, 249, 62, 153, 0, 138, 0, 249, 115, 249, 64, 165, 0, 147, 0, 249, 77, 249, 56, 143, 0, 163, 0, 249, 100, 249, 58, 168, 0, 146, 0, 249, 80, 249, 45, 158, 0, 168, 0, 249, 110, 249, 31, 168, 0, 134, 0, 249, 38, 104, 0, 187, 0, 134, 0, 160, 0, 132, 0, 135, 0, 142, 0, 249, 108, 145, 0, 157, 0, 154, 0, 152, 0, 249, 82, 136, 0, 163, 0, 165, 0, 146, 0, 249, 459, 117, 0, 146, 0, 249, 90, 130, 0, 166, 0, 154, 0, 194, 0, 249, 68, 154, 0, 140, 0, 158, 0, 168, 0, 249, 97, 155, 0, 146, 0, 134, 0, 184, 0, 249, 708, 249, 710, 249, 741, 249, 708, 249, 419, 126, 0, 119, 0, 82, 0, 112, 0, 84, 0, 98, 0, 86, 0, 109, 0, 98, 0, 113, 0, 249, 63, 55, 0, 158, 0, 135, 0, 210, 0, 161, 0, 138, 0, 249, 61, 141, 0, 195, 0, 139, 0, 155, 0, 223, 0, 248};
    const PROGMEM byte arrayTreeMC[] = {17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 5, 4, 9, 8, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 3, 2, 3, 2, 5, 4, 5, 4, 9, 8, 17, 16, 17, 16, 17, 16, 31, 30, 31, 30, 31, 30, 31, 30, 5, 4, 5, 4, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 31, 30, 31, 30, 31, 30, 31, 30, 3, 2, 5, 4, 3, 2, 17, 16, 3, 2, 5, 4, 3, 2, 17, 16, 3, 2, 5, 4, 3, 2, 17, 16, 3, 2, 5, 4, 3, 2, 17, 16, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 5, 4, 11, 10, 17, 16, 15, 14, 3, 2, 5, 4, 17, 16, 3, 2, 5, 4, 3, 2, 9, 8, 3, 2, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 17, 16, 17, 16, 9, 8, 5, 4, 3, 2, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 17, 16, 17, 16, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 5, 4, 3, 2, 5, 4, 5, 4, 5, 4, 9, 8, 17, 16, 5, 4, 9, 8, 9, 8, 9, 8, 17, 16, 13, 12, 3, 2, 3, 2, 5, 4, 9, 8, 9, 8, 17, 16, 9, 8, 3, 2, 5, 4, 9, 8, 9, 8, 9, 8, 17, 16, 3, 2, 5, 4, 5, 4, 5, 4, 9, 8, 9, 8, 9, 8, 17, 16, 17, 16, 17, 16, 5, 4, 3, 2, 3, 2, 5, 4, 5, 4, 5, 4, 9, 8, 17, 16, 3, 2, 5, 4, 5, 4, 9, 8, 17, 16, 9, 8, 3, 2, 5, 4, 3, 2, 9, 8, 3, 2, 5, 4, 3, 2, 17, 16, 3, 2, 5, 4, 3, 2, 17, 16, 3, 2, 5, 4, 3, 2, 17, 16, 17, 16, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 31, 30, 31, 30, 17, 16, 9, 8, 17, 16, 9, 8, 31, 30, 17, 16, 9, 8, 17, 16, 9, 8, 31, 30, 17, 16, 9, 8, 17, 16, 9, 8, 31, 30, 17, 16, 9, 8, 17, 16, 9, 8, 31, 30, 17, 16, 9, 8, 17, 16, 9, 8, 31, 30, 17, 16, 9, 8, 17, 16, 9, 8, 31, 30, 17, 16, 9, 8, 17, 16, 17, 16, 3, 2, 5, 4, 9, 8, 17, 16, 31, 30, 5, 4, 9, 8, 17, 16, 3, 2, 5, 4, 9, 8, 17, 16, 3, 2, 5, 4, 3, 2, 9, 8, 3, 2, 5, 4, 3, 2, 17, 16, 3, 2, 5, 4, 3, 2, 9, 8, 3, 2, 5, 4, 3, 2, 17, 16, 3, 2, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 17, 16, 17, 16, 9, 8, 5, 4, 3, 2, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 17, 16, 17, 16, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 9, 8, 17, 16, 3, 2, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 3, 2, 5, 4, 3, 2, 5, 4, 11, 10, 21, 20, 11, 10, 21, 20, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 3, 2, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 17, 16, 17, 16, 9, 8, 5, 4, 3, 2, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 17, 16, 17, 16, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 13, 12, 11, 10, 21, 20, 11, 10, 21, 20, 3, 2, 11, 10, 29, 28, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 21, 20, 11, 10, 21, 20, 11, 10, 31, 30, 11, 10, 21, 20, 11, 10, 31, 30, 11, 10, 21, 20, 11, 10, 31, 30, 11, 10, 21, 20, 11, 10, 31, 30, 11, 10, 21, 20, 11, 10, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 5, 4, 9, 8, 3, 2, 17, 16, 5, 4, 9, 8, 3, 2, 17, 16, 5, 4, 9, 8, 3, 2, 5, 4, 17, 16, 3, 2, 9, 8, 5, 4, 17, 16, 3, 2, 5, 4, 9, 8, 3, 2, 17, 16, 5, 4, 31, 30};
    const PROGMEM uint16_t arrayTimesHN[] = {28, 246, 1542, 246, 646, 246, 390, 246, 38, 246, 1222, 246, 70, 246, 358, 246, 70, 246, 326, 246, 70, 246, 1542, 246, 326, 246, 70, 246, 358, 246, 70, 246, 650, 246, 290, 246, 70, 246, 680, 246, 320, 246, 70, 246, 1550, 246, 1540, 246, 640, 246, 330, 246, 70, 246, 1250, 246, 70, 246, 360, 246, 70, 246, 330, 246, 0, 246, 1550, 246, 390, 246, 0, 246, 360, 246, 70, 246, 650, 246, 320, 246, 100, 246, 620, 246, 360, 246, 70, 246, 1540, 246, 1250, 246, 40, 246, 650, 246, 670, 246, 650, 246, 650, 246, 350, 246, 40, 246, 360, 246, 40, 246, 640, 246, 360, 246, 40, 246, 610, 246, 680, 246, 620, 246, 710, 246, 350, 246, 40, 246, 330, 246, 70, 246, 1540, 246, 680, 246, 640, 246, 650, 246, 360, 246, 40, 246, 630, 246, 660, 246, 640, 246, 360, 246, 70, 246, 650, 246, 640, 246, 330, 246, 70, 246, 330, 246, 70, 246, 640, 246, 650, 246, 640, 246, 360, 246, 70, 246, 620, 246, 640, 246, 650, 246, 360, 246, 70, 246, 610, 246, 680, 246, 640, 246, 330, 246, 100, 246, 650, 246, 610, 246, 360, 246, 70, 246, 360, 246, 40, 246, 640, 246, 650, 246, 640, 246, 650, 246, 680, 246, 610, 246, 650, 246, 680, 246, 610, 246, 650, 246, 670, 246, 650, 246, 680, 246, 640, 246, 650, 246, 360, 246, 40, 246, 640, 246, 650, 246, 250, 246, 250, 246, 246};
    const PROGMEM byte arrayTreeHN[] = {31, 30, 17, 16, 17, 16, 17, 16, 9, 8, 9, 8, 5, 4, 5, 4, 9, 8, 5, 4, 3, 2, 5, 4, 5, 4, 9, 8, 17, 16, 5, 4, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 31, 30, 31, 30, 31, 30, 17, 16, 17, 16, 9, 8, 9, 8, 5, 4, 5, 4, 9, 8, 5, 4, 3, 2, 31, 30, 5, 4, 9, 8, 17, 16, 7, 6, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 31, 30, 31, 30, 9, 8, 9, 8, 5, 4, 17, 16, 9, 8, 5, 4, 9, 8, 3, 2, 9, 8, 5, 4, 9, 8, 9, 8, 9, 8, 5, 4, 17, 16, 9, 8, 5, 4, 9, 8, 3, 2, 9, 8, 5, 4, 3, 2, 21, 20, 21, 20, 5, 4, 9, 8, 5, 4, 21, 20, 21, 20, 21, 20, 9, 8, 3, 2, 11, 10, 11, 10, 17, 16, 17, 16, 17, 16, 9, 8, 21, 20, 29, 28, 21, 20, 9, 8, 3, 2, 19, 18, 19, 18, 23, 22, 9, 8, 5, 4, 19, 18, 19, 18, 5, 4, 9, 8, 17, 16, 11, 10, 11, 10, 17, 16, 5, 4, 17, 16, 17, 16, 11, 10, 11, 10, 5, 4, 3, 2, 21, 20, 21, 20, 17, 16, 3, 2, 19, 18, 13, 12, 15, 14, 29, 28, 21, 20, 9, 8, 5, 4, 3, 2, 5, 4, 19, 18, 31, 30, 31, 30, 31, 30, 30};

    //put arrays here

    void setup() {
      initSD();
      initMP3Player();

      pinMode(TREEONE, OUTPUT);
      pinMode(TREETWO, OUTPUT);
      pinMode(TREETHREE, OUTPUT);
      pinMode(TREEFOUR, OUTPUT);

      digitalWrite(TREEONE, HIGH);
      digitalWrite(TREETWO, HIGH);
      digitalWrite(TREETHREE, HIGH);
      digitalWrite(TREEFOUR, HIGH);
    }

    void loop() {
      MP3player.playTrack(2);
      OHolyNight();
      delay(92000);
      MP3player.stopTrack();

      MP3player.playTrack(3);
      MetallicaChristmas();
      delay(192000);
      MP3player.stopTrack();
    }

    void initSD() {
      if (!sd.begin(SD_SEL, SPI_HALF_SPEED))
        sd.initErrorHalt();
      if (!sd.chdir("/"))
        sd.errorHalt("sd.chdir");
    }

    void initMP3Player() {
      uint8_t result = MP3player.begin();
      MP3player.setVolume(volume, volume);
      MP3player.setMonoMode(monoMode);
    }

    void AllLights() {
      digitalWrite(TREEONE, LOW);
      digitalWrite(TREETWO, LOW);
      digitalWrite(TREETHREE, LOW);
      digitalWrite(TREEFOUR, LOW);
    }

    void MetallicaChristmas() {
      for (i = 0; i < sizeof(arrayTimesMC); i++) {
        delay(pgm_read_word_near(arrayTimesMC + i));
        num = pgm_read_byte_near(arrayTreeMC + i);

        if (num > 15) {
          if ((num % 2) == 0) {
            digitalWrite(TREEONE, HIGH);
          } else {
            digitalWrite(TREEONE, LOW);
          }
        }
        if ((num % 16) > 7) {
          if ((num % 2) == 0) {
            digitalWrite(TREETWO, HIGH);
          } else {
            digitalWrite(TREETWO, LOW);
          }
        }
        if ((num % 8) > 3) {
          if ((num % 2) == 0) {
            digitalWrite(TREETHREE, HIGH);
          } else {
            digitalWrite(TREETHREE, LOW);
          }
        }
        if ((num % 4) > 1) {
          if ((num % 2) == 0) {
            digitalWrite(TREEFOUR, HIGH);
          } else {
            digitalWrite(TREEFOUR, LOW);
          }
        }
        if (i == sizeof(arrayTimesMC)) {
          break;
        }
      }
    }

    void OHolyNight() {
      for (i = 0; i < sizeof(arrayTimesHN); i++) {
        delay(pgm_read_word_near(arrayTimesHN + i));
        num = pgm_read_byte_near(arrayTreeHN + i);

        if (num > 15) {
          if ((num % 2) == 0) {
            digitalWrite(TREEONE, HIGH);
          } else {
            digitalWrite(TREEONE, LOW);
          }
        }
        if ((num % 16) > 7) {
          if ((num % 2) == 0) {
            digitalWrite(TREETWO, HIGH);
          } else {
            digitalWrite(TREETWO, LOW);
          }
        }
        if ((num % 8) > 3) {
          if ((num % 2) == 0) {
            digitalWrite(TREETHREE, HIGH);
          } else {
            digitalWrite(TREETHREE, LOW);
          }
        }
        if ((num % 4) > 1) {
          if ((num % 2) == 0) {
            digitalWrite(TREEFOUR, HIGH);
          } else {
            digitalWrite(TREEFOUR, LOW);
          }
        }
        if (i == sizeof(arrayTimesHN)) {
          break;
        }
      }
    }

body:
Since KIIV didn't write an answer to this question, I will do it.

You are using this for loop:

    for (i = 0; i < sizeof(arrayTimesHN); i++)

The `sizeof()` function will return the size of the array in bytes. Since the array is of type `uint16_t`, each element has a size of 2 bytes (16 bit). Concluding: The `sizeof()` function will return a number twice as high, as the actual element count of the array. The delays and state number, that you use for the LEDs, will be read from memory, that lies after the array. We don't know, what is saved there (or if there is actually some valid data or only random data), so this will seem random. That random notes are played by the MP3 Player must be a problem with the library (I'm not sure about that). What does the library do, if a song is finished, but you didn't call the `stopTrack()` method yet?

---

In the LED functions (for example `OHolyNight()`) you are using delays, but you also set a big delay after the execution of the function. I guess, the big delay is the duration of the song. So you delay twice. The first comes with the accumulated delays in the LED function (while the LED lights are changing). The second delay will kick in after that (when the LED function is finished). Maybe you thought, that it doesn't proceed to the next song, because you didn't wait for 92 seconds (your first big delay).

---

Lastly, in your LED functions you have this if statement:

    if (i == sizeof(arrayTimesHN)) {
      break;
    }

This is unnecessary, you used a for loop with the condition `i < sizeof(arrayTimesHN)`, so that `i` cannot ever be equal to `sizeof(arrayTimesHN)` inside of the loop.


message:
Value of uninitialized EEPROM in ESP8266?

In my limited testing it appears that the EEPROM in the Wemos D1 is not initialized to 255 like the specs say is the case for AtMega based Arduinos. In fact, the values look to be more-or-less random. Presumably this is because the ESP8266 doesn't actually contain EEPROM, but instead emulates it using flash. Is there a way to initialize the EEPROM region when flashing?

(This is pretty much the same question as [here][1], which has not been answered.) Since I need only a few bytes of data, I'd prefer not to have to use the SPIFS.

Update:

Use case: I'm using the WiFiManager library to select the network to connect a Wemos D1 mini to the web to upload data to Thingspeak. I'd like to use WiFiManager to request the api-key and channel id from the user. However, once the user has entered these, I'd prefer not to make them enter the values again. (The api key is 16 random looking chars and difficult to enter correctly.) This means that the device has to store the values persistently between boots - the main use case for EEPROM. But how do you tell that the values in EEPROM (actually flash on an ESP device) are uninitialized crap, not the previous value? As suggested in the comments, setting flag values in a number of vars make it statistically unlikely to the random values from uninitialized memory. On an AtMega device, unless previously used, the values will be 255 in each byte.

  [1]: https://arduino.stackexchange.com/questions/46519/set-eeprom-to-initial-values-when-flashing-esp8266

body:
I've done this in the past by simply checking for a string (array of characters if you prefer) at a specific memory location. I used "INITIALIZED". It would be very unlikely for the ROM to have this sequence of characters by accident. If I find the string I read the variables from ROM. If I don't, I write the string and set default values for the variables.

I found a slightly different example that uses the same technique:

    // EEPROM library.
    #include <EEPROM.h>
    // Persistent Shoe State.
    byte shoeState = 0;
    // Number of Shoe States.
    #define SHOE_STATE_MAX 3

    // setup() runs once at reset.
    void setup() {
      // EEPROM Init Code Base Address
      #define EEPROM_INIT_CODE_ADDR 0x00
      // Check EEPROM Init Code
      byte shoeStateInit[] = {0xde, 0xad, 0xbe, 0xaf, 0xaa};
      for(int b = EEPROM_INIT_CODE_ADDR; b < EEPROM_INIT_CODE_ADDR + sizeof(shoeStateInit); b++) {
        // EEPROM = Init Code?
        if(EEPROM.read(b) != shoeStateInit[b]) {
          // No, Write Init Code to EEPROM.
          EEPROM.write(b, shoeStateInit[b]);
          // Set Not Initialized Flag.
          shoeState = -1;
        }
      }
      // EEPROM Init Code?
      if(shoeState == 0) {
        // Yes, Read Shoe State from EEPROM.
        shoeState = EEPROM.read(sizeof(shoeStateInit));
      }
    }

The only variable being saved to ROM is shoeState.


body:
Calculate a checksum for the data and store as part of the data. Recalculate the checksum when you read the (questionable) data back again. If the checksum fails, it's invalid. If it passes, the data is valid to some statistical level of confidence.

A 16-bit checksum would make false acceptance highly unlikely, but  make it long enough for your own comfort level. What would be the worst consequence of a false acceptance: inconvenience (user has to re-enter a number)? Loss of money or property? Loss of life? Choose the complexity of your solution accordingly.


body:
Rather than use EEPROM, which is a real pain considering that it's shared between all stored data and you need to remember offsets and lengths, use SPIFFS.

By including `FS.h` in your program (or the include file that needs to store the data, if you are trying to be modular), you can store several megabytes of data as strings in a named file (much like fprintf() or open() would let you do in C++).

Call  `SPIFFS.begin();`  in setup(), and then use the following sections of code to read or write data to the file:

(assuming you want to store `start` and `end` in SPIFFS, but this works for any datatype known to Arduino, and probably anything with the printable attribute)

Read saved config:

    Serial.println(F("Loading config"));
    File f = SPIFFS.open("/ACTIVE_TIMES.cnf", "r");
    if (!f) {
      //File does not exist -- first run or someone called format()
      //Will not create file; run save code to actually do so (no need here since
      //it's not changed)
      Serial.println(F("Failed to open config file"));
      start = 8;
      end = 20; // defaults
      return;
    }
    while (f.available()) {
      String key = f.readStringUntil('=');
      String value = f.readStringUntil('\r');
      f.read();
      Serial.println(key + F(" = [") + value + ']');
      Serial.println(key.length());
      if (key == F("START_TIME")) {
        start = value.toInt();
      }
      if (key == F("END_TIME")) {
        end = value.toInt();
      }
    }
    f.close();
Save configuration:

    Serial.println(F("Saving config"));
    File f = SPIFFS.open("/ACTIVE_TIMES.cnf", "w+");
    if (!f) {
      //It's cases like this when calling SPIFFS.format() might be a good idea,
      //but you would not want to do so here, since if it's an error for a
      //different reason it would delete all your data. Make it manual or a prompt
      //instead.
      Serial.println(F("Failed to open config file"));
      return;
    }
    f.print(F("START_TIME="));
    f.println(start);
    f.print(F("END_TIME="));
    f.println(end);
    f.flush();
    f.close();
    Serial.println(F("Saved values"));

You may also call `SPIFFS.format()` to reset the filesystem (say, for a factory reset), but this will cause issues on attempting to read any stored data, since the file *will not exist*. Thus, have a section that sets reasonable defaults (or just prompts the user to set the values).

Note: Since this is for storing an API key and such, just have it fail, since the API key not working is a good notice the user needs to configure it, and you do NOT want to ship a product with a *working* API key that belongs to you rather than the user.

Final warning: Note carefully the use of `F()` around certain items in that code. This macro, specific to Arduino, allows one to store data in Flash ONLY, where strings normally consume RAM as well (once the system boots, it loads to RAM, since most code expects it there). The *benefit* of `F()`, rather than a progmem directive, is that many functions native to Arduino can read it directly thanks to overloads, or you can wrap `String()` around the `F()` to convert it to a string at runtime if the function does not allow that overload. The end result is that, as I've written it, this code should consume RAM only when it is actually running, as good code should (otherwise, it's really easy to use up all your RAM on such embedded devices if you add enough strings).

I have not bothered to do the latter with the filename passed to `open()` since it is used only once per load or save operation, does not support F() (thus I'd need to use the `String()` trick), and I'm fairly sure the compiler then shares the memory location, reducing the RAM used to only one edition of that filename.


message:
String compare when using Serial

I try to detect commands given by user in Serial Monitor, but `strcmp` fails to flag as identical.

What do I do wrong ?

Is there a better way not reading as `String` and convert to `char` for comparison ?

Guy

    char* additional_callbacks [] = {"command_1", "command_2", "command_3"};

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

    void loop() {
      if (Serial.available() > 0) {
        char tmpchar[50];

        Serial.print("entered_text:");
        String str = Serial.readString();
        str.toCharArray(tmpchar, 50);
        Serial.println(tmpchar);

        for (int i = 0; i < sizeof(additional_callbacks) / sizeof(char*); i++) {
          if (strcmp(tmpchar, additional_callbacks[i]) == 0) {
            Serial.println("match");
          }
        }
        Serial.flush();
      }
      delay(50);
    }

body:
In your for() loop, use Serial.println() to display both strings before the compare. You'll be able to see why the compare is failing.

Update:

> it seemed identical.

Something has to be different for the test to fail. If the strings look identical then there must be some non-printing characters that differ: \r, \n, <space>, <tab>, missing \0 <end-of-string>), etc.

Try printing your buffers byte-by-byte in hex for a few more bytes than the string length, to be sure there is an <end-of-string> where it should be.

Or print the buffers with this hexdump function which lists a specified memory range in both ASCII and hex:

    /***

    Name:  hexdump

    Function:   Dump memory contents to terminal

    Description:Dump a specified range of memory in hex and ASCII

    Parameters: byte *mem       - starting address
                uint16_t len    - # of bytes

    Returns: void

    Notes:      Based on: http://grapsus.net/blog/post/Hexadecimal-dump-in-C
                Formats with sprintf(); outputs with Serial.print().
                Modified to print ...0 - ...F of each hex-block containing
                any of the requested memory range. Data not in the range are
                not shown.

    ***/

    void hexdump(byte *mem, uint16_t len)
    {
       byte *p, *pfirst, *plast;    // -> curr byte, first & last hex-blocks to print from
       char buf[10+1];              // sprintf o/p buffer

       // Print entire hex-blocks that contain the requested mem range,
       // except only show data within the range.
       pfirst = (byte *)((uint16_t)mem & 0xFFF0);           // beg of 1st  hex-block
       plast = (byte *)((uint16_t)(mem + len) | 0xF);       // end of last hex-block

       for( p = pfirst;  p <= plast;  ++p ){

          /* Print block addr */
          if( ((byte *)((uint16_t)p & 0xF)) == 0 ){
             sprintf_P(buf, PSTR("X: "), (unsigned int)p);
             Serial.print(buf);
          }

          // Print hex data, or if outside mem range, print spaces
          if( mem <= p && p < (mem + len) ){
             sprintf_P(buf, PSTR("hhX "), *p);
             Serial.print(buf);
          }
          else
             Serial.print("   ");                   // outside requested range - just spaces

          // Maybe print gutters and/or ASCII data
          if( ((uint16_t)p & 0xF) == 0x7 )
             Serial.print(" ");                     // narrow gutter after 8 bytes
          // If at end of hex block, print a gutter & re-print the block as ASCII
          if( ((uint16_t)p & 0xF) == 0xF ){
             Serial.print("  ");                    // wide gutter after 16 bytes

             // Print as ASCII.
             // Note: In this loop, we re-use the outer loop's index, 'p', to rescan
             // the hex block. We must leave 'p' as we found it!
             for( p = (byte *)((uint16_t)p & 0xFFF0);  ; ++p ){
                if( !(mem <= p && p < mem+len) )
                   Serial.print(' ');               // not in requested mem range
                else if( !isprint(*p) )
                   Serial.print('.');               // not printable
                else
                   Serial.print(*(char *)p);        // print as ASCII

                if( ((uint16_t)p & 0xF) == 0xF ){
                   break;                           // end of hex-block
                }
             }
             Serial.print('\n');
          }
       }
    }


message:
Want to display an image from SD card to ILI9486 LCD display

I am completely new to Arduino. I have been given a side project to display a image from SD card to display. LCD used is ILI9486 which has a SD card slot at the back of the display module. I have inserted an 1 GB micro SD card. I am using below example code to try to open the SD card and display the image on display module. I am getting error on serial monitor "Initializing sd card - failed". Can anyone let me know how to display image from SD card to screen.

    #include <SD.h>
    #include <SPI.h>
    #include <TFT.h>  // Arduino LCD library

    // pin definition for the Uno
    #define sd_cs  4
    #define lcd_cs 10
    #define dc     9
    #define rst    8

    TFT TFTscreen = TFT(lcd_cs, dc, rst);

    // this variable represents the image to be drawn on screen
    PImage logo;

    void setup() {
        // initialize the GLCD and show a message
        // asking the user to open the serial line
        TFTscreen.begin();
        TFTscreen.background(255, 255, 255);

        TFTscreen.stroke(0, 0, 255);
        TFTscreen.println();
        TFTscreen.println(F("Arduino TFT Bitmap Example"));
        TFTscreen.stroke(0, 0, 0);
        TFTscreen.println(F("Open serial monitor"));
        TFTscreen.println(F("to run the sketch"));

        // initialize the serial port: it will be used to
        // print some diagnostic info
        Serial.begin(9600);

        while (!Serial) {
            // wait for serial port to connect. Needed for native USB port only
        }

        // clear the GLCD screen before starting
        TFTscreen.background(255, 255, 255);

        // try to access the SD card. If that fails (e.g.
        // no card present), the setup process will stop.
        Serial.print(F("Initializing SD card..."));
        if (!SD.begin(sd_cs)) {
            Serial.println(F("failed!"));
            return;
        }
        Serial.println(F("OK!"));

        // initialize and clear the GLCD screen
        TFTscreen.begin();
        TFTscreen.background(255, 255, 255);

        // now that the SD card can be access, try to load the
        // image file.
        logo = TFTscreen.loadImage("arduino.bmp");
        if (!logo.isValid()) {
            Serial.println(F("error while loading arduino.bmp"));
        }
    }

    void loop() {
        // don't do anything if the image wasn't loaded correctly.
        if (logo.isValid() == false) {
            return;
        }

        Serial.println(F("drawing image"));

        // get a random location where to draw the image.
        // To avoid the image to be draw outside the screen,
        // take into account the image size.
        int x = random(TFTscreen.width() - logo.width());
        int y = random(TFTscreen.height() - logo.height());

        // draw the image to the screen
        TFTscreen.image(logo, x, y);

        // wait a little bit before drawing again
        delay(1500);
    }

body: Make sure your SD card is Fat16 format.  At least that was a requirement of the test code I had on the same sort of display.


message:
Arduino NANO hardware SPI not working

I have an Arduino NANO clone and a 2.4" ILI9341 TFT display.  The VCC and LCD pins of the display are connected to the 5V pin of the board.  The GND to the GND.  All the logic pins are connected to voltage dividers (2k2 and 4k3 resistors), their connections checked and delivering 3.3V when 5V is supplied to them.

If I understand the source correctly, [if I specify all the pins to the constructor, then I use software SPI](https://github.com/adafruit/Adafruit_ILI9341/blob/master/Adafruit_ILI9341.cpp#L82), but [if I don't, then I use hardware SPI](https://github.com/adafruit/Adafruit_ILI9341/blob/master/Adafruit_ILI9341.cpp#L97).

Now, if I use the software SPI, everything is working fine, I can get the info, I can draw, etc.  However if I use the hardware SPI then it is not giving me anything.

<!-- language: c -->

    #include <Adafruit_GFX.h>
    #include <Adafruit_ILI9341.h>

    // Adafruit_ILI9341 tft = Adafruit_ILI9341(10, 9);              // NOT WORKING!
    Adafruit_ILI9341 tft = Adafruit_ILI9341(10, 9, 11, 13, 8, 12);  // WORKING!

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

        Serial.println("ILI9341 Test!");

        tft.begin();

        // read diagnostics (optional but can help debug problems)
        uint8_t x = tft.readcommand8(ILI9341_RDMODE);
        Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
        x = tft.readcommand8(ILI9341_RDMADCTL);
        Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
        x = tft.readcommand8(ILI9341_RDPIXFMT);
        Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
        x = tft.readcommand8(ILI9341_RDIMGFMT);
        Serial.print("Image Format: 0x"); Serial.println(x, HEX);
        x = tft.readcommand8(ILI9341_RDSELFDIAG);
        Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);
    }

    void
    loop()
    {
        // pass
    }

However, what really makes me totally confused is when I use the SD card reader with the `SD Library` alone (the SD card reader is on the ILI9341 board), then that is working fine as well (as if the hardware SPI would be working, unless the SD Library is switching to software SPI magically).  Anyway, the following is the working code:

<!-- language: c -->

    #include <SD.h>
    #include <SPI.h>

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

        Serial.println("ILI9341 Test!");

        if (!SD.begin(7))
        {
            Serial.println("Cannot initialise SD card");
            while (true);
        }

        File file;

        if ((file = SD.open("file.txt", FILE_WRITE)))
        {
            Serial.print("Writing to file...");
            file.println("Hello, World!");
            file.close();
            Serial.println(" DONE");
        }
        else
            Serial.println("Cannot open file for writing");

        if ((file = SD.open("file.txt")))
        {
            Serial.println("Opening file...");
            while (file.available())
                Serial.write(file.read());
            file.close();
            Serial.println("DONE");
        }
        else
            Serial.println("Cannot open file for reading");
    }

    void
    loop()
    {
        // pass
    }

---

**So what exactly is going on here?  Am I doing something obviously wrong?  Or is the board's hardware SPI not working?  Or is there a problem with the Adafruit library?**

---

**Extra info:**

I'm using the `arduino-cli` to upload sketches the following ways:

<!-- language: bash -->

    # To compile:
    arduino-cli                                     \
        compile                                     \
        --fqbn arduino:avr:nano:cpu=atmega328old    \
        --warnings all                              \
        MyArduinoSketch;

    # To upload
    sudo arduino-cli                                \
         upload                                     \
         --verify                                   \
         --verbose                                  \
         --port /dev/ttyUSB0                        \
         --fqbn arduino:avr:nano:cpu=atmega328old   \
         MyArduinoSketch;

I installed the mentioned libraries via `arduino-cli`.

body:
Use constructor `Adafruit_ILI9341(10, 9, 8);` to make the reset that works with software SPI.

To SD card as second device on the bus:

Every SPI device on SPI bus must be controlled by slave select pin. If a device is connected to the bus and the SS pin is left floating the device disturbs the bus.

The empty SD card adapter is not a device on the bus, only the inserted card is a device. If it is on the bus the corresponding SS pin must be set HIGH. If you use the SD libray SD.begin(SD_SS_PIN), the library initializes the pin. If you don't use the library in the sketch (because it takes much memory), remove the SD card or set the SS pin to OUTPUT and HIGH.


body:
Hi Peter First Adafruit spends a lot of time creating their libraries and i do appreciate that but my luck is that I never get anything working with their libraries it is just me

I use this library:

https://github.com/Bodmer/TFT_ILI9341

and it works wonders if I want to add other SPI devices like your SD card I edit the User_Setup File that is included in your sketch right at the bottom of the file you can find the following line:

// #define SUPPORT_TRANSACTIONS

uncomment that line and your Touch part as well as SD card will functional normally I have had a setup working with the screen, touch controller, RFID board and a SD card all working on SPI each with their own SS or Chip select pin

NB! if you are going to try the library it is best you remove the ADAfruit one first because there are some files with the same names and the IDE tends to include the first one it finds AKA Adafruit


message:
What are the purposes of the different LED lights on a Arduino UNO board?

The LEDs namely L, TX and RX on the board.
Furthermore, whenever the board is connected, the L LED blinks to the frequency of the delay that I set. [Eg: delay(1000);]
If I miss any other LED, do mention their purposes as well!
Thank you

body:
'L' shows the state of pin13 which is programmable by you for any purpose, whether to read or write to an external device, or just for turn the LED on and off as you have done.

'RX' and 'TX' show the states of the Receive and Transmit pins, respectively, and allow you see when serial communication is taking place.


message:
Does enabling the Timer1 CompareA interrupt instantly triggers an interrupt?

I am learning Arduino interruptions and I am unable to explain the behavior of a minimalistic interrupt driven project. The project is the following: an Arduino UNO is connected to two LEDs, on ports 9 and 10, and a button on port 2. The button is listened to for RISING interruptions, which are expected to trigger the following 3 seconds sequence: LED1 `HIGH` (one second); both LEDs `HIGH` (one second); LED2 `HIGH` (one second); during which pressing the button should have no effect.

    #define led1Pin 10
    #define led2Pin 9
    #define buttonPin 2

    void setup() {

      cli();//stop interrupts

      pinMode(led1Pin, OUTPUT);
      pinMode(led2Pin, OUTPUT);
      pinMode(buttonPin, INPUT);
      digitalWrite(led1Pin, LOW);
      digitalWrite(led2Pin, LOW);
      attachInterrupt(digitalPinToInterrupt(buttonPin), f, RISING);

      TCCR0A = 0;// set TCCR2A register to 0
      TCCR0B = 0;// set TCCR2B register to 0 (sets timer0 prescaler values to "disable timer")
      TCCR2A = 0;// set TCCR2A register to 0
      TCCR2B = 0;// set TCCR2B register to 0 (sets timer2 prescaler values to "disable timer")

      //set timer1 interrupt at 1Hz
      TCCR1A = 0;// set TCCR1A register to 0
      TCCR1B = 0;// set TCCR1B register to 0

      // set compare match register for 1hz increments
      OCR1A = 15624;// = (16*10^6) / (1*1024) - 1
      TCCR1B |= (1 << WGM12);   // turn on CTC mode 1 (compare to OCR1A)
      TCCR1B |= (1 << CS12) | (1 << CS10);// CS12|CS10 => Prescaler 1024
      TIMSK1 = 0;// disable timer compare interrupt

      sei();
    }

    volatile int index=0;

    volatile byte previousState=LOW;
    volatile byte state = LOW;

    void loop() {
      if (state && !previousState) {
        digitalWrite(led1Pin, HIGH); index=1;
        TCNT1H = 0;
        TCNT1L = 0; //initialize counter value to 0
        TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
        previousState = HIGH;
      }
    }

    void f() {
      state = HIGH;
    }

    ISR(TIMER1_COMPA_vect){ //timer1 interrupt 1Hz
      switch(index) {
      case 1:
        digitalWrite(led2Pin, HIGH); index=2;
        break;
      case 2:
        digitalWrite(led1Pin, LOW); index=3;
        break;
      case 3:
        digitalWrite(led2Pin, LOW); index=0;
        state=LOW; previousState=LOW;
        TIMSK1 = 0;// disable timer compare interrupt
        break;
      default:
        break;
      }

    }

Code adapted from https://www.instructables.com/id/Arduino-Timer-Interrupts/

Upon pressing the button, `state` is set to `HIGH`, which assuming `previousState` and `state` were `LOW`, should get the loop to perform a set of action once as it will set `previousState` `HIGH`.

These actions are the following: set `led1Pin` to `HIGH`, set `TCNT1H` and `TCNT1L` to 0, which should put the Timer1 counter to 0, and then set `TIMSK1` to `0b00000010`, that is, `1 << OCIE1A`, to accept the interrupt when it will be triggered, supposedly one second from the instruction that set the counter to 0, as the timer fires interrupts at 1Hz.

But while the expected behaviour is LED 1 on for one second, both LEDs on for one second, then LED 2 on for one second, the observed behaviour is the following, from my tests:

- First time pressing the button since Arduino reset : LED 1 and LED 2 on for one second, LED 2 on for one second.

- Button presses properly ignored until LED 2 turns off.

- Subsequent button presses : either proper behaviour (LED1 on, both LEDs on, LED2 on); or "first press" behaviour (both LEDs on, LED2 on). In both cases, the cycle sometimes instantly restart ([optional : LED1 on;] both LEDs on; LED2 on; LED1 on; both LEDs on; LED2 on), with each state taking one second.

The non-deterministic nature of the problem lets me think I'm mishandling interruptions. The project behaves as if enabling timer compare interrupts instantly triggered one, despite setting the relevant registers to 0 before that. I was unsuccessful in finding information regarding this that would explain the problem.

Is there asynchronous behaviour when setting the `TCNT1H` and `TCNT1L` registers to 0 ? Can a compare match interruption somehow be buffered ? And how comes the cycle sometimes execute twice ?

body:
> The project behaves as if enabling timer compare interrupts instantly
> triggered one

This can indeed happen, and it's likely what you are experiencing.

Explanation: an interrupt fires when three bits are simultaneously set:

- the “interrupt flag” that signals the detection of some specific event
- the “interrupt enable” bit associated with that particular interrupt
- the “global interrupt enable” bit that is set by the `sei()`
  instruction

In your case, the relevant interrupt flag is `OCF1A` (Timer/Counter1,
Output Compare A Match Flag), in register `TIFR1` (Timer/Counter1
Interrupt Flag Register). This flag is raised by a “timer compare”
event, i.e. when the timer value hits the value stored in `OCR1A`. If
the interrupt fires, the flag is automatically cleared when the CPU
starts executing the corresponding ISR. Alternatively, the flag can be
cleared manually by overwriting it with a logic 1 (yes, that's kind of
backwards). It is worth noting that the flag records the compare events
whether or not the interrupt is enabled.

You normally expect the interrupt flag to be the last of these three
bits to be set, so that the interrupt is triggered by the compare event.
But this need not be the case. In your program, it is likely that the
interrupt flag is raised one second after startup. The global interrupt
enable is set by your `sei()` at the end of `setup()`. Thus, at this
point, as soon as you set the interrupt enable bit the interrupt fires
immediately.

The standard solution to this problem is to clear the interrupt flag
right before setting the interrupt enable bit:

    TIFR1  |= _BV(OCF1A);   // clear timer compare flag
    TIMSK1 |= _BV(OCIE1A);  // enable timer compare interrupt


message:
Why a servo doesn`t move to angles properly

I've got to do a project which uses a servo to drive a turntable.
How much I adjusted the angle, the servo seemed to shift every time it spinned. For instance, the 0 degree angle was getting a bit bigger. I think it is caused by the imprecise PWM control of the Arduino or the bad translation using, I think, the `map()` function.

 [![How a servo works][1]][1]

Could you fix this issue in code, or the servo doesn't work properly. I observed that every servo (that I've tried) creates a buzzing noice for angles bigger than 170 degrees.

By the way, my code is:

<pre>
#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards

int pos = 0;    // variable to store the servo position

#define pos0 0
#define pos1 23
#define pos2 48
#define pos3 164

void setup() {
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  Serial.begin(9600);
}

void loop() {
  for (pos = pos0; pos < pos1; pos += 1) {
    myservo.write(pos);
    delay(30);
  }
  Serial.print("pos: ");
  Serial.println(pos);
  delay(5000);
  for (pos = pos1; pos < pos2; pos += 1) {
    myservo.write(pos);
    delay(30);
  }
  Serial.print("pos: ");
  Serial.println(pos);
  delay(5000);
  for (pos = pos2; pos < pos3; pos += 1) {
    myservo.write(pos);
    delay(30);
  }
  Serial.print("pos: ");
  Serial.println(pos);
  delay(5000);
  for (pos = pos3; pos > pos0; pos -= 1) {
    myservo.write(pos);
    delay(30);
  }
  Serial.print("pos: ");
  Serial.println(pos);
  delay(5000);
}
</pre>

Edit: Should I try with a more powerful Arduino, like the Mega, which I think will be the perfect option having more GPIO than the UNO.

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

body:
Not all Servos are perfectly built. One can get rid of the library itself; there is a way to make a servo turn by manually writing out the code.

    for(x=0; x<150; x=x+1)
    {
      digitalWrite(Servomotor, HIGH);
      delayMicroseconds(1500);          //Edit this delay to adjust the position
      digitalWrite(Servomotor, LOW);
      delayMicroseconds(18550);         //Don't touch this delay
    }

By trying out different delays for the first `delayMicroseconds()`, you can test out which delay you need for what position.

To make your code more clean, you could safe different angles in another void function, and when you need them just type out the name

Have a nice day ;)


body: Try to use `myservo.writeMicroseconds(x)` function. For standard servos the value of parameter x is between 1000 to 2000 for 0 degree to 180 degree rotation. But you know all servos are not manufactured perfectly. Thats why servos can response to 700 to 2300. At first you have to verify the minimum and maximum responding values then use it. You can use `map()` for easy coding.


body:
Every servo is different, they can have varying specifications:

 - Angular speed
 - Rotation range
 - Stall Torque
 - Size
 - Gear material/quality

Servos will vary based on brand; in addition each servo is going to have some individual variance.  So one has to characterize the servo, and discover what the proper control values are. Once the control values are established these are used to initialize the library so angular control will be accurate.

> For instance, the 0 degree angle was getting a bit bigger

I have found that errors in repeatability, like this, are usually found in the mechanism the servo is driving, especially the connection between the servo and the driven mechanisms. Check the connection for slop, see if everything is tightened properly.

>  I observed that every servo (that I've tried) creates a buzzing noice for angles bigger than 170 degrees.

The typical maximum range of a servo is 160-190 degrees of rotation. The noise you are hearing is the servo trying to drive the motor to set the angle, but it is stalled as it can't turn that far.

> Should I try with a more powerful Arduino, like the Mega, which I think will be the perfect option having more GPIO than the UNO.

IIRC the servo library can control 12 servos with a basic Arduino, and 48 with the MEGA. This difference is more than just pin count, the MEGA has 4x the hardware timers of the 328p; 12 x 4 = 48

If you need more features you can move to the MEGA, i.e. you need more PWM channels, and the servo library reduces PWM pins from 6 to 4 on the 328p. Another example could needing more timers.

Read the [Arduino Servo examples][1] for more information on usage of the servo library and control of servos, etc.

  [1]: https://www.arduino.cc/en/reference/servo


body:
An inexpensive servo tester, e.g....

https://www.amazon.com/DIYmall-Digital-Consistency-Controler-Checker/dp/B012LZKTDO/ref=sr_1_12?crid=3BLBBVDUPTN53&keywords=servo+tester&qid=1644245707&sprefix=servo+tester,aps,93&sr=8-12

...is useful for determining the exact mechanical limits of a specific servo quickly and easily.  If the servo will only physically move 170 degrees and the connected mechanism requires 180 degrees, a different servo is needed.

It should be possible to use an oscilloscope connected to the servo control lead to determine a) what the tester output duty cycle is at specific angular positions, and b) what the actual Arduino output duty cycle is when running a program.

Use the servo tester to assure that the range of motion of your servo is adequate to correctly operate the mechanism.

Note the tester output at desired positions.

Adjust your program to produce the duty cycle(s) necessary to replicate the tester output at the desired positions.


message:
Teensy not pulling down despite digitalWrite(x,LOW)

I'm trying to switch a ATX PSU on and off by serial command. My code is as follows:

    #include <Arduino.h>
    #define PIN_LOW_FOR_POWER PIN_F0

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

    void loop() {
      String sCode = Serial.readStringUntil('\n');
      if (sCode == "M80"){
        digitalWrite(PIN_LOW_FOR_POWER, LOW);
      }
      else if (sCode == "M81"){
        digitalWrite(PIN_LOW_FOR_POWER, HIGH);
      }
      else{
        Serial.println("Unknown command");
        return;
      }
      Serial.println("OK");
    }

I'm getting "OK" back, and the power switches. After sending M81 I read 5V across the pin and ground, but after sending M80 for some reason I read 2.37V and not 0V. If I switch to "F1" (keep the wire connected to F0) I do read 0V.

The ATX PSU needs F0 to be pulled down in order to turn on. I soldered the ground of the ATX PSU to the Teensy ground, and the wire to be pulled down (green) to F0. I supply the 5V to the Teensy through USB, so the VCC pin is left unconnected.

The PSU does turn on if I manually create a short between F0 and ground.

Why doesn't the Teensy pull F0 down, and how do I resolve this? (All I could come up with is something of internal resistance within the Teensy being too high, which seems unlikely to me. (If the resistance within the PSU and wires between "green" and ground is equal to the resistance within the Teensy this would happen, right?))

PS: It turns out I bought a fake Teensy from China, if it's related. Ordered a new one for a different project, but still had this one laying around.

body:
You forgot to set the IO pin to OUTPUT. Unless you do so all you are doing (if the Teensy core follows the Arduino API to the letter) is controlling the internal pullup.

    pinMode(PIN_LOW_FOR_POWER, OUTPUT);


message:
Mosquitto TLS over WifiMulti on ESP8266

With these few lines I am able to attach my certificate, tell it to `WifiClientSecure` the certificate, start the `wifi` as well as the mosquito `pubsubclient`:

    WiFiClientSecure espClient;
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }

    PubSubClient mqtt_client(espClient);
    mqtt_client.setServer(mqtt_server, 8883);
    mqtt_client.setCallback(mqtt_callback);
    espClient.setCertificate(ca_crt, ca_crt_len);

    if (!mqtt_client.connected()) {
      mqtt_reconnect();
    }

    mqtt_client.loop();

With these lines I am able to connect to wifi, depending on which the closest station is:

    ESP8266WiFiMulti wifiMulti;

    wifiMulti.addAP("primary-network-name", "pass-to-primary-network");
    wifiMulti.addAP("secondary-network-name", "pass-to-secondary-network");
    wifiMulti.addAP("tertiary-network-name", "pass-to-tertiary-network");

    wifiMulti.run();

How can I combine both? I.e, I am interested in sending data to secure MQTT over a set of possible wifi networks?

body:
The WiFiMulti has nothing to to with the MQTT and TLS side of things at all.  It only has anything to do with the WiFi.  As such it just replaces the code that directly interfaces with the WiFi.

That is, this code:

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }

is replaced by this in the global scope:

    ESP8266WiFiMulti wifiMulti;

This in setup():

    wifiMulti.addAP("primary-network-name", "pass-to-primary-network");
    wifiMulti.addAP("secondary-network-name", "pass-to-secondary-network");
    wifiMulti.addAP("tertiary-network-name", "pass-to-tertiary-network");

and this in `loop()`:

    wifiMulti.run();

All the MQTT side of things remains exactly the same.


body:
Follow up on the answer from @Majenko.

    #include <WiFiClientSecure.h>
    #include <ESP8266WiFiMulti.h>
    ESP8266WiFiMulti wifiMulti;
    WiFiClientSecure espClient;

    #include <PubSubClient.h>
    PubSubClient mqtt_client(espClient);

    Serial.println("setup_wifi_multi_addAP()");
    wifiMulti.addAP("ap1", "pass1");
    wifiMulti.addAP("ap2", "pass2");
    wifiMulti.addAP("ap3",  "pass3");

    while (wifiMulti.run() != WL_CONNECTED)
    {
      Serial.print(".");
      delay(500);
    }

    Serial.printf(" connected to %s\n", WiFi.SSID().c_str());

    mqtt_client.setServer(mqtt_server, 8883);
    mqtt_client.setCallback(mqtt_callback);
    espClient.setCertificate(ca_crt, ca_crt_len);

    if (!mqtt_client.connected()) {
      mqtt_reconnect();
    }
    mqtt_client.loop();

    void mqtt_reconnect() {
      Serial.println("mqtt_reconnect()");
      // Loop until we're reconnected
      while (!mqtt_client.connected()) {
        Serial.print("Attempting MQTT connection...");
        if (mqtt_client.connect("ESP8266mqtt_client-1")) {
          Serial.println("connected");
        } else {
          Serial.print("failed, rc=");
          Serial.print(mqtt_client.state());
          Serial.println(" try again in 5 seconds");
          // Wait 5 seconds before retrying
          delay(5000);
        }
      }
    }


body:
If you are using only secure connection without require_certificate in mosquitto configurattion just change
espClient.setCertificate(ca_crt, ca_crt_len);
to
espClient.setCACert(ca_crt, ca_crt_len);

setCertiticate is used mainly to mutual authentication.


message:
How to send characters to Arduino serial using Linux command line without tail -f?

I want to send characters to Arduino serial port which makes the Arduino turn on/off an LED. Here is the code:

    int led_main=8;

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

     Serial.begin(9600);
    }

    void loop()
    {
     char chr;

     if (Serial.available())
     {
      chr = Serial.read();

      if (chr == '0')
      {
       digitalWrite(led_main, LOW);
      }
      else if (chr == '1')
      {
       digitalWrite(led_main, HIGH);
      }
     }
    }

The Arduino is recognized as either `/dev/ttyACM0` or `/dev/ttyACM1` in my system. When I run the command `echo "1" > /dev/ttyACM0`, it doesn't work. But, when I open a second terminal, run `tail -f /dev/ttyACM0`, and then in the first terminal, run `echo "1" > /dev/ttyACM0`, it turns on the LED as expected. So why do I have to open a second terminal and keep monitoring the output with `tail -f` in order for this to work? Is there a way to do this with a single command?

body:
Arduinos have auto-reset circuit to reset the board if new connection is initiated on USB. It is good for convenient upload or to reset for debugging at Serial Monitor open. But it causes troubles if you want to communicate with MCU from computer over USB from command line tools, scripts, python, C++, C#, Java. Always on new connection the board resets.

One solution is to [disable the auto-reset circuit][1]. Other option is to wait a second after the connection while the board resets.

  [1]: http://playground.arduino.cc/Main/DisablingAutoResetOnSerialConnection


message:
'"/dev/ttyACM0": Permission denied' on Ubuntu 18.04

I'd like to say that I'm a noob at both Arduino & Ubuntu (have some command line experience).

I've set port permissions, joined the relevant groups (tty,uucp,dialout & plugdev). I know that the IDE recognizes the board because ttyACM0 only shows up when the board is plugged in. I've searched the Internet and Stack Exchange and Arduino troubleshooting guide and tried all the suggestions. It's not Genuino but a knock-off that's recognized as an Uno. I've got to be missing something.

Are there any relevant logs or a way to monitor whats going on in realtime?

Verbose upload output:

<!-- language: lang-none -->

    Arduino: 1.8.5 (Linux), Board: "Arduino/Genuino Uno"

    Sketch uses 928 bytes (2%) of program storage space. Maximum is 32256 bytes.
    Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.
    /snap/arduino-mhall119/5/hardware/tools/avr/bin/avrdude -C/snap/arduino-mhall119/5/hardware/tools/avr/etc/avrdude.conf -v -patmega328p -carduino -P/dev/ttyACM0 -b115200 -D -Uflash:w:/tmp/arduino_build_241052/Blink500.ino.hex:i

    avrdude: Version 6.3, compiled on Jan 17 2017 at 11:00:16
             Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
             Copyright (c) 2007-2014 Joerg Wunsch

             System wide configuration file is "/snap/arduino-mhall119/5/hardware/tools/avr/etc/avrdude.conf"
             User configuration file is "/home/harry/snap/arduino-mhall119/5/.avrduderc"
             User configuration file does not exist or is not a regular file, skipping

             Using Port                    : /dev/ttyACM0
             Using Programmer              : arduino
             Overriding Baud Rate          : 115200
    avrdude: ser_open(): can't open device "/dev/ttyACM0": Permission denied

    avrdude done.  Thank you.

    Problem uploading to board.  See http://www.arduino.cc/en/Guide/Troubleshooting#upload for suggestions.

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

body:
As stupid as it may sound but "have you tried turning it off and on again?".
Changes to groups only become effective when you have logged out of your account


message:
Does direct port access interfere with PWM?

I think I've scoured the SE for questions about PWM, and fast digitalWrite etc, but I didn't see this point addressed.

I need to use direct writes to some digital pins. Some of the pins on the port are using analogWrite/PWM, though not the pins I'm accessing digitally.

In the digitalWrite function the Arduino core checks to see if PWM is in use and disables it if a digital write is attempted. Since the pins here are isolated -- no digital writes to PWM pins -- is this a needed step?

The reason I ask is that when accessing a port directly, as in `PORTD |= (PORTD & mask) | somebit`, you are in fact writing to the pins being used for PWM, you just aren't writing changed bits.

Am I overthinking this? Is it 'PWM-safe' to use direct port outputs on the neighbor pins?

body:
A timer interrupt will be periodically toggling the PWM bit and might do so between your port read and port write.

The easy solution is to turn off interrupts during the read/modify/write portion of your port update sequence. This could cause a stretched PWM cycle. If you don't turn it off, you'd just glitch the PWM - creating an extra, short cycle. Which one is worse for your PWM recipient?

A better solution might be to to watch the port for the PWM bit to change, then jump in right afterward and make your port update. You could do his in either a blocking or a non-blocking manner.

Update:

> Watching the PWM bits seems as if it would be fairly slow, which
> somewhat defeats the purpose of the direct port writes.

Yes, it's less than ideal. There's a tradeoff here. Can your PWM consumer tolerate the potential occasional glitch, instead?

To be complete, there are a number of motivations to use direct I/O:

 - Smaller code;
 - Less I/O skew with multiple I/Os, or zero skew if the I/Os are in the same port;
 - Less execution time on a time-critical path;
 - Precise output timing;

among others. Those software solutions won't help much in any of those cases.

Can you reassign your output to another pin on a different port, avoiding the whole problem? That might be better than any of the "solutions". Adding hardware might accomplish the same thing - perhaps moving just the PWM to an ATtiny, for example.

Update 2:

> This seems so baked into the structure of the Arduino... does
> digitalWrite() itself actually overcome this?

It "addresses" it - overcomes it? As is so often the case, "that depends".

Here is the the source-code to digitalWrite() from: /Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino /wiring_digital.c (on a Mac; the top-level folder or two will be different on Windows):

    void digitalWrite(uint8_t pin, uint8_t val)
    {
     uint8_t timer = digitalPinToTimer(pin);
     uint8_t bit = digitalPinToBitMask(pin);
     uint8_t port = digitalPinToPort(pin);
     volatile uint8_t *out;

     if (port == NOT_A_PIN) return;

     // If the pin that support PWM output, we need to turn it off
     // before doing a digital write.
     if (timer != NOT_ON_TIMER) turnOffPWM(timer);

     out = portOutputRegister(port);

     uint8_t oldSREG = SREG;
     cli();

     if (val == LOW) {
      *out &= ~bit;
     } else {
      *out |= bit;
     }

     SREG = oldSREG;
    }

Notice that the interrupts are saved and restored around the read/modify/write of the port register. So digitalWrite() already addresses the possibility. This method will stretch one phase of an occasional PWM pulse by a few microseconds.

Alternatively, ignoring the possibility of a collision and having one occur, seems more severe: the pulse could be begun or ended prematurely. This occurrence will take longer - the rest of the disturbed phase - to get back in sync.

So the criterion for how to manage x becomes "Which way has the lesser - or more tolerable - consequence for your PWM consumer?"


message:
What is the sizeof() Arduino's built in HIGH and LOW?

This might be a stupid question to ask but I'm curious. I decided to test this myself and I got a value of 2 for both HIGH and LOW, why would it output 2?

body:
In Arduino AVR Boards, HIGH and LOW are currently macros:

https://github.com/arduino/ArduinoCore-avr/blob/1.6.23/cores/arduino/Arduino.h#L40-L41

    #define HIGH 0x1
    #define LOW  0x0

This means that `sizeof(HIGH)` is equivalent to `sizeof(0x1)`. `0x1` is an [integer constant](https://www.arduino.cc/reference/en/language/variables/constants/integerconstants/). The default type of integer constants is [int](https://www.arduino.cc/reference/en/language/variables/data-types/int). On an 8 bit microcontroller like the ATmega2560 used by your Arduino Mega, an int is 16 bits.

That is why `sizeof(HIGH)` returns 2 (16 bits / 8 bits/byte = 2 bytes).


message:
NEED Help With Servo motor

I have just bought a MG90s tower pro servo for my school project and there is a problem. As soon as I connect my servo to the cnc shield or directly arduino, the whole arduino board turns off. I believe the motor is aking very high power. I even tried to power the motor with a 5v 2amps adapter, but still it turns off.I checked the resistance between the input wires and the wires to DC motor which was very high. As soon as I connected motor to external supply, there was a huge voltage drop. The voltage became almost negligible. DC motor was working fine alone. The servo hasn't even rotated for 1 degree. Please give me a quick solution as I am in a hurry for school deadline is coming. Should I buy a new servo or am I doing something wrong?
Please be quick.
Thank you.
Circuit diagram is below...![![enter image description here][1]][1]

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

The code is below -

    #include <Servo.h>

    Servo name_servo;

    int servo_position = 0;

    void setup() {

    name_servo.attach (9);

    }

    void loop() {

      for (servo_position = 0; servo_position <=180; servo_position +=1){

        name_servo.write(servo_position);
        delay(10);
      }

      for (servo_position=180; servo_position >= 0; servo_position -=1){

        name_servo.write(servo_position);
        delay(10);
      }
    }

body:
Your conclusion is correct. The servo motor is asking a lot of current.

You need a power supply that is more than 2amps. Connect the grounds (the servo black wire to the Arduino GND). Don't let the current for the servo motor go through the Arduino board. Use wires for the servo motor that can handle high currents. Don't let the power for the servo motor go via a breadboard, because the small metal contacts of a breadboard are not for high currents.

Can you get a smaller servo motor?

Could there be something wrong with the 2 A power supply? Is it a certified and good quality power supply?

Tower Pro does not tell what the stall current of the MG90S is: [www.towerpro.com.tw/product/mg90s-3/][1]

  [1]: https://www.towerpro.com.tw/product/mg90s-3/


body:
I found different sources, that state stall currents for this servo between 0.2A and 0.8A, so a 2A power source should be enough for one of these.

From your wiring diagram (which looks good) I guess, that the Arduino is provided with power by other means (maybe USB). If not, please try it that way. You can easily use a USB power bank or a externally driven USB hub, if you don't want to risk your PCs USB ports with a currently unknown error.

Your code is also ok (it's basically the sweep example code of the servo library).

So there are only 2 possible culprits left:

1. The servo: It might be damaged. I have seen some forum entries, that there are many cheap versions of this servo, which don't meet most quality standards. Depending on where you bought it, it might also been DOA (Dead On Arrival: broken, when it reached you). You should try to connect it with a capable power source (without any connection to an Arduino) and measure the current draw. If the current is too high (or the voltage again dips), disconnect it directly and throw it away.
2. The power source: You didn't write, what power source you used exactly. It might be the case, that it is broken, or that it does not provide the specified amount of current. Some power sources can break on a short (or on drawing too much current). You might have created a short while experimenting and broke it. Then you need a new power source.

Test the servo first, with a fresh power source.


body:
> The servo hasn't even rotated for 1 degree.

This is fine, until you apply a control signal nothing much should happen.

> As soon as I connected motor to external supply, there was a huge voltage drop. The voltage became almost negligible. DC motor was working fine alone.

This is a problem; it sounds like your servo is shorted, busted, kaput, no good.


message:
Detecting the down time of a system by subtracting the time when the sytem gives ON signal and when it goes OFF

int pin_state = LOW;
    struct Channel {
        byte pin;
        byte state;
        byte count;
        unsigned long fell, rose;  // times of fall and rise
    };

    const int CHANNEL_COUNT = 3;
    Channel channels[CHANNEL_COUNT] = {
        { 2, LOW, 0, 0 },
        { 3, LOW, 0, 0 },
        //{ 4, LOW, 0, 0 },
        //{ 5, LOW, 0, 0 },
        //{ 6, LOW, 0, 0 }
    };

    void setup()
    {
        for (int i = 2; i <= CHANNEL_COUNT; ++i) {
            pinMode(channels[i].pin, INPUT);
        }
        Serial.begin(9600);
        //Serial.println("pin,fell,rose,low time");
        Serial.println("Minutes, Seconds, Count");
    }

    void loop()
    {
        for (int i = 0; i < CHANNEL_COUNT; ++i)
        {
            Channel &c = channels[i];
            byte new_state = digitalRead(c.pin);
            if (c.state == LOW && new_state == HIGH)   // input rose
            {
                c.rose = millis();
                c.count = c.count + 1;
            }
            else if (c.state == HIGH && new_state == LOW)  // input fell
            {
                c.fell = millis();
                display_channel(c);
            }
            c.state = new_state;
        }
    }

    void display_channel(const Channel &c)
    {
      int minutes, seconds;
      unsigned long difference;
      difference = c.fell - c.rose;
      seconds = int(difference/1000);
      if (seconds >= 60)
      {
           minutes = seconds / 60;
           seconds = seconds % 60;
      }
        //Serial.print(difference/1000);
        //Serial.print(",");
        Serial.print(minutes);
        Serial.print(",");
        Serial.print(seconds/1000);
        Serial.print(",");
        Serial.println(c.count-1);
        //Serial.print(",");
      }

In this code, I tried to measure the time taken between the two events (when the ON signal comes and when the signal goes OFF) in two different channels simultaneously. But the code doesn't give any output and the serial monitor is empty except for the statement in the main function.

It would be useful if anyone could find where exact;y the problem is and a valid solution to it would be helpful.

edit : I made the following changes but still output is never displayed. Any error is still ON the program?

body:
You have the same state being tested twice:

    if (c.state == LOW && new_state == HIGH)   // input rose

and:

    else if (c.state == LOW && new_state == HIGH)  // input fell

If "A", else if "A". It makes no sense. I think you wanted the second one to be the opposite:

    else if (c.state == HIGH && new_state == LOW)  // input fell

Also, this calculation in `display_channel` doesn't work:

    if (seconds >= 60)
    {
      seconds = seconds % 60;
      minutes = minutes + 1;
    }

For example, if seconds is 378, then seconds ends up as 18, and minutes as some undefined number plus 1.

That whole block should be replaced with:

    minutes = seconds / 60;
    seconds = seconds % 60;

In your code:

  * `minutes` starts off undefined
  * You add only 1 to `minutes` regardless of how many minutes have passed.


message:
What is the typical form for a finished Arduino project?

I just started with Arduino. I am an experienced software developer so the programming side was already mostly known to me, and I am surprised at just how easy Arduino have made the hardware side of things, and how easy to use the various libraries are.
So for my first non tutorial project, I want to make air quality sensor web servers to be placed in several rooms throughout my house. I will then have a program running on my PC which collects readings from each sensor and stores then somewhere, to be analyzed later.

All I have right now is an Arduino UNO R3 starter kit, and I am having a WiFi shield delivered today. I feel confident that I can have a working version using the kit that I have shortly after the shield gets delivered.

But my question is: what is the best (some combination of easiest and cheapest) way to crank out half a dozen of these?

Presumably, most experienced makers don't include a breadboard in their finished products? I suppose I should buy a soldering iron.

Should I buy half a dozen UNO R3s and half a dozen WiFi shields (along with air quality sensors)? Or is there a cheaper option that is intended for semi-productionizing an Arduino project?

PS: I feel like the tags I have included barely intersect with the purpose of this question, so if you know of any more appropriate ones, feel free to suggest/edit.

body:
I'm in the same boat as you (SW engineer by trade who likes to tinker with electronics, and is a "maker" at heart.)

I think the answer to your question is "it depends." For a one-off, a breadboard might be fine.

For half-a-dozen, you might want to get project cases and perf-boards, and solder up your design. (For the Mega, there is a very nice prototyping "shield" that brings all the pins from the Mega up on headers and has quite a bit of working room for soldering up circuits.) If you want to make more than a handful, though, you'd probably want to create a custom PC board. You can either create a design in a CAD program and send it off to be small-batch manufactured, or you can buy the equipment to do it yourself. If you make hundreds of units, you should think about ditching the Arduinos and designing a completely custom board using the AVR-family microcontroller and only the components you need.

(I'm still at the breadboard/hand soldered perf-board stage myself, and haven't created any custom PC boards yet, just read about it.)