message:
Arduino fast ADC sampling--which burst control is best?

If one wants to do quick bursts of free-running ADC conversions, should one pause and restart using:

The ADC enable bit: `bitClear(ADCSRA,ADEN)` & `bitSet(ADCSRA,ADEN)`,

The interrupt enable bit `bitClear(ADCSRA,ADIE)` & `bitSet(ADCSRA,ADIE)`,

The start conversion bit `bitClear(ADCSRA,ADSC)` & `bitSet(ADCSRA,ADSC)`,

The auto-trigger enable bit `bitClear(ADCSRA,ADATE)` & `bitSet(ADCSRA,ADATE)`,

or do you need some more complicated combination of the bits?

Here's some code where I'm trying to trigger a pulse and  burst of samples and then report back to the host computer:

    const int numSamples = 20;
    const byte startPin = PD0; // start signal (pullup)
    const byte pulsePin = PD6; // Normally low
    const int pulse_us = 10 ; // output pulse length

    int16_t sampleData[numSamples];
    volatile int sample;
    unsigned long t0, t;

    // state machine:
    typedef enum { STATE_NONE,  // idle
                   STATE_SAMPLING, // record ADC
                   STATE_DONE, // report data
     } states;
    // current state-machine state
    volatile states state = STATE_NONE;

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

      pinMode(startPin,INPUT_PULLUP);
      pinMode(pulsePin,OUTPUT);
      // Clear ADC
      ADCSRA = 0;
      ADCSRB = 0;
      ADMUX = 0;
      ADMUX |= (0b0000 << MUX0); // Choose ADC channel 0
      ADMUX |= (0b01 << REFS0);  // Choose VCC reference voltage
      bitSet(ADMUX,ADLAR);  // ADC left align ADC result into ADCH register

      // sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
      // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
      //ADCSRA |= (0b101 << ADPS0); // /32 : 16M/32/13=38461Hz 26us
      //ADCSRA |= (0b100 << ADPS0); // /16 : 16M/16/13=76923Hz 13us 10 bit precision
      ADCSRA |= (0b011 << ADPS0); // /8  : 16M/8/13=153.8KHz 6.5us low precision
      //ADCSRA |= (0b010 << ADPS0); // /4  : 16M/4/13=307.6KHz 3.2us lower precision
      //ADCSRA |= (0b001 << ADPS0); // /2  : 16M/2/13=615.4Hz 1.6us  bad precision

      ADCSRB |= (0b000 << ADTS0); // Choose free running trigger mode

      bitSet(ADCSRA,ADATE); // enable auto trigger mode per ADSCRB:ADTSx
      bitSet(ADCSRA,ADIE);  // enable interrupts when measurement complete
      bitSet(ADCSRA,ADEN);  // enable ADC
      bitSet(ADCSRA,ADSC);  // start ADC measurements

    }

    ISR(ADC_vect) // Record samples
    {
      sampleData[sample++] = ADC;  // read 10bit value from ADC
      if (sample >= numSamples) {
        bitClear(ADCSRA,ADEN); // stop recording
        state = STATE_DONE;
      }
    }

    void report(){
      t = micros()-t0;  // calculate elapsed time
      Serial.print("Sampling frequency: ");
      Serial.print((float)1000000/t);
      Serial.println(" KHz");
      for (int i = 0; i < numSamples; i++){
        Serial.print(i);
        Serial.print(' ');
        Serial.print(sampleData[i]);
        Serial.println();
      }
    }

    void startSampling(){
      sample = 0;
      t0 = micros();
      digitalWrite(pulsePin,HIGH);
      bitSet(ADCSRA,ADEN); // start ADC
      delayMicroseconds(pulse_us);
      digitalWrite(pulsePin,LOW);

    }

    void loop()
    {
      switch (state){
        case STATE_NONE:
          if(digitalRead(startPin)==LOW){
            startSampling();
            state = STATE_SAMPLING;
          }
          break;
        case STATE_SAMPLING:
          break;

        case STATE_DONE:
            report();
            state = STATE_NONE;
            break;
        default:
        ;;
      }
    }

Toggling `ADEN` was my first thought, but `ADIE` seems as if it would be faster, and `ADSC` seems cleanest, if it works to modulate free-running ADC mode.  Which would be fastest and cleanest?

I have a Nano on order, but nothing available for testing right now.

body:
After some bumbling around, several bit are important:

    ADCSRA &= ~(bit(ADATE) | bit (ADSC) | bit (ADIE)); // Disable

    ADCSRA |=   bit(ADATE) | bit (ADSC) | bit (ADIE); // Enable

 The interrupt enable bit `bitClear(ADCSRA,ADIE)` & `bitSet(ADCSRA,ADIE)`, would stop the current ADC measurement from triggering an interrupt event.

The auto-trigger enable bit `bitClear(ADCSRA,ADATE)` & `bitSet(ADCSRA,ADATE)`, triggers a new conversion as soon as the current one finishes.

The start conversion bit `bitClear(ADCSRA,ADSC)` & `bitSet(ADCSRA,ADSC)`, is important for kicking off the first conversion.

The ADC enable bit `bitClear(ADCSRA,ADEN)` & `bitSet(ADCSRA,ADEN)`, turns the ADC subsystem on and off, but there is a bit of a delay on start up.

Ultimately I left free-running automatic ADC enabled and switched the data recording on and off using the `ADCSRA&bit(ADIE)` as a "BURST" state variable.  I think this is good enough for generic impulse-response testing:

    //: ArduinoPulseADCSample.ino -- Pulse a pin and sample response on ADC
    // For Arduino Uno/Nano/mega
    // https://github.com/drf5n/foxyPulseInduction_Discrimination/tree/discrimination/ArduinoPulseADCSample
    // Adapted from  http://www.gammon.com.au/forum/?id=11488&reply=5#reply5
    //          and https://github.com/pedvide/ADC/tree/master/examples/analogContinuousRead
    //
    // This code emits a digital pulse on A1 and collects a sample of highspeed ADC from A0
    // It sets up a free-running ADC to quickly record a set of ADC data in
    // response to the pulse.  The size of the pulse, pins, number of samples,
    // speed of sampling, etc... are all configurable.
    // The ADC interrupt handler controls the pulse length and filling the sample buffer
    //
    // Serial Commands:
    //
    //  *  Write v and press enter on the serial console to get the value
    //  *  Write c and press enter on the serial console to check that the conversion status,
    //  *  Write s to stop the conversions, you can restart it writing r.
    //  *  Write r to restart the conversions.
    //  *  Write p to emit a pulse and record a burst of values
    //  *  Write d to see the data recorded during the burst (compatible with SerialPlotter)
    //  *  Write m to see metadata about the sample size and interval
    //
    //  Loopback test with a jumper or RC network between A1 and A2.
    //

    // Configurables:
    const byte adcPin = 0; // A0 -- Pin to read ADC data from
    const byte pulsePin = A1; // Next to A0 -- pin to pulse
    const byte oneshot_pin = 12; // OC1B pin on Mega, controlled by Timer1
    const int pulse_us = 50; // pulse duration
    const int numSamples = 20; // sample set
    // Change the sampling speed with the prescaler config in setup()

    volatile uint16_t samples[numSamples];
    volatile int sample = 0;    // position in sample state variable
    #define BURST (ADCSRA & bit(ADIE)) /* Sampling burst state variable */
    int adcReading;
    unsigned long sampleEnd;
    unsigned long pulseStart, pulseEnd;

    // ########## Timer1 One-shot functions
    // The one shot pulses are output on Digital pin OC1B (Arduino Uno D10, Mega D12, Nano D3)
    // Modified by Dave Forrest 2020-01-11 for Timer 1
    // Based on Josh Levine's Nov 23, 2015 work at https://github.com/bigjosh/TimerShot/blob/master/TimerShot.ino

    // Setup the one-shot pulse generator and initialize with a pulse width that is (cycles) clock counts long
    #define OSP_SET_WIDTH(cycles) (OCR1B = 0xffff-(cycles-1))
    void osp_setup(uint16_t cycles) { // 1 idles, 0xffff never matches, 2-0xfffe makes pulses
      const byte prescaler = 0b010; // Choose /8 for 0.5us resolution
                                    // 0b001: /1,      16MHz, 62.5ns resolution, 4ms max
                                    // 0b010: /8,       2MHz,  0.5us resolution, 32ms max
                                    // 0b011: /64,    250kHz,  4us  resolution, 263ms max
                                    // 0b100: /256,  62.5kHz  16us  resolution, 1.048s max
                                    // 0b101: /1024, 15625Hz, 64us  resolution, 4.194176s max
      TCCR1B =  0;      // Halt counter by setting clock select bits to 0 (No clock source).
      // This keeps anyhting from happening while we get set up
      TCNT1 = 0x00;     // Start counting at bottom.
      OCR1A = 0;      // Set TOP to 0. This effectively keeps us from counting because the counter just keeps resetting back to 0.
      // We break out of this by manually setting the TCNT higher than 0, in which case it will count all the way up to MAX and then overflow back to 0 and get locked up again.
      OSP_SET_WIDTH(cycles);    // This also makes new OCR values get loaded frm the buffer on every clock cycle.
      TCCR1A = 0b11 << COM1B0  | 0b11 << WGM10; // OC1B=Set on Match, clear on BOTTOM. Mode 15 Fast PWM.
      TCCR1B = (0b11 << WGM12) | (prescaler << CS10); // Start counting now. WGM 15=0b1111  to select Fast PWM mode
      // Setup the OC1B pin for one-shot output:
      //DDRB |= _BV(2);     // Uno Set pin to output (Note that OC1B = GPIO port PB2 = Arduino Uno Digital Pin 10)
      DDRB |= _BV(6);     // Mega Set pin to output (Note that OC1B = GPIO port PB6 = Arduino Mega Digital Pin 12)
      //DDRD |= _BV(3);     // Nano Set pin to output (Note that OC1B = GPIO port PD3 = Arduino Nano Digital Pin 3)
    }

    // Setup the one-shot pulse generator to idle:
    void osp_setup() {
      osp_setup(1);  // 1 puts it in idle mode, 0xffff never triggers, 2-0xfffe produces pulses.
    }

    // Macro to Fire a one-shot pulse. Use the most recently set width.
    #define OSP_FIRE() (TCNT1 = OCR1B - 1)

    // Macro to Test there is currently a pulse still in progress
    #define OSP_INPROGRESS() (TCNT1>0)

    // Macro to Fire a one-shot pulse with the specififed width.
    // Order of operations in calculating m must avoid overflow of the unint16_t.
    // TCNT2 starts one count lower than the match value because the chip will block any compare on the cycle after setting a TCNT.
    #define OSP_SET_AND_FIRE(cycles) {uint16_t m=0xffff-(cycles-1); noInterrupts();OCR1B=m;TCNT1 =m-1;interrupts();}

    // ##########  End of Timer1 One-shot functions
    ISR(TIMER1_OVF_vect) { //When overflow...
      //  OCRA1=ICR1; // Constant off in WGM 14, COM1A1:0==0b11
      TCCR1B &= ~(0b111 << CS10) ; //turn off clock
    }

    //######### ADC Bit-bang for free-running capture of A0
    void adc_setup_freerunning(const byte adcPin){
      // set the analog reference (high two bits of ADMUX) and select the
      // channel (low 4 bits).  this also sets ADLAR (left-adjust result)
      // to 0 (the default).
      ADMUX = bit (REFS0) | (adcPin & 0x07);

      // Set the ADC ADPSx prescaler flags to control sampling speed/accuracy
      ADCSRA &= ~(bit (ADPS0) | bit (ADPS1) | bit (ADPS2)); // clear prescaler bits

      //ADCSRA |= 0b001 << ADPS0;   //   2    5 bit,
      //ADCSRA |= 0b010 << ADPS0;   //   4    6 bit, 5.36us
      //ADCSRA |= 0b011 << ADPS0;   //   8    9 bit, 6.51us
      ADCSRA |= 0b100 << ADPS0;   //  16   10 bit, 13us
      //ADCSRA |= 0b101 << ADPS0;   //  32     10 bit, 26us
      //ADCSRA |= 0b110 << ADPS0;   //  64     10 bit, 52us
      //ADCSRA |= 0b111 << ADPS0;   // 128     10 bit, 104us

      //enable automatic conversions, start them and interrupt on finish
      //ADCSRA |= bit(ADATE) | bit (ADSC) | bit (ADIE);
        ADCSRA |= bit(ADATE) | bit (ADSC) ;

    }

    void setup ()
    {
      Serial.begin (115200);
      //pinMode(pulsePin, OUTPUT);
      osp_setup(); // Config Mega Digital 12 for oneshot output
      adc_setup_freerunning(adcPin);

    }  // end of setup

    // ADC complete ISR
    ISR (ADC_vect)  // Store ADC burst values
    {
      if (sample >= numSamples) // watch off-by-one
      {
        ADCSRA &= ~bit(ADIE);  // end of sampling burst so stop interrupting
        return;
      }
      // Handle samples
      samples[sample++ ] = ADC;
      //if ( sample == 0){
       // OSP_SET_AND_FIRE(pulse_us * 2); //
      //}
    }  // end of ADC_vect

    void loop ()
    {
      char c;
      char buff[80];
      unsigned long sampleDuration;
      unsigned long pulseDuration;
      // if last reading finished, process it

      // if we aren't taking a reading, start a new one

      if (Serial.available()) {
        c = Serial.read();
        switch (c) {
          case 'c': // Converting?
            Serial.print("ADCSRA: ");
            Serial.println(ADCSRA, BIN);
            break;
          case 's': // stop conversions
            ADCSRA &= ~(bit (ADSC) | bit (ADIE));
            break;
          case 'r': // restart conversions
            ADCSRA |= bit (ADSC) | bit (ADIE);
            break;
          case 'v':
            adcReading = ADC;
            Serial.print(adcReading);
            Serial.print(' ');
            Serial.print((0.5 + adcReading) * 5.0 / 1024, 4);
            Serial.println(" V");
            break;
          case 'm':
            {
              unsigned long sampleDuration = sampleEnd - pulseStart;
              unsigned long pulseDuration  = pulseEnd - pulseStart;

              Serial.print("# Pulse: ");
              Serial.print(pulseDuration);
              Serial.print("us and ");
              Serial.print(numSamples);
              Serial.println(" samples.");
              Serial.print("# Time: ");
              Serial.print(sampleDuration);
              Serial.print("us burst of ");
              Serial.print(numSamples);
              Serial.print(" samples at ");
              Serial.print(1.0 * (unsigned long)(sampleEnd - pulseStart) / numSamples);
              Serial.println("us/sample");
              sprintf(buff, " sampleEnd, pulseEnd, pulseStart lu : lu : lu \n", sampleEnd, pulseEnd, pulseStart);
              Serial.print(buff);
              break;
            }
          case 'p': // start pulse
            sample = 0;  // reset sample SV
            pulseStart = micros();
            OSP_SET_AND_FIRE(pulse_us * 2); // pulse outside ISR
            ADCSRA |= bit(ADIF) | bit(ADIE); // clear existing ADInterruptFlag and enable ADC Interrupts
            while(BURST); // block until burst done
            sampleEnd = micros(); // Record times
            pulseEnd = pulseStart + pulse_us;
            break;
          case 'D':
          case 'd': {// report Data
              sampleDuration = sampleEnd - pulseStart;
              for (int ii = 0 ; ii < numSamples ; ii++) {
                if (c == 'D') {
                  Serial.print(ii * sampleDuration / numSamples);
                  Serial.print(' ');
                }
                Serial.println(samples[ii]);
              }
            }
            break;
          case ' ':
          case '\n':
          case '\r':
            break;
          case 'h':
          case '?':
          default:
            {
              Serial.println("\nArduinoPulseADCSample.in -- Pulse A1 and read a burst of samples from A0\n"
                             "based on serial commands");
              Serial.println("# https://github.com/drf5n/foxyPulseInduction_Discrimination/tree/discrimination/ArduinoPulseADCSample\nCommands: [vcsrpdm] ?");
              Serial.println("Commands:\n"
                             "p: Pulse -- Start a pulse cycle on A1 and record data on A0\n"
                             "d,D: Data -- Dump the data from the last pulse\n"
                             "m: Metadata -- Print the length of pulse, number of samples and rate\n"
                             "v: Voltage -- Conver voltage on A0\n"
                             "c: Converting? -- show ADCSSRA register\n"
                             "h?: Help -- Print this\n"
                            );
            }
            break;
            ;;
        }
      }

      // do other stuff here

    }  // end of loop

