message:
Changing ESP8266 WiFi network via Access Point

I have an ESP8266 project that requires setting the SSID and password for a network via an Access Point.  Everything works fine, the only issue is if you send incorrect credentials to the access point, the server returns an empty response before the timeout period elapses, and the error message is never sent to the client.

If the connection is successful then the success message is appropriately sent to the client.  It's almost like the `WiFi.begin()` function detects the connection fails on its own, and something there is preventing me from sending my own response.

```
%  curl -X POST "http://192.168.1.1/authenticate?ssid=FakeNetworkpassword=87654321"
curl: (52) Empty reply from server
```

Did some research and saw some mentions to keep the `loop` running, so I attempted to do so below, but to no avail.  Would appreciate any ideas, thanks.

```
#include "ESP8266WiFi.h"
#include "ESP8266HTTPClient.h"
#include "ESP8266WebServer.h"

HTTPClient http;
WiFiClient client;

ESP8266WebServer server(80);
IPAddress ipAP(192, 168, 1, 1);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

unsigned long previousMillisConnection = 0;
unsigned long startingMillisConnection = 0;
const unsigned long CONNECTION_PERIOD = 1000;
const unsigned long CONNECTION_TIMEOUT = 10000;

int DELAY = 40;

char ssid[64] = { 0 };
char password[64] = { 0 };

char ssidNew[64];
char passNew[64];

const int STATE_DEFAULT = 0;
const int STATE_CREDS = 1;
int state = STATE_DEFAULT;

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

  WiFi.softAPConfig(ipAP, gateway, subnet);
  WiFi.softAP("ESP8266", "12345678");
  delay(100);

  server.on("/authenticate", HTTP_POST, onSetCredentials);
  server.begin();

  performWifiConnect(ssid, password);
  WiFi.waitForConnectResult(CONNECTION_TIMEOUT);

  Serial.println("Initialization complete");
}

void loop() {
  if (state == STATE_DEFAULT) {
    server.handleClient();
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("Connected!");
    }
  }

  else if (state == STATE_CREDS) {
    whileConnecting();
  }

  delay(DELAY);
}

void performWifiConnect(char ssid[], char password[]) {
  Serial.println("Attempting to connect to " + String(ssid) + "...");
  WiFi.setAutoReconnect(false);
  WiFi.persistent(false);
  WiFi.begin(ssid, password);
}

void onWifiConnected() {
  Serial.println("WiFi connected " + WiFi.localIP().toString());
  WiFi.setAutoReconnect(true);
  WiFi.persistent(true);
}

void onSetCredentials() {
  Serial.println("onSetCredentials");

  server.arg("ssid").toCharArray(ssidNew, 64);
  server.arg("password").toCharArray(passNew, 64);

  if (String(ssidNew) == String(ssid) && WiFi.status() == WL_CONNECTED) {
    Serial.println("Already connected to " + String(ssidNew));
    server.send(200, "application/json", "{ \"success\": true, \"changed\": false }");
  } else {
    Serial.println("Switching from " + String(ssid) + " to " + String(ssidNew));
    state = STATE_CREDS;
    performWifiConnect(ssidNew, passNew);
    startingMillisConnection = millis();
  }
}

void whileConnecting() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillisConnection >= CONNECTION_PERIOD) {
    previousMillisConnection = currentMillis;

    Serial.println("checking connection...");

    // Success
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("Connected to " + String(ssidNew) + " successfully!");

      strcpy(ssid, ssidNew);
      strcpy(password, passNew);

      server.send(200, "application/json", "{ \"success\": true, \"changed\": true }");

      state = STATE_DEFAULT;
    }

    // Failure
    if (currentMillis - startingMillisConnection >= CONNECTION_TIMEOUT) {
      Serial.println("connection failed, attempting to reconnect to old network!");
      Serial.println("ssidOld: " + String(ssid));
      Serial.println("passOld: " + String(password));

      String errorMessage = "Timed out while attempting to connect to " + String(ssidNew);
      Serial.println(errorMessage);
      server.send(500, "application/json", "{\"errorMessage\":\"" + errorMessage + "\"}");

      performWifiConnect(ssid, password);

      WiFi.waitForConnectResult(CONNECTION_TIMEOUT);

      state = STATE_DEFAULT;

      if (WiFi.status() != WL_CONNECTED) {
        Serial.println("Could not return to old network!");
      }
    }
  }
}
```

body:
I recommend you to use the WiFiManager library. It has the WiFi provisioning solved.

----------

To join an AP esp8266 must change the WiFi radio channel to the channel of the AP. Since the esp8266 has only one radio, the SoftAP must change the channel too. This causes the SoftAP clients to disconnect.

The solution is respond to the configuration request before connecting to AP, then let the configuration page do a new request for the result.

To illustrate here is a simple example:
```
#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif

void setup() {

  Serial.begin(115200);
  delay(500);

#ifdef ESP32
//  WiFi.begin(); // use SSID and password stored by SDK. commented out to test the Configuration AP
#else
//  WiFi.disconnect(); // forget the persistent connection to test the Configuration AP
#endif

  // waiting for connection to remembered  Wifi network
  Serial.println("Waiting for connection to WiFi");
  WiFi.waitForConnectResult();

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println();
    Serial.println("Could not connect to WiFi. Starting configuration AP...");
    configAP();
  } else {
    Serial.println("WiFi connected");
  }
}

void loop() {
}

void configAP() {

  WiFiServer configWebServer(80);

  WiFi.mode(WIFI_AP_STA); // starts the default AP (factory default or setup as persistent)

  Serial.print("Connect your computer to the WiFi network ");
#ifdef ESP32
  Serial.print("to SSID of you ESP32"); // no getter for SoftAP SSID
#else
  Serial.print(WiFi.softAPSSID());
#endif
  Serial.println();
  IPAddress ip = WiFi.softAPIP();
  Serial.print("and enter http://");
  Serial.print(ip);
  Serial.println(" in a Web browser");

  configWebServer.begin();

  while (true) {

    WiFiClient client = configWebServer.available();
    if (client) {
      char line[64];
      int l = client.readBytesUntil('\n', line, sizeof(line));
      line[l] = 0;
      client.find((char*) "\r\n\r\n");
      if (strncmp_P(line, PSTR("POST"), strlen("POST")) == 0) {
        l = client.readBytes(line, sizeof(line));
        line[l] = 0;

        // parse the parameters sent by the html form
        const char* delims = "=&";
        strtok(line, delims);
        const char* ssid = strtok(NULL, delims);
        strtok(NULL, delims);
        const char* pass = strtok(NULL, delims);

        // send a response before attemting to connect to the WiFi network
        // because it will reset the SoftAP and disconnect the client station
        client.println(F("HTTP/1.1 200 OK"));
        client.println(F("Connection: close"));
        client.println(F("Refresh: 10")); // send a request after 10 seconds
        client.println();
        client.println(F("<html><body><h3>Configuration AP</h3><br>connecting...</body></html>"));
        client.stop();

        Serial.println();
        Serial.print("Attempting to connect to WPA SSID: ");
        Serial.println(ssid);
        WiFi.persistent(true);
        WiFi.setAutoConnect(true);
        WiFi.begin(ssid, pass);
        WiFi.waitForConnectResult();

        // configuration continues with the next request

      } else {

        client.println(F("HTTP/1.1 200 OK"));
        client.println(F("Connection: close"));
        client.println();
        client.println(F("<html><body><h3>Configuration AP</h3><br>"));

        int status = WiFi.status();
        if (status == WL_CONNECTED) {
          client.println(F("Connection successful. Ending AP."));
        } else {
          client.println(F("<form action='/' method='POST'>WiFi connection failed. Enter valid parameters, please.<br><br>"));
          client.println(F("SSID:<br><input type='text' name='i'><br>"));
          client.println(F("Password:<br><input type='password' name='p'><br><br>"));
          client.println(F("<input type='submit' value='Submit'></form>"));
        }
        client.println(F("</body></html>"));
        client.stop();

        if (status == WL_CONNECTED) {
          delay(1000); // to let the SDK finish the communication
          Serial.println("Connection successful. Ending AP.");
          configWebServer.stop();
          WiFi.mode(WIFI_STA);
          return;
        }
      }
    }
  }
}
```


sender: user

sender: assistant

body:
There are several intertwined issues in this one.

Firstly, `setup()` has some code running before it should be.

That first problem is here:
```
  server.on("/authenticate", HTTP_POST, onSetCredentials);
  server.begin();

  performWifiConnect(ssid, password);
  WiFi.waitForConnectResult(CONNECTION_TIMEOUT);
```
You've already set `ssid` and `password` to be null, and server.begin() won't run the server yet (I'll get to that issue in a minute), so this is setting your credentials to be null at the start of the program. There's no point in running `waitForConnectResult()` then, because there is nothing to connect. There may be logic in setting `performWifiConnect()` though, since if you've ever set the Wi-Fi credentials with `wifi.begin()` *before* turning off persistent, those credentials are still remembered (it just won't remember new ones).

The next issue is that you're only handling server requests while the connection *is not invalid*. Thus, when there is an invalid credential for the network, the server doesn't run, and you don't get a response.

```
void loop() {
  if (state == STATE_DEFAULT) {
    server.handleClient();
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("Connected!");
    }
  }

  else if (state == STATE_CREDS) {
    whileConnecting();
  }

  delay(DELAY);
}
```
As you can see, `server.handleclient()` (the actual server; the ability to respond to requests) is only running while it does not have `state == STATE_DEFAULT`. *That* is then changed, `state = STATE_CREDS;`, during the callback for getting network credentials. You'll probably get a reply from the request handler that's currently running, but this will otherwise cause you problems since the server then never responds to any future requests. You **must** continually call `server.handleclient()` or nothing server-related will work.

