text:
I want to program multiple arduino at once
I am aware that using a USB Hub you can attach multiple arduino to one computer and either upload code one by one or use bash script to upload code on all arduinos together. But you can attach only as many arduino to a computer. I need to prgram around 100 arduinos/atmega ICs at once. Is there a way to do so?
There are other methods that I found online like programming ICs over Wifi network. But that require a lot of WiFi chips connected to arduino. I cant setup that. Also that doesn't seems cost effective.
Also Arduino sells their uno and other boards with pre-installed blink program. They must be doing batch programming only (multiple ICs at once). Any idea how they do this?

What is the use case? Production line? I've made shield for the raspberry pi zero so with button, few status leds and two ISP lines to upload communucation 16u2 and 2560 firmware+bootloader in about minute. It's not so much time to do it in parallel. Btw you can chain USB hubs - one 16port -> 16x 16port (=256 if there is no limit on usb itself) and it'll be slow..

To program over USB you need 1 connection per Arduino. The Serial connection cannot just be shared I think. Small deviations in the timing could disturb the whole communication. For programming over ISP you need a programmer for each Arduino. I would think that the production uses individual ISP programmers to program a small batch of Arduinos at once, then moving on to the next batch. When already building a product line automation, why would they need to program 100 of them at once, when the automation could also easily move the programmers between the batches

Why do you need to program 100 Arduinos at once? Can you give a little context here?

@chrisl I actually made a prototype with multiplexing Chip select pin on arduino, which is connected to RESET pin of target board to program. When I am connecting one target board at once I am able to program it but when I am connecting multiple target boards then not even one is programming. I am using Nick gammon's code for programming the target arduino using the master arduino https://github.com/nickgammon/arduino_sketches/tree/master/Atmega_Hex_Uploader_Fixed_Filename
This is rough block diagram of multiplexing chip select pin - https://imgur.com/a/XX4Nyf8

Arduino, the company, may sell on enough volume to make it worthwhile to get the microcontroller manufacturer to program the microcontrollers durin the production process
This wouldn't cost them extra if they already get the bootloader pre-programmed. I've read programming ICs is a service available to high volume customers.
I guess low volume makers use fixtures that use the ICSP headers, pogo sticks or IC clips and which trigger the programming on contact using a microswitch etc.
I suspect Adafruit do something of this sort, see GIFs and video discussing testing at
https://www.adafruit.com/product/2458

I actually made a prototype with multiplexing Chip select pin on arduino, which is connected to RESET pin of target board to program. When I am connecting one target board at once I am able to program it but when I am connecting multiple target boards then not even one is programming. I am using Nick gammon's code for programming the target arduino using the master arduino https://github.com/nickgammon/arduino_sketches/tree/master/Atmega_Hex_Uploader_Fixed_Filename
This is rough block diagram of multiplexing chip select pin - https://imgur.com/a/XX4Nyf8

I recommend using optiloader, which uses a standalone arduino to program an arduino connected to it.  You can therefore create as many arduino programmers as you want, each of which can run without connecting to a host computer.  This is how firmware is loaded for high volume production.

Any idea how they do this?

You can buy gadgets that let you upload code in a second or so. For example, here. You plug in the target board, press a button, and it's done.
These program a board in a couple of seconds. While this is hardly literally "at once" it would take time anyway to connect 100 Arduinos to "something" so connecting and disconnecting every couple of seconds is roughly the same thing.
That board mentioned above uses code I wrote which can run on an ordinary Arduino. In other words, use one to program another, where the code to be uploaded is stored on a micro-SD card.


text:
2 different operation modes for a motor
i want to press "unu" button of the remote, and the motor to rotate continuously, and when i press "sound" i want the motor to rotate untill the hall sensor detects a magnetic field. any ideas please?
in this configuration, even if i press "unu" or "sound", the motor rotates untill the hall sensor detects a magnetic field.

#include <TLE94112.h>
#include <Tle94112Motor.h>
#include <IRremote.h>

#define unu 0x1
#define sound 0x55

int RECV_PIN = 2;
int hallSensorPin1 = 3;
int state1;
int oldState1 = 1;

Tle94112 controller = Tle94112();
Tle94112Motor motor1(controller);

IRrecv irrecv(RECV_PIN);
decode_results results;

void setup()
{ irrecv.enableIRIn();
  controller.begin();

  motor1.connect(motor1.HIGHSIDE, controller.TLE_HB1);
  motor1.connect(motor1.LOWSIDE, controller.TLE_HB2);
  motor1.setPwm(motor1.HIGHSIDE, controller.TLE_PWM2);
  motor1.setPwmFreq(motor1.HIGHSIDE, controller.TLE_FREQ200HZ);

  motor1.begin();
}

void loop()
{
  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    irrecv.resume();
  }//add bracket here

  if (results.value == unu || results.value == 0x801 || results.value == 0x2049) {
    motor1.start(63);
  }

  if (results.value == sound || results.value == 0x55 || results.value == 0x2103 || results.value == 0x837 || results.value == 0x37) {
    motor1.start(63);

    oldState1 = 1;
    state1 = digitalRead(hallSensorPin1);

    if (state1 == LOW && oldState1 == 1) {
      motor1.coast();

    }
  }
}

thanks for your observation. i fixed this.