This is the output from the p,m,d commands with a jumper connecting pin 12 to A0 with the /16 prescaler:

    # Pulse: 50us and 20 samples.
    # Time: 276us burst of 20 samples at 13.80us/sample
     sampleEnd, pulseEnd, pulseStart 19270968 : 19270742 : 19270692
    0
    1020
    1023
    1023
    1023
    3
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0

And again with the /8 prescaler.  7.2us/sample or 139Ksamples/sec for 8-9bits isn't bad:

    # Pulse: 50us and 20 samples.
    # Time: 144us burst of 20 samples at 7.20us/sample
     sampleEnd, pulseEnd, pulseStart 4229952 : 4229858 : 4229808
    0
    792
    1020
    1022
    1022
    1020
    1022
    1022
    1022
    305
    3
    0
    0
    0
    0
    0
    0
    0
    0
    0

    ArduinoPulseADCSample.in -- Pulse A1 and read a burst of samples from A0
    based on serial commands
    # https://github.com/drf5n/foxyPulseInduction_Discrimination/tree/discrimination/ArduinoPulseADCSample
    Commands: [vcsrpdm] ?
    Commands:
    p: Pulse -- Start a pulse cycle on A1 and record data on A0
    d,D: Data -- Dump the data from the last pulse
    m: Metadata -- Print the length of pulse, number of samples and rate
    v: Voltage -- Conver voltage on A0
    c: Converting? -- show ADCSRA register
    h?: Help -- Print this

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

Here's an R-C pulse-decay trace on the Serial Plotter with a 22K resistor across A0&12 and a 22uF capacitor from GND to A0.

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

  [1]: https://i.stack.imgur.com/fnCYk.png
  [2]: https://i.stack.imgur.com/ztEva.png


sender: user

message:
ESP32 how to preserve RTC time during brownout

I want to use the ESP32 built-in RTC clock.
In my situation, my ESP32 will not have access to an NTP server
I do not want to use external RTC modules

ESP32 provides a pin VDD_RTC will powers the RTC domain exclusively
My problem would be solved if I attach a coin cell to this pin.
In this case, in the event of a brownout, the VDD_RTC will be powered and RTC clock preserved.

But, all dev kits I have seen seem to have VDD_CPU, VDD_DSIO and VDD_RTC connected together
So, if I would use a battery or some sort of small ups to power my ESP32 during brownout, it will be depleted by the use of GPIOs and CPU and other functions.

Solution would be here to detect brownout and force ESP32 to go to deep sleep, and then wake it up after brownout. But this would require an external source attached to a ESP32 pin to trigger deep sleep, and I don't see any pin to trigger it

Maybe I could have a circuit that would give me a signal when there is a brownout. I could attach this signal to a GPIO pin and trigger an interrupt that makes ESP32 go into deep sleep

But it seems too much for something that I am sure is super basic and should be implemented already somehow in a more convenient way

Could anyone share with me any experiences of how to preserve RTC using minimum external circuitry?

sender: assistant

body:
You don't need to do anything special to detect Brownouts. ESP32 itself detects them, and would reset the chip automatically. The reset reason would then indicate a brownout (don't remember the exact name). So you only need to check for the reset reason at the start of your code, whether it is normal powerup, or brownout. The esp won't boot up until the brownout is over, so you don't even need to check when the brownout condition starts nor when it stops.

Moreover, in general (irrespective of brownouts) you don't need any external pins to set the esp32 to sleep, nor do you need them to wake it up. You simply call:

```
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
esp_deep_sleep_start();
```

The first line tells the esp how long to sleep. The second one initiates deep sleep. The esp32 (unlike the esp8266), will automatically wake itself back up. If a brownout happens while it is asleep, it will boot up again once the brownout is over, but the wake-up reason would be different depending on the case.

The default voltage that triggers the brownout condition is I think 2.8V. This is only configurable in esp-idf, not Arduino. But you don't have to worry about it. Above 2.8V the esp32 continues to keep time correctly. Below 2.8V, it halts, then wakes up once it rises above 2.8V. However, if you don't use an external RTC, and don't use a stable power source, there is no way to keep track of time after the brownout. You can't know how long the brownout was. There is no way to do this. The only option is then to find the pin that supplies the RTC alone, sever it, and wire it to a separate battery. This requires alot of SMD skills.


message:
How to use ESP-01 GPIOs for input?

I'm trying to use one of ESP-01 GPIOs as an input, however, I'm always reading 1 and nothing attached to these pins.

Basically, I'm trying to detect high voltage from another sensor like a touch sensor or infrared to do some stuff (initial state will be low, so boot won't be affected).

**So what I'm supposed to do to read the actual value 0?**

Here is the code I'm running:

    #define PIN0 0
    #define PIN2 2
    #define PIN3 3 // Using RX as GPIO

    void setup() {
      Serial.begin(115200,SERIAL_8N1,SERIAL_TX_ONLY);
      pinMode(PIN0, INPUT);
      pinMode(PIN2, OUTPUT);
      pinMode(PIN3, INPUT);
      digitalWrite(PIN2, HIGH);
      digitalWrite(PIN0, LOW);
      digitalWrite(PIN3, LOW);
    }

    void loop() {
      Serial.print("PIN0: ");  Serial.print(digitalRead(PIN0));  Serial.print("\t");
      Serial.print("PIN2: ");  Serial.print(digitalRead(PIN2));  Serial.print("\t");
      Serial.print("PINRX: ");  Serial.print(digitalRead(PIN3));  Serial.println("");

      delay(500);
    }

Here is the Serial Reading:

    PIN0: 1 PIN2: 1 PINRX: 1
    PIN0: 1 PIN2: 1 PINRX: 1
    PIN0: 1 PIN2: 1 PINRX: 1
    PIN0: 1 PIN2: 1 PINRX: 1