But, something else is also wrong. You can only pass replies back from the server if you actually send them *while the server is still processing a request.*
```
else {
    Serial.println("Switching from " + String(ssid) + " to " + String(ssidNew));
    state = STATE_CREDS;
    performWifiConnect(ssidNew, passNew);
    startingMillisConnection = millis();
  }
```
As you can see, there is no `server.send()` in this branch, so you'll get no reply. This is likely the most immediate cause of your problem with an empty response.

Instead, you have that in the function `whileConnecting()`. As noted earlier, the server cannot send replies that aren't in the function it calls when it gets a request, or in functions called by that function. The server does not call `whileConnecting()`, `loop()` does. So it can't see or send that reply.

(Side note: This requirement of the server is implemented pretty weirdly, since you're calling server methods while one of its methods calls your code, only for the server to then ask itself what you told it while it was busy with your request, grab that buffer, and return it to the client. But it **only** does that check somewhere inside `server.handleClient()`, and other `send()` calls will either be ignored or get queued to send the next time the client makes a request.)

If you were to wait for a connection inside the server's request handler instead, and then send the error/success messages there too, this might work. It's still bad practice since the server (that part I said you always want to **not** hold up) and the entire rest of your code will be on hold while it waits to connect, but you'll *probably* have it work **as long as there's nothing else time-critical or important going on**.

The best approach would be to have your client poll a second address (or just the same address with no POST values, then have the server check whether there are no args) and have that say whether it is currently connected.

On that note, your connection checking code also has a problem. `loop()` has a delay in it, which is already going to bog things down. But you also have the whileConnecting function check for elapsed time. This *is* the proper way to coordinate multiple independent check-back-and-do-stuff operations, so you're aware of it, but this hasn't been transferred to the rest of the code.

Except, **also** in whileConnecting, you then call `WiFi.waitForConnectResult(CONNECTION_TIMEOUT);`. This will **block** that function until a result is present, which thus halts everything else for however long that timeout is. The only place you "should" use this (again, probably bad practice) is inside the server if you were trying to have it directly reply with the connection status **or** if there's not anything else important going on (which there is, so this is an issue). Since you're already running code periodically on a timer, just have this code check for the timeout directly (easiest method: call the connect function with the credentials, set the check-back time by `timeout`, then check again), and just reconnect then instead of forcing a wait. This will leave the server and the rest of your code responsive.

Now, with all (well, most) of that put together:
(NOTE: This code will need some changes made to the rest of your code, and may require adjustment itself, but it should get you very close. I suggest making a backup copy of your code first in case you need to reference or fix something. I also wrote this in a text editor, as I don't currently have access to the IDE to test this. There might be minor errors.)

Solution A (have the server wait and tell you the results):
(NOTE: also, delete `whileConnecting()` and all the `state` if you use this method; you want to make sure server.handleClient() is always being called until the connection is actually successful, or just plain always.)
```
void onSetCredentials() {
  Serial.println("onSetCredentials");

  server.arg("ssid").toCharArray(ssidNew, 64);
  server.arg("password").toCharArray(passNew, 64);

  if (String(ssidNew) == String(ssid) && WiFi.status() == WL_CONNECTED) {
    Serial.println("Already connected to " + String(ssidNew));
    server.send(200, "application/json", "{ \"success\": true, \"changed\": false }");
  } else {
    Serial.println("Switching from " + String(ssid) + " to " + String(ssidNew));
    performWifiConnect(ssidNew, passNew);
    startingMillisConnection = millis();
    //code to detect the server connection status and respond starts here//
    WiFi.waitForConnectResult(CONNECTION_TIMEOUT);
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("Connected to " + String(ssidNew) + " successfully!");

      strcpy(ssid, ssidNew);
      strcpy(password, passNew);

      server.send(200, "application/json", "{ \"success\": true, \"changed\": true }");
    }

    // Failure
    if (currentMillis - startingMillisConnection >= CONNECTION_TIMEOUT) {
      Serial.println("connection failed, attempting to reconnect to old network!");
      Serial.println("ssidOld: " + String(ssid));
      Serial.println("passOld: " + String(password));

      String errorMessage = "Timed out while attempting to connect to " + String(ssidNew);
      Serial.println(errorMessage);
      server.send(500, "application/json", "{\"errorMessage\":\"" + errorMessage + "\"}");
    }
  }
}
```
This solution (A) will *probably* give you the connection status back, assuming the Wi-Fi connection attempt times out before the cURL request/server does. I haven't actually tested this and I did mention it's kinda bad practice.

Solution B (Poll the server for connection status rather than waiting for a reply):
(Note: Again, delete any `state` logic and `whileConnecting()` from the other code.)
```
void onSetCredentials() {
  Serial.println("onSetCredentials");
  if (!server.hasArg("ssid")){ //check for no-arg request and return conn status//
    server.send("200", "text/plain", (WiFi.status() != WL_CONNECTED)? "Connected" : "Not Connected"); //or whatever other message(s) you want
    //You may also want to add some sort of Serial.print()-type logging here too, since I didn't.//
  }
  else{ //existing connection setup request handler resumes here//
    server.arg("ssid").toCharArray(ssidNew, 64);
    server.arg("password").toCharArray(passNew, 64);

    if (String(ssidNew) == String(ssid) && WiFi.status() == WL_CONNECTED) {
      Serial.println("Already connected to " + String(ssidNew));
    } else {
      Serial.println("Switching from " + String(ssid) + " to " + String(ssidNew));
      performWifiConnect(ssidNew, passNew);
      startingMillisConnection = millis();
    }
  }
}
```

With Solution B, you can call the cURL command to the ESP8266 *without* the `ssid` and `password` set, and you'll get a connection status back instead. This may take a few attempts while it's still in the process of connecting, but if it *remains* not connected, you know the credentials are wrong.


message:
Can a three wire Electrical conductivity sensor (Sensorex CS 150) be used directly with arduino?

I am having an electrical conductivity sensor (Sensorex CS150 with three tinned wires Red, Black and white <https://sensorex.com/product/sensorex-cs150-12-mm-graphite-contacting-conductivity-sensor/> ). I want to measure EC of nutrient soultion used in aquaponics. I have searched on internet for connection setup and everywhere sensor (with BNC connector) is connected to arduino via expansion board. Do I require this type of expansion board or can I directly connect sensor to analog pin of arduino.

body:
[Product Manual][1]

  [1]: https://sensorex.com/wp-content/uploads/2021/09/CS150-Instructions.pdf
Seem to be a simple conductivity measurement so applying a voltage direct from the Arduino via a suitable resistor and using an analog input to measure the voltage drop should work OK. You may need to experiment with the resistor value to get a good range of readings depending on the conductivity of the solution you are measuring


body:
EC electrodes is an active sensor that requires an excitation voltage to be applied to get the result. When A DC voltage is apply to the two conductors, it caused iron to be flow from one conductor to another, causing polarisation and chemical reaction. Therefore you can't use it directly with Arduino.

To measure EC you need a Wien bridge oscillator which is used to generate an alternative current(AC) waveform for the excitation of the EC electrode. In order to avoid polarization, an alternative current (AC) typically ranging from 1kHz to 20kHz is used to provide the exitation of the electrode. The AC current is read and converted back to a DC voltage as the measurement result.

You also need a precision amplifier in order to get a meaningful measurement.

The EC value is also subject to temperature changes, so it may also requires to measure the temperature of the liquid and adjust the result for temperature compensation.

I have an [product review article](https://www.e-tinkers.com/2020/07/a-review-on-seeed-studio-ph-and-ec-sensor-kits-part-2/) where it describe how EC measurement works and what is required (both hardware and software) to measure EC, you might want to further read to understand more.

Other reference:

[Conductive of a solution - Andy Connelly](https://andyjconnelly.wordpress.com/2017/07/14/conductivity-of-a-solution/).

[Conductivity Measurement Theory Guide - ](https://www.mt.com/us/en/home/library/guides/lab-analytical-instruments/Conductivity-Measurement-Theory-Guide.html).

[One-chip conductivity meter monitors salt concentration - Michael Ahmon Electronics/Sept 15, 1977](https://www.e-tinkers.com/wp-content/uploads/2020/07/one-chip_conductivity_meter_by_Michael_Ahmon_Sept_1977_Electronics.pdf).


message:
Why am I receiving this Error: Debug exception reason: Stack canary watchpoint triggered (task1) in ESP32 using a FreeRTOS program?

I'm getting this error by running a FreeRTOS program on my ESP32 using arduino ide, I don't understand why this happens because this same program works on an arduino Uno with no errors:
```
Guru Meditation Error: Core  0 panic'ed (Unhandled debug exception).
Debug exception reason: Stack canary watchpoint triggered (task1)
Core  0 register dump:
PC      : 0x40088a4f  PS      : 0x00060636  A0      : 0x800d3155  A1      : 0x3ffb9130
A2      : 0x3ffb8eb4  A3      : 0xffffffff  A4      : 0x00060620  A5      : 0x00060623
A6      : 0x00060623  A7      : 0x00000001  A8      : 0x00000001  A9      : 0x00000000
A10     : 0x00060623  A11     : 0x00000000  A12     : 0x00000000  A13     : 0x00000000
A14     : 0x007bee88  A15     : 0x003fffff  SAR     : 0x00000000  EXCCAUSE: 0x00000001
EXCVADDR: 0x00000000  LBEG    : 0x00000000  LEND    : 0x00000000  LCOUNT  : 0x00000000
```

This is the code I'm using:

```
//#include <Arduino_FreeRTOS.h>
//Overload happens if xTaskGetTickCount – lastTickCount (the first parm to vTaskDelayUntil) is >= period in ticks

void task1(void *pvParameters);
void task2(void *pvParameters);
void task3(void *pvParameters);

void setup() {

  Serial.begin(115200);

  //Create tasks
//xTaskCreate(Task function, Task name, , Task parameter, Task priority, );
  Serial.println("111111");
  xTaskCreate(task1, "task1", 512, NULL, 1, NULL);
  Serial.println("222222");
  xTaskCreate(task2, "task2", 512, NULL, 2, NULL);
  xTaskCreate(task3, "task3", 512, NULL, 3, NULL);
  //vTaskStartScheduler();

}

void loop() {}

void task1(void *pvParameters) {

  (void) pvParameters;
  TickType_t waketime, period = 1000 / portTICK_PERIOD_MS;

  waketime = xTaskGetTickCount();

  while(1){

    Serial.println('M'); //This happens almost immediately, so we need to add an artificial delay, a  to simulate a task running for a few ms, it only serves as a notification that the task started
    vTaskDelay(10);
    if(xTaskGetTickCount() - waketime >= period)
      Serial.println("Overload in task 1");

    vTaskDelayUntil(&waketime, period);

  }

}

void task2(void *pvParameters) {

  (void) pvParameters;
  TickType_t waketime, period = 1000 / portTICK_PERIOD_MS;

  waketime = xTaskGetTickCount();

  while(1) {

    Serial.println('E'); //This happens almost immediately, so we need to add an artificial delay, a  to simulate a task running for a few ms, it only serves as a notification that the task started
    vTaskDelay(10);
    if(xTaskGetTickCount() - waketime >= period) Serial.println("Overload in task 2");
    vTaskDelayUntil(&waketime, period);

  }

}

void task3(void *pvParameters) {

  (void) pvParameters;
  TickType_t waketime, period = 1000 / portTICK_PERIOD_MS;

  waketime = xTaskGetTickCount();

  while(1) {

    Serial.println('S'); //This happens almost immediately, so we need to add an artificial delay, a  to simulate a task running for a few ms, it only serves as a notification that the task started
    vTaskDelay(10);
    if(xTaskGetTickCount() - waketime >= period) Serial.println("Overload in task 3");
    vTaskDelayUntil(&waketime, period);

  }

}
```

I tried increasing the task stack memory in xtaskcreate and the same error occurs, although when I increased it to 1024 nothing shows up in the serial monitor. This same program works flawlessly on arduino uno and raspberry pi pico. I also tried changing the tasks' period and their execution time, which is the delay, and it still doesn't work

body:
> although when I increased it to 1024 nothing shows up in the serial monitor.

Doing nothing to your code except using 4096 for stack size causes it to print things on serial.

```txt
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13864
load:0x40080400,len:3608
entry 0x400805f0
111111
222222M

E
S
S
E
M
S
ME
```

I won't tell you that it's correct, but it seems fairly clear that you haven't given it enough stack to work with.

With my current setup
```c++
Serial.println(configMINIMAL_STACK_SIZE);
```
is printing 828. I don't know how exactly how to interpret that number. But unless I found otherwise, I could default to considering it the requirement to start a task that uses no stack of it own (no local variables, no calling). The memories of the esp32 seem large enough that no matter how you're using them it doesn't make sense to go so minimal for a handful to tasks. I chose 4096 somewhat arbitrarily. I'm not suggesting is a good value.


message:
Pls help with this prompt. I've been struggling last 2 days with this and its due tomorrow

"Use an Arduino, two potentiometers, and an alarm. Make one of the potentiometers act like a volume control, and make the other potentiometer control the tone that the alarm makes."
I added what I have so far. I'm not sure how to control the volume

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

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

body: Use the other potentiometer as a variable resistor. Instead of connecting to pins 1 and 3 (to control tone), Use the 2nd pin of the potentiometer to make a voltage divider. From the 3rd pin go to a + on a buzzer. I don't see the reason to have the circuit connected the way you have. if you want to control the tone with potentiometer, connect it to stable 5v, and connect the second pin with any analog pins that is configured as input. Then, use map function, and map the voltage, accordingly to the tone you'd like to use.


message:
Arduino 75kHz output frequency setup

i don't know how to manipulate arduino uno or mega registers and timers to be close to 75kHz output frequency. Could you help please ?

body:
First you have to compute, from your desired frequency, the number of
CPU cycles per period of the signal:

F\_CPU / 75 kHz = 16,000 kHz / 75 kHz ≈ 213.33

Since the timers can only count up to an integer, the closest you can
get is 213 CPU cycles. The frequency you get will then be

F\_CPU / 213 = 16,000 kHz / 213 ≈ 75.12 kHz

Now you can configure a timer. I find that the easiest is to use a so
called “fast PWM” mode. Choose one of those modes where the TOP value
can be set with a register, and set it to one unit less than the desired
period: the timer will then repeatedly count from 0 to 212.

Here is an example using channel A of Timer 1 on an Arduino Uno.
The output is on digital pin 9 = OC1A = PB1:

```c++
// Configure Timer 1 for PWM @ 75.12 kHz.
DDRB  |= PB1;         // set OC1A = PB1 as output
TCCR1A = 0;           // clear the settings of the Arduino core
TCCR1B = 0;           // ...ditto
TCNT1  = 0;           // clear the timer
TCCR1A = _BV(COM1A1)  // non-inverting PWM on OC1A
       | _BV(WGM11);  // mode 14: fast PWM, TOP = ICR1
TCCR1B = _BV(WGM12)   // ...ditto
       | _BV(WGM13)   // ...ditto
       | _BV(CS10);   // clock at F_CPU
ICR1   = 213 - 1;     // period = 213 CPU cycles = 13.3125 us
OCR1A  = 213/2 - 1;   // duty cycle ~ 50%
```

You can easily adapt this to any timer on the Uno or Mega. Just avoid
Timer 0 if you are going to use the Arduino timekeeping functions.


body:
I think the answer given by Edgar Bonet is the right one, all things considered, and I up-voted it for that reason.

For S&G, I want to add the following:

1. The **easiest** way is to simply use the tone(GPIO,Frequency); command - and there are caveats. **BUT**, the frequency argument is an unsigned int so the fastest frequency is 65535Hz - it will do you no good for 75kHz.

Using a frequency counter and an UNO (crystal), tone(10,65535); the output was 65556/8 Hz. On a Pro Mini 5V (ceramic resonator as I recall), it was 65540 Hz.

2. Again, for S&G, I tried this code (and adjusted the number of NOPs) to get as close as I could to 75kHz:

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

    void loop() {
    here:
      digitalWrite(10, HIGH);
      delayMicroseconds(3);
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      digitalWrite(10, LOW);
      delayMicroseconds(3);
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      __asm__("nop\n\t");
      goto here;
    }

The output on the UNO was 75004/6 Hz  - not too bad. On the Pro Mini, the best I could do was 74986 Hz.

Of course, we are talking about square waves.


message:
4x3 keypad not providing any output and the output it does provide is incorrect

I am trying to figure out how to use a 4x3 keypad and just want to receive the key numbers I select on the serial monitor. The problem I am getting is that some of the keys I type don't give me any output and then the keys that do provide output do not match their corresponding number. For example key 1 does not provide any output, whereas keys 3 and 4 give an output of 4 and 9 respectively. I have attached pictures of how the keypad is connected [![Wiring that I used to connect the pins][1]][1] [![Close up of the pins][2]][2] [![wire diagram][3]][3]

The code that I am using is below:

    #include <Keypad.h>

    // Constants for row and column sizes
    const byte ROWS = 4;
    const byte COLS = 3;

    // Array to represent keys on keypad
    char hexaKeys[ROWS][COLS] = {
      {'1', '2', '3'},
      {'4', '5', '6'},
      {'7', '8', '9'},
      {'*', '0', '#'}
    };

    // Connections to Arduino
    byte rowPins[ROWS] = {9, 8, 7, 6};
    byte colPins[COLS] = {5, 4, 3};

    // Create keypad object
    Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

    void setup() {
      // Setup serial monitor
      Serial.begin(9600);
    }

    void loop() {
      // Get key value if pressed
      char customKey = customKeypad.getKey();

      if (customKey) {
        // Print key value to serial monitor
        Serial.println(customKey);}
    }

I just need help identifying where I am going wrong and how I can fix the problem I am having. Thanks.

  [1]: https://i.stack.imgur.com/y70Yl.jpg
  [2]: https://i.stack.imgur.com/6OTz0.jpg
  [3]: https://i.stack.imgur.com/awCP5.jpg

body:
I determined where I was going wrong. The keypad has a different wiring compared to the traditional way of doing it. I found this [this][1] article helpful. The changes made to the code are as follows:

    byte rowPins[ROWS] = {8, 3, 4, 6};
    byte colPins[COLS] = {7, 9, 5};

As can be seen, the rows and columns pins need to be changed.

[![Diagram showing what connections are for rows and which ones are for columns][2]][2]

  [1]: https://electropeak.com/learn/interfacing-4x3-membrane-matrix-keypad-with-arduino/
  [2]: https://i.stack.imgur.com/GoWUr.jpg


message:
Interrupt on button press + debouncing

I want to have an interrupt function executed whenever a button is pressed.
The button is connected to `pin 2` and the `GND`. Therefore, the pin is turned to `LOW` whenever the button is pressed. In addition to that, proper debouncing should be used
As a proof of concept, the interrupt function should just toggle the `BUILTIN_LED` whenever the button is pressed.

I have tried many different approaches but i cannot make it work.

This is my last iteration:

    bool led_status = LOW; // current state of output pin
    int buttonState; // the current reading from the input pin
    int lastButtonState = HIGH;  //the previous reading from the input pin

    // the following variables are unsigned longs because the time, measured in
    // milliseconds, will quickly become a bigger number than can be stored in an int.
    unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
    unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

    int button_switch = 2; // external interrupt pin
    bool initialisation_complete = false; // inhibit any interrupts until initialisation is complete

    // ISR for handling interrupt triggers arising from associated button switch
    // check to see if you just pressed the button
    // (i.e. the input went from LOW to HIGH), and you've waited long enough
    // since the last press to ignore any noise:
    void button_interrupt_handler()
    {
      //static long int elapse_timer;

      if (initialisation_complete == true) //only able to run the ISR when arduino has finished initialization
      {
        // new interrupt so okay start a new button read process -
        // now need to wait for button release plus debounce period to elapse
        // this will be done in the button_read function

        int reading = digitalRead(button_switch);
        if ( reading != lastButtonState) // If the switch changed, due to noise or pressing:
        {
          lastDebounceTime = millis(); // reset the debouncing timer
        }

        // whatever the reading is at, it's been there for longer than the debounce
        // delay, so take it as the actual current state:
        if ( (millis() - lastDebounceTime) > debounceDelay)
        {
          if (reading != buttonState) // if the button state has changed:
          {
            buttonState = reading;
            if (buttonState == HIGH) // only toggle the LED if the new button state is HIGH
            {
              led_status = !led_status;
            }
          }
        }
        digitalWrite(LED_BUILTIN, led_status); //set the LED
        lastButtonState = reading; // save the reading. Next time through the loop, it'll be the lastButtonState:
      }
    } // end of button_interrupt_handler

    void setup()
    {
      pinMode(LED_BUILTIN, OUTPUT);
      pinMode(button_switch, INPUT_PULLUP); //no res = change to INPUT_PULLUP
      attachInterrupt(digitalPinToInterrupt(button_switch), button_interrupt_handler, FALLING); //no res = change to FALLING
      digitalWrite(LED_BUILTIN, led_status);
      initialisation_complete = true; // open interrupt processing for business
    }

    void loop()
    {
      //do nothing
    }

I am not sure what I am doing wrong or why this does not work.

EDIT: When I press the button, nothing happens at all.

body:
In almost any run of the ISR it will read the button state as LOW, because the ISR is triggered by the falling edge. The time from the falling edge to the reading is very short, about microseconds, and therefore a level change is improbable.

As others already suggest, you can make the ISR "deaf" for some time after the accepted falling edge. You _can_ do this inside the ISR. The approach is to accept subsequent triggers only if they are long enough after the former one.

Please be aware that some buttons bounce even when released. You might experience a trigger in such cases.

Anyway, do not base a decision on the reading of button state after its falling edge.

---

The most simple solution to read buttons is a cyclic timer with a period of several milliseconds. Take a sample each 50ms or so, and detect the button change in software. You don't even need to add debouncing code, if the period is longer than the bouncing time of your button.

Since this timer will commonly trigger an ISR, you have already an interrupt as source of the button state for other parts of your software.

If you want an extra interrupt, trigger some unused interrupt in software.


body:
Here is a non-blocking debouncing solution which is suitable also for electrically noisy environments. For example where there are long wires to the buttons which could pick up spurious signals. In this case, you cannot rely on short pulses being the direct result of button activity and must check that the button state has been stable for X ms before accepting it. It also handles potential bounces on the release of the button. It uses a simple finite state machine approach and does not use interrupts.

It can be tried also in a simulator: https://wokwi.com/projects/351021820324872788

```

const uint8_t ledPin = 13 ;
const uint8_t button_switch = 2;  // the button is wired between this pin and ground (LOW side)
const unsigned long debounceDelay = 100 ;    // the debounce time; increase if the output flickers

enum ButtonState  { PENDING_PRESS, IN_PRESS, PENDING_RELEASE} ;
ButtonState buttonState = ButtonState::PENDING_PRESS ;
uint32_t stateEnteredAtMs = millis() ;

void setup() {
  Serial.begin(115200);
  pinMode( ledPin, OUTPUT) ;
  pinMode( button_switch, INPUT_PULLUP) ;

}

void loop() {
  uint32_t ms = millis() ;
  static uint32_t lastButtonCheckAtMs = 0 ;

  if( ms - lastButtonCheckAtMs > 10 ) {

    switch ( buttonState ) {

     case ButtonState::PENDING_PRESS : {
        if ( digitalRead(button_switch)  == LOW ) {
          buttonState = ButtonState::IN_PRESS ;
          stateEnteredAtMs = ms ;
        }
        break ;
     }

     case ButtonState::IN_PRESS : {
        if ( digitalRead(button_switch) == HIGH )  {
          if ( ms - stateEnteredAtMs < debounceDelay ) {
            stateEnteredAtMs = ms ;
            buttonState = ButtonState::PENDING_PRESS ;
          }
          else {
            stateEnteredAtMs = ms ;
            buttonState = ButtonState::PENDING_RELEASE ;
            digitalWrite( ledPin, ! digitalRead(ledPin)) ;  // toggle led
          }
        }
        break ;
     }

     case ButtonState::PENDING_RELEASE : {
        if ( ms - stateEnteredAtMs > debounceDelay ) {
            stateEnteredAtMs = ms ;
            buttonState = ButtonState::PENDING_PRESS ;
          }
        break ;
     }
    }
    lastButtonCheckAtMs = ms ;
  }
}

```


body:
Take a look at this line in your code - the very first thing that is done in the ISR,

*int reading = digitalRead(button_switch);*

I think that the reason that your program does not “do anything” is because you are reading the button state inside the ISR and, because you trigger an interrupt on a falling edge, you will ALWAYS see 0 as the button state at that point. It can never change when you read it once at the beginning of the ISR, it will always =0, unless you stay in the ISR and wait for a change, which is a very, very, bad idea.

The rest of your comparisons and detections all fail because within the ISR, the button read is always going to be the same and = 0, because that is how you got to the ISR. As far as your program is concerned, the button has never been pressed or depressed.

It is true, depending on how you configure the button; a single state change will be detected because of initialization, but that is besides the point.

You can test this yourself by moving all of your variables to volatile globals and then in your loop run this:

    void loop()
    {
    Serial.print("lastButtonState ");
    Serial.println(lastButtonState);
    Serial.print("buttonState ");
    Serial.println(buttonState);
    Serial.print("reading ");
    Serial.println(reading);
    }

You may have other problems, but that one stuck out to me.

I would suggest that you take a look at this project and see how he is doing it - https://create.arduino.cc/projecthub/ronbentley1/button-switch-using-an-external-interrupt-7879df

He does read the switch within the interrupt [I don't see why he needs to test the value since in his case it will always be HIGH]. The difference is that he uses the ISR only as a trigger. The rest of the reading of the switch to detect when there are state changes, is all done outside of the ISR.

Additionally, once an interrupt occurs, a triggered status is set and, thereafter the ISR just leaves until the status is changed to "not triggered" and that is done outside of the ISR. The accompanying article explains what he is doing in the code and why.

You are doing, literally nothing [after setup()] outside of the ISR and I think maybe you should re-think that approach.

I tested his program and it works fine. I note that he functionally defines a "press" as pressing and releasing the button (with associated debouncing). So, you don't see the led toggle until you press and release the button. That's not always how I would like it, but it is also besides the point.

Two other points...

Keep your ISR as short as you can. I don't have any hard core evidence, but, right or wrong, yours looks longer than I would be comfortable with.

Finally, I think you would enjoy this excellent thread on millis() inside an ISR. https://arduino.stackexchange.com/questions/22212/using-millis-and-micros-inside-an-interrupt-routine

To be sure, you are NOT using delays inside an ISR and there is nothing wrong with using millis() inside an ISR, but you need to be aware of the behavior.

That's my two cents - hope it helps.


message:
Analog Microphone values not changing

I just bought a microphone for my Ardoino Nano 33 BLE. The mic can use both Analog and Digital input. Here is the mic and how it's connected. [![Mic and connection][1]][1]

Here is the code where I read the input

    int sensorPin = A5; // select the input pin for the potentiometer
    int sensorValue = 0;
    void setup ()
    {
     Serial.begin (9600);
    }
    void loop ()
    {
     sensorValue = analogRead (sensorPin);
     delay (500);
     Serial.println (sensorValue, DEC);
    }

I've followed an example by the manufacturer and the reads are going random between 0 and 5 sometimes a little higher. It states in the example that it should go up to 1023.

Is something wrong, can I have connected something wrong that would make this? Also when I give 5v nothing happens on the Mic but if I connect 3.3v the mic turns on 2 red led lights and gives me a value around 80 but doesnt respond to any sounds.

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

body:
/* edited to specifically provide a potential solution as commented by @jstola */

You have posted a picture of a ubiquitous sound detection sensor - typically a Keyes KY-037.

It is based on an LM393 dual comparator.
[![LM393][1]][1]

The board has a digital output [marked DO] and **an analog output marked AO**. It also has + and G (Ground) connections.
[![keyes sound board][2]][2]

I dug mine out and attached it to a Nano 33 BLT.

[![Nano 33 BLT with sound sensor][3]][3]

Notice that I have + connected to 3.3v, G connected to ground and AO connected to A5.

A little trick is to connect just power and ground and turn the potentiometer until L2 (that's the LED nearest the pot) turns off. If you make some noise, you will see L2 flash briefly. This sets the digital output threshold and works well for testing the analog out.

Then I ran this simple program (very similar to yours)

    void setup() {
      pinMode(A5,INPUT); // not absolutely needed in this case
      Serial.begin(9600);
    }
    void loop() {
      Serial.println(analogRead(A5));
    }

Opened the Arduino IDE serial plotter (shift+ctr+L) and watched the waveform change when I snapped my fingers - see the spikes?.

[![serial plotter waveform][4]][4]

So what is the solution to your problem that is does not work?

A couple of possibilities.

1. You have a different board.

Does your board look just like the one I posted or does it look different? If it is a different board then what you posted, that is another matter.

Assuming it is the same board (or at least the same generic board), it is possible that:

2. You don't have the connections correct. Double check that.

3. You don't have the pot set near the mid point - follow the direction for that and observe that the LED can be turned off. That is a multi-turn pot and if you hear a little 'click', you went too far in that direction - move it the other way and see if you can get that LED to just turn off.

4. Failing any of those, your board could be toast

  [1]: https://i.stack.imgur.com/FMnAD.jpg
  [2]: https://i.stack.imgur.com/9aZL4.jpg
  [3]: https://i.stack.imgur.com/a4ySM.jpg
  [4]: https://i.stack.imgur.com/dR86t.jpg


body:
Welcome! This is generic in nature because you did not provide any links to the hardware items so everything is a pure SWAG.

I cannot properly answer your question without knowing what board you have, there are several that look similar in red and other colors. Maybe the following will help you determine what you have. Look at the specifications closely.

Your statement "The mic can use both Analog and Digital input." The mic is analog by nature but can be converted to a digital signal with an op-amp  or comparator circuit as many of these modules have done.

 It appears to me that your board will give you a logic 1 or zero, not an analog output. The pot on those generally sets the reference voltage for the comparator (may be an op amp) function, If it is a dual op amp the other half is an amp for the microphone. If there is an analog output the microphone signal needs to be amplified as the microphone output is only a few millivolts and the A/D needs volts.


message:
ESP8266 Wemos D1 Mini Pro v2.0 - Load sharing and battery

I have a simple question regarding the new version of **Wemos D1 Mini Pro v2.0** and specifically about its load sharing circuitry. Schematic is here :

https://www.wemos.cc/en/latest/_static/files/sch_d1_mini_pro_v2.0.0.pdf

Battery charger is TP4054 and there's a load sharing configuration based on P-MOSFET CJ2301.

My question is what happens if you do NOT connect any battery.

It seems that the charging LED faintly flashes, and positive voltage appears in positive battery terminal. Moreover, voltage appears in A0 and ADC input (provided that SJ1 is connected), while someone would expect a zero voltage there, since there's no battery.

Am I missing something here? Is there any way to fix this issue?

body:
I have test it and you are right. When you plug power into the USB connector with no battery connected to the Wemos D1 mini Pro v2.0.0 (provided BAT-A0 is connected) and I have got 1023, the maximum read into A0, when it should be 0.

I think a related problem is that when you are running with battery and you connect a charger into the USB port you can *not* read the battery voltage, you are getting always 1023, like if the battery was fully charged. So, you can use A0 to monitor battery voltage when discharging, but not when charging.


message:
A few Bitshifting questions!

So ```int``` in Arduino is 2 bytes, which could technically hold up to a value of 65535. However, the MSB is used as a sign bit, so now we have -32,768 to 32,767. So it's a *signed integer*, easy stuff. While I was messing around with bitshifting I ran across something interesting. If I do the following code:

    int a = 1023 << 6;  // 1023 = 0b0000001111111111
    Serial.println(a, BIN);

it returns a ridiculous number, 11111111111111111111111111000000, which is 4 bytes. I know this is some error with bit shifting into the signed bit, because if I do

    int a = 1023 << 5;  // equals 111111111100000 as expected

It works just fine. **Question 1:** What is happening here? Where is that number coming from?

So I got smart (so I thought) and was like okay, if I need more bytes, then I'll just use ```long```. So I tried the following code:

    long a = 1023 << 6;
    Serial.println(a, BIN);

I figured I'd have 3 "extra" bytes to shift my number into. However, the same number is returned. **Question 2:** What is happening?

**Question 3:** What is the order of operations with bitshifting?

    Wire.write(CMD_VDR | PD_NPD | voltageLevel >> 6);
This code I wrote produces the correct result. However, what is the order of operations? Is it just left to right? Putting ```voltageLevel >> 6``` in parenthesis does not change the output. *It's working fine but I want to know why!*

Thanks!

body:
> So `int` in Arduino is 2 bytes

This is not true in the general case, for what it's worth. It is true of the AVR based Arduinos though, which I'll assume are in use below.

Strictly speaking, when you do `int a = 1023 << 6;` with a 16-bit integer, all bets are off, because you're already in undefined behaviour. 1023 is type `int` right hand side is expected to be of type `int` and trying to store something that won't actually fit in a signed integer is undefined.

But for the moment, lets just say it does roughly what you expect with the bit pattern, like it would for an unsigned type. You've produced the bit representation for a signed 16-bit integer with the value -64.

You're calling the `println(int, int)` [here][1].
It's in turn calling `println(long, int)` [here][2]. It is only handling `signed`ness for base 10. So, you are just forwarding your -64 value to `printNumber` [here][3], which handle `unsigned long` values (which may have been prefixed by `-` for base 10).

So you are converting a -64 into an `unsigned long`. Conversion to unsigned types reduce modulo their maximum value plus 1.  The 32-bit `unsigned long` maximum is 0xFFFFFFFF, with one added you get 0x100000000. In other words, you're ultimately printing 0x100000000 - 64, which is the number you're seeing.

`1023 << 5` does not overflow the 16-bit signed int. Does not result in a negative number (again if we're being charitable about undefined behavior) and so you see different result.

  [1]: https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/cores/arduino/Print.cpp#L77
  [2]: https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/cores/arduino/Print.cpp#L87-L101
  [3]: https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/cores/arduino/Print.cpp#L203


body:
timemage provided an excellent answer to your first question (upvoted!).
Let me try to answer the subsequent ones:

> ```c++
> long a = 1023 << 6;
> ```

Here you are evaluating `1023 << 6`, then assigning the result to a
`long`. It is important to realize that the C++ rules for evaluating an
expression do not depend on what you are going to do later with the
result. Given that `1023` is an `int` constant, the expression has the
type `int` and is evaluated as such. The result is then undefined
behavior, which just happens, because [you are unlucky][nayuki], to give
the expected value, i.e. −64.

Assigning −64 to a `long` converts the type while preserving the value.
This is [sign extension][] at work. As explained by timemage,
`println(long, int)` casts the value to `unsigned long`, hence the
result you see.

> What is the order of operations
> [in the expression `CMD_VDR | PD_NPD | voltageLevel >> 6`]?

The shift has higher precedence than the bitwise OR. The expression is
thus equivalent to

```c++
CMD_VDR | PD_NPD | (voltageLevel >> 6)
```

C.f. [C++ Operator Precedence][precedence].

[nayuki]: https://www.nayuki.io/page/undefined-behavior-in-c-and-cplusplus-programs
[sign extension]: https://en.wikipedia.org/wiki/Sign_extension
[precedence]: https://en.cppreference.com/w/cpp/language/operator_precedence


message:
Ramping servo motor taking longer than calculated

I'm learning how to code a "BOE Shield bot" with a partner at my university (first year). To clarify for those that do not know: a BOE Shield bot is a small robot equipped with 2 servo motors, a battery pack and an Arduino Uno. If you google the name you'll find plenty of pictures.

We were tasked to code a program that would make the robot accelerate the continuous rotational servo motors according to a given velocity-time graph in RPMs and seconds. We wrote the code, followed a pretty logical method, and passed the assignment. However one thing, and I spent days on trying to fix it, is still confusing me. The code is ahead, I've tried to make it as readible as possible. The RPM to PWM conversion for the motors is: <br/> PWM = 2 \times RPM + 1500

```
#include <Servo.h>

class motor {
public:
  double Speed = 0;  //The actual speed of the servo in RPM
public:
  Servo servo;

  //returns true if the desired speed "newSpeed" is reached, otherwise increments the current speed and returns false.
  //increment is the calculated speed increase based on the differance in time (interval) and the acceleration which is constant.
  bool accel(double increment, double newSpeed) {
    if (abs(Speed - newSpeed) < 0.1) {
      return true;
    }

    Speed += increment;
    return false;
  }

  void writeMS(double value) {
    servo.writeMicroseconds(value);
  }
};

motor servoLeft = motor();
motor servoRight = motor();

void setup() {
  Serial.begin(9600);
  servoLeft.servo.attach(11);   //vänster -2 * speedLeft + 1500
  servoRight.servo.attach(10);  //höger 2 * speedLeft + 1500
}

//This nested array contains instructions for both servo motors: the desired speed, how long it should take to accelerate to it and how long
//the instruction duration is. The first instruction starts from the second row. The first row is skipped and only used for calculations.
//The columns are in the following order: {instruction length in ms, speed of the left motor in RPM, speed of right motor in RPM, acceleration time}.
double instructions[7][4] = {
  { 0, 0, 0, 0 },
  { 3000, 25, 25, 500 },
  { 2550, 50, 10, 500 },
  { 3000, 25, 25, 500 },
  { 2850, 10, 50, 500 },
  { 3000, 25, 25, 500 },
  { 3000, 15, -15, 500 },
};

//time stuff
unsigned long currentMillis;
unsigned long previousMillis = 0;
unsigned long lastInstructionMillis = 0;
const double interval = 20;

//i is the index for the instructions.
int i = 0;
bool updateL = false;
bool updateR = false;

//the speed increments for each servo. Calculated in the loop.
double incrementL;
double incrementR;

void loop() {
  //This is to help keep track of the time so we can calculate the increments. It essentially means the speeds are only updated ever 20ms.
  currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    //if the desired speed is reached, stop updating. This is just to optimize code.
    if (updateL)
      updateL = !servoLeft.accel(incrementL, instructions[i][1]);

    if (updateR)
      updateR = !servoRight.accel(incrementR, instructions[i][2]);
  }

  //this runs only once after each instruction.
  if (currentMillis - lastInstructionMillis >= instructions[i][0]) {
    lastInstructionMillis += instructions[i][0];
    i++;

    //exit program after all instructions have been completed.
    if (i == 7)
      exit(0);

    //the increments are calculated like such: increment = acceleration * interval
    //where constant acceleration = (newSpeed - oldSpeed) / accelerationTime
    incrementL = (instructions[i][1] - instructions[i - 1][1]) * interval / instructions[i][3];
    incrementR = (instructions[i][2] - instructions[i - 1][2]) * interval / instructions[i][3];

    updateL = true;
    updateR = true;
  }

  Serial.println((String)servoLeft.Speed + " " + (String)servoRight.Speed + " " + (String)currentMillis + " " + (String)i);

  //the actual ms signlas sent to the servos.
  servoLeft.writeMS(2 * servoLeft.Speed + 1500);
  servoRight.writeMS(-2 * servoRight.Speed + 1500);
}
```
For some reason the acceleration is taking longer than specified in the instructions. For example, the first instruction specifies that both servos will accelerate from 0 to 25 RPM within 500ms. But printing out the speeds and time to the serial monitor shows that it actually takes around 860ms. That is if interval is set to 20. If it's set to 50, it takes 560ms.

Suspected causes were:

 1. **Void loop taking longer than the interval**

Not the case as measuring it with micros() proved it never took longer than 0.26ms; this was the done with complete program as well.

 2. **Rounding errors**

Not the case as switching pretty much all the number types to double still didn't fix anything. And double is more than enough precise for this program.

 3. **millis() not being accurate enough**

I don't believe this is the case. I researched how accurate it actually is, and while it's nowhere near perfect, it should be accurate enough for the program. I tried using micros() instead and that lead to the same result, I do not know if that means something.

Other than that I have no idea what the cause could be. The code itself runs fine, and the robot actually seems to be following the instructions perfectly with no errors. It's just that the speeds and accelerations aren't accurate for some reason.

body:
There are two things going on here.

You are printing too much to the serial port. After the first second
(between 1000 and 9999 ms), each line you print is 20 bytes, including
the CRLF terminator. At 9600 b/s, each bytes takes 1.04 ms (1 start bit,
8 data bites and 1 stop bit). This is about 20.8 ms for the whole line,
which is slightly longer than `interval`. You should either print less
often (say, every other loop iteration) or faster. Just moving to the
next standard speed (19200 b/s) will be enough to ensure you do not miss
any `interval`. You can go faster though.

The second issue is the way you keep track of `previousMillis`:

```c++
if (currentMillis - previousMillis >= interval) {
  previousMillis = currentMillis;
  // ...
}
```

This is prone to accumulating errors. The test will most likely not
happen exactly at `previousMillis + interval`, mostly because of the
serial port. You are a little bit late and, by updating `previousMillis`
this way, these errors are _cumulative_. You can avoid this by updating
`previousMillis` as:

```c++
previousMillis += interval;
```

You will still have timing errors, but these will manifest themselves in
the form of _jitter_, not as a systematic timing drift.

Interestingly, you are updating `lastInstructionMillis` the right way!

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

**Edit**: Here are some extra comments about your question and your
sketch, not necessarily related to the problem you are seeing.

You wrote:
> measuring [loop()] with micros() proved it never took longer than
> 0.26ms.

It seems you measured incorrectly. Maybe you measured a version of the
program that was not printing so much to the serial port. Or maybe you
looked only at the first iterations of the loop, where
`Serial.println()` is fast because the output buffer hasn't filled yet.

The following code is fragile:
> ```c++
> bool accel(double increment, double newSpeed) {
>   if (abs(Speed - newSpeed) < 0.1) {
>     return true;
>   }
>   // ...
> }
> ```

The value 0.1 is arbitrary, and the “right choice” is dependent on the
program timing. I suggest something more robust, like:

```c++
bool accel(double increment, double newSpeed) {
  if (increment > 0) {
    Speed = min(Speed + increment, newSpeed);
  } else {
    Speed = max(Speed + increment, newSpeed);
  }
  return Speed == newSpeed;
}
```

Note that, although it is generally recommended to not test floating
point numbers for exact equality, in this case it is safe, because
`min()` and `max()` return _exactly_ one of their arguments.

The optimization consisting of calling `motor::accel()` only during the
acceleration phase is futile: this methods takes an very tiny fraction
of the `loop()` time. In the same vein, there would be no harm in
calling `Servo::writeMicroseconds()` on every loop iteration, even if
some of the calls turn out to be useless.

The code would be more readable if `instructions` was an array of
`struct` rather than an array of arrays: this way the fields of each
instruction could have evocative names rather than numeric indices.

You are using too much floating point here. Most of the data fields,
including all the contents of `instructions`, could be integers of
suitable length.


message:
ATTiny85(Digispark) not connected/recognized

I have 1xDigispark(ATTiny85) from Amazon https://www.amazon.pl/gp/product/B076KS2QDS/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&th=1.

When i connect it into USB port nothing happen i didn't get windows sound alert.
And Arduino IDE not detecting it(Not displayed as a port).
[![Ports][1]][1]
I have this link to the drivers in settings and drivers installed.
When I try to upload a code with "COM1" port nothing relly happens.

Regards,
Wiktor Wołos

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

body:
You have the wrong board selected in your IDE

This
[![three digispark clones][1]][1]

Is a "Digispark (Default 16.5 mhz)" (sic) not a "Digispark Pro". The latter is based on an ATtiny167 not an ATtiny85.

I have bought the exact same item from the same seller.

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


message:
Sketch uses 33218 bytes (102%) of program storage space. Maximum is 32256 bytes?

I need to upload code on atmega328 wihout bootloader
<https://github.com/EasyOne2030/test>
but see Sketch uses 33218 bytes (102%) of program storage space. Maximum is 32256 bytes ?

body:
In the case where the size of the program (sketch) has become too large for the available program storage space (flash memory), there are a number of options. Note that this is not the same case as exceeding the amount of dynamic memory (RAM) which requires a different set of solutions.

**_1. Microcontroller (MCU) upgrade.**

This can be a solution. The closer
    the architecture of the new MCU matches that that of the old MCU the
    easier this is likely to be. However, this approach can become
    complex, even when using a different MCU in the same series as the
    original, if low level configuration of (and access to) hardware
    peripherals such as timers, ports etc. has been used. Be aware that
    any libraries used may not be compatible with the new MCU so testing
    is important. In the worst case, there may be no supporting Arduino
    core available for the new MCU. Major incompatibilities can be
    tested with a simple compilation of a sketch for the new target MCU
    and this does not even require the new MCU to be present.

In the
    specific case of the ATmega328P, this is already the highest
    specified MCU in its series so a new MCU is required to increase
    resources such as Flash memory, RAM etc. An ATMega1284 may be a
    possible replacement within the AVR range. Also to consider is an
    ATmega4809 (newer megaAVR range) based board such as the Nano Every
    but here there are more significant architectural differences

**_2. Optimising the use of flash memory.**

**_2.1 Bootloader.**

Sometimes, changing the bootloader for a smaller one can help. For example, with some Arduino Nanos, this can free 1.5KB of flash memory by changing to the same bootloader which is used on the Arduino Uno (Optiboot). Dropping the bootloader altogether and using an ISP programmer (or an Arduino configured as one) to program the MCU can also save flash memory. Here it is important to select an Arduino core which supports a "No Bootloader" option to achieve the maximum benefits from this approach. The core "Minicore" https://github.com/MCUdude/MiniCore is such an example. Important to note is the the Arduino IDE (base 1.8.19) has a special upload procedure when using a programmer (Sketch--> Upload using programmer).
Note also that the target (AVR) MCU must have the fuses correctly set for "no bootloader" operation. That is the fuse BOOTRST must be unset. This is achieved by using the "burn bootloader" option supplied by the core. Despite its (inappropriate) name this has the effect of setting the fuses. Alternatively, the fuses can be set manually using the AVRDUDE command line.

**_2.2 General.**

The compiler is quite good at optimising code however, it is important to be aware that the use of some program features can have a one time penalty when used. Examples are the String class, sprintf(), floating point handling etc. which force a large amount of code to be added to the compiled sketch. Some libraries can consume a large amount of program memory. Graphic libraries are notorious for this because often these include large font tables etc. Here the options are limited to looking for a lighter weight library or a hacking out unused parts of an existing library.


body:
**Using Minicore  to compile and load a program onto an ATmega328P without a bootloader. Screen shots and sample output.**

Resources used
1. CH340 ATmega328P Arduino Nano clone
2. A programmer (Nano based) running the Arduino ISP sketch
3. Minicore 2.1.3   https://github.com/MCUdude/MiniCore
4. Arduino IDE 1.8.19

```
/*
   Example sketch to use all flash memory of an ATmega328P
*/

const uint8_t bigArray[30121] PROGMEM = {0} ;

void setup() {
  Serial.begin( 115200 ) ;
  Serial.println("test-01" ) ;
  byte buffer = pgm_read_byte_near(bigArray+50); // stop compiler optimising the array away
  Serial.println(buffer ) ;
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}
```

**Select Board**
[![Select Board][1]][1]

**Select Programmer**
[![Select Programmer][2]][2]

**Select No Bootloader**
[![Select No Bootloader][3]][3]

**Verify**
[![Verify][4]][4]

**Burn Bootloader /set fuses**
[![Burn Bootloader /set fuses][5]][5]

Yes, even though you don't want a boot loader, you have to do this to correct the fuses (specifically, BOOTRST is unset by this procedure)

```
. . .
. . .
Writing | ################################################## | 100% 0.02s

avrdude: 1 bytes of lock written
avrdude: verifying lock memory against 0x0f:
avrdude: load data lock data from input file 0x0f:
avrdude: input file 0x0f contains 1 bytes
avrdude: reading on-chip lock data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of lock verified

avrdude done.  Thank you.

```

**Upload Using Programmer**
[![Upload Using Programmer][6]][6]

```
C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.57.0_x86__mdqgnx93n4wtt\arduino-builder -dump-prefs -logger=machine -hardware C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.57.0_x86__mdqgnx93n4wtt\hardware -hardware C:\Users\6v6gt\Documents\ArduinoData\packages -hardware C:\Users\6v6gt\Documents\Arduino\hardware -tools C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.57.0_x86__mdqgnx93n4wtt\tools-builder -tools C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.57.0_x86__mdqgnx93n4wtt\hardware\tools\avr -tools C:\Users\6v6gt\Documents\ArduinoData\packages -built-in-libraries C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.57.0_x86__mdqgnx93n4wtt\libraries -libraries C:\Users\6v6gt\Documents\Arduino\libraries -fqbn=MiniCore:avr:328:bootloader=no_bootloader,eeprom=keep,variant=modelP,BOD=2v7,LTO=Os,clock=16MHz_external -vid-pid=1A86_7523 -ide-version=10819 -build-path C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964 -warnings=all -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.avrdude.path=C:\Users\6v6gt\Documents\ArduinoData\packages\arduino\tools\avrdude\6.3.0-arduino18 -prefs=runtime.tools.avrdude-6.3.0-arduino18.path=C:\Users\6v6gt\Documents\ArduinoData\packages\arduino\tools\avrdude\6.3.0-arduino18 -prefs=runtime.tools.arduinoOTA.path=C:\Users\6v6gt\Documents\ArduinoData\packages\arduino\tools\arduinoOTA\1.3.0 -prefs=runtime.tools.arduinoOTA-1.3.0.path=C:\Users\6v6gt\Documents\ArduinoData\packages\arduino\tools\arduinoOTA\1.3.0 -prefs=runtime.tools.avr-gcc.path=C:\Users\6v6gt\Documents\ArduinoData\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7 -prefs=runtime.tools.avr-gcc-7.3.0-atmel3.6.1-arduino7.path=C:\Users\6v6gt\Documents\ArduinoData\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7 -verbose C:\Users\6v6gt\Documents\Arduino\big_flash_V0_01\big_flash_V0_01.ino
C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.57.0_x86__mdqgnx93n4wtt\arduino-builder -compile -logger=machine -hardware C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.57.0_x86__mdqgnx93n4wtt\hardware -hardware C:\Users\6v6gt\Documents\ArduinoData\packages -hardware C:\Users\6v6gt\Documents\Arduino\hardware -tools C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.57.0_x86__mdqgnx93n4wtt\tools-builder -tools C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.57.0_x86__mdqgnx93n4wtt\hardware\tools\avr -tools C:\Users\6v6gt\Documents\ArduinoData\packages -built-in-libraries C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.57.0_x86__mdqgnx93n4wtt\libraries -libraries C:\Users\6v6gt\Documents\Arduino\libraries -fqbn=MiniCore:avr:328:bootloader=no_bootloader,eeprom=keep,variant=modelP,BOD=2v7,LTO=Os,clock=16MHz_external -vid-pid=1A86_7523 -ide-version=10819 -build-path C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964 -warnings=all -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.avrdude.path=C:\Users\6v6gt\Documents\ArduinoData\packages\arduino\tools\avrdude\6.3.0-arduino18 -prefs=runtime.tools.avrdude-6.3.0-arduino18.path=C:\Users\6v6gt\Documents\ArduinoData\packages\arduino\tools\avrdude\6.3.0-arduino18 -prefs=runtime.tools.arduinoOTA.path=C:\Users\6v6gt\Documents\ArduinoData\packages\arduino\tools\arduinoOTA\1.3.0 -prefs=runtime.tools.arduinoOTA-1.3.0.path=C:\Users\6v6gt\Documents\ArduinoData\packages\arduino\tools\arduinoOTA\1.3.0 -prefs=runtime.tools.avr-gcc.path=C:\Users\6v6gt\Documents\ArduinoData\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7 -prefs=runtime.tools.avr-gcc-7.3.0-atmel3.6.1-arduino7.path=C:\Users\6v6gt\Documents\ArduinoData\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7 -verbose C:\Users\6v6gt\Documents\Arduino\big_flash_V0_01\big_flash_V0_01.ino
Using board '328' from platform in folder: C:\Users\6v6gt\Documents\ArduinoData\packages\MiniCore\hardware\avr\2.1.3
Using core 'MCUdude_corefiles' from platform in folder: C:\Users\6v6gt\Documents\ArduinoData\packages\MiniCore\hardware\avr\2.1.3
Detecting libraries used...
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-g++" -c -g -Os -w -std=gnu++17 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_ATmega328 -DARDUINO_ARCH_AVR "-IC:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\MiniCore\\hardware\\avr\\2.1.3\\cores\\MCUdude_corefiles" "-IC:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\MiniCore\\hardware\\avr\\2.1.3\\variants\\standard" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\sketch\\big_flash_V0_01.ino.cpp" -o nul
Generating function prototypes...
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-g++" -c -g -Os -w -std=gnu++17 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_ATmega328 -DARDUINO_ARCH_AVR "-IC:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\MiniCore\\hardware\\avr\\2.1.3\\cores\\MCUdude_corefiles" "-IC:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\MiniCore\\hardware\\avr\\2.1.3\\variants\\standard" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\sketch\\big_flash_V0_01.ino.cpp" -o "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\preproc\\ctags_target_for_gcc_minus_e.cpp"
"C:\\Program Files\\WindowsApps\\ArduinoLLC.ArduinoIDE_1.8.57.0_x86__mdqgnx93n4wtt\\tools-builder\\ctags\\5.8-arduino11/ctags" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\preproc\\ctags_target_for_gcc_minus_e.cpp"
Compiling sketch...
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-g++" -c -g -Os -Wall -Wextra -std=gnu++17 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_ATmega328 -DARDUINO_ARCH_AVR "-IC:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\MiniCore\\hardware\\avr\\2.1.3\\cores\\MCUdude_corefiles" "-IC:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\MiniCore\\hardware\\avr\\2.1.3\\variants\\standard" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\sketch\\big_flash_V0_01.ino.cpp" -o "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\sketch\\big_flash_V0_01.ino.cpp.o"
Compiling libraries...
Compiling core...
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-gcc" -c -g -x assembler-with-cpp -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_ATmega328 -DARDUINO_ARCH_AVR "-IC:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\MiniCore\\hardware\\avr\\2.1.3\\cores\\MCUdude_corefiles" "-IC:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\MiniCore\\hardware\\avr\\2.1.3\\variants\\standard" "C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\MiniCore\\hardware\\avr\\2.1.3\\cores\\MCUdude_corefiles\\wiring_pulse.S" -o "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\wiring_pulse.S.o"
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\hooks.c.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\WInterrupts.c.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\wiring.c.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\wiring_shift.c.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\wiring_digital.c.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\wiring_analog.c.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\wiring_pulse.c.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\CDC.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\HardwareSerial1.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\HardwareSerial2.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\HardwareSerial.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\IPAddress.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\PluggableUSB.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\HardwareSerial3.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\Stream.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\Print.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\HardwareSerial0.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\Tone.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\abi.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\USBCore.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\new.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\main.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\wiring_extras.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\WMath.cpp.o
Using previously compiled file: C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964\core\WString.cpp.o
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\wiring_pulse.S.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\WInterrupts.c.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\hooks.c.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\wiring.c.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\wiring_analog.c.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\wiring_digital.c.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\wiring_pulse.c.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\wiring_shift.c.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\CDC.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\HardwareSerial.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\HardwareSerial0.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\HardwareSerial1.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\HardwareSerial2.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\HardwareSerial3.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\IPAddress.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\PluggableUSB.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\Print.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\Stream.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\Tone.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\USBCore.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\WMath.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\WString.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\abi.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\main.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\new.cpp.o"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-ar" rcs "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\core.a" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\core\\wiring_extras.cpp.o"
Linking everything together...
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-gcc" -Wall -Wextra -Os -Wl,--gc-sections -mmcu=atmega328p -o "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964/big_flash_V0_01.ino.elf" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964\\sketch\\big_flash_V0_01.ino.cpp.o" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964/core\\core.a" "-LC:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964" -lm
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-objcopy" -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964/big_flash_V0_01.ino.elf" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964/big_flash_V0_01.ino.eep"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-objcopy" -O ihex -R .eeprom "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964/big_flash_V0_01.ino.elf" "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964/big_flash_V0_01.ino.hex"
cmd /C "C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-objdump" --disassemble --source --line-numbers --demangle --section=.text "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964/big_flash_V0_01.ino.elf" > "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964/big_flash_V0_01.ino_atmega328p_16000000L.lst"
"C:\\Users\\6v6gt\\Documents\\ArduinoData\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-size" -A "C:\\Users\\6v6gt\\AppData\\Local\\Temp\\arduino_build_577964/big_flash_V0_01.ino.elf"
Sketch uses 32640 bytes (99%) of program storage space. Maximum is 32768 bytes.
Global variables use 196 bytes (9%) of dynamic memory, leaving 1852 bytes for local variables. Maximum is 2048 bytes.
C:\Users\6v6gt\Documents\ArduinoData\packages\arduino\tools\avrdude\6.3.0-arduino18/bin/avrdude -CC:\Users\6v6gt\Documents\ArduinoData\packages\MiniCore\hardware\avr\2.1.3/avrdude.conf -v -patmega328p -cstk500v1 -PCOM6 -b19200 -Uflash:w:C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964/big_flash_V0_01.ino.with_bootloader.hex:i

avrdude: Version 6.3-20201216
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "C:\Users\6v6gt\Documents\ArduinoData\packages\MiniCore\hardware\avr\2.1.3/avrdude.conf"

         Using Port                    : COM6
         Using Programmer              : stk500v1
         Overriding Baud Rate          : 19200
         AVR Part                      : ATmega328P
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PC2
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  3600  3600 0xff 0xff
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0xff 0xff
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : STK500
         Description     : Atmel STK500 Version 1.x firmware
         Hardware Version: 2
         Firmware Version: 1.18
         Topcard         : Unknown
         Vtarget         : 0.0 V
         Varef           : 0.0 V
         Oscillator      : Off
         SCK period      : 0.1 us

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964/big_flash_V0_01.ino.with_bootloader.hex"
avrdude: writing flash (32640 bytes):

Writing | ################################################## | 100% 35.80s

avrdude: 32640 bytes of flash written
avrdude: verifying flash memory against C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964/big_flash_V0_01.ino.with_bootloader.hex:
avrdude: load data flash data from input file C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964/big_flash_V0_01.ino.with_bootloader.hex:
avrdude: input file C:\Users\6v6gt\AppData\Local\Temp\arduino_build_577964/big_flash_V0_01.ino.with_bootloader.hex contains 32640 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 19.57s

avrdude: verifying ...
avrdude: 32640 bytes of flash verified

avrdude done.  Thank you.

```

  [1]: https://i.stack.imgur.com/Ei2io.jpg
  [2]: https://i.stack.imgur.com/BGNNq.jpg
  [3]: https://i.stack.imgur.com/XkGtJ.jpg
  [4]: https://i.stack.imgur.com/pIWz9.jpg
  [5]: https://i.stack.imgur.com/IQzQH.jpg
  [6]: https://i.stack.imgur.com/cEaMw.jpg


message:
ESP32 can not deep sleep longer than 35 minutes

I'm trying to get my Lilygo T5 4.7" epaper to deep sleep for 12 hours.
But I only seem to be able to get about half an hour (2100s) of deepsleep on it.
If I set the timer for longer, it just reboots right away.

```
#include <Arduino.h>
#include "epd_driver.h"

long DEEP_SLEEP_TIME_SEC = 43200;

void start_deep_sleep()
{
    epd_poweroff_all();
    esp_sleep_enable_timer_wakeup(1000000L * DEEP_SLEEP_TIME_SEC);
    Serial.println("Starting deep-sleep period...");
    esp_deep_sleep_start();
}

void setup() {
  Serial.begin(115200);
  Serial.println("\n- - - - - - - - -INITIALIZING - - - - - - - - - -");
  delay(10000);
  start_deep_sleep();
}

void loop() {
}
```

The sbove code gives the following:

```
16:44:25.104 -> - - - - - - - - -INITIALIZING - - - - - - - - - -

16:44:35.105 -> Starting deep-sleep period...

16:44:35.105 -> ets Jul 29 2019 12:21:46
```

- and it just continues to reboot..

Maybe I'm using the wrong variables in some way?

Regards
    Kasper

body:
So, formalizing this into an answer:

```c++
long DEEP_SLEEP_TIME_SEC = 43200;
// ...
esp_sleep_enable_timer_wakeup(1000000L * DEEP_SLEEP_TIME_SEC);
```

This is attempting to calculate the result of `1000000L * DEEP_SLEEP_TIME_SEC` as a `long` type because both operands are of `long` type. The language does not consider the values of the operands (your constant and variable) of an operator (the multiplication) when determining the type of the result (the product) nor what you do with the result after that (passing it to the function).

The `long` type on ESP32 has a maximum value of 2147483647 which is as you said, "about half an hour" (not quite 36 minutes) worth of microseconds.

According to the [documentation][1] `esp_sleep_enable_timer_wakeup` accepts a `uint64_t` type for its requested duration parameter. I don't know what the *valid* maximum value to call with is, but the original poster confirmed it was large enough for 12 hours.

An `unsigned long long` is 64-bit on the ESP32 and the ULL suffix on `1000000ULL` forces the compiler to only consider types which are unsigned and which are not smaller than a long long. In practice it means make me an `unsigned long long` with value 1000000. In
```c++
esp_sleep_enable_timer_wakeup(1000000ULL * DEEP_SLEEP_TIME_SEC);
```
the compiler follows something called the [usual arithmetic conversions][2] which will cause it to upconvert the `long` type of `DEEP_SLEEP_TIME_SEC` to match the `unsigned long long` that it is finding in `1000000ULL`. The multiplication is therefore carried out in the `unsigned long long` type, so that the calculation itself accommodates more microseconds than you'll ever know what to do with. What the actual maximum is for `esp_sleep_enable_timer_wakeup` is still unclear. If I find out I will update with that information.

---

The ESP32-Arduino support comes with a fairly complete C++ standard library. So, if you want to get fancy you can use the `<chrono>` [header][3]. Just to give an example of what that could look like in your context:

```c++
#include <chrono>
// ...
static constexpr auto DEEP_SLEEP_TIME = std::chrono::hours{12};
// ...
esp_sleep_enable_timer_wakeup(
    std::chrono::duration_cast<std::chrono::microseconds>(
        DEEP_SLEEP_TIME
    ).count()
);
```

I'm being very explicit in the above. But you can import parts of the chrono namespace so you don't have to name everything fully. <s>You can also import [chrono literals support][4] so that you can use time constants that look more like natural language</s>(not yet apparently; there's still no C++14 support in Arduino-ESP32 I guess). You can control the underlying integer type used to represent the unit. It is also possible to create and name your own duration types to represent things like bit durations in a serial protocol etc. The default underlying type for `chrono::microseconds` is large enough for what you're doing; the default widths of underlying types are generally pretty sensible.  Different time units are different `std::chrono` types so you can't mix them up accidentally. `duration_cast` is a means of explicit conversion of time units. The `.count()` in the above is just a way to get the raw integer value out of the chrono type for when you need to do that, like calling this function.

If you wrap the function with your own taking `std::chrono::milliseconds` the unit conversion could just happen automatically in the call to your own wrapper:

```c++
static constexpr auto DEEP_SLEEP_TIME = std::chrono::hours{12};
//...
esp_err_t esp_sleep_enable_timer_wakeup_using_chrono(
  std::chrono::milliseconds duration
) {
  return esp_sleep_enable_timer_wakeup(
    duration.count()
  );
}
// ...
esp_sleep_enable_timer_wakeup_using_chrono(DEEP_SLEEP_TIME);
```
The way durations work in chrono is such that you don't need to `duration_cast` when you're going to type that can represent the same values as the source type. The the prior example the point of the `duration_cast` was just so that `.count()` was getting a count of microseconds. In other words, the `duration_cast` performed the multiplication and would have selected a more appropriate underlying integer size. Here that conversion takes place during the call. Anyway, it may be worth some effort to learn about as it tends to help avoid problems with unit conversions and integer ranges.

  [1]: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/sleep_modes.html#_CPPv429esp_sleep_enable_timer_wakeup8uint64_t
  [2]: https://en.cppreference.com/w/c/language/conversion
  [3]: https://en.cppreference.com/w/cpp/chrono/duration
  [4]: https://en.cppreference.com/w/cpp/chrono/operator""s


message:
How to tri-state output circuit

I need a circuit where an Arduino MCU can set an output to 3 different states.

* HIGH (12V)
* LOW (GND)
* N/A (completely disconnected)

Using transistors seems to be the correct way but I am too much of a noob in this area to be sure.

I’ve been researching “tri-state” online but there seems to be different meanings of this.

I’d appreciate a circuit for this or information that can get me on the right track.

Update:

I did test this schematic and it almost works. Although in the high state I got 2.7V output when the input was 12V. Very odd. I used two NPN transistors.

This is a half h-bridge, right?

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

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

body:
The simplest solution could probably be an H-bridge, like the ones you
have on motor driver shields. Actually you only need half an H-bridge.
You will typically be driving two inputs of the chip: “input 1” and
“enable”:

- if you set “enable” to `LOW` the bridge output will be in the high
  impedance state (your “completely disconnected” state)
- if you set “enable” to `HIGH`, the output will be `HIGH` or `LOW`,
  mirroring “input 1”.

**Edit**: your transistor circuit looks slightly similar to half an
H-bridge. However, in order to operate from 12 V, you typically need at
least three transistors, one of them being a PNP. See for example [this
discussion][forum] in the Arduino forum. I suggest you use a ready-built
H-bridge, as this will simplify things for you.

[forum]: https://forum.arduino.cc/t/custom-h-bridge-circuit-not-working-when-adding-motor/379745


body: Another possibility is a tristate buffer with enable. There are lots available, just make sure the voltage can be 12 volts (eg MC14503B)


message:
Arduino Pro Mini doesn't automatically reset

I have an issue with my Arduino pro mini.
Yesterday, I uploaded a sketch a few times on the pro mini, with an FTDI adapter, and everything worked fine. Today I'm trying to re-upload a sketch, but now, for some obscure reasons, my Arduino pro mini doesn't want to reset itself. I need to manually reset it. Since it is embedded in s case, I can't do that if I want to upload a sketch.

**EDIT**: I managed to make some tests, and it would seem that the DTR pin on the mini doesn't work anymore. When I short the DTR PIN to GND, the mini doesn't reset itself. I believe that could be a reason. But why? And how? It was working a day ago.

I soldered the FTDI like that, and it didn't work several times.
(At the moment I left it unsoldered because I don't want to solder it yet):

[![setup][1]][1]

Can anyone complete my intuition?

Thanks in advance.

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

body:
Is this is an actual photo of your FTDI and mini? I can't tell whether the FTDI pins are soldered to the mini. If not, I would guess that the problem is an unreliable electrical connection at one of the pins, and look there for the problem.

If it helps, this is what I use for my embedded devices. The FTDI is in the USB-A connector. The embedded end is just a female connector that pushes onto the 6 pins on the board. This cable supplies +5v; there are also ones that supply 3.3v.

[![FTDI Cable][1]][1]

> Thanks for your answer, the connection is soldered.

In that case, I'd check the resistance of the solder joints including trying to wiggle them; then trying to narrow it down by swapping FTDI boards if you have another; and likewise, swapping the mini board.

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


body: The reset pulse issued by the USB-Serial adapter via the DTR line may be of low amplitude (3.3V). This is occasionally too low for the Pro Mini reset function.  Sometimes, it helps to solder a 47k resistor across the reset button contacts, lowering the initial DC level of the reset input. This applies to 5V/16MHz and 3.3V/8MHz versions of the Pro Mini.