the two if (results.value == statements execute the same code

yes, and i tried the configuration that you can see now in the initial post (i updated it) and this one works fine for continuous rotation, but when the magnetic field is detected, the motor receives small pulses without pressing any button, and again when its not detecting a magnetic field, rotates normally till it finds again the magnetic field.

introduce a layer of separation between if (results.value == and motor1.start(63); .... the if statement should only set two flags, motorOn and motorMode (you pick names) .... there should be only one code line that turns on the motor if (motorOn) { .... the hall sensor code should be wrapped in if (motorMode) {

you provided incomplete information ... i see nothing in your post about the serial monitor output

Serial.println(results.value, HEX); this is what you saying?

yes, that prints debugging information to serial monitor

its not showing anything in the serial monitor. im a beginner in arduino, i just used it with a couple of sensors before and this project it is too much for me now i think. anyway i figured out the problem. can i ask how that serial monitor output influence the program?

it should be printing something when you press a button on the remote control

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Is there something wrong with my code or my Arduino is malfunctioning
A 12v motor is connected to a 5v relay and a HC-SRO4 is connected to an Arduino. Sometimes the relay clicks so the motor is on for less than 170 seconds which is the delay time but sometimes the motor just keep on running but also there are times that it works properly so I am wondering if my Arduino or my relay is malfunctioning or there's something wrong with my code?
int echopin=10;
int trigpin=9;
int motorpin=8;
int sensorval;
int delayt=170;
int greenpin=7;
int redpin=2;

void setup() {
  Serial.begin(9600);
  pinMode(echopin,INPUT);
  pinMode(trigpin,OUTPUT);
  pinMode(motorpin,OUTPUT);
  pinMode(redpin,OUTPUT);
  pinMode(greenpin,OUTPUT);
}

void loop() {

 digitalWrite(trigpin,LOW);
 delayMicroseconds(10);
 digitalWrite(trigpin,HIGH);
 delayMicroseconds(10);
 digitalWrite(trigpin,LOW);
 delayMicroseconds(10);
 sensorval=pulseIn(echopin,HIGH);
 Serial.println(sensorval);

 if(sensorval<500){
 digitalWrite(motorpin,HIGH);
 digitalWrite(greenpin,HIGH);
 digitalWrite(redpin,LOW);
 delay(delayt);
 digitalWrite(motorpin,LOW);
 digitalWrite(greenpin,LOW);
 digitalWrite(redpin,HIGH);
 delay(1500);
 }
 digitalWrite(motorpin,LOW);
 digitalWrite(redpin,HIGH);
 digitalWrite(greenpin,LOW);

 if(sensorval>500){
 digitalWrite(greenpin,LOW);
  digitalWrite(redpin,HIGH);
  digitalWrite(motorpin,LOW);
 }

}

what is redpin and greenpin? .... why are you providing incomplete information? ... you said nothing about the values printed in serial monitor

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Arduino sleep mode problem while sending data with gsm module
i am trying to send gps data via sim800l gsm module. Working fine without the power down code but when i add the power down code it stops working (not sending the gps data. code execution stops in sendGPS() function). Tried different functions but i could not get it work. Thanks.
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <avr/power.h>
#include <avr/sleep.h>
#include <avr/wdt.h>

volatile bool flag_wdt=HIGH;                           // flag of watchdog
ISR(WDT_vect) {                                        // Watchdog Interrupt Service est exécité lors d'un timeout du WDT
  if(flag_wdt == LOW){flag_wdt = HIGH;}                // Reset watchdog flag
}

void setup_my_watchdog(const byte interval) {
  MCUSR = 0;                              // reset various flags
  WDTCSR |= 0b00011000;                   // see docs, set WDCE, WDE
  WDTCSR =  0b01000000 | interval;        // set WDIE, and appropriate delay
  wdt_reset();
}

TinyGPSPlus gps;
int RXPin = 8;
int TXPin = 9;
int GPSBaud = 9600;
SoftwareSerial gpsSerial(RXPin, TXPin);
SoftwareSerial gprsSerial(2, 3); // RX, TX

void enterSleep(int hour_to_sleep) {
  int i=0;                                // Create a counter
  //time_to_sleep = 360*hour_to_sleep;   // how many 10sec i need to sleep ? 6*60*hour(s)

  // ---------------------------- START Save power -------------------
  power_adc_disable();                  // ADC OFF
  power_spi_disable();                  // SPI OFF
  //power_twi_disable();                  // ? OFF
  power_usart0_disable();               // USART et USB COM OFF
  power_timer0_disable();               // Timer 0 OFF (attention timer0 utilisé par millis ou delay)
  //power_timer1_disable();               // Timer 1 OFF
  //power_timer2_disable();               // Timer 2 OFF
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // Configures the Atmega168 for the specified sleep mode

  for(i=0 ; i< hour_to_sleep ; i++){
    setup_my_watchdog(0b100001);          // Set-up first watchdog 8sec
    sleep_enable();                       // Enables the sleep mode to be entered;
    sleep_mode();                         // Entre dans le mode veille choisi
    // -----------------------------------// program restart here after watchdog 8sec timeout
    sleep_disable();                      // First : disable sleep mode
    setup_my_watchdog(0b000111);          // Set-up new watchdog 2sec
    sleep_enable();                       // Enables the sleep mode to be entered;
    sleep_mode();                         // Entre dans le mode veille choisi
    // -----------------------------------// program restart here after watchdog 2sec timeout
  }

  power_adc_enable();                  // ADC ON
  power_timer0_enable();               // Timer 0 ON
  power_usart0_enable();               // USART et USB COM OFF
}

void setup() {
  gpsSerial.begin(GPSBaud);
  gprsSerial.begin(9600);
  delay(10000);
}

void loop() {

    sendGPS();
    enterSleep(30);

}

void sendGPS() {
  gpsSerial.listen();
  while (gpsSerial.available() > 0) {
    if (gps.encode(gpsSerial.read()))
      if (gps.location.isValid())
      {
        gprsSerial.listen();
        String geo;
        geo.concat("field1=" + String(gps.location.lat(), 6));
        geo.concat("&field2=" + String(gps.location.lng(), 6));
        gprsSerial.println("AT");
        delay(1000);
        gprsSerial.println("AT+CGATT?");
        delay(1000);

        gprsSerial.println("AT+CIPSHUT");
        delay(1000);

        gprsSerial.println("AT+CIPSTATUS");
        delay(2000);

        gprsSerial.println("AT+CIPMUX=0");
        delay(2000);
        gprsSerial.println("AT+CSTT=\"internet\"");//start task and setting the APN,
        delay(1000);
        gprsSerial.println("AT+CIICR");//bring up wireless connection
        delay(3000);
        gprsSerial.println("AT+CIFSR");//get local IP adress
        delay(2000);
        gprsSerial.println("AT+CIPSPRT=0");
        delay(3000);
        gprsSerial.println("AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",\"80\"");//start up the connection
        delay(6000);
        gprsSerial.println("AT+CIPSEND");//begin send data to remote server
        delay(4000);
        String str = "GET https://api.thingspeak.com/update?api_key=XXXXXXXXX" + String("&") + geo.c_str();
        String str1 = str + String("&");
        String str2 = str1 + geo.c_str();
        gprsSerial.println(str2);
        delay(4000);
        gprsSerial.println((char)26);//sending
        delay(5000);//waitting for reply, important! the time is base on the condition of internet
        gprsSerial.println();
        gprsSerial.println("AT+CIPSHUT");//close the connection
        delay(2000);
        delay(60000);
      }
  }
}

Define "stops working"...?

i mean not sending the gps data. code execution stops in sendGPS() function.

So... you're waking up, seeing there's no data to read (which there won't be - it's been asleep...), then going back to sleep again? Maybe you should actually wait until some valid data arrives before going back to sleep?


text:
Arduino Micro: Why am I getting 6.00 as a result instead of 6.66?
Basically, on the TWR calculator page, when I entered 20 as the initial value and 3 as the value that comes after, I somehow get 6.00 as a result instead of 6.66 in the computeTWR() function. How can I fix this?
// ------------------- DIVIDER ---------------------
/*
   Jebediah's Launch Control System for Kerbal Space Program
   Alpha Build 1.1
   An Open-Source Project by John Seong
*/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>

const byte ROWS = 4;
const byte COLS = 3;

char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[ROWS] = {12, 11, 10, 9};
byte colPins[COLS] = {8, 7, 6};

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// Show a two-line message on the LCD.
void lcdShow(const char *line0, const char *line1) {
  lcd.clear();
  lcd.print(line0);
  lcd.setCursor(0, 1);
  lcd.print(line1);
}

void computeTWR(int thrustR, int weightR) {
  float result = thrustR / weightR;
  lcd.print(result);
}

void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcdShow("Jeb's Launch", "Control System");
  delay(3000);
  lcdShow("Alpha Build 1.1", " STUDIO HORIZON");
  delay(3000);
  lcdShow("Welcome, Kerman", "Press any key...");
  while (!keypad.getKey()) ;  // wait for key press
}

void loop() {
  static enum {START, MENU, SET_COUNT, COUNT_DOWN, SET_THRUST, SET_WEIGHT, TWR_COMPUTE} state = START;
  static uint32_t last_second;  // millis() value on last full second
  static int count, thrust, weight;             // countdown, thrust, weight value
  static float ratio;

  char key = keypad.getKey();

  switch (state) {
    case START:  // transitional state
      lcdShow("1. Countdown", "2. TWR");
      state = MENU;
    /* fallthrough */
    case MENU:
      if (key == '1') {  // Countdown
        lcdShow("Countdown Timer", "Seconds: ");
        count = 0;
        state = SET_COUNT;
      } else if (key == '2') {  // TWR
        lcdShow("TWR Calculator", "Thrust: ");
        thrust = 0, weight = 0, ratio = 0;
        state = SET_THRUST;
      }
      break;
    case SET_COUNT:
      if (key >= '0' && key <= '9' && count <= 99) {
        lcd.print(key);
        count = 10 * count + (key - '0');
      } else if (key == '#') {
        lcdShow("Lift off in", "     seconds");
        // Force a refresh on entering COUNT_DOWN:
        last_second = millis() - 1000;
        count++;
        state = COUNT_DOWN;
      } else if (key == '*') {
        state = START;
      }
      break;
    case COUNT_DOWN:
      if (millis() - last_second >= 1000) {
        last_second += 1000;
        count--;
        if (count == 0) {
          Serial.println("Lift off!");
        } else if (count < 0) {
          state = START;
          break;
        }
        lcd.setCursor(1, 1);
        lcd.print(count < 10 ? "  " : count < 100 ? " " : ""); // pad
        lcd.print(count);
      } else if (key == '*') {
        state = START;
      }
      break;
    case SET_THRUST:
      if (key >= '0' && key <= '9' && thrust <= 9999) {
        lcd.print(key);
        thrust = 10 * thrust + (key - '0');
      } else if (key == '#') {
        lcdShow("TWR Calculator", "Weight: ");
        state = SET_WEIGHT;
      } else if (key == '*') {
        state = START;
      }
      break;
    case SET_WEIGHT:
      if (key >= '0' && key <= '9' && weight <= 9999) {
        lcd.print(key);
        weight = 10 * weight + (key - '0');
      } else if (key == '#') {
        lcdShow("Thrust-to-weight", "ratio: ");
        computeTWR(thrust, weight);
      } else if (key == '*') {
        state = START;
      }
      break;
  }
}

Where? From what? Some calculation? Some entry? What?

Divide two integers you get an integer. No matter what you assign to, you're calculating with integers, so the result is an integer.

use float as parameter types

float result = (float) thrustR / weightR;

OO thanks! I was dumb

thats a blooper

(community wiki answer derived from comments - takes Q off unanswered list)

Why am I getting 6.00 as a result instead of 6.66?

because integer arithmetic discards fractional parts of results, including intermediate results
static int count, thrust, weight;             // countdown, thrust, weight value

If some of these are intended to have decimal values you need to use a more suitable data type (e.g. float)


text:
Run a part of a code only 4 second
I have two different programs written for my Arduino. One control the rockets thrust vector. The other one is for parachute.
I need to first run rotationmatrices() for a 4 second and then parachute.
How could i do that?
Here is my code:
//Libraries
#include <Servo.h>
#include <Wire.h>
#include <MPU6050_tockn.h>
#include <AFMotor.h>
#include <I2Cdev.h>

MPU6050 mpu6050(Wire);

const int MPU = 0x68;
int16_t AcX, AcY, AcZ, Tmp, GyX, GyroY, GyroZ;
double PIDX, PIDY, errorX, errorY, previous_errorX, previous_errorY,
       pwmX, pwmY, previouslog, OutX, OutY, OutZ, OreX, OreY, OreZ;
double PreviousGyroX, PreviousGyroY, PreviousGyroZ, IntGyroX,
       IntGyroY, IntGyroZ, DifferenceGyroX, DifferenceGyroY,
       DifferenceGyroZ, matrix1, matrix2, matrix3;
double matrix4, matrix5, matrix6, matrix7, matrix8, matrix9, Ax, Ay;

//Upright Angle of the Flight Computer-Dik durum açısı
int desired_angleX = 0;

//Offsets for tuning
int servoX_offset = 100;

//Position of servos through the startup function
int servoXstart = 80;

//The amount the servo moves by in the startup function
int servo_start_offset = 20;

//Ratio between servo gear and tvc mount
float servo_gear_ratio = 5.8;

double OrientationX = 0;
double OrientationY = 0;
double OrientationZ = 1;
double accAngleX;
double accAngleY;
double yaw;
double GyroX;
double gyroAngleX;
double gyroAngleY;
double pitch;

Servo servoX;

AF_DCMotor motor1(1); // create motor #1
AF_DCMotor motor2(2); // create motor #2
AF_DCMotor motor3(3); // create motor #1
AF_DCMotor motor4(4); // create motor #2

int buzzer = 3;

double dt, currentTime, previousTime, s, p;

//"P" Constants-Orantısal Değişken
float pidX_p = 0;
float pidY_p = 0;

//"I" Constants-Integral Değişken
float pidY_i = 0;
float pidX_i = 0;

//"D" Constants-Türevsel Değişken
float pidX_d = 0;
float pidY_d = 0;

int pos;

//PID Gains
double kp = 0.2;
double ki = 0.0;
double kd = 0.05;

int state = 0;

void setup() {
    Serial.begin(9600);
    Wire.begin();
    mpu6050.begin();
    gyrocalibrate();

    servoX.attach(10);

    motor1.setSpeed(255);
    motor2.setSpeed(255);
    motor3.setSpeed(255);
    motor4.setSpeed(255);

    pinMode(buzzer, OUTPUT);
}

void loop() {
    mpu6050.update();
    //Defining Time Variables-Zaman değişkeni tanımlanması
    previousTime = currentTime;
    currentTime = millis();
    dt = (currentTime - previousTime) / 1000;
    launchdetect();
    rotationmatrices();
    parachute();
}

void parachute() {
    motor1.run(BACKWARD);
    delay(1500);
    motor1.run(RELEASE);
    delay(20000);
}

void gyrocalibrate() {
    mpu6050.calcGyroOffsets(true);
}

void rotationmatrices(x) {
    mpu6050.update();
    PreviousGyroX = IntGyroX;
    PreviousGyroY = IntGyroY;
    PreviousGyroZ = IntGyroZ;

    IntGyroX = mpu6050.getGyroAngleX() * (PI / 180);
    IntGyroY = mpu6050.getGyroAngleY() * (PI / 180);
    IntGyroZ = mpu6050.getGyroAngleZ() * (PI / 180);

    DifferenceGyroX = (IntGyroX - PreviousGyroX);
    DifferenceGyroY = (IntGyroY - PreviousGyroY);
    DifferenceGyroZ = (IntGyroZ - PreviousGyroZ);

    OreX = OrientationX;
    OreY = OrientationY;
    OreZ = OrientationZ;

    //X Matrices
    matrix1 = (cos(DifferenceGyroZ) * cos(DifferenceGyroY));
    matrix2 = (((sin(DifferenceGyroZ) * -1) * cos(DifferenceGyroX)
            + (cos(DifferenceGyroZ)) * sin(DifferenceGyroY)
                * sin(DifferenceGyroX)));
    matrix3 = ((sin(DifferenceGyroZ) * sin(DifferenceGyroX)
            + (cos(DifferenceGyroZ)) * sin(DifferenceGyroY)
                * cos(DifferenceGyroX)));

    //Y Matrices
    matrix4 = sin(DifferenceGyroZ) * cos(DifferenceGyroY);
    matrix5 = ((cos(DifferenceGyroZ) * cos(DifferenceGyroX)
            + (sin(DifferenceGyroZ)) * sin(DifferenceGyroY)
                * sin(DifferenceGyroX)));
    matrix6 = (((cos(DifferenceGyroZ) * -1) * sin(DifferenceGyroX)
            + (sin(DifferenceGyroZ)) * sin(DifferenceGyroY)
                * cos(DifferenceGyroX)));

    //Z Matrices
    matrix7 = (sin(DifferenceGyroY)) * -1;
    matrix8 = cos(DifferenceGyroY) * sin(DifferenceGyroX);
    matrix9 = cos(DifferenceGyroY) * cos(DifferenceGyroX);

    OrientationX = ((OreX * matrix1)) + ((OreY * matrix2))
                 + ((OreZ * matrix3));
    OrientationY = ((OreX * matrix4)) + ((OreY * matrix5))
                 + ((OreZ * matrix6));
    OrientationZ = ((OreX * matrix7)) + ((OreY * matrix8))
                 + ((OreZ * matrix9));

    Serial.println(Ax);
    OutX = OrientationX * 60;
    Ax = asin(OrientationX) * (-180 / PI);
    pidcompute();
}

void servowrite() {
    servoX.write(pwmX);
}

void pidcompute() {
    previous_errorX = errorX;
    errorX = Ax - desired_angleX;

    //Defining "P"
    pidX_p = kp*errorX;

    //Defining "D"
    pidX_d = kd*((errorX - previous_errorX)/dt);

    //Defining "I"
    pidX_i = ki * (pidX_i + errorX * dt);

    PIDX = pidX_p + pidX_i + pidX_d;
    pwmX = ((PIDX * servo_gear_ratio) + servoX_offset);
    servowrite();
}

void launchdetect() {
    if (mpu6050.getAccZ() > 1) {
        state = 1;
    }
    if (state == 1) {
    }
}

void abortstart() {
    if (OrientationX > 40 || OrientationY > 40) {
        digitalWrite(buzzer, HIGH);
    }
    else if (OrientationX < 40 || OrientationY < 40) {
    }
}

Look at the BlinkWithoutDelay example. Learn how to use millis() or micros(). There are many tutorials about that online and its an imprtant principle to learn for Arduino programming.

@chrisl Thanks so much.I will look at them.

at first glance, it looks like your progran stops running when launch is detected  ... the code listing is kind of messy and unfocused looking ... maybe it is an indication of the clarity of your thoughts about the project

here is an example of well formatted code ... it could use a blank line between the case statements, but overall, it should give you an idea of proper formatting ... https://arduino.stackexchange.com/questions/76834/arduino-micro-why-am-i-getting-6-00-as-a-result-instead-of-6-66 ...

you can do it like this using millis it's just an small portion of code just for your understanding you will require some editing for your code.
unsigned long milli1;
void setup()
{
}
void loop()
{
     // code before rotationmatrices() function to be active.
     milli1= millis();
     while(millis()-milli1 <= 4000)  //4000milli sec = 4 sec
     {
      rotationmatrices();
     }
     parachute();

}

That's not a proper use of millis, because it is blocking code as well. Take a look at BlinkWithoutDelay


text:
ESP32 - DeepSleep loop or not?
I'm trying to create a battery & solar-powered ESP32 for future use with sensors.
It connects to Wifi, MQTT, publishes some readings and status messages and goes back to sleep. From time to time (it can happen after a few sleep cycles and sometimes after a few hundred cycles), I get 2 unexplained behaviours: 1) fails to connect to MQTT at boot, 2) fails to sleep.
Sometimes those behaviours happen simultaneously.
Is there a known issue with deepsleep and MQTT (using PubSubClient)? Most deepsleep examples I see online, all code is outside the loop() section - is it mandatory to be like that?
I don't share code, since it is more a general question.
Guy
EDIT1

most of callback was commented out, leaving only printing the incoming message.

LED was attached to a GPIO, generating a blink on loop() - when sleep succeeds - it goes off, when it fails, it stays on. This test shows that when this "error" happens, code actually stop running, but does not enter deep sleep (power-wise).

skip the call to MQTT publish to see if the device still fails to sleep .... skip the call by doing a calculation such as if (a+1 == 2) {, not by commenting the line, because commenting the line would cause the compiler to generate different code ........ do the same with the sleep code

@jsotola just to understand  - a+1 should create a logic state that wont enter the if loop to void publish ? and the other part to the esp_deep_sleep_start(); ? I dont understand why so... by the way- see edit 1/

if you use a comment mark // to prevent the MQTT publish command from running, then the compiler will produce different code that may not have the sleep problem .... using an if statement makes sure that the compiler does not skip un-executed code ..... do the same kind of a test for the sleep code to see if it is affecting the MQTT code ...... do the tests separately

@jsotola - I understood the reason why to do this, I asked only for the sleep part. by the way - the publish  workaround did not work, even not when I increased MQTT_MAX_PACKET_SIZE to 512 to be sure

@jsotola for the second check ( "masking" sleep phase ) - all went as expected. In order to cause "reboots" a ESP.restart() every 30 sec was added to loop()

Is there a known issue with deepsleep and MQTT ?

No. There may be a specific problem with the specific library you are using, but the concept of there being an issue with MQTT in general is nonsense.

Most deepsleep example I see online, all code is outside loop()section - is it mandatory to be like that ?

No, that's just being structured and tidy with your code. Whether code is in loop or in functions that are called by loop makes no difference. It can be a lot easier to manage your code if you structure it in functions rather than dumping it all in loop.

I don't know about the nonsense, but s similar question was asked in https://github.com/knolleary/pubsubclient/issues/634 ( same behviour, but case is still open... )

MQTT is just a protocol. The concept of it having a problem makes no logical sense. If there is a problem that is related to using MQTT then it's a problem with pubsubclient not MQTT.

OK, I agree, I ment to pubsubClient

The problem with calling ESP.deepSleep(xx) inside loop() is that watchdog is already activated there, and then a reset occurs during the sleep state.
To fix this, I used the software's own ESP.restart() reset technique after having written a signature to a "not init" variable, as follows:
Variable area:
uint16_t SleepSign __attribute__((section(".noinit"))); // Hot reset / deep sleep signature.

Then, at the beginning of setup() we write the code that tests the content of that uninitialized variable, and if it contains the signature, ESP.deepSleep(xx) is called. In my case I use ESP.deepSleep(0) because I intend for the device to reboot only on a new boot:
void setup()
{
     if (SleepSign == 0xdd11) ESP.deepSleep(0);
     Rest of the initialization:
     ...

Inside loop():
     ...
     if ((millis() - timeconnect) > 300*1000) {
       SleepSign = 0xdd11; // deep sleep at restart
       ESP.restart();
     }
     ...

This system is tested and works correctly, reducing consumption to the minimum specified by espressif. I previously tried to block watch before exiting setup(), but it didn't work, of course:
*((volatile uint32_t*) 0x60000900) &= ~(1); // Hardware WDT OFF

Obviously, if we are interested in using a timed deepSleep, and have the device do anything before going back to sleep, we can assign several values to the SleepSign variable to control the restart, also resetting its value before calling ESP.deepSleep(0):
 void setup()
 {
 if (SleepSign == 0xdd11) {
    SleepSign = 0xffff;
    ESP.deepSleep(xx);
  }
  Rest of the initialization:
  ...

The only drawback I find is that the esp will perform a reset before going to sleep, but I don't think that matters much.


text:
PubSubClient - MQTT_MAX_PACKET_SIZE How is it calculated
I'm using an ESP32, and I want to rule out a probable MQTT error. In PubSubClient , MQTT_MAX_PACKET_SIZE is set to 256. Is 256 the size for message only ? if not, what is left for message only ?

It is the maximum size of an entire packet.  In publish() this check is done:
if (MQTT_MAX_PACKET_SIZE < MQTT_MAX_HEADER_SIZE + 2+strlen(topic) + plength) {

So the maximum length of a message payload will be
MQTT_MAX_PACKET_SIZE - MQTT_MAX_HEADER_SIZE - 2 - strlen(topic)

MQTT_MAX_HEADER_SIZE is defined as 5, so if you have, for example, a 20 character topic you would have 256 - 5 - 2 - 20 = 229 bytes left for your payload.


text:
How do I set up an Arduino to be a wireless HID?
The question below describes how to set up an Arduino as an HID (Human Input Device -- like a keyboard, mouse, etc.).  How can I set up an Arduino as a wireless HID?
I'm flexible as to the wireless format.  Bluetooth, USB receiver, or any other format is acceptable.
Arduino as USB HID

This has been done with ESP32. If you connect a bluetooth module to the Arduino, that might work as well.

@ThomasWeller, this looks like what I need.  If you make it into an answer I'll accept it.

I'm not sure for Arduino, but it has been done with ESP32. If you have not yet spent the money into a Bluetooth module for Arduino, you'll find that the ESP32 is not expensive either.
You can find the code on Github. The author uses a TinyPico because it's pin compatible with one of his earlier projects. IMHO, any ESP32 should do as well.
The key thing is to
#include <BleKeyboard.h>

the ESP32 BLE Keyboard library that you need to download and install. That library comes with example code that should be easy to adapt to your needs.
You can program the ESP32 in Arduino IDE, but you need to add support for the boards by adding a URL to the board manager.
Have fun with the project. It sounds very interesting. Maybe I try that myself.


text:
Arduino Micro: Button inputs are not working!
I have no clue why this is happening to me but the buttons (in this case, buttonAbort and buttonStage) are not working whatsoever.
Edit:
Basically the LEDs are placed right next to the button,(e.g. ledStage -> placed next to the buttonStage) they start to blink when the timer hits zero with a buzzer noise, and if the user presses one of the buttons, the buzzer noise stops and the LED placed next to the button they pressed turns on whereas the other turns off. I also connected the buttons without resistors. (directly to the pins)
/*
   Jebediah's Launch Control System for Kerbal Space Program
   Alpha Build 2.00
   An Open-Source Project by John Seong
*/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>

const byte ROWS = 4;
const byte COLS = 3;

const int buzzer = A3;
const int ledAbort = 5;
const int ledStage = A5;
const int buttonAbort = 4;
const int buttonStage = A4;

char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[ROWS] = {12, 11, 10, 9};
byte colPins[COLS] = {8, 7, 6};

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// Show a two-line message on the LCD.
void lcdShow(const char *line0, const char *line1) {
  lcd.clear();
  lcd.print(line0);
  lcd.setCursor(0, 1);
  lcd.print(line1);
}

void lcdShowResult(float result) {
  lcd.print(result);
}

void setup() {
  pinMode(buzzer, OUTPUT);
  pinMode(ledAbort, OUTPUT);
  pinMode(ledStage, OUTPUT);
  pinMode(buttonAbort, INPUT_PULLUP);
  pinMode(buttonStage, INPUT_PULLUP);

  Serial.begin(9600);
  lcd.begin(16, 2);
  while (!keypad.getKey()) ;  // wait for key press
}

void loop() {
  static enum {START, MENU, SET_COUNT, COUNT_DOWN, LAUNCH, SET_THRUST, SET_WEIGHT} state = START;
  static uint32_t last_second;  // millis() value on last full second
  static int count;
  static float thrust, weight, ratio;

  int stageConfirm = digitalRead(buttonStage);
  int abortConfirm = digitalRead(buttonAbort);

  char key = keypad.getKey();

  switch (state) {
    case START:  // transitional state
      lcdShow("1. LAUNCH SEQ", "2. TWR CALC");
      state = MENU;
    /* fallthrough */

    case MENU:
      if (key == '1') {  // Countdown
        lcdShow("COUNTDOWN TIMER", "SECONDS: ");
        count = 0;
        state = SET_COUNT;
      } else if (key == '2') {  // TWR
        lcdShow("TWR CALCULATOR", "THRUST: ");
        thrust = 0, weight = 0, ratio = 0;
        state = SET_THRUST;
      }
      break;

    case SET_COUNT:
      if (key >= '0' && key <= '9' && count <= 99) {
        lcd.print(key);
        count = 10 * count + (key - '0');
      } else if (key == '#') {
        lcdShow("    T-MINUS", "     SECONDS");
        // Force a refresh on entering COUNT_DOWN:
        last_second = millis() - 1000;
        count++;
        state = COUNT_DOWN;
      } else if (key == '*') {
        state = START;
      }
      break;

    case COUNT_DOWN:
      if (millis() - last_second >= 1000) {
        last_second += 1000;
        count--;
        if (count <= 10) {
          tone(buzzer, 500);
          delay(500);
          noTone(buzzer);
        }
        if (count == 0) {
          Serial.println("Lift off!");
        } else if (count < 0) {
          state = LAUNCH;
          break;
        }
        lcd.setCursor(1, 1);
        lcd.print(count < 10 ? "  " : count < 100 ? " " : ""); // pad
        lcd.print(count);
      } else if (key == '*') {
        state = START;
      }
      break;

    case LAUNCH:
      tone(buzzer, 3000);
      digitalWrite(ledAbort, HIGH);
      digitalWrite(ledStage, HIGH);
      lcdShow(" T-ZERO WARNING", "CONFIRM IGNITION");
      delay(1000);
      lcd.clear();
      digitalWrite(ledAbort, LOW);
      digitalWrite(ledStage, LOW);
      delay(500);

      stageConfirm = digitalRead(buttonStage);
      abortConfirm = digitalRead(buttonAbort);

      if (stageConfirm == LOW) {
        noTone(buzzer);
        digitalWrite(ledStage, HIGH);
        digitalWrite(ledAbort, LOW);
        lcdShow("  LIFT OFF", "HAVE A SAFE FLIGHT");
        break;

      } else if (abortConfirm == LOW) {

        break;
      }
      Serial.println(stageConfirm);
      Serial.println(abortConfirm);

      break;

    case SET_THRUST:
      if (key >= '0' && key <= '9' && thrust <= 9999) {
        lcd.print(key);
        thrust = 10 * thrust + (key - '0');
      } else if (key == '#') {
        lcdShow("TWR CALCULATOR", "WEIGHT: ");
        state = SET_WEIGHT;
      } else if (key == '*') {
        state = START;
      }
      break;

    case SET_WEIGHT:
      if (key >= '0' && key <= '9' && weight <= 9999) {
        lcd.print(key);
        weight = 10 * weight + (key - '0');
      } else if (key == '#') {
        lcdShow("THRUST-TO-WEIGHT", "RATIO: ");
        if (thrust != 0 || weight != 0) {
          ratio = thrust / weight;
          lcdShowResult(ratio);
        }
      } else if (key == '*') {
        state = START;
      }
      break;
  }
}

Try printing the values of stageConfirm and abortConfirm right after you read the buttons and see if they read what you think they should.  Your logic in your if statements seems weird to me, if the stageConfirm button is not pressed OR if the abort button IS pressed then say "Have a safe flight".  Seems to me like pressing the abort button should not lead to a liftoff.

Show your wiring as well.

That commented /* ... */ music stuff is distracting. Why do you keep it? Would you mind creating a copy of your program and remove everything that is not related to the button problem, e.g. the LCD intro in setup(). That would help as well.

Oh, it's supposed to be && not ||. Sorry for the confusion!

you have to explain what you expect the buttons to do

if buttonStage == 1 -> ledStage = 1, ledAbort = 0

if buttonAbort == 1 -> ledStage = 0, ledAbort = 1

Basically the LEDs are placed right next to the button,(e.g. ledStage -> placed next to the buttonStage)  they start to blink when the timer hits zero with a buzzer noise, and if the user presses one of the buttons, the buzzer noise stops and the LED placed next to the button they pressed turns on whereas the other turns off.

This code is reading the buttons at two places in loop(), but the
first time the results are ignored. Only the readings done in the LAUNCH
state can have any effect. The problem is that the reading is done only
at one very specific time, 1.5 seconds after displaying “CONFIRM
IGNITION”. If you press the button before or after this moment, it has
no effect.
Reading only once per loop iteration is fine, as long as the loop turns
fast enough, without getting stuck in a delay(). As a general rule,
you try to avoid delay() whenever you want to write a program that
should react to external events such as button presses. See the Arduino
example Blink without delay for a technique for achieving that. A
finite state machine is a good way to program without delays, and
fortunately you are already working with one. To detect a button press,
you typically use two distinct states:

a “wait for button press” state that is sensitive to the button
a “button has been pressed” state that is reached when the user
presses the button.

There can be multiple “button pressed” states if there are multiple
buttons to wait for. The transition from the “waiting” state to the
others is then conditioned on the button presses:
case WAIT_FOR_BUTTON_PRESS:
    if (digitalRead(button_1_pin) == LOW) {
        do_the_action_relevant_to_button_1();
        state = BUTTON_1_HAS_BEEN_PRESSED;
    } else if (digitalRead(button_2_pin) == LOW) {
        do_the_action_relevant_to_button_2();
        state = BUTTON_2_HAS_BEEN_PRESSED;
    }
    break;

Obviously you would choose state names that are more relevant for your
specific project.


text:
arduino due: how to read more than one byte at a time in serial uart with tfmini liar sensor
I'm trying read tfmini lidar sensor from arduino due board with uart. Here i can read only one byte at a time using serail.read() method but i need to read 9 byte at a time and store it in array. Means i don't want to repeat loop again and again to store byte by byte.

Serial is only one byte. If something send multiple bytes then you have to read each individual byte.

https://www.arduino.cc/reference/en/language/functions/communication/serial/readbytesuntil/

Majenko, That means i have to repeat the loop untill a would not get the last data!!!

You would have to repeat a loop. Not necessarily "the" loop. But it depends how "blocking" you are happy for your code to be.

Do we have any UART interrupt in arduino due board?

Yes but it is being used by the UART reception code. You do know the bytes get placed into a buffer, and you can read them any time you like, don't you?

No, i don't know, may you please share UART reception code to read data from the UART interrupt.


text:
How to make Serial.read() return an integer instead of an ascii value?
I want Serial.read() to return an integer instead of an ASCII value. For example, in the below code if I input 2, I want the output as 2 instead of 50
void setup(){
    Serial.begin();
}

void loop(){
    if(Serial.available()){
    int t = Serial.read();
    Serial.println(t);
}

your code does not compile because of a syntax error

Serial.read() returns a byte ... what that byte means to you, is not realted to that fact

If it's a single digit:
if (t >= '0' && t <= '9') {
    int numeric_value = t - '0';
} else {
    // Handle the input error.
}

You can use an alternate method like this
void setup()
{
Serial.begin(9600);
}
void loop()
{
 if(Serial.available()){
    String a = Serial.read();
    int b = a.toInt();
    Serial.println(b);
}


text:
How to control 2 micro magnetic actuators with esp12e
i want to control two micro magnetic actuators (just two coil where I want to flow current in +to- and-to+ each motor for wifi airplane) with esp12e
Do I need an h-bridge like l293d ?
Also I will be using mit app inventor any advice for it will nice:)))

Yes you need an H-bridge. "Any advice" is rather broad. This site works best for more narrow questions

Alternatively you can get by with half an H bridge but will need a power supply which can deliver positive, ground and negative voltages.  Your choice.

Thanks for your response but I noticed that l293d works on min.4.5v but I can provide 3.3v or 4v only:((


text:
Calculating the Distance between a Special Object and Center
I just want to detect a small object specified in the system and show the distance between it and the object. If I need to explain briefly; I want to detect a small object that I put on the foot of a bird when it approaches 10-15 meters to its cage and measure the distance between them. I plan to have a device that scans around, like a radar. When there is a special object approaching this tool 15 meters, I need to detect it and measure the distance between them. (for example, 12 meters now, and 9 meters after 3 seconds). I thought that if i use a very small (electromagnetic or infrared ray, etc.) signal emitted by the small object attached to the bird's foot, the continuously operating radar can detect this particular signal. Also, it should measure the distance between radar center and the signal. It's like a bluetooth device. But also, it should measure the distance between radar center and the signal.
But I could not find a sensor to do this. (I tried to explain briefly in the photo)

Do you think which product should i use or what should i do for this?
Thank you

How big a bird are we talking? Anything "active" will need a battery, and that will need a golden eagle to carry it on its ankle.

How long does it need to last?  A super cap is light and might last for minutes to hours.  But will eventually need an energy source.  Also, you never required a heading - only distance.  So any number of COTS technologies which indicate signal strength should work.

Dear @Majenko , Thank you for your comment. Unfortunately it’s not a golden eagle :( . I understood what you mean. I’ve been searching this subject. And I learnt that there are products to find out where homing pigeons went to by saving coordinates for weeks. I think saving enough energy in a small battery can be possible to do this. I just want it to work 2 or 3 hours

Dear @st2000 , Thank you for your comment. I want it to work 2 or 3 hours. And you're right about energy source. Do you think which product is the best to measure the distance in this situation? If you don't mind, could you please give a product name ?


text:
.toFloat() giving incorrect anwsers
I am broadcasting a fixed value float over a HC-12 radio which is then received by another HC-12 radio. I am then trying to convert that String to a Float which requires 6 decimal places. However, when I print the String value out and then the Float value out, I get two different answers.
Code:
    String lat=getValue(_msg, '|', 6); // Function to get lat value from incoming message
    Serial.println(lat);
    Serial.println(lat.toFloat(), 6);

This then results in the following values being displayed to the user:
51.507401
51.507396

The value 51.507401 is the correct value, so I would ideally like the float value to be the same.

A float is only an approximation. That is as close as it can get.

Is there anyway to get closer? Even .toDouble() gives the same result

There is no double on an Arduino. It's all float.

I would suggest not working in any form of floating point. Instead work in a fixed point. Use long and use the value x 1,000,000 or something like that.

Store 51.507401 degrees as 51507401 microdegrees

Thanks! I think I'll do that!

It seems the toFloat() method is being a bit sloppy in its conversion.
The float closest to 51.507401 is 51.5074005126953125, which is only
0.13 ulps off. The number you got is the float right before it,
namely 51.507396697998046875, which is 1.13 ulps off. Alas, the
avr-libc functions atof() and strtod() make the same error.
I would suggest first considering whether the error is really
significant for your application: it is only about 48 cm on the
surface of the Earth. If this level of accuracy is relevant for you,
then follow Majenko's suggestion and use an integer count of
microdegrees.


text:
Triggering a Sleep Wake-up Event using analog output from a triple axis accelerometer?
I am working on a project that uses a Arduino MKR GSM 1400 and a ADXL335 Accelerometer . I am having trouble setting a interrupt wake up event on one of the GSM's interrupt-capable pin due to the analog nature of the ADXL335's output. The axis outputs typically range between ~1.4V-~2.2V with ~1.65V being the resting voltage level.
I have tried using a NTE987 op-amp to amplify the analog output enough to trigger a CHANGE on the interrupt pin I'm using. This resulted in the analog signal outputted by the ADXL335 boosting to a certain voltage level and not varying at all with any motion.
My current solution, which works very well but is not ideal for power consumption reasons, is using a smaller micro controller with less power draw's ADC to interpret the ADXL335's output and send digital wake-up signals to the GSM when certain thresholds are met. I would like to know if there's a better way to do this, as using an additional microcontroller to wake up the original microcontroller feels like a kludge.

What is the power draw of the opamp? That opamps shouldn't draw that much current.

I'm not familiar with the SAMD21. But some micro controllers have comparitors in them that can trigger an interrupt when the voltage gets above/below a certain value. I'm not sure what you are measuring with the accelerometer, but if the triggering motion isn't a short one, you could have the MCU sleep most of the time, and wake up, say, once a second to do a measurement.

this may help ... https://duckduckgo.com/?q=ultra+low+power+comparator&ia=web

You need to remove that 1.65V offset before amplifying it. The simplest way is to AC couple it with a capacitor.


text:
watchdog timer giving me fits on ESP8266, how to find relevant code from Serial output describing the RST?
I've written a pair of sketches for two NodeMCUs to implement a noise meter. The master MCU voltage samples off an opamp's output pin and periodically digests 500 samples at a time into an RMS-type calculation. Every 500ms or so, when it has accumulated 10 of those RMS samples, it sends off a packet with a timestamp and checksum to the slave MCU. This mostly works -- It's been running for about 4 and a half hours without a RST. However, I added a bit of logic recently to request an updated value from the slave and now I'm having trouble with the watchdog timer resetting the master MCU. These resets lose anywhere from a single packet to about 2 minutes of data.
NOTE: WiFi is disabled on this master MCU using a preinit function.
I've done some trial-and-error, including:

adding delay(1) to allow housekeeping and interrupts but this seems to introduce other instabilities
add calls to system_soft_wdt_feed() which has very little explanation in the docs.

Given that the problem is infrequent, it's quite difficult to reproduce the conditions for it to happen. There appears to be some perfect storm of unusual conditions that cause it to trigger. So my question is this:
Is there some way to determine from the serial monitor output where the watchdog timer is firing? And a follow-on question what does this wdt output (boot mode, csum, etc) mean? Here are a handful of watchdog timer messages I see in the serial monitor when the reset happens:
ets Jan  8 2013,rst cause:4, boot mode:(3,2)

wdt reset
load 0x4010f000, len 3456, room 16
tail 0
chksum 0x84
csum 0x84
va5432625
~ld
--
 ets Jan  8 2013,rst cause:4, boot mode:(3,2)

wdt reset
load 0x4010f000, len 3456, room 16
tail 0
chksum 0x84
csum 0x84
va5432625
~ld
--
 ets Jan  8 2013,rst cause:4, boot mode:(3,2)

wdt reset
load 0x4010f000, len 3456, room 16
tail 0
chksum 0x84
csum 0x84
va5432625
~ld
--
 ets Jan  8 2013,rst cause:4, boot mode:(3,2)

wdt reset
load 0x4010f000, len 3456, room 16
tail 0
chksum 0x84
csum 0x84
va5432625
~ld
--
 ets Jan  8 2013,rst cause:4, boot mode:(3,2)

wdt reset
load 0x4010f000, len 3456, room 16
tail 0
chksum 0x84
csum 0x84
va5432625
~ld
--
 ets Jan  8 2013,rst cause:4, boot mode:(3,2)

wdt reset
load 0x4010f000, len 3456, room 16
tail 0
chksum 0x84
csum 0x84
va5432625
~ld
--
 ets Jan  8 2013,rst cause:4, boot mode:(3,2)

wdt reset
load 0x4010f000, len 3456, room 16
tail 0
chksum 0x84
csum 0x84
va5432625
~ld

As you can see, the RST output seems quite consistent, I just have no idea how to locate the point in my code where code execution goes on too long. The docs here have a stack trace associated with these resets if they are triggered from the software watchdog, but my serial monitor output does not have these stack traces, which suggests that it's the hw watchdog that's doing it. That page says:

Please note that for restarts initialized by h/w wdt, there is no stack trace to help you identify the place in code where the lockup has happened. In such case, to identify the place of lock up, you need to rely on debug messages like Serial.print distributed across the application.

Sadly, I don't know how wise it is to use Serial.print in my loop. The code inside my loop() completes in an average of about 5 microseconds so the output might be extremely verbose. In practice, adding Serial.print commands to track things tends to destabilize the sketch even more, dwarfing the problem I'm trying to solve.
The sketch is pretty lengthy, but its code is here. I've removed the comments for brevity, but it's still about 500 lines. I'm happy to post that code in this post, but worry it might make this post too long.
EDIT: If this is indeed the hardware watchdog that's firing, I would add a question: Is it possible to disable the hardware watchdog or somehow adjust its behavior? I am certain that my app is not locked up because its output continues to be communicated to the slave which posts the samples to a web server. Is the only solution to allow the loop function to complete more frequently?
EDIT: I added a timer which checks micros() at beginning and tracks the maximum amount of time to execute the loop. Usually, this is less than 2500 microseconds, although in one case it took 100ms -- but this did not cause a watchdog reset. The hardware watchdog reset doesn't appear to be related to how much time it takes to execute my loop function. It's something else.
EDIT: I updated my ESP8266 core to 2.7.2 and this did not solve the problem. I would add an additional question: Why is the hardware timer firing and not the software timer?. I have not disabled the software watchdog, and I have no indications that there are any infinite loops preventing completion of the main loop() routine.

system_soft_wdt_feed appears to be related to some type of a software watchdog timer ... that particular command pospones the software WDT reset ... i have a suspicion that it is different from the hardware WDT ... it is unclear if the software WDT triggers the hardware WDT

@jsotola I agree. It would appear from the docs here that software watchdog resets come with a stack trace, but hw wdt resets do not. Also, I have tried numerous calls to system_soft_wdt_feed() and these don't seem to remedy the problem. Sounds like hw watchdog to me, too. Is there any way to disable it? Or appease it somehow?

googled esp8266 feed watchdog ... found this ... https://techtutorialsx.com/2017/01/21/esp8266-watchdog-functions/

@jsotola I've read that, and it mostly just refers back to the docs i linked. It does provide a bit of additional detail -- e.g., the argument to ESP.wdtEnable() isn't even used -- but it does not provide any detail about how to pinpoint the code where timeouts are happening, or how hw wdt works or how to adjust its behavior.

it shows you that disabling the software WDT allows the hardware WDT to take over .... it also shows you how to feed the hardware watchdog .... feed the watchog at the begining of loop() ... if that is not enough, feed near middle of loop() also .... otherwise time your loop and find out how much time various parts use

@jsotola ahhhh I missed the part where it says the feed function also feeds the hw wdt. If you look at the source I linked, you'll see that I'm already calling system_soft_wdt_feed() in at least a couple of spots and also that the entire loop() runs in an average of 5 microseconds. Any thoughts on where to put yet another call to system_soft_wdt_feed?

maybe the way to debug this is to determine the baseline ... write a minimal sketch that only includes a delay ... vary the delay to find out where the hardware WDT fires  ... start with 8 seconds ... add or subtract 4 seconds, then 2 seconds, then 1, then 0.5, etc. .... you do not have to run too many iterations before you determine the delay to within a couple of milliseconds

i re-read that page and it is confusing .... this page https://sigmdel.ca/michel/program/esp8266/arduino/watchdogs_en.html says that the software watchdog feeds the hardware watchdog

@jsotola that sigmdel article looks pretty informative, but I can't imagine any situation that would cause my loop to run anywhere nearly as long as an entire second. also, i do not turn off the software wdt, so i don't know why the hw wdt would fire first. EDIT: I'm also calling the system_soft_wdt_feed fn in four places.

system_adc_read() can cause this if used frequently (in every loop). but I would not expect it if WiFi is off

@Juraj thank you for your response. WiFi is indeed off as you can see from the preinit fn in the  sketch. I also call WiFi.forceSleepBegin(0); in the setup fn.  I do use system_adc_read in the hw timer function which runs as often as possible -- every 100ns. However, it didn't cause any problems in a sketch that is only the tiniest bit simpler than this one. I find it puzzling that the hw watchdog would fire instead of the software watchdog.

then it hangs or crashes somewhere

if i take more than about 800 adc reads per second, the same thing happens to me. i put a 10u cap on it and lowered my sampling rate to fix it w/o much loss of signal.

@Juraj: if it hangs or crashes, shouldn't I see a stack dump? I don't see any stack dump, just the terse reset reports like I provided in my original post.

in corrupted stack anything can happen.

Juraj: i have repeatedly reloaded new code over the past week as I've tried various tweaks. i finally altered the loop() fn to remove the while loop that retried delivery of my data packets, leaving packet delivery to a subsequent loop iteration. i also removed a master-slave status exchange which seemed unecessary. it's been running for 17 hours now. I may have solved the problem, but my question remains unanswered. every crash has nearly the exact same rst message, which is in my original post.

I opened an issue at the 8266 arduino repo and got a response that's pretty high-handed, and wrongly accuses me of using third party libs or hardware, but also has some useful information. Ironic part: they told me to post on stack exchange.


text:
library problem ? how to solve this?
Arduino: 1.8.11 (Windows 10), Board: "ESP32 Dev Module, Disabled, Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS), 240MHz (WiFi/BT), QIO, 80MHz, 4MB (32Mb), 921600, None"
Multiple libraries were found for "WiFi.h"
 Used: C:\Users\User\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\libraries\WiFi
 Not used: C:\Program
 In file included from C:\Users\User\Documents\Arduino\libraries\async-mqtt-client-master\src/AsyncMqttClient.h:4:0,
             from C:\Users\User\Desktop\sketch_jul13a\sketch_jul13a.ino:3:

C:\Users\User\Documents\Arduino\libraries\async-mqtt-client-master\src/AsyncMqttClient.hpp:9:22: fatal error: AsyncTCP.h: No such file or directory

compilation terminated.

exit status 1
Error compiling for board ESP32 Dev Module.

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

Not used: C:\Program - is that where you put your Arduino code, or is something going wrong with C:\Program Files (x86)?

sir what i have to do for this ? pls tell

i updated the ide but again it show same error

Then install the Async TCP library, or whag ever library gives you the file AsyncTCP.h. The compiler complains, that the file is missing, so most likely you didn't install all the needed libraries

do what it tells you to do at the end of the printout


text:
Using sim900a GSM module, sending data to xampp Database
I am using a soil moisture sensor, dht11, and a relay module. To send data to xampp (database) sever I used the sim900a GPRS module and wrote a PHP code as well. But it doesn't connect and pass data to the database.
what is the problem?
Ardunio code:
#include <SoftwareSerial.h>                           //GSM module Library
SoftwareSerial gprsSerial(7, 8);                      //GSm module pin configration
#include <String.h>                                   //Header file
#include <DHT.h>                                      //Moisture sensor library
#define DHTPIN A1                                     //Define humidity sensor as Analog pin 1
#define soilHumPIN A0                                 //Define Soil moisture sensor as Analog pin 0

DHT dht(DHTPIN, DHT11);                               //Specify the DHT sensor
int relayEnable = 4;                                  //Define the digital pin to which dc water pump is to be connected
int soilHum = 0;                                      //Integer to store soil moisture value.
int output_value ;                                    //Integer to store the output value of soil moiture sensor
int current_value;                                    //Integer to store current value of soil moisture sensor reading
int threshold = 320;                                  //set the threshold value = 320
const int analogOutPin = 8;                           //Set analog output pin to pin 1

void setup()
{
  gprsSerial.begin(9600);                             // the GPRS baud rate
  Serial.begin(9600);                                 // the baud rate
  pinMode(relayEnable, OUTPUT);                       //set relayEnable pin as OUPUT
  dht.begin();

  delay(1000);
}

void loop()
{
  float humid = dht.readHumidity();
  float t = dht.readTemperature();
  output_value = analogRead(soilHum);                 //read the value of soil moisture sensor and store it in output_value
  current_value = output_value;                       //set current_value equal to output_value
  output_value = constrain(output_value, 10, 1023);   //set the contrain on output_value. Minimum = 10 Maximum = 1023
  output_value = map(output_value, 10, 1023, 100, 0); //map the output_value
  analogWrite(analogOutPin, output_value);            //send the output_value to transmitter pin
  delay(100);

  Serial.print("Temperature = ");                     //Print Temperature
  Serial.print(t);                                    //Serial print
  Serial.println(" °C");                              //Print temperature in Celcius
  Serial.print("Humidity = ");                        //Print Humidity
  Serial.print(humid);                                    //Serial print
  Serial.println(" %");                               //Print Humidity as a precentage value
  Serial.print("Soil Moisture = ");                   //print Moisture=
  Serial.print(output_value);                         //print the output_value
  Serial.println("%");                                //print %

if(current_value >=threshold)                                        //check if current_value >= 800

   {
    //if yes then
    Serial.println("\nWater Level Low... Turning Solenoid on..");       //print water level low.. turning water pump on..
    digitalWrite(relayEnable,LOW);                                     //turn on the dc water pump

   }
   else
   {
    //if no then
    Serial.println("\nWater Level High... Turning Solenoid off");       //print water level high.. turning water pump off..
    digitalWrite(relayEnable,HIGH);                                      //turn off the dc water pump

   }
   delay(10000);                                                        //create a delay of 10 second

  if (gprsSerial.available())
    Serial.write(gprsSerial.read());

  gprsSerial.println("AT");                           //Checking the status
  delay(1000);

  gprsSerial.println("AT+CPIN?");                    //Pin code of the sim is accepted or not
  delay(1000);

  gprsSerial.println("AT+CREG?");                   //Gives information about access technology
  delay(1000);

  gprsSerial.println("AT+CGATT?");                 //Attach or deattach pacakge domain service
  delay(1000);

  gprsSerial.println("AT+CIPSHUT");               //GPRS tcp contact
  delay(1000);

  gprsSerial.println("AT+CIPSTATUS");             //Reteun the connection status
  delay(2000);

  gprsSerial.println("AT+CIPMUX=0");              //Device single or multi ip address
  delay(2000);

  ShowSerialData();

  gprsSerial.println("AT+CSTT=\" \"");   //start task and setting the APN, for dialog APN is blank
  delay(1000);

  ShowSerialData();

  gprsSerial.println("AT+CIICR");             //bring up wireless connection
  delay(3000);

  ShowSerialData();

  gprsSerial.println("AT+CIFSR");           //get local IP adress
  delay(2000);

  ShowSerialData();

  gprsSerial.println("AT+CIPSPRT=0");   //echo is prompt or not
  delay(3000);

  ShowSerialData();

  gprsSerial.println("AT+CIPSTART=\"TCP\",\"IP/fruitinfo/insertDB.php\",\"3306\"");//start up the connection
  delay(6000);

  ShowSerialData();

  gprsSerial.println("AT+CIPSEND");         //begin send data to remote server
  delay(4000);
  ShowSerialData();

  //Sending data to server
  String str = "GET fruitinfo/insertDB.php";
  Serial.println(str);
  gprsSerial.println(str);            //begin send data to remote server

  delay(4000);
  ShowSerialData();

  gprsSerial.println((char)26);               //sending
  delay(5000);                                //waitting for reply, important! the time is base on the condition of internet
  gprsSerial.println();

  ShowSerialData();

  gprsSerial.println("AT+CIPSHUT");           //close the connection
  delay(100);
  ShowSerialData();
}
void ShowSerialData()
{
  while (gprsSerial.available() != 0)
    Serial.write(gprsSerial.read());
  delay(5000);

}

PHP code insertDB:
<?php

    require 'database_connection.php';

    if ( !empty($_POST)) {
        // keep track post values
        $soil_moisture = $_POST['soil_moisture'];
        $solenoid = $_POST['solenoid'];
        $humid = $_POST['humid'];

        // insert data
        $pdo = Database::connect();
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $sql = "INSERT INTO fruit_details (soil_moisture,solenoid,humid) values(?, ?, ?)";
        $q = $pdo->prepare($sql);
        $q->execute(array($soil_moisture,$solenoid,$humid,));
        Database::disconnect();
        header("Location: user data.php");
    }
?>

database_connection php code
<?php
    class Database
    {
        private static $dbName = 'fruitdb' ;
        private static $dbHost = 'localhost' ;
        private static $dbUsername = 'root';
        private static $dbUserPassword = 'hesn2412tutoo2';

        private static $cont  = null;

        public function __construct() {
            die('Init function is not allowed');
        }

        public static function connect()
        {
           // One connection through whole application
           if ( null == self::$cont )
           {
            try
            {
              self::$cont =  new PDO( "mysql:host=".self::$dbHost.";"."dbname=".self::$dbName, self::$dbUsername, self::$dbUserPassword);
            }
            catch(PDOException $e)
            {
              die($e->getMessage());
            }
           }
           return self::$cont;
        }

        public static function disconnect()
        {
            self::$cont = null;
        }
    }
?>

write a test sketch and test php script for testing the connection between the arduino and php server ... proceed with code for connecting to database only after connection to php server is established

@jsotola I have written a php code and modified arduino code using this command AT+HTTPPARA="URL","(http://axxxxxxxxxx.com/conn.php?&humid=87&temp=27.5&soil_moisture=76"r"). This will save in xampp database as  87, 27.5 and 76. To send another data I need to modifed above parameters manually. How to get the sensor values automatcally to post it in xampp database?


text:
Is there a variable type of half byte? Is there a workaround?
I have this long array of 64 values going from 0 to 15, values which only cost 8 bits, for a pulse width modulation.
So I made a test to see its cost in space, commenting one of the two arrays.
const byte wave[64] = {8,9,9,10,11,11,12,12,13,13,14,14,14,15,15,15,15,15,15,15,14,14,14,13,13,12,12,11,11,10,9,9,8,7,7,6,5,5,4,4,3,3,2,2,2,1,1,1,1,1,1,1,2,2,2,3,3,4,4,5,5,6,7,7};
//const byte wave[2] = {8,9};
byte i = 0;
void setup() {pinMode(1,OUTPUT);}
void loop() {            //(Don't worry about the code in here,
  analogWrite(1,wave[i]);//it's just to get the program
  i++;delay(1);          //to hold on to the data)
}

The compiler said Sketch uses 1112 and 1050 bytes (3%) of program storage space. or a difference of 62 bytes.
This tells me that one could save a lot of memory by keeping them in a 4-bit or what I'd like to call half byte, going from 0 to f rather than from 00 to ff.
How could I do so without turning the code to unreadable bit mush?

You can always use Nibbles. Just store on number in the first half of a byte and the other in the second half. to read it back, just shift and AND it with an appropriate mask.

I understand this can help, just wondering if the masking won't use also a lot of dynamic memory?

You could definitely stuff 64 of your 4-bit integers into a byte array with 32 slots, but if your plan is to specify the contents of that byte array as you have in your sample code, then it might not help much. If, on the other hand, you were reading your array of 4-bit integers from somewhere else (e.g., from flash memory or from a UART input) then you might be in luck. In declaring const byte wave[64] you've told your program to allocate 64 bytes and the ship has sailed.

If the compiler get's it right, it is just ONE additional instruction (AND) to read the right Nibble and TWO instructions (SWAP + AND) to read the left Nibble. So it takes 6 bytes more for your code, but on the other hand you save 32 bytes on your data.

That makes a lot of sense! So I should find a way to store these nibbles prior to having it in the program? Any way you can recommend?

Are you sure you don't have enough memory? How likely is it? Are you going to manufacture tens of thousands of it, or could you just buy a chip with more memory? Otherwise I'd say that's premature optimization.

I've actually came to something quite interesting by turning this array into a int variable. It's really long but with 64*4 bit it still fits! and I saved a whopping 186 bytes o_O

the data looks like a sine wave lookup table ... you only need to store a 1/4 wave

@jsotola True! But the actual data I'm working with is a bunch of multiple sine waves together hence the need for the full cycle.

I think you can use union which is part of C. The compiler will then do all the bit manipulations for you. But I not really that well versed in C. Maybe @Majenko can chime in.

Keeping your 4-bit values in half-bytes is doable using structs and bitfields. You'll want an access function to separate the "array index" into a byte-index and a nibble selector (the LSb of the "array index") and return or store the appropriate nibble.
This related question on StackOverflow has some answers showing ways to do this. There will be obviously be some overhead to unpacking 4-bit nibbles since they can't be addressed directly, but it will be minor and is the trade-off for saving memory when memory is scarce.

If the point is to save program storage space, you're probably going to have to live with some unreadable bit mush or do bit-swapping in your head. Here's a code example that encodes your same array as a 32-byte array, but you have to combine pairs of your original numbers into bytes. It's not especially difficult because each hex digit represents one of your original numbers.
I.e., 8,9 becomes 0x89. Likewise, A is 10, B is 11, etc. Then you can iterate 1 thru 64 and do some division and bit-shifting to pull out the original value you wanted. This will iterate through your 32-byte array and pull out 64 half-byte values.
    const byte wave[32] = {0x89,0x9A,0xBB,0xCC,0xDD,0xEE,0xEF,0xFF,0xFF,0xFF,0xEE,0xED,0xDC,0xCB,0xBA,0x99,0x87,0x76,0x55,0x44,0x33,0x22,0x21,0x11,0x11,0x11,0x22,0x23,0x34,0x45,0x56,0x77};
    for(int i=0; i<64; i++) {
        byte val;
        if (i % 2) {
            // the little byte is first (LITTLE ENDIAN)
            val = wave[i/2] & 0x0F;
        } else {
            // the BIG byte is second
            val = (wave[i/2] >> 4) & 0x0F;
        }
        Serial.printf("%i=%i\n", i, val);
    }

NOTE: that the Endianness if your system may be different than mine. Most systems are little-endian these days, but you never know.


text:
What do you do when you finish a project?
I have just about completed my first Arduino project using an Arduino Uno board, but is that what I use inside the finished device? I figured I’d keep the Uno for future projects and have something else controlling the finished product. Are you supposed to just keep purchasing the Uno board every project?
I just got it a couple of days ago so I’m not very familiar with any of it. If that is the case do you use the batter for power since I can’t have it connected to my laptop once it’s done.

https://majenko.co.uk/product/arduino-prototype-plus

There are many options, so it all ends up depending on your personal
preferences:

You could indeed dedicate this Arduino to this project, and buy a new
one for the next project. This may be the simplest solution, if not
the cheapest. Just make sure you are not using a breadboard for the
other parts. A “proto-shield” may be a good option for soldering the
rest of your circuit in a permanent form.

You may replace the Uno with a smaller Arduino, like the Micro (but
beware it uses a different MCU) or a Pro Mini clone (same MCU). These
smaller boards can then be soldered onto a PCB using standard 0.1” pin
headers.

You could buy a cheap clone, test it to make sure it works as intended
on this particular project, and dedicate the real one for further
prototyping.

You could get a bare ATmega328P plus crystal and caps and put them,
together with the rest of your circuit, onto a perf-board or a
strip-board. C.f. Michel Keijzers’ answer. Note that if your program
can run happily off a somewhat inaccurate 8 MHz clock, you can
use the MCU's internal oscillator instead of a crystal.

If your program is far from using all the resources of the Uno, you
may consider a smaller MCU. The ATtiny85 is a popular “minimalistic”
choice. Make sure an Arduino core is available for it, unless you want
to program all low-level.

For the most professional result, you could design and order a real
PCB for your whole circuit, including the MCU.

Regarding your fifth point: There are many people who have made available Arduino "cores" for the ATtiny85:  ATtinyCore by Spence Konde seems to be well-regarded. It does introduce a lot of extra options in the tools dialog. . ATtiny by David A Mellis is simpler.

Thanks a lot. I’m brand new to this so have no knowledge but I knew I could count on SE.

What you can do is:

Buy the main IC (Atmel 328P)
Use some external components to get it working (like a crystal). Check this on a breadboard to see if it works (and check.
Buy a case to put it in
Buy some protoboard or PCB to solder it on (or use a footprint)
For power, use some components (voltage regulator) or an adapter, or battery, whatever you need. Make sure you check this on a breadboard before you solder it.

If you want to read more about the subject, search for 'prototyping'.

I particularly like Adafruit's high quality proto-boards for my one-off builds. There are several sizes but the 1/2-breadboard size I linked to is the size I use most.

They seem very easy to convert from breadboard to proto board. If you have no space constraints,  those are probably the easiest.


text:
How to program ATmega4809 from Raspbeery GPIO
From this tutorial  I'm able to nicely program an ATmega328 using SPI raspberry GPIO pins. However, when I try the same steps with  ATmega4809, avrdude seems not having instructions and outputs the following:
program enable instruction not defined for part "ATmega4809"

So, how do I program ATmega4809 chip from Raspberry?

The ATMega4809 uses UPDI (Unified Programming and Debugging Interface) for programming, not ICSP like the older ATMega328P. You need a UPDI programmer.
There is a project jtag2updi which you can run on an Uno that turns it into a JTAG to UPDI adaptor which is then compatible with avrdude -c jtag2updi ....

But in that case, why does it have MOSI, MISO and SCK pins?
Also, I'm doing some experiments with Arduino Nano Every, which does not have UPDI pin available.

Because MOSI, MISO and SCK are SPI, not ICSP. It just so happens that on the ATMega328P those pins perform two functions: SPI and ICSP. But the two are not related in any way whatsoever.


text:
i2c high speed and pull-up resistors
hello guys i want to ask about 2 things
first one is i'm connecting and arduino uno attached to a usb host sheild and transferring data of a mouse coordinates to 10 arduino leonardo
i'm using the standard speed 100
normal mode
my wires is all about 10 cm long

i need to speed up the comm to fast mode
how to make this ? and the line of code where to put it in the code and in the master or slave ?

what about the pull-up resistors ? does arduino uno includes built in pull-up resistors ? does it needs to disable it and put my own pull up resistors ?
i’m using wire library

i need to speed up the comm to fast mode how to make this

Wire.setClock(400000);

and the line of code where to put it in the code

Just after Wire.begin() in setup().  Wire.begin() sets the speed to 100,000 and you need to then override that afterwards to set it to 400,000 (or whatever speed you want to run at).

and in the master or slave ?

In the master, since it's the master that generates the clock.

what about the pull-up resistors ? does arduino uno includes built in pull-up resistors ?

Yes, but they're too high for reliable I2C operation. You should add your own resistors in the region of 1kΩ.

does it needs to disable it and put my own pull up resistors ?

No, yours will just be in parallel with them, with the net result of a small reduction of overall resistance.

so i need a total of 2.2k ohm ? is it good enough ? so i will check in the data sheet the internal one and calculate to be in the total 2.2 ?

Each of SCL and SDA need a pullup in the region of 1kΩ to 4.7kΩ. I use 1kΩ. That's 1kΩ each, not two 1kΩ resistors in series. The internal pullups are so big you can ignore them.

even if i’m having 10 slaves arduino leonardo i will put a1kohm on each scl and sda ?

There is only 1 scl and 1 sda.

yes i know that , i mean the external resistor is depending on the number of devices of slaves and the distance between them and the seed of clock so if there’s 10 slaves of leonardo of 50k ohm each internal resistor sobthe number is huge

With 11 devices each with 30-50kΩ pullups internally the total resistance without adding any external pullups will be between 2.2kΩ and 4.7kΩ approximately. You may get away without adding any external pullups in that case.


text:
Continuous voltage on IO Pins while 5V is not Connected?
i have a small project where i just sucessfully destroyed my frist of 5 Digisparks (Attiny85).

In the Picture you see the Cirucit. I have 2 Liion cells connected in series to get high enough voltage to step it down to constant 5V. To these 5V some Neopixels and a Digispark controller are connected which will set the color for the Neopixels. A0 and A1 measure the Voltage of the Cells to signal the user if the Voltage is to low so it can manually be switched of.
While prototyping it i didnt have the 10k resistors in there.
Now what happend: While connecting the cells after each other the Controllers LEDs already lit up with the Frist cell. I guess it was powered trough the A0 pin (again i didnt have the 10k resistor in there),  so i guess the internal IO Protection diodes conductet the voltage trough and this way the controller got damanged. Since this happend it wont turn on Anymore.
The problem: since i have really small space i cant use a multiple pole switch to also remove the voltage from the IO pins and therefore i will always have voltage von A0 and A1 while there is no 5V Supplyvoltage. I would guess that the Series resistance on the pin would be enough to Limit the current trough them and this way protect the controller from damange. But i dont really have experience with that and hope that you guys can give me some hints what could also be a problem or what could help :) I really dont want to destroy a second one xD
Thanks in advance and have a nice day :)

You are correct in your analyses of the original problem. The 10k resistor should be fine, as it would only let through 0.4mA. Though it's not exactly elegant. This current might be a problem for the bottom battery, if it's left turned off for a long time. As it would slowly drain the battery.

@Gerben I thought the analog inputs on most Arduino boards were capacitive, so the current flow is near zero? (I guess if the board is off, the pin might be operating as a digital output on LOW, which would connect it to ground.)

Normally in this situation you would isolate the connections to the batteries with P-channel MOSFETs and only switch them on when you want to sample the voltage.

@DuncanC the problem here were the clamping diodes inside the IC on each IO pin. So the 3.7V was going into the pin, though the clamping diode, to Vcc. Powering the entire circuit through this diode. This can work for a few milliamps, but with the LED strip, the diode won't survive for long.

That makes sense. I forgot about the clamping diodes providing a path for inputs going to VCC.

For this I would recommend isolating the power from the batteries with P-channel MOSFETs and only switching them on when you want to sample the voltage. This means that there is no power consumption at all (aside from an absolutely minuscule leakage current) when turned off.
The whole setup would require 4 MOSFETs - two P-channel and two N-channel. They don't need to be big, since the currents involved are very small, but they do need to have "logic level" thresholds, ideally < 1.5V (-1.5V for the P-channel).
The basic circuit looks like this:

simulate this circuit – Schematic created using CircuitLab
The circuit is made up of two identical segments - M1+M3 and M2+M4.  The operation is fairly straightforward:

M1 (M2) is kept in the OFF state by R1 (R2) pulling the gate up to source.
M3 (M4) can pull the gate of M1 (M2) LOW turning it on and allowing current to flow
Any GPIO pin (D7 in this example) can control both M3 and M4 together
R5 keeps M3 (M4) off when there is no power - otherwise it floats.
R3/R4 are your existing voltage divider.

The purpose of M3 and M4 is to both turn the GPIO (D7) into "open drain" so that it's either pulling down or floating high (rather than driving high at 5V) and to isolate the two pullup gate voltages. The same effect could be achieved by two diodes and one MOSFET but it's simpler to just use two MOSFETs and not have to get diodes as well.

Wooow, didnt expect such a detailed answer, thanks very much.

Sendt out the last comment before i wanted xD so here the rest:
Now i have to order some common logic level mosfets :')
Since im using a mechanical switch to turn off the power i guess i would still have to assure that Pin D7, in this example, would be low when i switch off, because if not it would still be connected to the pin for a split second. Any thoughts on this ? :)

You can keep the inline current limiting resistors for that.

Also you would only have the FETs turned on briefly when you're doing the reading of the battery voltage, and off the rest of the time.

As a general rule, you should not apply a higher voltage to the logic pins of digital ICs than you do to their power pin. This means that if you disconnect power, you must also shut off voltage to the logic pins.
Failure to follow that rule will often destroy an IC.
I don't know about the specifics of the inputs on your DigiSpark. 10K resistors will certainly lower the current that is able to flow into those pins, but you would still be breaking the "don't put more voltage into an input pin than you put into the VIN pin" rule.

If all you are doing with A0/A1 is 'signalling the user that the voltage is too low for continued operation', then consider the following:

remove the lead from the top of the lower battery entirely
instead of the 1/1 voltage divider, use something like 10/1 (i.e. a 680K on top and a 68K on the bottom to provide a large series resistance (making the steady-state current drain on the battery negligible).  This will also put the nominal full-charge voltage as measured at the ADC input well within the DC voltage range of the Digispark at a small cost in accuracy.  The specs for the ATiny85 ADC input impedance is something like 100 MegOhms, so the accuracy drop from using a 680K series resistor shouldn't be more than a few percent.  Use a variable power supply to calibrate the A/D setup so your controller will alert the user when the battery stack gets low.  If you don't have a variable power supply, consider something like this

Frank

Jeah, measureing only the top cell is great if you always use "married cells" and have some puffer for inaccuarcy, but since i plan to make the Cells swappable i think in my application i should always monitor both cells.

Miss-matching battery types is usually a very bad idea, but if you must, measure both voltages with high-ratio voltage dividers as described above in order to make the current drain through the divider comparable to the self-discharge current of the batteries.


text:
TI ADS7250 Read From SPI and SPI1 Simultaneously
I'm so confused by the ADS2750 datasheet here, I can't seem to figure the proper bit shift to read data from bits 15-27 properly. I'm not even sure what some of the acronyms mean on page 23 table 1. I get that the first 15 bits are empty while the ADC takes a reading and then the last 12 bits for the 12 bit ADC are the value from that ADC that matches the SPI A or B input. Would someone be willing to explain to me how you would read data based on this datasheet using information from table 2 page 24?
My hardware set up to ADC7250
VCC 5 Volts

D5 SS fro Both SPI & SPI1
D13 SCK for Both SPI & SPI1
D11 MISO SPI_A from ADC
D4 MISO SPI_B from ADC
No MOSI connected

I'm not sure what to send in the SPI.Transfer(0x00). I'm also not sure if I'm setting up the modes properly, SPISettings settings(24*MHZ, MSBFIRST, SPI_MODE1); as I not 100% on the clock speed. I also I'm confused if this is LSB or MSB as the datasheet has two conflicting notes, the transfer function used LSB and then two paragraphs say "MSBs of ADC_A and ADC_B are output"
I'd love some help decoding this data sheet and getting a script that can read data from this chip using both SPI and SPI1 simultaneously.
Working on only reading SPI first the will add SPI1.
unsigned int readRegister(byte thisRegister, int bytesToRead);

const int CS_ADC_ISOLATOR = D5;
__SPISettings settings(24*MHZ, MSBFIRST, SPI_MODE0);
const int buffersize = 30;
unsigned char dataBuffer [buffersize];
const byte READ = 0x22;

// setup() runs once, when the device is first turned on.
void setup() {
  Serial.begin(115200);
  pinMode (CS_ADC_ISOLATOR, OUTPUT);
  digitalWrite (CS_ADC_ISOLATOR, HIGH);
  SPI.begin();
  SPI1.begin();
}

// loop() runs over and over again, as quickly as it can execute.
void loop() {
    digitalWrite (CS_ADC_ISOLATOR, LOW);
    SPI.beginTransaction(settings);
    for(unsigned char i = 0; i < buffersize; i ++)
    {
        dataBuffer[i] = SPI.transfer(0x00 << 14);
    }
    digitalWrite (CS_ADC_ISOLATOR, HIGH);
    SPI.endTransaction();
    for(unsigned char n = 0; n < buffersize; n ++)
    {
        Serial.print(dataBuffer[n]);
    }
    Serial.print("::");
}

You can't use the normal SPI library for communicating with this device properly. Well, you can, but you will only be able to use one channel - the other will be completely ignored.
SPI only works on one MISO pin - you need two.  There are two other types of "SPI" that are used by devices, most notably SPI flash chips: DSPI and QSPI (dual SPI and quad SPI). You want DSPI.
Unfortunately the Arduino doesn't do DSPI, so you will have to "bit bang" it, which means manually manipulating the IO pins to create your own SPI signals in software.
Now... on to the datasheet:
The important part is the timing diagram on page 9. From that you can see that you just send 32 clock pulses and the chip responds, after 15 pulses, with the data.
So if you just do 4 8-bit transfers back-to-back then you get the data. It doesn't matter what you "send" in those transfers since the MOSI pin isn't connected to anything.
As far as speed goes, 24MHz is the maximum speed that it will run at. The actual speed is dictated by the Arduino and how fast you manipulate the SCK pin. That can be as slow as 1x10-1000Hz if you really want.
Data should be read on the falling edge of SCK.
So you could write a little routine that looks like:
uint32_t resa = 0;
uint32_t resb = 0;

pinMode(SCK, OUTPUT);
pinMode(SDI_A, INPUT);
pinMode(SDI_B, INPUT);
pinMode(CS, OUTPUT);
digitalWrite (CS, HIGH);

digitalWrite (CS, LOW);
for (int i = 0; i < 32; i++) {
    digitalWrite(SCK, HIGH);
    digitalWrite(SCK, LOW);
    resa <<= 1;
    resb <<= 1;
    resa |= digitalRead(SDI_A);
    resb |= digitalRead(SDI_B);
}
digitalWrite (CS, HIGH);

Serial.print("A: "); Serial.println(resa);
Serial.print("B: "); Serial.println(resb);

So for 32 iterations you pulse the clock HIGH then LOW, then shift each result 1 bit to the left, and then add in the newly read bit into the lowest bit position.
You could speed up operation by using direct port manipulation and avoiding the slow digitalWrite() and digitalRead() functions.

Let's say I selected an MCU with DSPI, it has SPI and SPI1 capabilities, would I be able to use the SPI library then or would bit danging be my best beat still? I'm using a Particle Boron which has DSPI.

No, that doesn't have DSPI (or if it does, you can't tell from that picture. That has two independent SPI channels. That's not DSPI. DSPI, and QSPI, are just one channel, but with multiple data pins on the one channel.

So I'm going to have to bit dang... dang. How would you recommend holding CL low for the correct amount of time without a delay? I'd like something that checks the data and pulls CS pin HIGH again based data's status, but can't confidently think of a solution.

Sorry, I don't understand. You just lower CS, send your clocks and read the data, then raise CS again. There's nothing to "check".

Ok, so I should be able to drow CS low fro 32 CLK cycles and read the data coming from the ADC into any GPIO instead of the standard SPI library. The Boron uses a nRF52840 datasheet page 399 talks about the SPI bus and page 286 talks about the Quad serial peripheral interface. What I understood from reading 6.19 is that the QSPI is not useful here because teh two SPI buses are designed for memory and won't be able to share a single CLK. What recommendation do you have to reading a ADC with two SPI MISO inputs?