body:
You are writing `0` to an input pin. From the [Arduino reference](https://www.arduino.cc/reference/en/language/functions/digital-io/digitalwrite/):

"If the pin is configured as an INPUT, digitalWrite() will enable (HIGH) or disable (LOW) the internal pullup on the input pin. It is recommended to set the `pinMode()` to INPUT_PULLUP to enable the internal pull-up resistor."

Also, when you leave an input pin floating, ie. don't connect anything to it, and also don't enable (or explicitly disable) the internal pull-up or connect an external pull-up, the input pin can show `1`, or it could show `0`.

TL;DR: You shouldn't leave the input pins floating; floating pins are susceptible to electrical noise and can show anything or even fluctuate. If you want them to show `0` when nothing is connected, add an external pull-down resistor.


message:
How to make better looking webpages on an Arduino webserver?

I have a Teensy 4.1 with ethernet, but I have other networked MCUs like a D1 mini, various ESP8266s and Arduino ethernet shields.

My question is: how I can make better looking web pages on these devices, where having a filesystem is limited by memory, or which lack a filesystem.

Specifically, I would like to add SVG images; I'm interested in how to make things like background images. I understand HTML/CSS, and I can code in C, get my data, whatever, but I want to make the page look good too.

Here's an example of the issue as it relates to HTML being rendered; here is an HTML page:

```html
<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
           background-image: url(example.svg);
           }
    </style>
  </head>
  <body>
  </body>
</html>
```

Cool, well to write that in something an Arduino can render, you use print statements; you might write:

```c++
// listen for incoming clients
// forgoing all of server setup
EthernetClient client = server.available();
client.println("<!DOCTYPE html><head><style>");
client.println("body {background-image: url(example.svg);}");
client.println("</style></head><body></body></html>");
```

This won't work without a filesystem, or won't work as is.

Then, I tried inline SVG:

```c++
// listen for incoming clients
// forgoing all of server setup
EthernetClient client = server.available();
client.println("<!DOCTYPE html><head><style>");
client.println("body { ");
client.println("background-image: url("data:image/svg+xml;utf8,<svg>**Omited**</svg>);");
client.println("}");
client.println("</style></head><body></body></html>");
```

This works, sometimes, but seems to have limitations as well.

I'm just wondering how I can make great looking webpages with stylesheets on an Arduino, only using print statements, or not requiring a filesystem.

body:
well, I still want to know more about writing great looking webpages on ardunio network devices.

I got my immediate issue sorted for now.
html/css seems to have some issues I dont quite understand as they relate to print statements, and Im pretty sure the url attribute is what is getting me.

I found this great github project that encodes svg for css inline functions.
[https://yoksel.github.io/url-encoder/][1]

[![etchasketch svg][2]][2]

I set up a basic web server example to simplify the code I was looking at.
its weird, on html pages I have put full style sheets on one line and never had a problem. here, it wouldn't work until I broke the style sheet into multiple lines (even with the url encoded svg).

Here is my simpler example for a page with a background image:

    #include <SPI.h>
    #include <NativeEthernet.h>
    void  pageWrite(EthernetClient client);
    void listenClient(EthernetClient client);
    byte mac[] = {
      0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
    };
    IPAddress ip(10, 1, 0, 177);
    EthernetServer server(80);
    void setup() {

      delay(5000);  //you want this delay. reason: tl;dr
      Serial.begin(9600);
      Ethernet.begin(mac, ip);

    if (Ethernet.linkStatus() == LinkOFF) {
        Serial.println("Ethernet cable is not connected.");
      }
      // start the server
      server.begin();
      delay(100);
      Serial.print("server is at ");
      Serial.println(Ethernet.localIP());
    } //end setup

    void loop() {
       EthernetClient client = server.available();
    listenClient(client);
    }  //end loop
    void listenClient(EthernetClient client){

       if (client) {
        boolean currentLineIsBlank = true;
        while (client.connected()) {
           if (client.available()) {
              char c = client.read();
           // Serial.write(c);   //tells about the client connection
            if (c == '\n' && currentLineIsBlank) {
              pageWrite(client);
              break;
            }
            if (c == '\n') {
              // you're starting a new line
              currentLineIsBlank = true;
            } else if (c != '\r') {
              // you've gotten a character on the current line
              currentLineIsBlank = false;
            }
          }//end avail
        } //end conect
        // give the web browser time to receive the data
        delay(1);
        // close the connection:
        client.stop();
      } //end client
    }//end listenClient()
    void  pageWrite(EthernetClient client){
    client.println("<!DOCTYPE html>");
     }

  [1]: https://yoksel.github.io/url-encoder/
  [2]: https://i.stack.imgur.com/sjLwY.png


body:
Gonna answer my own question again lol.
I looked at spiffs, but it seemed to just be an esp thing.
anyhow, I realized that `<!DOCTYPE html>`
probably wasn't the only doctype there is, and that svg would probably render just fine without html or css. which is true! I used `<!DOCTYPE svg>` and got rid of html and css, which means I didn't need to use some fancy inline css encoding, and could instead make much simpler println() statements, and still generate an accessible "webpage" written in only svg.
I could probably clean up the svg too, I drew it in inkscape, which generates overly complicated svg data.

But the project works now.. in a basic sort of way anyway.

    /*
    An IoT Etch-A-Sketch
    uses 2 rotory encoders to generate x,y data points
    in a svg poly line.

    */
    #include <SPI.h>
    #include <NativeEthernet.h>
    #include <SD.h>
    File dataFile;

    byte mac[] = {
      0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
    };

    IPAddress ip(10, 1, 0, 177);
    EthernetServer server(80);
    //Function defs
    void rotors();
    void rotorA(EthernetClient client);
    void rotorB(EthernetClient client);
    void resetImg();  //erase datalog.txt
    void Abuton();
    void Bbuton();
    void listenClient(EthernetClient client);
    void pageWrite(EthernetClient client);
    void polyLineBegin(EthernetClient client);
    void startPage(EthernetClient client);
    void endPage(EthernetClient client);

    //int potX = A0;
    //int potY = A1;

    int sensorValX = 0;
    int sensorValY = 0;

    int oldX = 0;
    int oldY = 0;

    /**Rotor Vars**/
    // Rotary Encoder Input defintions
    #define CLKA 2
    #define DTA 3
    #define SWA 4

    #define CLKB 5
    #define DTB 6
    #define SWB 7

    int Acounter = 0;
    int Bcounter = 0;

    int AcurrentStateCLK;
    int BcurrentStateCLK;

    int AlastStateCLK;
    int BlastStateCLK;

    unsigned long AlastButtonPress = 0; //butons on rotory encoders
    unsigned long BlastButtonPress = 0;

    void setup() {

      delay(10000);  //you want this delay. reason: tl;dr
      /** Set encoder pins as inputs **/
      pinMode(CLKA,INPUT);
      pinMode(DTA,INPUT);
      pinMode(SWA, INPUT_PULLUP);
      pinMode(CLKB,INPUT);
      pinMode(DTB,INPUT);
      pinMode(SWB, INPUT_PULLUP);

      // Read the initial state of CLK
      AlastStateCLK = digitalRead(CLKA);
      BlastStateCLK = digitalRead(CLKB);
      /***End Rotary Encoder vars****/

      Serial.begin(9600);

      Ethernet.begin(mac, ip);

    if (Ethernet.linkStatus() == LinkOFF) {
        Serial.println("Ethernet cable is not connected.");
      }

      // start the server
      server.begin();
      delay(100);
      Serial.print("server is at ");
      Serial.println(Ethernet.localIP());
      Serial.print("Initializing SD card...");

      if (!SD.begin(BUILTIN_SDCARD)) {
        Serial.println("SD Card init failed!");
        while (1);
        }
    /****SD CARD and Ethernet intialized*****/
    //if data file (on SD Card) Doesn't exist, create it.
    //if data file (on SD Card) does exist errase it and create a new one
      if (SD.exists("datalog.txt")) {
         Serial.println("datalog.txt exists: \n Removing it.");
         while(SD.remove("datalog.txt")!=1){
           Serial.println("Deleeting old file data");
           if (SD.remove("datalog.txt")==1){
              Serial.println ("old dataFile removed");
           }
         }
      } else {
        Serial.println("datalog.txt doesn't exist.");
             }

      // open a new file and immediately close it:
      Serial.println("Creating datalog.txt...");
      dataFile = SD.open("datalog.txt", FILE_WRITE);
      dataFile.close();

      // Check to see if the file exists:
      if (SD.exists("datalog.txt")) {
        Serial.println("datalog.txt exists.");
      } else {
        Serial.println("datalog.txt wasn't created.");
             }
    } //end setup

    void loop() {
     // listen for incoming clients
      EthernetClient client = server.available();
    rotors();
    listenClient(client);
    }  //end loop
    void listenClient(EthernetClient client){

       if (client) {
        boolean currentLineIsBlank = true;
        while (client.connected()) {
           if (client.available()) {
              char c = client.read();
           // Serial.write(c);   //tells about the client connection
            if (c == '\n' && currentLineIsBlank) {
              pageWrite(client);
              break;
            }
            if (c == '\n') {
              // you're starting a new line
              currentLineIsBlank = true;
            } else if (c != '\r') {
              // you've gotten a character on the current line
              currentLineIsBlank = false;
            }
          }//end avail
        } //end conect
        // give the web browser time to receive the data
        delay(1);
        // close the connection:
        client.stop();
      } //end client
      }//end listener()

    void pageWrite(EthernetClient client){
              startPage(client);
              polyLineBegin(client);
              endPage(client);
      }
    void startPage(EthernetClient client){
         // doctype svg no need for html
              client.println("HTTP/1.1 200 OK");
              client.println("Content-Type: text/html");
              client.println("Connection: close");  // the connection will be closed after completion of the response
              client.println("Refresh: 1");  // refresh the page automatically every 5 sec
              client.println();
              client.println("<!DOCTYPE svg>");
              client.println("<svg   xmlns='http://www.w3.org/2000/svg'  viewBox='0 0 227.35277 156.29323' height='6.1532764in' width='8.9508963in'><path  style='fill:#ff0000; stroke:#ff0000; stroke-width:1.32300019;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1' d='m 12.000819,0.66145838 c -6.2819637,0 -11.33936062,5.05739692 -11.33936062,11.33936062 V 144.29249 c 0,6.28197 5.05739692,11.33936 11.33936062,11.33936 H 215.35224 c 6.28197,0 11.33885,-5.05739 11.33885,-11.33936 V 12.000819 c 0,-6.2819637 -5.05688,-11.33936062 -11.33885,-11.33936062 z M 18.932696,12.696383 H 205.5854 c 5.02557,0 9.07128,4.04571 9.07128,9.071282 v 77.03923 c 0,5.025575 -4.04571,9.071285 -9.07128,9.071285 H 18.932696 c -5.025572,0 -9.0712819,-4.04571 -9.0712819,-9.071285 v -77.03923 c 0,-5.025572 4.0457099,-9.071282 9.0712819,-9.071282 z' /><ellipse style='fill:#ffffff;fill-opacity:1; stroke:#ff0000; stroke-width:1.32300007; stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1' cx='21.16666'  cy='130.59085'  rx='10.583334' ry='9.0714283' /><ellipse  style='fill:#ffffff; fill-opacity:1; stroke:#ff0000; stroke-width:1.32300007; stroke-miterlimit:4; stroke-dasharray:none;stroke-opacity:1' cx='200.62982'   cy='131.57361' rx='10.583334' ry='9.0714283'/>");
              client.println("\n<polyline points='15,15");
       }
     void endPage(EthernetClient client){
      client.print("' \nfill='none' stroke='#ff0000'/></svg>");
       }
    void polyLineBegin(EthernetClient client){
    //read data points from SD card
        File dataFile = SD.open("datalog.txt");
      // if the file is available, read it:
      if (dataFile) {
        while (dataFile.available()) {
          //Serial.write(dataFile.read());
          client.write(dataFile.read());
        }
        dataFile.close();
      }
    }

    int rotorA(){ //X coords
      AcurrentStateCLK = digitalRead(CLKA);
      if (AcurrentStateCLK != AlastStateCLK  && AcurrentStateCLK == 1){
         if (digitalRead(DTA) != AcurrentStateCLK) {
          Acounter --;
          }else{
           Acounter ++;
           }
         }
    // Remember last CLK state
      AlastStateCLK = AcurrentStateCLK;
    Abuton(); //errase the data file if A button pressed.
    //X limits
    if(Acounter<=15){
      Acounter=15;
      }
    if(Acounter>=215){
      Acounter=215;
      }
    return Acounter;
      }//endA rotor

    int rotorB(){ //Y coords
      BcurrentStateCLK = digitalRead(CLKB);
      if (BcurrentStateCLK != BlastStateCLK  && BcurrentStateCLK == 1){
        if (digitalRead(DTB) != BcurrentStateCLK) {
           Bcounter --;
           }else{
            Bcounter ++;
         }
        //Serial.println(Bcounter);
      }
      BlastStateCLK = BcurrentStateCLK;
    Bbuton();
    //Y limits
    if(Bcounter<=15){
      Bcounter=15;
      }
    if(Bcounter>=210){
      Bcounter=210;
      }
      return Bcounter;
      }//EndB rotor

    void rotors(){
    //read rotors and write x,y points to datalog.txt
     sensorValX=rotorA();
     sensorValY=rotorB();
    String dataString = "";

    if(sensorValX!=oldX || sensorValY!=oldY){
       dataString += ",";
       dataString += String(sensorValX);
       dataString += ", ";
       dataString += String(sensorValY);

       Serial.println(dataString);

       dataFile = SD.open("datalog.txt", FILE_WRITE);
        // if the file is available, write to it:
       if (dataFile) {
          dataFile.print(dataString);
          dataFile.close();
          //clear dataString
          dataString="";
          }else{
        // if the file isn't open, pop up an error:
        Serial.println("error opening datalog.txt");
      }
      dataFile.close();
      }else{
      ;
      }

     oldX=sensorValX;
     oldY=sensorValY;

    }//end rotors
    void resetImg(){
      //clear datapoints by errasing datafile.
      if (SD.exists("datalog.txt")) {
         Serial.println("Deleting data.");
         while(SD.remove("datalog.txt")!=1){
           Serial.println("Deleeting old file data");
           if (SD.remove("datalog.txt")==1){
              Serial.println ("old dataFile removed");
           }
         }
      } else {
        Serial.println("datalog.txt doesn't exist.");
             }

      // open a new file and immediately close it:
      Serial.println("Creating datalog.txt...");
      dataFile = SD.open("datalog.txt", FILE_WRITE);
      dataFile.close();

      // Check to see if the file exists:
      if (SD.exists("datalog.txt")) {
        Serial.println("New datalog.txt created.");
      } else {
        Serial.println("datalog.txt wasn't created.");
             }

      }//end resetImg

    void Abuton(){ //X buton
        int AbtnState = digitalRead(SWA);
      //If we detect LOW signal, button is pressed
    if (AbtnState == LOW) {
        if (millis() - AlastButtonPress > 500) {
          Serial.println("Resting image!");
          resetImg();
        }
      AlastButtonPress = millis();
      }
      } //end Abuton

    void Bbuton(){ //Y buton
    int BbtnState = digitalRead(SWB);
        if (BbtnState == LOW) {
        //if 50ms have passed since last LOW pulse, it means that the
        //button has been pressed, released and pressed again
        if (millis() - BlastButtonPress > 50) {
          Serial.println("Button B pressed!");
        }
        BlastButtonPress = millis();
      }
    }


body:
Here's an alternative way of doing things I like to use:

What I like to do, when working with Arduinos with a decent amount of memory like the SAMD21-based ones, is create a fully self-contained webpage, that is, a webpage that has all HTML, CSS and Javascript in the same file, and all bitmap and SVG images in-lined in that same file. In short, a webpage file that is *completely* self-contained.

I then gzip that file (which compresses it *a lot*), and then base64 encode the gzipped file. The base64-encoded page is then copy/pasted into the code / memory as a `const char*`.

When the page needs to be served, I base64-decode it, and then serve the gzipped version, which all browsers accept if you put `Content-Encoding: gzip` in the header.

I put an [elaborate example](https://github.com/ocrdu/arduino-webinterface-websocket-ap) on Github, maybe you can get some inspiration from that. The [webpage in the example](https://github.com/ocrdu/arduino-webinterface-websocket-ap/blob/master/WebpageServedByArduino.html) is 26.8 kB in size, and the base64-encoded, gzipped webpage string as put into the code comes in at a little under 7 kB.


body:
Your method of embedding SVG seems unnecessarily complicated to me. You don't need to give a URL of anything. Below is valid for putting SVG onto a web page:

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  <title>Test</title>
</head>
<body>
<div style="position:absolute; z-index:-1;">
  <svg width="500" height="500">
    <rect x="5" y="5" width="450" height="450" fill="lightblue" stroke="black"></rect>
  </svg>
</div>
<p style="padding:10px;">
Hello, world
</body>
</html>
```

The "position:absolute" and the z-index styles put the SVG in a fixed position on the page (like a background image) and underneath anything else you might put there.


body:
As I understand what you want to send is basically a big string(s) stored in memory. You can quite easily store it  it in external memory. You can use FRAM which is non volatile with 32K x 8 modules available for less then $5.00. They will run (Read / Write) at I2C or SPI speeds, no delays for writing or reading. There are other memory types that will also do the job but this is simple and inexpensive.

I am currently doing that with a project I am working on.  It is using an Arduino Nano with about 20K of messages and several of application / program data that I store. Flash will not contain the messages and the program, not enough room. The program data is created via sensors and a rotary switch. I load the data into the FRAM sometimes in sections depending on size with my loading code. I then go to my application code which retrieves the messages from the FRAM and displays them on the LCD and terminal.

There is a pointer table in a specific location in FRAM that is pointing to each message address, size etc. This allows messages and other data to change without changing the main code. The FRAM in my case is a plug in module. This approach although a bit convoluted works nicely and you do not have to have a file structure. You can if you want. I do not know if this will work for you but it does for me.


message:
Arduino uno spi sck not working

I am trying to verify sck output on my arduino uno. I don't have oscilloscope so I loopbacked miso to sck and tried Executing int rx0=SPI.transfer(5) while printing this using Serial.printrx0) it is giving 255.Whether this is expected output?

body:
As suggested by KIIV and myself, you can test the SPI port by:

* connecting MOSI to MISO and checking if you receive what you send
* connecting SCK to the timer input T1 and counting the clock pulses.

Below is a sketch that performs both tests:

```c++
/*
 * Test the SPI port.
 *
 * Connect:
 *   MOSI (11) to MISO (12)
 *   SCK (13) to T1 (5)
 */

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

    // Configure SPI port.
    DDRB |= _BV(PB2)   // SS (digital 10) as output
          | _BV(PB3)   // MOSI (digital 11) as output
          | _BV(PB5);  // SCK (digital 13) as output
    SPCR = _BV(SPE)    // enable port
         | _BV(MSTR);  // master mode

    // Configure Timer 1.
    TCCR1A = 0;          // normal mode
    TCCR1B = _BV(CS10)   // count rising edges of T1 = digital 3
           | _BV(CS11)   // ditto
           | _BV(CS12);  // ditto
}

void loop() {
    TCNT1 = 0;  // clear timer
    uint8_t data = random(256);
    Serial.print(data);
    Serial.print(" -> ");
    SPDR = data;  // send
    delay(1);
    if (bit_is_set(SPSR, SPIF)) {  // transfer complete?
        Serial.println(SPDR);
    } else {
        Serial.println("nothing received");
    }
    Serial.print("    clock pulses: ");
    Serial.println(TCNT1);
    delay(1000);
}
```

It should print:

```text
167 -> 167
    clock pulses: 8
241 -> 241
    clock pulses: 8
217 -> 217
    clock pulses: 8
[...]
```


message:
Switching fan on with transistor, fan running very slowly

I want to control a fan with an arduino from 0 rpm to full rpm. Using a (modified) pwm signal from the arduino I can control the speed w/ the pwm signal, but it cannot go all the way to 0 rpm.

So I decided to add a transistor as a switch using following schematic.

[![schematic][1]][1]

  [1]: https://i.stack.imgur.com/hapjQ.png

The fan is a Snowman F120, I used BC337 as a transistor (800mA) and a resistor of 2.2 kOhm, for controller I use pin 6 on an arduino nano and set it high/low. Arduino and the fan are both run from the 12v power supply. I removed the pwm signal to just have it full on or off for testing purposes.

I was hoping to use the transistor as an on/off switch and when on just send the pwm signal as that was working already.

The fan can now be turned off/on with the arduino but it spins super slow, say 10% of full pwr. Can someone explain why this is? Is there a better way to control this?

Edit: I did try to remove the resistor completely and the fan still moves only slowly

Edit: it is a 4 wire fan, but it cannot go all the way to 0 with pwm. That's why I want the 'switch'

I lowered the resistor to 120 ohm, and switched gpio pin, no effect, if I wait long enough the transistor gets hot

Edit: I connected the transitor to the 5V of the Arduino instead of the Digital out (high) and low and behold fan works well (resistor still in between, both 120 and 2.2kOhm tested, both situations work). I guess the digital output cannot provide enough current?

**
Solution:
* Used IRLZ34N mosfet with a 120Ohm as gate resistor
* and a 100 kOhm as pull down resistor to GND as otherwise the mosfet would always be open
**

body:
With a 2.2K resistor you're massively limiting the current that can flow through the transistor.

I haven't looked up the specs on that transistor, but taking typical values for Vbe (0.6V) and Hfe (100) we can calculate:

    Ibe = (5V - 0.6V) / 2200 ohm = 0.002A

    Ice = Ibe x Hfe = 0.002 x 100 = 0.2A

So even though your transistor is capable of 800mA you're actually only allowing 200mA maximum.

Add to that the voltage drop of the transistor and you have a recipe for a slow fan.

Really you would be better off using an N-channel MOSFET for this job since it is controlled by the voltage at the gate, not the current flowing through it. Also in saturation mode they are more like a very low value resistor rather than a couple of diodes.

Also if your fan is a 4-wire fan (as the ones I have found on Google looking for that model are) then you don't even want a transistor: one of the pins of the fan is a PWM input which you can connect (along with fan ground) direct to the Arduino (it basically includes the transistor internal to the fan) for speed control.


body:
I have used the BC337 to switch small loads like fans, so I know this works in general. As Majenko explained, 2.2kOhm base resistance is a bit high, though.

"I did try to remove the resistor completely and the fan still moves only slowly" - if you controlled the transistor without base resistor, chances are that the GPIO got damaged, try another GPIO *with* 500-1000 Ohm.
As a rule of thumb: If the transistor gets warm when switching a small load, something is wrong. If there's a reasonable voltage drop between emitter and collector, reduce the base resistance if possible.

Another thing is that you should not low-side-switch a 4-pin fan if you want to control it with its PWM input at the same time. In case the ground path is disconnected, the entire fan's circuit is at supply voltage level: Arduino will see 12V at its pins. Use a high-side switch instead

Edit: did you actually make sure that the fan had 100% duty cycle at the PWM input when the transistor was on?


message:
Can't burn fuse bits on ATMega168 with Arduino Uno as ISP

I have an ATMega168 that I am programming via my Arduino Uno as ISP. I can burn the bootloader and transfer a hex file just fine, but I can't seem to be able to change the fuse bits. I found a lot of people having similar problems, but most still weren't resolved after many years or can't connect to their chip at all.

A weird thing I notice is that my ATMega is recognized as an 328p all the time. I know they're practically identical, but nothing works when I change settings to an 168, I always have to set it to 328p. Avrdude tells me the signature is wrong, whenever I try it with 168. Might that already be an indicator for something being wrong!? I ordered a 168 and it's printed on the chip, so it should be an actual 168.

Furthermore I noticed that I can only use the Baud rate of 115200, but I read that only 19200 should be correct and when I use that I get no response as well.

This is the command I'm trying to use:
```
avrdude -Cavrdude.conf -patmega328p -PCOM3 -carduino -b115200 -U efuse:w:0x00:m -U hfuse:w:0xDD:m -U lfuse:w:0xFF:m
```

And the response I get is:
```
avrdude: verifying ...
avrdude: verification error, first mismatch at byte 0x0000
         0x00 != 0xdd
avrdude: verification error; content mismatch
```

I tried different software and different USB cables, to no avail.

If anyone could provide any direction I can try and look for a solution or mistakes I might have made, I'd be really grateful!

body: I got an answer on another forum. I was missing a **10μF capacitor** between the Ground and Reset of the Arduino. Not a single documentation, image or video I saw mentioned that. Everything works fine now.


message:
Why i am not getting the decimal number as output? The code is explained with the help of comments

// Defined three array arr0,arr1,arr2
    int arr0[] = {0, 0, 0, 0, 0, 0, 0, 0};
    int arr1[] = {0, 0, 0, 0, 0, 0, 0, 0};
    int arr2[] = {0, 0, 0, 0, 0, 0, 0, 0};

    //cord function takes binary number array as input and returns decimal
    //number to a single variable as output
    int cord(int a[]) {
      int v = 0;
      for (int i = 0; i < 8; i++)
      {
        int p = 1;
        for (int j = 0; j < i; j++)
        {
          p = p * 2;
        }
        v = v + a[i] * p;
      }
      return v;
    }

    //function bcord takes input row & col and updates the value in arr0,arr1,arr2 to 1 wherever
    // there is some value in the row and column coordinate Eg.2,0 will make 2nd index of arr0
    // to 1 or 2,1 will make 2nd index of arr1 to 1
    int bcord(int row[], int col[])
    {

      int n = sizeof(col) / sizeof(col[0]);

      for (int i = 0; i < n; i++)
      {
        int j;
        if (col[i] == 2)
        {
          j = row[i];
          arr2[j] = 1;
        }
        if (col[i] == 1)
        {
          j = row[i];
          arr1[j] = 1;
        }
        if (col[i] == 0)
        {
          j = row[i];
          arr0[j] = 1;
        }
      }
      int led0 = cord(arr0);
      Serial.print(led0);
      int led1 = cord(arr1);
      Serial.println(led1);
      int led2 = cord(arr2);
      Serial.println(led2);
      return 0;
    }

    void setup()
    {
      Serial.begin(9600);
      int row[] = {0, 0, 2, 2, 1};
      int col[] = {0, 1, 0, 1, 1};
      bcord(row, col);
    }

    void loop() {}
    // Output expected is decimal numbers which are stored in led0, led1 and led2 on the serial
    // monitor

body:
In C++, you cannot pass an array as a parameter to a function. When you
write the function prototype

```c++
int bcord(int row[], int col[], int n)
```

the compiler considers it a synonym of:

```c++
int bcord(int *row, int *col, int n)
```

In other words, both `row` and `col` are pointers, not arrays.

When you call the function like this:

```c++
bcord(row, col);
```

the compiler implicitly converts the call into this:

```c++
bcord(&row[0], &col[0]);
```

In other words, you are really passing pointers to the first element of
each array. This is a standard language behavior called “decay to
pointer”.

When I compile your code with warnings enabled, I get the following:

```text
In function 'int bcord(int*, int*)':
warning: 'sizeof' on array function parameter 'col'
will return size of 'int*' [-Wsizeof-array-argument]
   int n = sizeof(col) / sizeof(col[0]);
                     ^
arr-ind.ino:31:30: note: declared here
 int bcord(int row[], int col[])
                              ^

```

Thus the compiler is telling you what is wrong. The variable `n` is not
what you expect.

The standard solution is to pass the size of the array from the caller:
move the definition of `n` to `setup()`, define `bcord()` as:

```c++
int bcord(int row[], int col[], int n)
```

and call it as

```c++
bcord(row, col, n);
```


message:
Arduino ESP8266WebServer hangs after a while but responds pings

I have an ESP8266 module that I use to be able to power on three computers if they are off. The ESP8266WebServer has what I needed to have a POST method rather than a simpler GET one since I am sending a password and I want that little extra security.

The code works and the circuits work as expected but only for a while. I have not been able to track down what is happening but whatever I do, it always hangs after some time but only the web server, it stills continues to respond pings so I know it is still connected and the serial monitor writes back my debug texts.

What I have tried after researching for some time:

 - The HTML output string probably gets too big for the memory and should use PROGMEM but in the end, I sill need to manipulate it and something breaks. Gave up on it.
 - The HTML output had an embedded image for the logo that also probably gets too big for the memory. Erased the image but stills hangs about the same time with or without it.
 - Looked for a way to hardreset the ESP8266 module, could not find how and it is surely bad practice and may come with other kind of problems.
 - Add a timeout for the connection, did not make any difference either.

I am missing something with the handle of the web server that gets the memory or something full and it stops answering request after a while because of it.

Here is the code:

    #include <ESP8266WiFi.h>
    #include <ESP8266WebServer.h>

    const char* ssid     = "";
    const char* password = "";
    const char* hostname = "";
    const String imgLogo = "";

    ESP8266WebServer server(9080);

    String header = "";

    String output1State = "off";
    String output2State = "off";
    String output3State = "off";

    const int output1 = D1;
    const int output2 = D2;
    const int output3 = D8;

    const int input1 = D5;
    const int input2 = D6;
    const int input3 = D7;

    const int ledPin =  LED_BUILTIN;

    unsigned long currentTime = millis();
    unsigned long previousTime = 0;
    const long timeoutTime = 2000;

    unsigned long previousMillisOff = 0;
    unsigned long previousMillisOn = 0;
    unsigned long previousMillisMsg = 0;

    void setup() {
      Serial.begin(9600);
      pinMode(output1, OUTPUT);
      pinMode(output2, OUTPUT);
      pinMode(output3, OUTPUT);
      pinMode(input1, INPUT);
      pinMode(input2, INPUT);
      pinMode(input3, INPUT);

      digitalWrite(output1, LOW);
      digitalWrite(output2, LOW);
      digitalWrite(output3, LOW);

      WiFi.disconnect();
      delay(500);
      pinMode(ledPin, OUTPUT);
      digitalWrite(ledPin, HIGH);

      WiFi.mode(WIFI_STA);
      WiFi.hostname(hostname);
      WiFi.begin(ssid, password);

      while (WiFi.status() != WL_CONNECTED)
      {
        delay(500);
        Serial.print(".");
        digitalWrite(ledPin, !digitalRead(ledPin));
      }
      Serial.println("");
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
      Serial.println(WiFi.getAutoConnect());
      digitalWrite(ledPin, HIGH);

      server.on("/", HTTP_GET, handleRoot);
      server.on("/serverAction", HTTP_POST, serverAction);
      server.onNotFound(handleNotFound);

      server.begin();
      Serial.println("HTTP server started");
    }

    void loop(void)
    {
      server.handleClient();

      unsigned long currentMillis = millis();
      if(currentMillis - previousMillisOff > 5000)
      {
        previousMillisOff = currentMillis;
        digitalWrite(ledPin, LOW);
        previousMillisOn = currentMillis;
      }

      currentMillis = millis();
      if(!digitalRead(ledPin) && currentMillis - previousMillisOn > 250)
      {
        previousMillisOn = currentMillis;
        digitalWrite(ledPin, HIGH);
        previousMillisOff = currentMillis;
      }

      currentMillis = millis();
      if(currentMillis - previousMillisMsg > 30000)
      {
        Serial.println(WiFi.localIP());
        previousMillisMsg = currentMillis;
      }
    }

    void handleRoot()
    {
      boolean PC01 = digitalRead(input1);
      boolean PC02 = digitalRead(input2);
      boolean PC03 = digitalRead(input3);

      String HTML = String("<!DOCTYPE html>\r\n\r\n") +
        " \r\n    <meta charset=\"UTF-8\">\r\n    <meta http-equiv=\"cache-control\" content=\"no-cache, must-revalidate, post-check=0, pre-check=0\" />\r\n    <meta http-equiv=\"cache-control\" content=\"max-age=0\" />\r\n   <meta http-equiv=\"expires\" content=\"0\" />\r\n   <meta http-equiv=\"expires\" content=\"Tue, 01 Jan 1980 1:00:00 GMT\" />\r\n    <meta http-equiv=\"pragma\" content=\"no-cache\" />\n\r   <link href=\"data:image/x-icon;base64," + imgLogo + "\" rel=\"icon\" type=\"image/x-icon\" />\r\n   \r\n \r\n \r\n    \r\n\r\n
Server switch
\r\n  " +
        "
Estado PC01 - " + (PC01 ? "Encendido" : "Apagado") + "\r\n" +
        "
\r\n" +
        "   <form action=\"/serverAction\" method=\"post\">\r\n" +
        "     Contraseña: <input type=\"password\" name=\"pwd\">\r\n" +
        "
\r\n" +
        "     <input type=\"text\" name=\"server\" value=\"PC01\" hidden>\r\n" +
        "     <button class=\"button " + (PC01 ? "" : "button2") + "\" type=\"submit\"" + (PC01 ? " disabled> PC01 encendido" : ">Encender PC01") + "</button>\r\n" +
        "   </form>\r\n\r\n" +
        "
Estado PC02 - " + (PC02 ? "Encendido" : "Apagado") + "\r\n" +
        "
\r\n" +
        "   <form action=\"/serverAction\" method=\"post\">\r\n" +
        "     Contraseña: <input type=\"password\" name=\"pwd\">\r\n" +
        "
\r\n" +
        "     <input type=\"text\" name=\"server\" value=\"PC02\" hidden>\r\n" +
        "     <button class=\"button " + (PC02 ? "" : "button2") + "\" type=\"submit\"" + (PC02 ? " disabled> PC02 encendido" : ">Encender PC02") + "</button>\r\n" +
        "   </form>\r\n\r\n" +
        "
Estado PC03 - " + (PC03 ? "Encendido" : "Apagado") + "\r\n" +
        "
\r\n" +
        "   <form action=\"/serverAction\" method=\"post\">\r\n" +
        "     Contraseña: <input type=\"password\" name=\"pwd\">\r\n" +
        "
\r\n" +
        "     <input type=\"text\" name=\"server\" value=\"PC03\" hidden>\r\n" +
        "     <button class=\"button " + (PC03 ? "" : "button2") + "\" type=\"submit\"" + (PC03 ? " disabled> PC03 encendido" : ">Encender PC03") + "</button>\r\n" +
        "   </form>\r\n \r\n";

      server.send(200, "text/html", HTML);

    }

    void serverAction()
    {

      if( ! server.hasArg("pwd") || ! server.hasArg("server") || server.arg("pwd") == NULL || server.arg("server") == NULL)
      {
        server.send(400, "text/plain", "400: Invalid Request");
        return;
      }

      if(server.arg("pwd") == "0123456789")
      {
        String redirect = String("");
        if(server.arg("server") == "PC01")
        {
          if(!digitalRead(input1))
          {
            server.send(200, "text/html", "
Encendiendo " + server.arg("server") + "
" + redirect);
            digitalWrite(output1, HIGH);
            delay(1000);
            digitalWrite(output1, LOW);
          }
          else
            server.send(200, "text/html", "
" + server.arg("server") + " ya encendido
" + redirect);

        }
        else if(server.arg("server") == "PC02")
        {
          if(!digitalRead(input2))
          {
            server.send(200, "text/html", "
Encendiendo " + server.arg("server") + "
" + redirect);
            digitalWrite(output2, HIGH);
            delay(1000);
            digitalWrite(output2, LOW);
          }
          else
            server.send(200, "text/html", "
" + server.arg("server") + " ya encendido
" + redirect);
        }
        else if(server.arg("server") == "PC03")
        {
          if(!digitalRead(input3))
          {
            server.send(200, "text/html", "
Encendiendo " + server.arg("server") + "
" + redirect);
            digitalWrite(output3, HIGH);
            delay(1000);
            digitalWrite(output3, LOW);
          }
          else
            server.send(200, "text/html", "
" + server.arg("server") + " ya encendido
" + redirect);
        }
        else
        {
          server.send(401, "text/plain", "401: Unauthorized");
        }
      }
      else
      {
        server.send(401, "text/plain", "401: Unauthorized");
      }
    }

    void handleNotFound(){
      server.send(404, "text/plain", "404: Not found");
    }

Any suggestions would be appreciated.

body:
When you use `String` the way you do, you're doing a lot of memory allocations. The ESP8266 doesn't have a lot of memory and is easily subject to a problem called ["heap fragmentation"](https://cpp4arduino.com/2018/11/06/what-is-heap-fragmentation.html) - memory is allocated from a fixed pool called a "heap". Over time the free parts of the heap may become so fragmented that you can no longer allocate chunks of memory over a certain size. The way that you're building the string in the variable `HTML` will probably cause this to happen quickly.

To check for heap fragmentation, add this code to the end of `handleRoot()`:
```
  Serial.print("getFreeHeap: ");
  Serial.println(ESP.getFreeHeap());
  Serial.print("getHeapFragmentation: ");
  Serial.println(ESP.getHeapFragmentation());
  Serial.print("getMaxFreeBlockSize: ");
  Serial.println(ESP.getMaxFreeBlockSize());
```

And use your web server, especially reloading the root page, until you see the problem happen.

If you have a memory leak (memory is being allocated but never freed), you'll see `getFreeHeap` drop and not go back up.

If you have heap fragmentation, you'll see `getMaxFreeBlockSize` get smaller until it's smaller than the biggest strings you're trying to allocate (probably the total length of the root web page). You'll also see `getHeapFragmentation` get bigger over time - it's a metric from 0 to 100% of how fragmented the heap is. If it gets to 40 or 50% you're in trouble.

If you are seeing heap fragmentation you're going to need to rethink the way you build the web page you're serving. You need to minimize the number of times that you allocate memory. You may not know it but every time you add something on to a `String`, it frees the memory for the old string and allocates memory for the new one.

For instance, you build the web page like this:
```
 String HTML = String("<!DOCTYPE html>\r\n<html>\r\n") +
    " <head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta http-equiv=\"cache-control\" content=\"no-cache, must-revalidate, post-check=0, pre-check=0\" />\r\n    <meta http-equiv=\"cache-control\" content=\"max-age=0\" />\r\n   <meta http-equiv=\"expires\" content=\"0\" />\r\n   <meta http-equiv=\"expires\" content=\"Tue, 01 Jan 1980 1:00:00 GMT\" />\r\n    <meta http-equiv=\"pragma\" content=\"no-cache\" />\n\r   <link href=\"data:image/x-icon;base64," + imgLogo + "\" rel=\"icon\" type=\"image/x-icon\" />\r\n   <style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;} .button { background-color: #195B6A; border: none; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;} .button2 {background-color: #800000;}</style>\r\n </head>\r\n <body>\r\n    <img src=\"data:image/png;base64," + imgLogo + "\"/>\r\n\r\n    <h1>Server switch</h1>\r\n  " +
    "   <p>Estado PC01 - " + (PC01 ? "Encendido" : "Apagado") + "\r\n" +
    "   <p>\r\n" +
    "   <form action=\"/serverAction\" method=\"post\">\r\n" +
```

Every time you use `+` to add to the `String` here, you're causing the compiler to unnecessarily allocate memory. It's completely unnecessary to add most of these strings together. The C++ compiler will automatically concatenate strings written on separate lines, like so:
```
 String HTML = String("<!DOCTYPE html>\r\n<html>\r\n") +
    " <head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta http-equiv=\"cache-control\" content=\"no-cache, must-revalidate, post-check=0, pre-check=0\" />\r\n    <meta http-equiv=\"cache-control\" content=\"max-age=0\" />\r\n   <meta http-equiv=\"expires\" content=\"0\" />\r\n   <meta http-equiv=\"expires\" content=\"Tue, 01 Jan 1980 1:00:00 GMT\" />\r\n    <meta http-equiv=\"pragma\" content=\"no-cache\" />\n\r   <link href=\"data:image/x-icon;base64," + imgLogo + "\" rel=\"icon\" type=\"image/x-icon\" />\r\n   <style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;} .button { background-color: #195B6A; border: none; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;} .button2 {background-color: #800000;}</style>\r\n </head>\r\n <body>\r\n    <img src=\"data:image/png;base64," + imgLogo + "\"/>\r\n\r\n    <h1>Server switch</h1>\r\n  "
    "   <p>Estado PC01 - " + (PC01 ? "Encendido" : "Apagado") + "\r\n"
    "   <p>\r\n"
    "   <form action=\"/serverAction\" method=\"post\">\r\n"
```

Just making that change will reduce the heap fragmentation. This won't solve the problem but it should allow your program to run longer without crashing.

This is a big subject. The best way to do it is to use C strings (character arrays) and avoid allocating memory altogether, but this is difficult and tedious even for experienced programmers. The [ESP8266 Arduino Core documentation offers some advice](https://arduino-esp8266.readthedocs.io/en/latest/faq/a02-my-esp-crashes.html) (see the section "Memory, memory, memory"), including using `PROGMEM` for constant literal strings and creating `String` objects with all the space they'll need when they're allocated, to avoid freeing and re-allocating the internal buffer they use to store the string.

If you're having heap fragmentation issues, do everything you can to reduce `String` use in your program. If that doesn't get your web server working reliably, search the web and Stack Overflow for more advice on how to avoid heap fragmentation, and post new questions here about specific issues.


message:
Assign a delay value generated by a random function called randomBlink()

I'm trying to make a sketch where my led blinks with random delay. I have 2 functions: ledBlink() and randomBlink(). The randomBlink use as delay parameter a random number "r" generated from 1 to 499 and pass this value to the ledBlink function to make the led blink with a delay according the random number generated. But seems like that led  doesn't consider the random value of blinkDelay. Any help is appreciated, thank you so much!

    #include <JC_Button.h>

    int ledPin = 11;

    int ledState = LOW;
    unsigned long blinkDelay;
    unsigned long lastBlinkMillis = 0;

    void setup() {

      Serial.begin(9600);
      pinMode(ledPin, OUTPUT);
    }

    void ledBlink()
    {
      unsigned long currentMillis = millis();

      if (currentMillis - lastBlinkMillis >= blinkDelay)
      {
        // save the last time you blinked the LED
        lastBlinkMillis = currentMillis;

        // if the LED is off turn it on and vice-versa:
        ledState = !ledState;

        // set the LED with the ledState of the variable:
        digitalWrite(ledPin, ledState);
      }
    }

    void randomBlink()
    {
      unsigned long r = random(500);
      blinkDelay = r;
      ledBlink();

    }

    void loop() {
      randomBlink();
    }

body:
Your problem descriptions is a bit unclear, though I think I see your problem.

On every `loop()` iteration you call `randomBlink()`, which generates a new random delay value and then calls `ledBlink()`, which in turn checks `millis()` for the time to toggle the LED and exits fast. So you are blinking only when the current `blinkDelay` has passed, but you generate new random values for `blinkDelay` on every `loop()` iteration - so really really fast. In the time needed for even the small delays you may have generated thousands of new random values, so it is very likely that some of them are rather small values. You check against these so you only get short delays.

Think of how you would do such thing in real life. Lets say you use a dice to determine the numbers of minutes to wait. You are throwing the dice every few seconds while watching the clock. Chances are that you will at some point get a 1 or 2 after waiting 1 or 2 minutes. It is unlikely that you don't get a 6 for 6 minutes straight. Instead you would want to through the dice only once per waiting period.

For the code this means, that you need to restructure it. Calculate the new delay value only when you toggle the LED. So something like this:

    void ledBlink()
    {
      unsigned long currentMillis = millis();

      if (currentMillis - lastBlinkMillis >= blinkDelay)
      {
        // save the last time you blinked the LED
        lastBlinkMillis = currentMillis;

        // if the LED is off turn it on and vice-versa:
        ledState = !ledState;

        // set the LED with the ledState of the variable:
        digitalWrite(ledPin, ledState);

        // generate new random delay
        randomBlink();
      }
    }

    void randomBlink()
    {
      unsigned long r = random(500);
      blinkDelay = r;
    }

    void loop() {
      ledBlink();
    }

Calling `ledBlink()` in every `loop()` iteration makes sure, that the toggling of the LED actually happens. A new random value for the delay is only called after the LED just got toggled. Now the range of the delay will be the full 499ms.


message:
Multiplexer 74HC4067, conflict between channels

I am currently working on an Arduino Zero with a 74HC4067 multiplexer and I am experiencing inconsistencies when testing some of the channels.

My class is the following (it should be functional for 8 or 16 channels multiplexers).

Multiplexer.h :

```
#ifndef Multiplexer_h
#define Multiplexer_h

#include "Arduino.h"

class Mux
{
  public:
    Mux(uint8_t numberOfChannels, byte sigPin, byte adress1, byte adress2, byte adress3, byte adress4 = 0);

    uint8_t muxRead(byte pin);//Read specific mux pin
    void selectMuxPin(byte pin);

  private:
    uint8_t m_numberOfChannels;
    byte m_sigPin ;
    byte m_adress1 ;
    byte m_adress2 ;
    byte m_adress3 ;
    byte m_adress4 ;
    uint8_t m_numberOfAdressPins;
};

#endif
```

Multiplexer.cpp :
```
#include "Multiplexer.h"

//**************************************************************

Mux::Mux(uint8_t numberOfChannels,
         byte sigPin,
         byte adress1,
         byte adress2,
         byte adress3,
         byte adress4)

:   m_numberOfChannels(numberOfChannels),
    m_sigPin(sigPin),
    m_adress1(adress1),
    m_adress2(adress2),
    m_adress3(adress3),
    m_adress4(adress4)
{
  if(m_numberOfChannels > 8) {m_numberOfAdressPins = 4;}
  else {m_numberOfAdressPins = 3;}

  //Set adresses to OUTPUT
  pinMode(m_adress1, OUTPUT);
  pinMode(m_adress2, OUTPUT);
  pinMode(m_adress3, OUTPUT);
  if(m_numberOfChannels > 8){pinMode(m_adress4, OUTPUT);};

  //Set adresses to LOW
  digitalWrite(m_adress1, LOW);
  digitalWrite(m_adress2, LOW);
  digitalWrite(m_adress3, LOW);
  if(m_numberOfChannels > 8){digitalWrite(m_adress4, LOW);};

  pinMode(m_sigPin, INPUT_PULLUP);
}

//**************************************************************

uint8_t Mux::muxRead(byte pin)
{
  selectMuxPin(pin);
  bool value = digitalRead(m_sigPin);
  return(value) ;
}

void Mux::selectMuxPin(byte pin)
{
  const int selectPins[4] = {m_adress1, m_adress2, m_adress3, m_adress4};
  if (pin > (m_numberOfChannels - 1)) return; // Exit if pin is out of scope

  for (int i = 0; i < m_numberOfAdressPins; i++)
  {
    if (pin & (1<<i)) {digitalWrite(selectPins[i], HIGH);}
    else {digitalWrite(selectPins[i], LOW);}
  }
}
```

To make my tests on the 74HC4067, I connect my multiplexer, I put the pin 8 of my Arduino to the "LOW" state and with the help of a jumper cable I test each of the pins via the following code:

```
#include "Multiplexer.h"

//**************************************************************

Mux Mux0(16, 6, 2, 3, 4, 5);

//**************************************************************

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

//**************************************************************

void loop() {

  //Set pin 8 to LOW for the test with a jumper
  analogWrite(8, LOW);

  //For this test, we print the name of the multiplexer's channel if it's LOW

  bool channel0 = Mux0.muxRead(0);
  if(!channel0)
    Serial.println("Channel 0");

  bool channel1 = Mux0.muxRead(1);
  if(!channel1)
    Serial.println("Channel 1");

  bool channel2 = Mux0.muxRead(2);
  if(!channel2)
    Serial.println("Channel 2");

  bool channel3 = Mux0.muxRead(3);
  if(!channel3)
    Serial.println("Channel 3");

  bool channel4 = Mux0.muxRead(4);
  if(!channel4)
    Serial.println("Channel 4");

  bool channel5 = Mux0.muxRead(5);
  if(!channel5)
    Serial.println("Channel 5");

  bool channel6 = Mux0.muxRead(6);
  if(!channel6)
    Serial.println("Channel 6");

  bool channel7 = Mux0.muxRead(7);
  if(!channel7)
    Serial.println("Channel 7");

  bool channel8 = Mux0.muxRead(8);
    if(!channel8)
    Serial.println("Channel 8");

  bool channel9 = Mux0.muxRead(9);
  if(!channel9)
    Serial.println("Channel 9");

  bool channel10 = Mux0.muxRead(10);
  if(!channel10)
    Serial.println("Channel 10");

  bool channel11 = Mux0.muxRead(11);
  if(!channel11)
    Serial.println("Channel 11");

  bool channel12 = Mux0.muxRead(12);
  if(!channel12)
    Serial.println("Channel 12");

  bool channel13 = Mux0.muxRead(13);
  if(!channel13)
    Serial.println("Channel 13");

  bool channel14 = Mux0.muxRead(14);
  if(!channel14)
    Serial.println("Channel 14");

  bool channel15 = Mux0.muxRead(15);
  if(!channel15)
    Serial.println("Channel 15");
}
```

For most of the channels it works quite well. When I connect the jumper (pin 8) to a channel of the multiplexer, the name of the corresponding pin is displayed in the console.

However, two channels are problematic. Channel 0 and channel 8. No matter if I connect the jumper to one or the other, I see in the console "Channel 0" and "Channel 8" as if both were connected and the change of state of one would cause the change of state of the other.

Any idea why?

Thanks

body: I gather it is part of a learning experiment. Logically this does not compute however there are many reasons something like this could happen. A bad IC is the first thing that comes to mind but they are generally very rugged devices. If you have a scope probe the power supplies to be sure they are clean and stable, if so start by holding it in one of the bad states and take voltage measurements on VCC, Ground, several other pins and the related pins. Your voltage on each pin should be within 0.1V of the appropriate power supply pin.  If not it would indicate a short especially if it goes somewhere mid supply voltage. If this is a breadboard flip the bad pins out and test again. If everything is in speck it is a short, if it still show you probably have a bad IC.


message:
Morse encoder code not working as expected on Arduino UNO

I'll start saying that I don't have much experience working with Arduino and programming in C. I have an Elegoo Arduino UNO clone.

Recently I was trying to build a morse encode which converts a text to morse and then flashes a LED to communicate the morse code. The code is as follows

```
#define OUT_PIN 8
#define END_PIN 7

const short dot_time = 200; // Time LED is ON for dot
const short dash_time = dot_time*3; // Time LED is ON for dash
const short same_letter_space = dot_time; // Time LED is OFF between dots/dashes of the same letter
const short letter_space = dot_time*3; // Time LED is OFF between letters
const short word_space = dot_time*5; // Time LED is OFF between words
const char letter_separator[] = "_";
const char word_separator[] = "/";

typedef struct {
  char * morse;
  char letter;
}morse_pair;

morse_pair morse_table_letters[] = {{".-", 'A'}, {"-...", 'B'}, {"-.-.", 'C'}, {"-..", 'D'}, {".", 'E'}, {"..-.", 'F'}, {"--.", 'G'}, {"....", 'H'}, {"..", 'I'}, {".---", 'J'},//
{"-.-", 'K'}, {".-..", 'L'}, {"--", 'M'}, {"-.", 'N'}, {"---", 'O'}, {".--.", 'P'}, {"--.-", 'Q'}, {".-.", 'R'}, {"...", 'S'}, {"-", 'T'}, {"..-", 'U'}, {"...-", 'V'},
{".--", 'W'}, {"-..-", 'X'}, {"-.--", 'Y'}, {"--..", 'Z'}};
morse_pair morse_table_digits[] = {{"-----", '0'}, {".----", '1'}, {"..---", '2'}, {"...--", '3'}, {"....-", '4'}, {".....", '5'}, {"-....", '6'}, {"--...", '7'}, {"---..", '8'},//
{"----.", '9'}};

char test_text[] = "aaa";

morse_pair letter_encoder(char letter){
  int letter_value = (int) letter;
  if(letter_value >= 97){
    //lowercase
    return morse_table_letters[letter_value-97];
  }
  else if (letter_value>=65){
    //uppercase
    return morse_table_letters[letter_value-65];
  }
  else {
    //digits
    return morse_table_digits[letter_value];
  }
}

char* word_to_morse(char* word, size_t len){
  Serial.print("Encoding word: ");
  Serial.println(word);
  size_t len_morse = 0;
  char* letters[len];
  for(size_t l=0;l<len;l++){
    letters[l] = letter_encoder(word[l]).morse;
    len_morse += strlen(letters[l])+1;
  }
  char* morse_string = malloc(len_morse*sizeof(char));
  for(size_t l=0;l<len;l++){
    strcat(morse_string, letters[l]);
    if(l<len-1){
      strcat(morse_string, letter_separator);
    }
  }
  strcat(morse_string, word_separator);
  Serial.print("Result: ");
  Serial.println(morse_string);
  return morse_string;
}

char* text_to_morse(char* text){
  Serial.print("Encoding text: ");
  Serial.println(text);
  size_t len = strlen(text);
  char* text_morse = malloc((4*len+len)*sizeof(char));
  char* swp = text;
  for(char* ewp = text;ewp!=(text+len);ewp++){
    if(*(ewp+1)==' ' || *(ewp+1) == '\0'){
      char * wtm = word_to_morse(swp, ewp-swp+1);
      strcat(text_morse, wtm);
      swp=ewp+2;
      free(wtm);
    }
  }
  Serial.print("Result: ");
  Serial.println(text_morse);
  return text_morse;
}

void morse_to_pin(char* text_morse){
  Serial.println("Playing with pins");
  size_t len = strlen(text_morse);
  for(size_t l=0;l<len;l++){
    char letter = text_morse[l];
    Serial.println(letter);
    if(letter == '.'){
      digitalWrite(OUT_PIN, HIGH);
      delay(dot_time);
    }
    else if(letter=='-'){
      digitalWrite(OUT_PIN, HIGH);
      delay(dash_time);
    }
    else if(letter=='_'){
      digitalWrite(OUT_PIN, LOW);
      delay(letter_space);
    }
    else if(letter=='/'){
      digitalWrite(OUT_PIN, LOW);
      delay(word_space);
    }
    else {
      digitalWrite(OUT_PIN, LOW);
      delay(same_letter_space);
    }
  }
}

void start_comm(){
  Serial.println("Start comm.");
  digitalWrite(END_PIN, HIGH);
  delay(2000);
  digitalWrite(END_PIN, LOW);
}

void end_comm(){
  Serial.println("End comm.");
  digitalWrite(END_PIN, HIGH);
  delay(500);
  digitalWrite(END_PIN, LOW);
  delay(500);
  digitalWrite(END_PIN, HIGH);
  delay(500);
  digitalWrite(END_PIN, LOW);
}

void setup(){
  Serial.begin(9600);
  pinMode(OUT_PIN, OUTPUT);
  pinMode(END_PIN, OUTPUT);
}

void loop ()
{
  start_comm();
  delay(1000);
  char* ttm = text_to_morse(test_text);
  morse_to_pin(ttm);
  free(ttm);
  delay(1000);
  end_comm();
  delay(1000);
}
```
The part of the code that converts text to a morse string behaves correctly when run on my laptop, but when I upload it to my Arduino UNO behaves weirdly and the morse LED doesn't flashes at all.

---

## **Edit:**

the Arduino UNO just seems to run only the `start_comm` and `end_comm` functions, as if there's nothing inbetween. It changed behaviour and doesn't behaves always the same, before it printed some garbage to the serial monitor, but now it just skips the whole code inbetween the two functions mentioned above.

body:
I kind of solved it, I was using `malloc` incorrectly and was accessing uninitialized bits, thus causing undefined behaviour. The code below should work correctly
```
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define OUT_PIN 8
#define END_PIN 7

const short dot_time = 200; // Time LED is ON for dot
const short dash_time = dot_time * 3; // Time LED is ON for dash
const short same_letter_space = dot_time; // Time LED is OFF between dots/dashes of the same letter
const short letter_space = dot_time * 3; // Time LED is OFF between letters
const short word_space = dot_time * 5; // Time LED is OFF between words
const char letter_separator[] = "_";
const char word_separator[] = "/";
const char unkown_letter[] = "?";

typedef struct {
  char * morse;
  char letter;
} morse_pair;

const morse_pair morse_table_letters[] = {{".-", 'A'}, {"-...", 'B'}, {"-.-.", 'C'}, {"-..", 'D'}, {".", 'E'}, {"..-.", 'F'}, {"--.", 'G'}, {"....", 'H'}, {"..", 'I'}, {".---", 'J'},//
  {"-.-", 'K'}, {".-..", 'L'}, {"--", 'M'}, {"-.", 'N'}, {"---", 'O'}, {".--.", 'P'}, {"--.-", 'Q'}, {".-.", 'R'}, {"...", 'S'}, {"-", 'T'}, {"..-", 'U'}, {"...-", 'V'},
  {".--", 'W'}, {"-..-", 'X'}, {"-.--", 'Y'}, {"--..", 'Z'}
};
const morse_pair morse_table_digits[] = {{"-----", '0'}, {".----", '1'}, {"..---", '2'}, {"...--", '3'}, {"....-", '4'}, {".....", '5'}, {"-....", '6'}, {"--...", '7'}, {"---..", '8'},//
  {"----.", '9'}
};

const char* letter_encoder(char letter) {
  int letter_value = (int) letter;
  if (letter_value >= 97 && letter_value <= 122) {
    //lowercase
    return morse_table_letters[letter_value - 97].morse;
  }
  else if (letter_value >= 65 && letter_value <= 90) {
    //uppercase
    return morse_table_letters[letter_value - 65].morse;
  }
  else if (letter_value>=48 && letter_value<=57) {
    //digits
    return morse_table_digits[letter_value].morse;
  }
  else {
    //Boh
    return unkown_letter;
  }
}

void word_to_morse(char* morse_word, char* word, int len) {
  Serial.print("Encoding word: ");
  Serial.println(word);
  for (int l = 0; l < len; l++) {
    strcat(morse_word, letter_encoder(word[l]));
    if (l < len - 1) {
      strcat(morse_word, letter_separator);
    }
  }
  strcat(morse_word, word_separator);
  Serial.print("Word result: ");
  Serial.println(morse_word);
}

void text_to_morse(char* morse_text, char* text, int len) {
  Serial.print("Encoding text: ");
  Serial.println(text);
  char* swp = text;
  int morse_len = 0;
  for (char* ewp = text; ewp != (text + len); ewp++) {
    if (*(ewp + 1) == ' ' || *(ewp + 1) == '\0') {
      int w_len = ewp - swp + 1;
      char * morse_word = (char*) malloc((5*w_len+w_len)*sizeof(char));
      strcpy(morse_word, "");
      word_to_morse(morse_word, swp, w_len);
      morse_len += strlen(morse_word);
      Serial.print("Word result: ");
      Serial.println(morse_word);
      Serial.print("Word len: ");
      Serial.println(morse_len);

      strcat(morse_text, morse_word);
      swp = ewp + 2;
      free(morse_word);
    }
  }
  morse_text = (char*) realloc(morse_text, ++morse_len*sizeof(char));
  Serial.print("Text result: ");
  Serial.println(morse_text);
}

void morse_to_led(const char* text_morse, int len) {
  Serial.println("Flashing morse with pins");
  for (int l = 0; l < len; l++) {
    char letter = text_morse[l];
    Serial.println(letter);
    switch(letter){
      case '.':
        digitalWrite(OUT_PIN, HIGH);
        delay(dot_time);
        break;
      case '-':
        digitalWrite(OUT_PIN, HIGH);
        delay(dash_time);
        break;
      case '_':
        digitalWrite(OUT_PIN, LOW);
        delay(letter_space);
        break;
      case '/':
        digitalWrite(OUT_PIN, LOW);
        delay(word_space);
        break;
      default:
        digitalWrite(OUT_PIN, LOW);
        delay(same_letter_space);
        break;
    }
  }
}

void start_comm() {
  Serial.println("Start comm.");
  digitalWrite(END_PIN, HIGH);
  delay(dash_time);
  digitalWrite(END_PIN, LOW);
}

void end_comm() {
  Serial.println("End comm.");
  digitalWrite(END_PIN, HIGH);
  delay(dot_time);
  digitalWrite(END_PIN, LOW);
  delay(dot_time);
  digitalWrite(END_PIN, HIGH);
  delay(dot_time);
  digitalWrite(END_PIN, LOW);
}

void setup() {
  Serial.begin(9600);
  pinMode(OUT_PIN, OUTPUT);
  pinMode(END_PIN, OUTPUT);
}

void loop ()
{
  //Start
  start_comm();
  delay(2000);

  //Convert
  char test_text[] = "test";
  int len = strlen(test_text);
  char * morse_text = (char*) malloc((5*len+len)*sizeof(char));
  strcpy(morse_text, "");
  text_to_morse(morse_text, test_text, len);
  morse_to_led(morse_text, strlen(morse_text));
  free(morse_text);
  delay(2000);

  //End
  end_comm();
  delay(2000);
}
```


message:
Sunfounder IR remote controller issue

I've been making a hoverboard using arduino, tinkercad and c++ (pic included). When I wired it up irl, I wired it exactly as I did in the picture (arduino UNO)

However, when I tested it out, it didn't work. The IR sensor got signal from my Sunfounder IR remote, but the fans didn't turn like I expected it to. The entire thing works fine with tinkercad.

I'm really sure it's not my wiring, since I took extra extra care to wire it properly.
This leads me to believe that it's a problem with my [remote code][1]

The IR remote control used was a random one in tinkercad. I'm using sunfounder ir remote irl.
Starting line 37, I've put code that uses the remote in the tinkercad to control the motors.

Is it possible that I need to recode specifically with the cases of the sunfounder IR remote? If so, where can I find a list of what buttons are what cases/code. so that I can rewire the entire thing?

I hope you all can help me. Thank you! :)

[![my tinkercad project][2]][2]

  [1]: https://pastebin.com/XSLVX5S9
  [2]: https://i.stack.imgur.com/3UYgI.png

body:
You're saying that your remote is SunFounder's so I assume this is the one?

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

If it is then this should be the equivalent codes:

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

Try if it works for you.

  [1]: https://i.stack.imgur.com/ZU2xS.jpg
  [2]: https://i.stack.imgur.com/MjMmQ.png


message:
How to use HC-SR04 sensor to make a flowmeter?

I am somewhat familiar with Arduino and am trying to use two ultrasonic HC-SR04 modules to measure the direction of water flow inside a pipe. The sensors are kept as in the image below.
The direction is determined by emitting a signal from one sensor and receiving it in the other, noting down the time and repeating with the other set(See image below). This is called an ultrasonic time of flight flowmeter.

We then use the obtained values to determine the direction by seeing which one is greater. Further details on how it works can be found here: https://www.youtube.com/watch?v=rqJ9snaqYiY
![](https://aws1.discourse-cdn.com/arduino/original/4X/c/2/a/c2a54541f965aeda3f3366b1d01ab1739327414a.gif)

I used the below code to collect the data to determine direction for this but it doesn't seem to be working, as only the first value is displayed and the second is always 0.
```
long firstduration = 0;
long secondduration = 0;

void setup() {
  // put your setup code here, to run once:
pinMode(13, OUTPUT);
pinMode(12, INPUT);
pinMode(11, INPUT);
Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
digitalWrite(13,LOW);
delayMicroseconds(2);
digitalWrite(13,HIGH);
delayMicroseconds(10);
digitalWrite(13,LOW);
firstduration = pulseIn(12,HIGH);
secondduration = pulseIn(11, HIGH);
Serial.print(firstduration);
Serial.print(", ");
Serial.println(secondduration);
}
```

Updated code:

```
long firstduration;
long secondduration;

void setup() {
  // put your setup code here, to run once:
pinMode(10, OUTPUT);
pinMode(13, OUTPUT);
pinMode(12, INPUT);
pinMode(11, INPUT);
Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
digitalWrite(13,LOW);
delayMicroseconds(2);
digitalWrite(13,HIGH);
delayMicroseconds(10);
digitalWrite(13,LOW);
firstduration = pulseIn(12,HIGH);

digitalWrite(10,LOW);
delayMicroseconds(2);
digitalWrite(10,HIGH);
delayMicroseconds(10);
digitalWrite(10,LOW);
secondduration = pulseIn(11,HIGH);

Serial.print(firstduration);
Serial.print(", ");
Serial.println(secondduration);
}
```

What would the issue be?

I am using an Arduino Uno board.

I have ruled out wiring issues...

Thanks!

body:
I don't think this will work with HC-SR04 sensors. They are not just ultrasonic transducers. They incorporate extra electronics for the sole purpose of measuring the time difference between the sended and received signal. They just don't provide the needed control on the ultrasonic transducers. To change their function to suite you you will need to fully understand their circuitry (I surely don't). Or build your own support circuitry. Additionally you need to think about how to transmit the ultrasonic wave into the fluid. It isn't enough to just tag a standard transducer to the pipe. The small transducers on the HC-SR04 sensors are made for transmitting through air, so the actual transducer is hidden behind the grill inside the capsule. I thin you need to at least bring the transducer itswlf directly to the pipe, if not directly to the water. You will need to buy fizting ultrasonic transducers.

 Also you have a problem due to the workings of `pulseIn()`.

If you want to read a HIGH pulse it will wait for the pin to go LOW, then to go HIGH again, and then counting the time until it goes LOW again. This means it blocks from the moment it is called until the pulse is finished (or the 1s timeout hits).

I will assume that you trigger the sensor which has its echo pin on pin 12, though a similar problem arises when you trigger the other sensor.

With the HC-SR04 the HIGH pulse will start at a specific time after the trigger pulse. Lets assume the pulse starts at the same time on both sensors (despite the described problems above). Directly after the trigger pulse you call `pulseIn()` on the sending sensor. It will block until it receives the each. Since this needs about twice as long as the other sensor to receive the signal (signal needs to go to the second sensor and then back to its source) the end of the echo pulse from the receiving sensor will be inside this time, thus putting its echo pin low again. The sending snsor receives its echo, the `pulseIn()` function ends. Now you call `pulseIn()` on the receiving sensor. But its pulse already ended, so the function waits and waits for the pulse to start and finally reaches its timeout. In this case it returns zero.

You would need to check the pins in a non-blocking way. Maybe even an Input Capture Interrupt would be fitting (depending on the requirements on the resolution).


message:
How do I create a code that lets me use an array of 10 thermistors on one arduino?

I am new to programming and am trying to create an array of 10 thermistors on one arduino. So far I have found a code for Temperature Sensor Using NTC Thermistor that is only for one thermistor. How do I fix this code for 10 thermistors?
Here is the link where I found the code.
https://thecustomizewindows.com/2020/10/temperature-sensor-using-ntc-thermistor-arduino-ntc/
The code below has been changed a little for the thermistor I am using.
Thank you.
~~~
#define RT0 10000   // Ω
#define B 3470      // K
#define VCC 5       //Supply voltage
#define R 10000     // R=10kΩ

float RT, VR, ln, TX, T0, VRT;

void setup() {
  Serial.begin(9600);
  T0 = 25 + 273.15;                 //Temperature, Celsius to Kelvin
}

void loop() {
  VRT = analogRead(A0);              //Acquisition analog value of VRT
  VRT = (5.00 / 1023.00) * VRT;      //Conversion to voltage
  VR = VCC - VRT;
  RT = VRT / (VR / R);               //Resistance of RT

  ln = log(RT / RT0);
  TX = (1 / ((ln / B) + (1 / T0))); //Temperature from NTC thermistor

  TX = TX - 273.15;                 //Conversion to Celsius

  Serial.print("Temperature:");
  Serial.print("\t");
  Serial.print(TX);
  Serial.print("C\t\t");
  Serial.print((TX * 1.8) + 32);    //Conversion to Fahrenheit
  Serial.println("F");
  delay(500);
}
~~~

body:
You haven't said which (of the many kinds) of "Arduino" you plan to use, but Uno being the most common, I'll assume that. You also haven't said why/whether you must use a particular temperature sensor, but if you can be flexible about that, there will more choices of solution.

First, thermistors: You read a thermistors with an an A/D converter. Uno has an A/D converter but it has only 6 channels available - not enough for your spec of 10 sensors.
 - You could add an external A/D multiplexer with 5 channels fed into one of your on-board channels plus the remaining 5 on-board channels.
 - Or add a 10-channel multiplexer for all 10 sensors and feed it to one of the on-board A/D channels. This is better because it's simpler - all of the sensor signals will be processed identically, and all accessed the same way in the code.
- Add an external 10-channel A/D. It will cost a little more but will be even easier to work with.

If you don't require thermistors, I'd suggest the Dallas/Maxim DS18b20 "1-wire" sensors. The "1-Wire" bus is a proprietary protocol developed by Dallas Semiconductor on which these sensors depend. You use one, simple, twisted-pair bus to access all of them, needing only 1 Arduino pin (and ground) to provide both power and communication to/from the sensors. Libraries are available to manage the bus and the communication. The 1-wire bus can be in a linear or a branched configuration, to suit your installation. You can use 2 wires (ground and power+data) or 3 wires (ground, power, data). Here's a link to the [DS18b20 data sheet][1] for the details.

Update:<br>
I didn't really answer your question about *coding* for 10 thermistors (since you can't directly connect 10 thermistors to an Uno), I'll try to address that now without getting into any more detail about what kind of sensors you use or how you connect them.

You'll need to read 10 sensors, compute the sensor data to temperature and store it, and do whatever you plan to do with the temperature value. Your present code prints it (as both degC and degF, but let's just describe that part as printing the value).

You'll need a `for( )` loop that executes 10 times, once for each sensor, where the loop index tells which sensor (0-9) you'll be processing. In time the loop executes, read a sensor, compute the temperature from what the sensor gives you, if it isn't already in the units you need, and print the value. So structuring that as if it were code (but I won't be writing it out in full C++) it would look like:

```
tell all 10 sensors to take a measurement; // if necessary
for( i = 0; i < 10; ++i ){
   read data from sensor[i];
   convert it to temperature;      // depends on the sensor
   print the temperature value;
}
```
If that is all you want to do, code this loop in your `setup()` function. Each time you reset the Arduino, it will measure and print all 10 temperatures and stop (actually, loop forever, doing nothing, until you power it down). If you want it to do this periodically, code this loop in your `loop()` function, with a `delay(5000);` statement after it. Now it will print the 10 temperatures every 5 seconds. You can change the 5000 (it's in milliseconds) to whatever period you want.

But it's the details that get you. You've got code to read and convert thermistors but your Arduino can't directly connect to 10 thermistors. If you use an external multiplexer, then you'll have to include code for that. If you use DS18b20 1-Wire sensors, you'll need to download and use the code library for those, as well as converting their 1/16-degC units to the units of your choice.

I'd recommend you start with 2 or 3 thermistors since you have the code for them, and write the loop for those. Once that's working, you'll have the answer to your title question. Then you'll have to decide how to connect 10 sensors of some kind, as I wrote about earlier. That will involve some additional coding, for an analog multiplexer, or for 1-Wire sensors, or whatever solution you choose. Just expand your experiment by small steps at a time and get each step working before you move on.

  [1]: https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf


message:
Selenoid motor not responding to NodeMCU instructions

I just start a project migrating from Arduino Uno to NodeMCU, basically this projects control some selenoid motors triggered by a website instructions. For example: if website returns 2, the motor #2 start work.

I hace everything ready, fetching from the website but, the motors are not working. In Arduino Uno works but in NodeMCU did not.

The selenoid motor is this one from AliExpress: [the 3v --> https://es.aliexpress.com/item/4000807560712.html](https://aliexpress.com/item/4000807560712.html)

The circuit I made is like this:

**NodeMCU / Motor**

D2 -> Positive motor wire (red wire).

3.3V -> Positive motor wire (red wire).

GND -> Negative motor wire (black wire).

All this is attached to a protoboard for easy my work, but those are the connections of the circuit.

At otherwise, the code looks something like this:
```
void setup() {
  Serial.begin(115200);
  pinMode(D2, OUTPUT);

}

void loop() {
  digitalWrite(D2, LOW);
  delay(3000);
  digitalWrite(D2, HIGH);
  delay(3000);

}
```
I also tried instead of pin name `D2` use `4` corresponding of the GPIO number. Didn't work.

The wired part is in Arduino Uno the same code and same circuit works perfectly, but in NodeMCU not.

body:
So you connected 3.3V and pin D2 both to the positive motor wire. When the pin is high the motor runs and gets its current from the 3.3V pin. When you set the pin to LOW you essentially short the 3.3V pin to ground through the output hardware of the pin. That is highly risky. The output hardware of the pin only can withstand a certain amount of current (around 20mA, 40mA absolute max). Since you have nothing that would limit the current in this path you can easily fry the output hardware of the pin. **Don't do that!** The same is valid for driving a motor directly only from the digital output pin.

The correct way of controlling a motor with an Arduino or ESP is by using a fitting driver. For just turning it on and off a simple transistor or MOSFET is sufficient (depending on the current draw of the motor a MOSFET is better than a bipolar transistor). Google something like "MOSFET as switch" and you will get many tutorials on that. You can also add the term "Arduino" and you will get tutorials specifically for Arduinos.

Why it worked for the Uno but not for the NodeMCU? You didn't describe how exactly you connected it on the Uno (to the 3.3V pin or the 5V pin?). Probably the digital output pin on the NodeMCU cannot sink enough current so that it is not able to lower the voltage enough. Though if it would be able to do this it would also cause a power failure for the whole microcontroller. Maybe that also happened with your Uno difficult to say without more information.