text:
Running a motor for a 3 seconds continuously with and without interrupt
I have interfaced a dc motor and IR sensor to my nano. The DC motor is supposed to run only if the IR sensor detects an obstacle. Now, I'm trying to get the motor to turn off if continuously obstructed for 3 seconds, and exit the interrupt (in case of the first code with interrupt), and again wait for the sensor to go low again (falling edge). I have implemented this using millis(), but the code doesnt seem to be working consistently, as the timing seems to have gone for a toss (random behavior; sometimes it keeps running continuously and sometimes it stops) . Can anyone on this forum please review it and suggest me a correction. Also, would it be possible to use a LOW trigger instead of falling edge to achieve this ?
#include <LowPower.h>

const int out1 = 5; //motor
const int IRSensor = 3; // connect ir sensor to arduino pin 6
const int LED = 6; // conect Led to arduino pin 9
const int Switch = 2;
const int Mspeed = 175;//0-255
const int Mtime =1500;//500-1000
int statusSensor=1;
int switchSensor=1;
unsigned long prevTime;
volatile int count =0;
volatile int count1=0;
volatile int count2 =0;
volatile int count3=0;
volatile int buttonstate=0;
volatile int lastbuttonstate=0;
volatile bool flag=false;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(out1,OUTPUT);
  //pinMode(out1,OUTPUT);
  pinMode (IRSensor, INPUT); // sensor pin INPUT
  pinMode (LED, OUTPUT); // Led pin OUTPUT
  pinMode(Switch, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(IRSensor),IRinterrupt,FALLING);
}

void loop() {
  // put your main code here, to run repeatedly:
  LowPower.powerDown(SLEEP_FOREVER , ADC_OFF, BOD_OFF);
  delay (100);
  if (flag==true){
  //Serial.println("true");
  switchSensor = digitalRead (Switch);
  //Serial.println ("zloop");

  statusSensor = digitalRead (IRSensor);
  //Serial.println (statusSensor);
  if (count1==1)
  { prevTime = millis();
    Serial.println(prevTime);
  }
  if (millis() - prevTime >= 1000)
  { doSomethingElse();
    Serial.println("going to else");
  }
  }
  //prevState = digitalRead(IRSensor);
  doSomething();

}

void IRinterrupt(){

   flag=true;
  }

void doSomething(){
  buttonstatus();
  if (statusSensor == 0 and switchSensor == 0 and count3==0){

     analogWrite(out1,Mspeed);
     //digitalWrite(out1,HIGH);
     count1=count++;
     Serial.println(count);
     digitalWrite(LED, LOW);
  }
   else if (statusSensor == 0 and switchSensor == 1) {

      //digitalWrite(out1,LOW);
      digitalWrite(LED, HIGH);
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      }
   else if (statusSensor == 1 and switchSensor == 0) {

      //digitalWrite(out1,LOW);
      digitalWrite(LED, LOW);
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      }
    else {
      //Serial.println ("ir high");
      //digitalWrite(out1,LOW);
      digitalWrite(LED, HIGH);
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      buttonstatus();
      }
}
void doSomethingElse(){

      //Serial.println ("ir high else");
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      count2++;
      count3=count2;

      //analogWrite(out1,0);
  }

void buttonstatus(){
  buttonstate=digitalRead (IRSensor);
   if (buttonstate != lastbuttonstate) {
    // if the state has changed,
    if (buttonstate == LOW) {
      count3=0;
    }
    delay(50);
   }
   lastbuttonstate = buttonstate;
}

I have written another piece of code without interrupts. How do I achieve the same timing part for this too ?
int out1 = 5; //motor
int IRSensor = 3; // connect ir sensor to arduino pin 6
int LED = 6; // conect Led to arduino pin 9
int Switch = 2;
int statusSensor=1;
int switchSensor=1;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(out1,OUTPUT);
  //pinMode(out1,OUTPUT);
  pinMode (IRSensor, INPUT); // sensor pin INPUT
  pinMode (LED, OUTPUT); // Led pin OUTPUT
  pinMode(Switch, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:
  switchSensor = digitalRead (Switch);
  //Serial.println (switchSensor);

  statusSensor = digitalRead (IRSensor);
  //Serial.println (statusSensor);
  delayStart = millis();
  //Serial.println ("ir interupt");

   if (statusSensor == 0 and switchSensor == 0){
     Serial.println ("ir low");
     analogWrite(out1,120);
     digitalWrite(LED, LOW);
   }
      else {
      Serial.println ("ir high");
      analogWrite(out1,0);

      }

}

EDIT: I have now successfully implemented the code (without interupts) with timing part in the code below.Also, I have updated the first code in the post with interrupts, but I am not able to get the timing part working. Can, someone please help me how timing can now be done with interrupts, so that the arduino nano is in sleep, until it receives a falling edge on the interrupt pin from the IR sensor, so that it can process the next part. Doing so I believe I would save power consumed since its on all the time.
const int out1 = 5; //motor
const int IRSensor = 3; // connect ir sensor to arduino pin 6
const int LED = 6; // conect Led to arduino pin 9
const int Switch = 2;
const int Mspeed = 175;//0-255
const int Mtime =1500;//500-1000
int statusSensor=1;
int switchSensor=1;
unsigned long prevTime;
volatile int count =0;
volatile int count1=0;
volatile int count2 =0;
volatile int count3=0;
volatile int buttonstate=0;
volatile int lastbuttonstate=0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(out1,OUTPUT);
  pinMode (IRSensor, INPUT); // sensor pin INPUT
  pinMode (LED, OUTPUT); // Led pin OUTPUT
  pinMode(Switch, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(100);
  switchSensor = digitalRead (Switch);
  statusSensor = digitalRead (IRSensor);
  if (count1==1)
  { prevTime = millis();
    Serial.println(prevTime);
  }
  if (millis() - prevTime >= Mtime)
  { doSomethingElse();
    //Serial.println("going to else");
  }
  doSomething();

}

void doSomething(){
  buttonstatus();
  if (statusSensor == 0 and switchSensor == 0 and count3==0){

     analogWrite(out1,Mspeed);
     //digitalWrite(out1,HIGH);
     count1=count++;
     Serial.println(count);
     digitalWrite(LED, LOW);
  }
   else if (statusSensor == 0 and switchSensor == 1) {

      //digitalWrite(out1,LOW);
      digitalWrite(LED, HIGH);
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      }
   else if (statusSensor == 1 and switchSensor == 0) {

      //digitalWrite(out1,LOW);
      digitalWrite(LED, LOW);
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      }
    else {
      //Serial.println ("ir high");
      //digitalWrite(out1,LOW);
      digitalWrite(LED, HIGH);
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      buttonstatus();
      }
}
void doSomethingElse(){

      //Serial.println ("ir high else");
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      count2++;
      count3=count2;

      //analogWrite(out1,0);
  }

void buttonstatus(){
  buttonstate=digitalRead (IRSensor);
   if (buttonstate != lastbuttonstate) {
    // if the state has changed,
    if (buttonstate == LOW) {
      count3=0;
    }
    delay(50);
   }
   lastbuttonstate = buttonstate;
}

Comments are not for extended discussion; this conversation has been moved to chat.

Your interrupt code looks reasonable, except that once you set flag to true you never set it back to false again. You need a way to identify the the IR sensor is no longer active.
Perhaps change your interrupt to fire on a change of state and set the flag to true when it switches to LOW (like it does no) and false when it switches back to high? I'd need to know more about your IR sensor to tell you exactly what to do, but I can tell you that the way your coe is currently written, once you detect the first falling edge on the IRSensor pin, your flag will switch to true and never change back to false.
I also don't understand what all the if/else if/else if logic is supposed to do, so can't really tell if you have any coding errors there.

I'm using an IR sensor which goes low only when an obstacle is detected. There is also float switch (switchsensor) which when goes high (tank being empty), the motor is supposed to go off and turn on an LED. That is why multiple if else statements are there. The same code without the interrupt part (flag) works fine, wherein the motor stops if continuously running for 1.5 seconds. But with interrupt in place, the timing part doesn't work.

Again, your code sets flag=true in the interrupt code, but never sets flag=false. That is wrong.


text:
Trying to draw a bitmap to an LED matrix only draws the left half
I'm EXTREMELY new to Arduino and fairly new to programming as a whole, but I thought it would be fun to try and write a program that draws arbitrary 1-bit bitmaps to an LED matrix using the Adafruit RGBMatrixPanel library. I'm trying to draw this image to the screen:

But it conks out after 16 pixels each row...

Below is my code in full. It seems like the bit mask only works for the first 16 columns, but I can't seem to figure out why it stops at that point. I'm using an Arduino Nano, if that helps.
#define CLK  8
#define OE   9
#define LAT 10
#define A   A0
#define B   A1
#define C   A2

RGBmatrixPanel matrix(A, B, C, CLK, LAT, OE, false);
unsigned long int pixelGrid[] = {
  0x00000000,
  0x31CEFDCE,
  0x78CCFCCC,
  0x78CC84CC,
  0x78CC04CC,
  0x78CC04CC,
  0x78CC24CC,
  0x78783CFC,
  0x783024FC,
  0x303004CC,
  0x303004CC,
  0x303004CC,
  0x003084CC,
  0x3030FCCC,
  0x3078FDCE,
  0x00000000
};
unsigned long int bitMask = 0x00000001;
void setup() {
  matrix.begin();
  uint8_t r=0, g=0, b=0;

  for(uint8_t y=0; y<16; y++) {
    unsigned long data = pixelGrid[y]; // select row of bits from image
      for (byte x = 0; x <32; x++) { //iterate through columns
        if (data & (bitMask << x)) {// works!
          r = 1; // set LED to ON
        }
        else {
          r = 0; // LED is OFF
        }
      matrix.drawPixel(x, y, matrix.Color333(r, g, b));
    }
  }
}

void loop() {
}

Here's the part of the code that's probably messing up, isolated:
for (byte x = 0; x <32; x++) {
        if (data & (1 << x)) {
          r = 1;
        }
        else {
          r = 0;
        }

Thanks for your help!
Edit: Changing the data variable from int to long to avoid it being truncated lead adds another column of pixels, but it kind of looks like they're all squished into column 16 for some reason:
Note: I tried drawing a rectangle from (0,0) to (31, 15) to make sure that all the LEDs worked, and I was able to do that.
Edit 2: Instead of the bitmask being 1, I made it so that:
unsigned long int bitMask = 0x00000001;
// ...
 if (data & (bitMask << x)) { // works!
          r = 1; // set LED to ON
        }
        else {
          r = 0; // LED is OFF
        }

I'm guessing regular numbers default to 16-bit unsigned ints.
The issue is fixed, woo! I edited the big code block to match.

I'd try exchanging the x and y coordinates in matrix.drawPixel(x, y, matrix.Color333(r, g, b)); to see if the data is layed out in landscape and not in portrait.

Changing the x/y coordinates rotates the image 90 degrees, as expected: https://i.imgur.com/GXzS4LG.png It's a 32x16 panel, so I unfortunately can't check if it goes down any lower.

'pixelGrid[]' are longs but your temp inside the for() loop, 'data', is an int. Thus, it gets only half the data. Easy mistake to make (and they can be so hard to spot when you know perfectly well what you meant... :)
Update:

By switching the int to long, I've successfully unlocked a seventeenth
  column! Unfortunately, it looks like all the pixels are bunched up in
  that seventeenth column.

Another error of the same kind (I missed it the first time around):
Change (1 << x) to (1L << x). The original expression is calculated as int and the result is widened in the assignment to 'data' (and I think there was compiler bug int the code that did that, besides). The corrected expression is calculated as a long in the first place, which is what I think you intended.
Update 2:
From your question Edit 2:

I'm guessing regular numbers default to 16-bit unsigned ints.

You are correct - ints of unspecified size default to 16-bits in the Arduino gcc compiler used by the Arduino IDE (and just about everywhere else in the Arduino domain that I know of). The language standard leaves the compiler writer free to choose the size of an int that best fits the target-machine's architecture. 16-bits is the most common, but by no means the only - size implemented in most compilers. For this reason, most compilers' pre-processors implement specific-sized data types, and application writers - you & I - are advised to use these wherever data-size matters. For the Arduino's gcc compiler, there are predefined types such as int8_t (signed 8-bit int), uint32_t (unsigned long int), etc.
int is an ok "I don't care, just as long as it works" option. When you do care - specify.
(If my answer helped you, please upvote it or select as best answer. The latter has the important function on this site of marking the question as "completed" so it doesn't keep re-appearing as an unanswered question.)

By switching the int to long, I've successfully unlocked a seventeenth column! Unfortunately, it looks like all the pixels are bunched up in that seventeenth column...https://i.imgur.com/tgpcnH3.png

perhaps you edit your question? Both code, and error description...

Marked you as best answer just now. Thank you for all your help!

source: Stack Exchange

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

sort: votes


text:
Arduino mega PinChangeInterrupt with 16 bit timer
With reference to this question ::I have written a program by using 16-bit timer,
The program is as follows .
volatile uint32_t ovfCount = 0;

struct Pulse {
  uint32_t last_toggle;
  uint32_t width;
  bool stateHigh;
  uint32_t get_width() {
    noInterrupts();
    uint32_t width_copy = width;
    interrupts();
    return width_copy;
  }
};

Pulse ch1, ch2, ch3, ch4, ch5, ch6;

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

  pinMode(13, OUTPUT);

  /*
     Pin Change Interupt for
     measuring the pulse width
     from the receiver

  */

  DDRK = 0; // A8:A15 -> direction as Input
  PORTK = B00111111; // A8:A15 -> pullupResistor

  PCIFR = 0; // resetting the flags
  PCIFR  = _BV(PCIF2);
  PCMSK2 = B00111111; // activating from A8:21 :: 6
  PCICR = B00000100; // activating 2 nd PCINT

  /*
     16 bit timer setup for counting
     timer 3 is used
  */
  TCCR3B = 0x00;
  TCCR3A = 0x00; // wave generation is normal:: all zeros
  TCNT3 = 0x00;
  TIFR3 = 0x00; // resetting all flags
  TIMSK3 = 0x01; //timer overflow enable
  TCCR3B = 0x01; // no prescaling

}

ISR(TIMER3_OVF_vect) {
  ovfCount++;
}

ISR(PCINT2_vect) {
  uint8_t tcnt3 = TCNT3;
  uint32_t ovf_count = ovfCount;

  if ( bit_is_set(TIFR3, TOV3) && tcnt3 < 32768 ) {
    ovf_count ++;
  }

  uint32_t time = ovf_count << 16 | tcnt3;

  pinChangeFunction(&ch1, time, PK0);

}

void pinChangeFunction(Pulse *channel, uint32_t time, uint8_t pin) {
  bool input_is_high = bit_is_set(PINK, pin);
  if (input_is_high && !channel->stateHigh) {
    channel->stateHigh = true;
  } else if (! input_is_high && channel->stateHigh) {
    channel->width = time - channel->last_toggle;
    channel->stateHigh = false;
  }
  channel->last_toggle = time;
}

void loop() {
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
  delay(200);

  Serial.println(ch1.get_width() / 16e3, 5);

}

The output for the same is attached below,
999.42663
999.43060
999.42645
999.42614
999.42730
999.42889
1003.52416
999.41473
999.42681
999.42211
999.42077
999.42718
999.42016
1003.52447
999.41802
999.42480
999.42541
999.43603
999.42767
1003.52075
999.42199
999.42767
999.41876
999.42816
999.41143
999.41998
1003.52429
999.42730
999.42950
999.41149
999.42028
999.42700
1003.50775
999.43743
999.42858
999.42584
999.41381
999.42852
999.43347
1003.52490
999.41925
999.41540
999.42510
999.42895
999.42980
999.42883
1003.52526
999.43658
999.43707
999.42889
999.41284
999.42401
1003.52343
999.42901
999.42950
999.42822
999.43481
999.42718
999.41986
1003.52398
999.42303
999.41442
999.42498
999.42950
999.42547
1003.51074

When I observed the output , I am seeing 999 millis almost instead of 1000 as expected and  in-between  1003 is coming instead either of 999/1003.
Also if we look carefully it can be observed that ,999 is coming 6 times then one 1003 is coming and is going 2 times like that then 5 times 999 then 1003
so I want to know what mistake I am making in my program , and what is the reason behind these kind of behaviour .

Please answer  @edgar-bonet .

TCNT3 does not fit in a uint8_t.

Thanks . Its working

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


text:
External Interrupt and Input Capture pin | Arduino MEGA
I have a code for finding the rpm of one system calling here as engine , the engine have a hall sensor output and I have tried the following Code

#define SERVO_MIN 2000
#define SERVO_MAX 4000

struct Pulse {
  uint32_t last_toggle;
  uint32_t width;
  uint32_t width_prev;
  uint32_t time_prev;
  bool stateHigh = false;
  uint32_t get_width() {
    noInterrupts();
    uint32_t width_copy = width;
    interrupts();
    return width_copy;
  }
};

struct Engine {
  uint16_t servoMin = 2000, servoMax = 4000;
  uint16_t rpm_desired;
  volatile Pulse pulse;
  uint32_t get_rpm() {
    cli();
    uint32_t rpm_width = pulse.get_width();
    sei();
    return 12e7 / rpm_width;
  }
};

Engine engine1,engine2;

void pin_initialization() {
  // INT2
  pinMode(19, INPUT_PULLUP);

  // Input capture points
  pinMode(49, INPUT_PULLUP);
  pinMode(48, INPUT_PULLUP);

}

void timer4_initialization() {
  cli();
  TCCR4A = 0; TCCR4B = 0; TCCR4C = 0;
  TCCR4A = B10101011;
  TIMSK4 = B00100000;
  TIFR4 = _BV(ICF4);
  TCCR4B = B11011010;
  OCR4A = 39999;
  OCR4B = SERVO_MIN;//7
  OCR4C = SERVO_MIN;//8
  sei();
}

void timer5_initialization() {
  cli();
  TCCR5A = 0; TCCR5B = 0; TCCR5C = 0;
  TCCR5A = B10101011;
  TIMSK5 = B00100000;
  TIFR5 = _BV(ICF5);
  TCCR5B = B11011010;
  OCR5A = 39999;
  OCR5B = SERVO_MIN;//45
  OCR5C = SERVO_MIN;//44
  sei();
}

void timer3_initialization() {
  TCCR3A = 0x00; TCCR3C = 0x00;

  TCNT3 = 0x1FF; // from datasheet
  TIFR3 = _BV(TOV3);
  TIMSK3 = _BV(TOIE3); // overflow enable
  TCCR3B = B00000010; // 8 prescaling
}

volatile uint32_t ovfCount = 0;
ISR(TIMER3_OVF_vect) {
  ovfCount++;
}

void pulseWidthCalculator(Pulse *channel) {
  unsigned char sreg;
  sreg = SREG;
  cli();
  uint16_t tcnt3 = TCNT3;
  uint32_t ovf_count = ovfCount;
  SREG = sreg;

  if (bit_is_set(TIFR3, TOV3) && tcnt3 < 16384) {
    ovf_count++;
  }

  uint32_t time = ovf_count << 16 | tcnt3;

  if (!channel->stateHigh) {
    channel->stateHigh = true;
  } else if ( channel->stateHigh) {
    channel->width = time - channel->last_toggle;
    channel->stateHigh = false;
  }
  channel->last_toggle = time;
  sei();
}

void externalInterrputInitialization() {
  EIFR = _BV(INTF2) ;
  EICRA = 0; EICRB = 0;
  EICRA = B00100000;
  EIMSK = B00000100;
}

ISR(INT2_vect) {
      pulseWidthCalculator(&engine1.pulse);
}

ISR(TIMER4_CAPT_vect) {
  pulseWidthCalculator(&engine2.pulse);
}

ISR(TIMER5_CAPT_vect) {
//  pulseWidthCalculator(&engine2.pulse);
}

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

  pin_initialization();
  delayMicroseconds(10);

  externalInterrputInitialization();
  delayMicroseconds(10);

  timer3_initialization();
  delayMicroseconds(10);

  timer4_initialization();
  delayMicroseconds(10);

  timer5_initialization();
  delayMicroseconds(10);

}

void loop() {
  Serial.print(engine1.get_rpm());
  Serial.print("\t" );
  Serial.println(engine2.get_rpm());
}

The same hall sensor output is given to the INT2 (pin #19) pin and ICP4(pin #49) and the results obtained is given below
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
24590   1626
1658    1626
1658    1626
1658    1626
1658    1626
1658    1626
1658    1626
1658    1646
1658    1646
1658    1646
1658    1646
1658    1646
1658    1646
1658    1646
1658    1646
1658    1646
1658    1646
1658    1646
1658    1646
1658    1646
1658    1646
1658    1646
4577    1646
4577    1646
4577    1646
4577    1646
4577    1646
4577    1646
4577    1646
1667    1581
1667    1581
1667    1581
1667    1581
1667    1581
1667    1581
1667    1581
1667    1581
1667    1581
1667    1581
1667    1581
1667    1581
1667    1581
1667    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
2029    1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1581
3428571 1546
3428571 1546
3428571 1546
3428571 1546
3428571 1546
3428571 1546
3428571 1546
3428571 1546
3428571 1546
3428571 1546
3054    1565
3054    1565
3054    1565
3054    1565
3054    1565
3054    1565
3054    1565
3054    1565
3054    1565
3054    1565
3054    1565
3054    1565
3054    1565
3054    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
2961    1565
4615384 1565
4615384 1565
4615384 1565
4615384 1565
4615384 1565
4615384 1565
4615384 1565
4615384 1565
4615384 1565
4615384 1565
4615384 1565
4615384 1565
4615384 1565
3792    1565
3792    1565
3792    1565
3792    1565
3792    1565
3792    1565
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
3792    1587
1542    1587
1542    1587
1542    1587
1542    1587
1542    1587
1542    1587
1542    1587
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1542    1521
1710    1521
1710    1521
1710    1521
1710    1521
1710    1521
1710    1521
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
1710    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3062    1619
3361    1619
3361    1619
3361    1619
3361    1619
3361    1619
3361    1619
3361    1619
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
3361    1581
1449    1581
1449    1581
1449    1581
1449    1581
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
1449    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1541
2166    1628
2166    1628
2166    1628
2166    1628
2166    1628
2166    1628
2166    1628
2166    1628
2166    1628
2166    1628
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
9880    1544
1588    1544
1588    1544
1588    1544
1588    1544
1588    1544
1588    1544
1588    1544
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1588    1586
1693    1586
1693    1586
1693    1586
1693    1586
1693    1586
1693    1586
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1693    1599
1584    1599
1584    1599
1584    1599
1584    1599
1584    1599
1584    1599
1584    1599
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1584    1567
1526    1567
1526    1567
1526    1567
1526    1567
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1526    1646
1693    1646
1693    1646
1693    1646
1693    1646
1693    1646
1693    1646
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
1693    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1682
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
2464    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
1699    1623
3947    1623
3947    1623
3947    1623
3947    1623
3947    1623
3947    1623
3947    1623
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
3947    1688
1537    1688
1537    1688
1537    1688
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1537    1655
1709    1655
1709    1655
1709    1655
1709    1655
1709    1655
1709    1655
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
1709    1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
61696   1699
83449   1699
83449   1699
83449   1699
83449   1699
83449   1699
83449   1699
83449   1699
83449   1699
83449   1699
83449   1699
83449   1699
83449   1699
83449   1699
83449   1699
83449   1699
83449   1699
83449   1699
83449   1699

I have a feeling that the Noise canceller in the input capture pin is helping here, I would like to get help on

How to make the interrupt values also correct
What logical mistake am I making.

how to add the logic of noise cancelling to Interrupt subroutine code.
If I have to add 4/6 such engines what is the best option.
** with a function generator both INT and ICP are giving the correct result.


text:
Issue using Arduino Mega Timer2 with PinChange Interrupt
I was working on a program to measure the pulse width , for that I thought of using Timer 2 in Arduino mega along with pin change interrupt,
The program I have written is as follows
volatile float ovfCount = 0;

typedef struct{
  float curr_ovfCount,prev_ovfCount;
  uint8_t curr_tcnt2, prev_tcnt2;
  uint16_t width;
  bool stateHigh = true;
}Pulse;

Pulse ch1, ch2, ch3, ch4, ch5, ch6;

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

  /*
   * Pin Change Interupt for
   * measuring the pulse width
   * from the receiver
   *
   */

  DDRK = 0; // A8:A15 -> direction as Input
  PORTK = B00111111; // A8:A15 -> pullupResistor

  PCICR = B00000100; // activating 2 nd PCINT
  PCIFR = 0; // resetting the flags
  PCMSK2 = B00111111; // activating from A8:21 :: 6

  /*
   * 8 bit timer setup for counting
   * timer 2 is used
   */
   TCCR2B=0x00;
   TCCR2A = 0x00; // wave generation is normal:: all zeros
   TCNT2 = 0x00;
   TIFR2 = 0x00; // resetting all flags
   TIMSK2 = 0x01; //timer overflow enable
   TCCR2B = 0x01; // no prescaling

}

ISR(TIMER2_OVF_vect){
  ovfCount++;
}

ISR(PCINT2_vect){
  float ovf_count = ovfCount;
  uint8_t tcnt2 = TCNT2;

  if( (PINK & 1 << PINK0) & ch1.stateHigh ){
    //Low-High
    ch1.prev_ovfCount = ovf_count;
    ch1.prev_tcnt2 = tcnt2;
    ch1.stateHigh = false;
  } else if( ! ((PINK & 1 << PINK0) & ch1.stateHigh)){
//    High-Low
    ch1.curr_ovfCount = ovf_count;
    ch1.curr_tcnt2 = tcnt2;
    ch1.width = (256.0*(ch1.curr_ovfCount - ch1.prev_ovfCount) + (ch1.curr_tcnt2 - ch1.prev_tcnt2) ) * 1000 / 16e6;
    ch1.stateHigh = true;
  }

}

void loop() {
  Serial.println(ch1.width);
  pinMode(13, OUTPUT);
  digitalWrite(13,!digitalRead(13));
  delay(1000);

}

and the output I am getting is ,
16:22:05.667 -> 0
16:22:05.847 -> 927
16:22:06.826 -> 927
16:22:07.820 -> 1001
16:22:08.847 -> 1001
16:22:09.837 -> 1001
16:22:10.843 -> 1001
16:22:11.835 -> 1002
16:22:12.863 -> 1002
16:22:13.871 -> 1002
16:22:14.854 -> 1002
16:22:15.873 -> 1003
16:22:16.875 -> 1003
16:22:17.887 -> 1003
16:22:18.860 -> 1003
16:22:19.875 -> 1003
16:22:20.867 -> 1003
16:22:21.907 -> 1003
16:22:22.895 -> 1003
16:22:23.922 -> 1008
16:22:24.921 -> 1008
16:22:25.938 -> 1008
16:22:26.922 -> 1008
16:22:27.939 -> 1008
16:22:28.961 -> 1008
16:22:29.946 -> 1008
16:22:30.971 -> 1008
16:22:31.993 -> 1008
16:22:32.974 -> 1008
16:22:34.011 -> 1008
16:22:35.016 -> 1008
16:22:36.026 -> 1008
16:22:37.012 -> 1008
16:22:38.024 -> 1008
16:22:38.939 -> 1008
16:22:39.802 -> 906
16:22:40.638 -> 906
16:22:41.508 -> 844
16:22:42.345 -> 844
16:22:43.189 -> 842
16:22:44.059 -> 842
16:22:44.905 -> 843
16:22:45.750 -> 843
16:22:46.593 -> 842
16:22:47.428 -> 842
16:22:48.305 -> 842
16:22:49.139 -> 842
16:22:50.011 -> 845
16:22:50.839 -> 845
16:22:51.707 -> 842
16:22:52.539 -> 842
16:22:53.419 -> 842
16:22:54.260 -> 842
16:22:55.111 -> 842
16:22:55.975 -> 842
16:22:56.791 -> 842
16:22:57.642 -> 842
16:22:58.492 -> 842
16:22:59.372 -> 842
16:23:00.212 -> 842
16:23:01.046 -> 842
16:23:01.918 -> 842
16:23:02.775 -> 842
16:23:03.600 -> 849
16:23:04.473 -> 849
16:23:05.329 -> 842
16:23:06.159 -> 842
16:23:07.022 -> 842
16:23:07.862 -> 842
16:23:08.709 -> 842
16:23:09.574 -> 842
16:23:10.412 -> 843
16:23:11.292 -> 843
16:23:12.116 -> 848
16:23:12.996 -> 848
16:23:13.899 -> 848
16:23:14.779 -> 848

The output I am expecting is 1000 as the connection to the PCINT is directly form the digital pin13 of the Arduino and it is made to blink at that interval
I want to know

What mistake I am making here in measuring the counts
How can I generalise this method for measuring width of 6 channels simultaneously.

===== Edit after input from Edgar Bonet ===========
I have written a program , can you please tell me is this a good way to accomplish my requirement
volatile uint32_t ovfCount = 0;

struct Pulse {
  uint32_t last_toggle;
  uint32_t width;
  bool stateHigh;
  bool input_is_high;
  uint32_t get_width() {
    noInterrupts();
    uint32_t width_copy = width;
    interrupts();
    return width_copy;
  }
};

Pulse ch1, ch2, ch3, ch4, ch5, ch6;

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

  /*
     Pin Change Interupt for
     measuring the pulse width
     from the receiver

  */

  DDRK = 0; // A8:A15 -> direction as Input
  PORTK = B00111111; // A8:A15 -> pullupResistor

  PCIFR = 0; // resetting the flags
  PCMSK2 = B00111111; // activating from A8:21 :: 6
  PCICR = B00000100; // activating 2 nd PCINT

  /*
     8 bit timer setup for counting
     timer 2 is used
  */
  TCCR2B = 0x00;
  TCCR2A = 0x00; // wave generation is normal:: all zeros
  TCNT2 = 0x00;
  TIFR2 = 0x00; // resetting all flags
  TIMSK2 = 0x01; //timer overflow enable
  TCCR2B = 0x01; // no prescaling

  DDRH = B00111000;
  fastPWM_init();

}

void fastPWM_init() {
  //    clearing
  TCCR4A = 0; TCCR4B = 0; TCCR4C = 0;
  //    Initializing
  TCCR4A = B10101010; // OC4A, OC4B, OC4C : ICR-WGM
  TCCR4B = B00011010; // ICR-WGM prescalar : 8
  //    Setting frequency
  ICR4 = 39999;
  //    Setting PWM
  OCR4A = 2000; OCR4B = 2000; OCR4C = 2000;
}

ISR(TIMER2_OVF_vect) {
  ovfCount++;
}

ISR(PCINT2_vect) {
  uint8_t tcnt2 = TCNT2;
  uint32_t ovf_count = ovfCount;

  if ( bit_is_set(TIFR2, TOV2) && tcnt2 < 128 ) {
    ovf_count ++;
  }

  uint32_t time = ovf_count << 8 | tcnt2;

  pinChangeFunction(&ch1, time, PK0);
  pinChangeFunction(&ch2, time, PK1);
  pinChangeFunction(&ch3, time, PK2);
  pinChangeFunction(&ch4, time, PK3);
  pinChangeFunction(&ch5, time, PK4);
  pinChangeFunction(&ch6, time, PK5);

}

void pinChangeFunction(Pulse *channel, uint32_t time, uint8_t pin){
  channel->input_is_high = bit_is_set(PINK, pin);
  if (channel->input_is_high && !channel->stateHigh) {
    channel->stateHigh = true;
  } else if (! channel->input_is_high && channel->stateHigh) {
    channel->width = time - channel->last_toggle;
    channel->stateHigh = false;
  }
  channel->last_toggle = time;
}

void loop() {

  if(Serial.available() > 0){
    OCR4A = Serial.parseInt();
  }

  Serial.print(ch1.get_width() / 16e3);Serial.print("\t");
  Serial.println(ch6.get_width() / 16e3);

}

The PWM is only used for testing.

This program is doing floating point calculations (which are super-slow on AVR) within an ISR that is triggered every 16 µs. I am surprised it works at all.

thanks for the suggestion , so what datatype should I use for overFlow count .?

Pin change interrupts are slower than normal interrupts. Also, for the resolution you are working with, just use millis() or micros() to get the current timestamp instead of messing with timers.

There are quite a few issues with this program. The most obvious is the
use of floating point calculations in interrupt context. Interrupts
should be served as fast as possible, and floating point is really slow
on the AVR.
Some other issues:

Interrupt flags should be cleared by writing a logic 1 to them,
however silly it may sound.

A couple if & operators in ISR(PCINT2_vect) are probably meant to
be &&.

The logic for detecting rising and falling edges is all wrong.

There is no need to store so much data in the Pulse objects.

ch1.width should be read with interrupts disabled in order to avoid
a data race.

There is a subtle race condition when reading ovfCount and TCNT2:
if the timer overflows right when ISR(PCINT2_vect) starts running,
that overflow will not be counted.

Here is a version of the program that attempts to fix all these points.
I also changed it for running on an Uno (with pin 13 = PB5 =
PCINT5), so that I could test it:
/*
 * Pulse width via PCINT.
 *
 * https://arduino.stackexchange.com/questions/81688
 */

volatile uint32_t ovfCount = 0;

struct Pulse {
    uint32_t last_toggle;
    uint32_t width;
    bool stateHigh;
    uint32_t get_width() {
        noInterrupts();
        uint32_t width_copy = width;
        interrupts();
        return width_copy;
    }
};

Pulse ch1, ch2, ch3, ch4, ch5, ch6;

void setup() {
    Serial.begin(115200);
    pinMode(13, OUTPUT);

    /* Setup Pin Change Interrupt for detecting pulses. */
    PCMSK0 = _BV(PCINT5);  // sense change on pin 13 = PB5 = PCINT5
    PCIFR  = _BV(PCIF0);   // reset interrupt flag
    PCICR  = _BV(PCIE0);   // enable PCINT0_vect: pins PCINT[7:0]

    /* Setup Timer 2 for counting. */
    TCCR2B = 0;           // stop
    TCCR2A = 0;           // normal mode
    TCNT2  = 0;           // reset timer
    TIFR2  = _BV(TOV2);   // reset interrupt flag
    TIMSK2 = _BV(TOIE2);  // enable timer overflow interrupt
    TCCR2B = _BV(CS20);   // count at F_CPU/1
}

ISR(TIMER2_OVF_vect) {
    ovfCount++;
}

ISR(PCINT0_vect) {
    uint8_t tcnt2 = TCNT2;
    uint32_t ovf_count = ovfCount;

    // Was there an overflow that has not yet been accounted for?
    if (bit_is_set(TIFR2, TOV2) && tcnt2 < 128) {
        ovf_count++;
    }

    uint32_t time = ovf_count << 8 | tcnt2;

    bool input_is_high = bit_is_set(PINB, PB5);
    if (input_is_high && !ch1.stateHigh) {  // low -> high
        ch1.stateHigh = true;
    } else if (!input_is_high && ch1.stateHigh) {  // high -> low
        ch1.width = time - ch1.last_toggle;
        ch1.stateHigh = false;
    }
    ch1.last_toggle = time;
}

void loop() {
    digitalWrite(13, HIGH);
    delay(1000);
    digitalWrite(13, LOW);
    delay(200);
    Serial.println(ch1.get_width() / 16e3, 5);
}

And here is the output:
1000.02349
1000.01959
1000.01916
1000.02496
1000.01959
1000.02032
1000.01947
1000.02795
1000.02642
1000.01855
1000.01916
1000.02105
1000.02490
1000.01782
1000.03033
1000.01898
...

The printed values are larger than 1000 because of the time needed to
execute digitalWrite().
Also note that an 8-bit timer running at the full CPU speed overflows
every 16 µs. That's quite a lot of pressure on the CPU, and many
operations will take longer that expected because of these interrupts.
If I wanted to time something with single-cycle resolution, I would
reach for a 16-bit timer. And I would prefer using input capture,
although sadly only two input capture channels are available on the Mega
(on pins 48 and 49).

Edit: Answering the questions in the comments.

please have a look at my question edits and please advice.

I did not test it, but it seems to me this code should work. I would
prefer, however, having a different interrupt for each channel.
Otherwise, the successive calls to pinChangeFunction() can make the
execution of this ISR quite long.
Also note that Pulse::input_is_high serves no useful purpose. Storing
this value in the object slows down the ISR, as it has to access memory,
whereas a local variable would be kept in a (much faster) internal CPU
register.

what will we do if we have 8 channels as in the radio receiver?

You could use 6 external interrupts and 2 pin change
interrupts.

Why did you take tcnt2 < 128 when tcnt2 max is 256?

This one is tricky. I'll try to explain the whole logic of the test.
Consider the following naive version of the ISR:
ISR(PCINT0_vect) {
    // ← A
    uint8_t tcnt2 = TCNT2;
    uint32_t ovf_count = ovfCount;
    uint32_t time = ovf_count << 8 | tcnt2;
    // ...
}

There is a small chance that Timer 2 overflows at point A, i.e.
while this ISR is executing its prologue and has not yet read TCNT2.
If this happens, the TIMER2_OVF ISR will not run immediately, because
we are already executing an ISR, and ISRs do not nest. Then, ovfCount
is not updated. If this happens, we then read a value of TCNT2
affected by the overflow, and a value of ovfCount that does not
account for that overflow. We then combine together those inconsistent
values into a time value that misses 256 timer ticks.
We can detect this situation by reading the TOV2 flag in TIFR2. This
flag is set only when there is a pending interrupt request for
TIMER2_OVF, i.e. if the counter has overflowed and that overflow has
not yet been accounted for in ovfCount. Thus the “fixed” ISR looks
like this:
ISR(PCINT0_vect) {
    // ← A
    uint8_t tcnt2 = TCNT2;
    // ← B
    uint32_t ovf_count = ovfCount;
    // ← B
    if (bit_is_set(TIFR2, TOV2)) {
        ovf_count++;
    }
    uint32_t time = ovf_count << 8 | tcnt2;
    // ...
}

With this, if the overflow happens at point A, we manage to compute the
proper time. But consider now what would happen if the timer overflows
at either of the points marked B, i.e. after reading TCNT2 but before
reading TOV2. If this happens, we read the pre-interrupt values of
both TCNT2 and ovfCount. No correction is thus needed for computing
a consistent time. Yet, TOV2 is raised when we test it: we then
apply an unneeded correction, and we end up with a time that is too
large by 256 ticks.
In order to fix this problem, we have to make sure the correction is
applied if the overflow happens at point A, but not if it happens at
point B. How can we tell apart those two situations? The answer is: by
looking at the value recorded in tcnt2. In case A, the counter was
read right after the overflow, so it had a very small value (close
to 0) when it was copied to tcnt2. In case B, the counter was
read when it was just about to reach the overflow, so it had a very
large value (close to 255). If TOV2 is set when we read it, this
means an overflow happened during the very beginning of the current ISR,
very close to the point where we read TCNT2. So the value recorded in
tcnt2 has to be either very small or very large. It cannot be in the
middle (close to 128).
So we have to decide whether tcnt2 is very small or very large. There
are many possible values that could be used as a threshold. The most
natural is the mid range: 128. It is also the most efficient to compute,
as the compiler can optimize the comparison into a simple test of the
most significant bit. Thus the final version of the test:
    if (bit_is_set(TIFR2, TOV2) && tcnt2 < 128) {
        ovf_count++;
    }

How to modify the same for using with 6 channels .? sorry but  I am getting confused ..

@Lawliet: You have only 3 pin change interrupts. Reading 6 channels would make the ISRs more complex, as they would need to find out which channels triggered the interrupt. I would rather use regular external interrupts, as there are 6 of them available on the Mega (INT0–INT5). You could use a template to void repeating code.

please have a look at my question edits and please advice.

Also what will we do if we have 8 channels as in the radio receiver. ?

Doubt1: Why did you take tcnt2 < 128  when tcnt2 max is 256 . ?

@Lawliet: See amended answer.

with your advices I tried to write a program with 16bit timer and I am getting some sort of error in the consistency of measuring the clock tick . please have a look . link

The reason why I'm using PCINT is I have to use one IMU- which is I2C :: for that I have to access scl and sda pins , Then I have 4 in one setup and 8 servos in another setup that also have to be used , and finally I have to measure the rpm of 4/8 motors also .
So for this which all pin combination will you suggest.
(1.) Receiver :: 6/8 channels - width to be calculated
(2.) I2C ::
(3.) 4/8 :: servos
(4.) 4/8 :: speed measuring sensors

Please help me with this issue @edgar-bonet  . QuestionLink


text:
Need help with EEPROM not storing array values on ESP8266 after restart
I am struggling through a program. I am trying to store my uploaded string into an array then write that array to EEPROM. I run the program, upload the new array and store it in the EEPROM. all values display correctly until I reset or power off the device. I am sure I am overwriting or something obvious, but i am breaking down and asking for help.
The read and write EEPROM subroutines are at the bottom of the code. I call the EEPROM_Write() in server.on after parsing the http get.
EDIT: per feedback, removed all but the function, with the EEPROM.commit(); suggestion included... still not working

void EEPROM_Write(){
Serial.begin(115200);
EEPROM.begin(280);
  // store values in EEPROM
  for (int i = 0; i < pwmarray1Size; i++)
  {
    Serial.println(pwmarray1[i]);
    EEPROM.put( EEPROMStartAdress + (i * sizeof pwmarray1[0]), pwmarray1[i]);
  }
  Serial.println();
  EEPROM.commit();
 // EEPROM.end();
}

what is EEPROMStartAdress? you can put the whole array in EEPROM with one 'put'

The ESP has no real EEPROM. Instead the EEPROM class for ESPs uses the flash memory. There is a difference in the implementations of this class between Arduinos and ESPs:
On an ESP every data, that you write, will first be placed in a buffer in RAM. You  need to call EEPROM.commit() to actually write that data to the underlying flash memory.
So you need to add
EEPROM.commit();

to the end of your EEPROM_Write() function, or the data will stay in RAM and thus be lost on power cycle or reset.

I think your problem (besides the commit) lies not in your EEPROM_Write() function, but in the EEPROM_Read() function. If it doesn't work correctly, you are just not able to see, if the data gets written correctly. In your code (which can be seen in the edit history), you have this function:
void EEPROM_Read(){
   //load array pwmarray1 with stored values in EPROM
  for (int x = 0; x < pwmarray1Size; x++){
    EEPROM.get(EEPROMStartAdress + (x * sizeof pwmarray1[0]), pwmarray1[x]);
        Serial.print("loading program from EPROM: ");
    Serial.println(pwmarray1[x]);
    }
}

While in EEPROM_Write() you are calling EEPROM.begin(280) every time, you don't EEPROM.end() it there and you are also not begin the EEPROM in the EEPROM_Read() function. I'm not sure about the underlying implementation, but it started to work for me, when I began and ended the EEPROM object in both functions.
I've written a test code, that I composed party of your code and that for me correctly saves and reads an array via the EEPROM object into the flash memory. It keeps the data over resets and power cycles just correctly. You can control it via Serial Monitor. Just type c (for clearing the array to zero), r (for reading the array from EEPROM/flash) or i (for incrementing all array elements and save them to EEPROM/flash).
#include <EEPROM.h>

#define EEPROM_SIZE 280

int array[60] = {0};
const unsigned arraySize = sizeof array / sizeof array[0];

#define EEPROMStartAdress 0

void setup(){
  Serial.begin(115200);
  Serial.println("///////////////////////////////////////");
  delay(2000);
}

void loop(){
  if(Serial.available()){
    char c = Serial.read();
    switch(c){
      case 'c':
        for(uint8_t i=0;i<arraySize;i++) array[i] = 0;
        EEPROM_Write();
        Serial.println("EEPROM RESET");
        break;
      case 'r':
        EEPROM_Read();
        break;
      case 'i':
        for(uint8_t i=0;i<arraySize;i++) array[i] += 1;
        EEPROM_Write();
        break;
    }
  }
}

void EEPROM_Write(){
  EEPROM.begin(EEPROM_SIZE);
  // store values in EEPROM
  for (int i = 0; i < arraySize; i++)
  {
    EEPROM.put( EEPROMStartAdress + (i * sizeof array[0]), array[i]);
  }
  EEPROM.commit();
  EEPROM.end();
}

void EEPROM_Read(){
  EEPROM.begin(EEPROM_SIZE);
  for (int x = 0; x < arraySize; x++){
    EEPROM.get(EEPROMStartAdress + (x * sizeof array[0]), array[x]);
    Serial.print(" ");
    Serial.print(array[x]);
    }
  Serial.println();
  EEPROM.end();
}

Removing begin() and end() from EEPROM_Read() and also end() from EEPROM_Write() gives me the same results, that you described as your problem.

the labels are misleading. I am using "put" and "get". can i use EEPROM.commit() after a put?

put and get are just wrappers around write and read, that help you to write more complex data than single bytes. In the background the exact same is happening. So yes, you can use EEPROM.commit() after EEPROM.put().

I have added the EEPROM.commit() and still am not getting values stored in the EEPROM. Do you know if the "EEPROMStartAdress" location has any effect?

ok, I have spent 30 hours staring and trying to make this work to no avail. i parsed down a test to a single number. posted the new question here: https://stackoverflow.com/questions/62415395/eps8266-writing-number-to-eeprom-fails-to-write-returns-0?fbclid=IwAR1QxJ_EXw8jqKaiLLNoDsChW2l0CpGUlQcmTu3WrKaijchN4qc_8Mn5quo

I'm currently working on a test sketch, but as of now, my your function works with my ESP32. I will make complete a minimal functioning test sketch, that you can test with your board. Maybe I'm able to do this tomorrow evening. The EEPROMStartAdress just tells the function, where to start writing in the provisioned EEPROM. Should not make a problem.

unless EEPROMStartAdress is larger then the allocated size

@deathrace2020 Now I was able to reproduce exactly and get a fix. I've added the solution and also the testsketch, that I used, to the answer

you can write the whole array with one put and read it with one get. `end' calls 'commit'


text:
Not able to setup Arduino port
I bought my Robotics kit yesterday. And, I am not able to set up my Arduino port.
I have tried every method I could find on the internet. I am attaching images of my device manager and error I am getting while trying to update my ports. Any help would be highly appreciated.

So the error says, that the best drivers are already installed. Can you choose the port COM3 or COM5 in your IDE? Or don't they show up?

@chrisl they don't show up. I am not able to select the option for ports.

add a sreenshot from the Tools menu

@Juraj Yes, added. Do let me know what might be the error.

@Juraj yes, I just did that. Followed https://forum.arduino.cc/index.php?topic=572898.0 for reference. Can you tell me how to proceed?

@Juraj I followed the instructions. Still getting the same error. Moreover, I have an Arduino Uno. So, it doesn't show me Duo Port programming under Ports(COM&LPT).

so your Uno is detected by Windows as Due?

@Juraj I am not quite sure of that. My model is Arduino UNO R3, and it detects the ports as COM3 and COM5.

uninstall the drivers you installed for the com port(s). do you have a link to description of the kit?

@Juraj Yes. https://www.amazon.in/gp/product/B08CBLDNVL/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&psc=1


text:
Arduino Nano 33 IoT StandardFirmataPlus
newbie here. So I've been trying to upload StandardFirmataPlus into my Arduino Nano 33 IoT so that I can program in Johnny-Five. However I have this issue.

I've checked that my port is connected and that the libraries are up to date. The docs say that if my board does not enough flash or RAM then the code wouldn't work. The code seems to work fine on other boards which have the same memory such as the Arduino UNO. My board is not a clone. And I've also checked that my Board Manager is set to "SAMD". If anyone has faced this issue and resolved, do share how you did it. Thanks in advance. If I've mentioned anything wrong do correct me =).
EDIT 1: I'm using macOS Catalina 10.15.5. Arduino version 1.8.13. All I did was to try compiling the code. This is the Arduino IDE.
EDIT 2: Error Messages:
In file included from /Users/thebird/Desktop/Code/Arduino1/libraries/Firmata/Firmata.h:17:0,
from /Users/thebird/Desktop/Code/Arduino1/libraries/Firmata/examples/StandardFirmataPlus/StandardFirmataPlus.ino:49:
/Users/thebird/Desktop/Code/Arduino1/libraries/Firmata/Boards.h:824:2: error: #error "Please edit Boards.h with a hardware abstraction for this board"
#error "Please edit Boards.h with a hardware abstraction for this board"
^~~~~
Multiple libraries were found for "Firmata.h"
Used: /Users/thebird/Desktop/Code/Arduino1/libraries/Firmata
Not used: /private/var/folders/kx/l1lw7kfn0t387jt7bd3ccg3h0000gn/T/AppTranslocation/D1572E71-F02B-4F61-BAF9-E73A3ABEB39A/d/Arduino.app/Contents/Java/libraries/Firmata
exit status 1
Error compiling for board Arduino NANO 33 IoT.

what is the issue?  ... you did not include the error message printout

Hello, sorry about that, I thought it was only 2 lines, I've added the error screenshot to my question.

why are you bothering with screenshots? ... it is much easier and much more useful to add the actual text ... screenshot of text cannot be used for doing web searches so most people won't even bother to look at your post

Hello, sorry this is my first time asking a question here. Yeah I've learnt my mistake, thank you =). I've also added the text for the errors.


text:
couldn't connect to MQTT broker via esp8266/32 and pub/sub client
I want to use hiveMQ public broker in my project that's the same broker as what available in PubSubClient esp8266 examples but when I change WiFi SSID and password in example and upload it I got this output:
Connecting to <SSID NAME>
........
WiFi connected
IP address:
192.168.1.14
Attempting MQTT connection...failed, rc=-2 try again in 5 seconds
Attempting MQTT connection...failed, rc=-2 try again in 5 seconds
Attempting MQTT connection...failed, rc=-4 try again in 5 seconds
Attempting MQTT connection...failed, rc=-4 try again in 5 seconds
Attempting MQTT connection...failed, rc=-4 try again in 5 seconds
Attempting MQTT connection...

I tried this with pubsub client v2.8/v2.6/v2.4 and esp32 latest version and esp8266 latest version and 2.3
in response to the comment as I said my code is esp8266_basic example in the PubSub client examples and here is my code:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// Update these with values suitable for your network.

const char* ssid = "<SSID>";
const char* password = "<PASS>";
const char* mqtt_server = "broker.mqtt-dashboard.com"; //tested with broker.mqttdashboard.com

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

void setup() {
  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883); //8000 and 1883 tested
  client.setCallback(callback);
}

void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

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

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  // Switch on the LED if an 1 was received as first character
  if ((char)payload[0] == '1') {
    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is acive low on the ESP-01)
  } else {
    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
  }

}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP8266Client")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("outTopic", "hello world");
      // ... and resubscribe
      client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
void loop() {

  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  long now = millis();
  if (now - lastMsg > 2000) {
    lastMsg = now;
    ++value;
    snprintf (msg, 75, "hello world #%ld", value);
    Serial.print("Publish message: ");
    Serial.println(msg);
    client.publish("outTopic", msg);
  }
}

on esp32 I remove pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output and
  if ((char)payload[0] == '1') {
    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is acive low on the ESP-01)
  } else {
    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
  }

sections and includes
and sometimes output is like this:
Attempting MQTT connection...connected
Attempting MQTT connection...connected
Attempting MQTT connection...failed, rc=-4 try again in 5 seconds
Attempting MQTT connection...connected
Attempting MQTT connection...connected
Attempting MQTT connection...connected
Attempting MQTT connection...failed, rc=-4 try again in 5 seconds
Attempting MQTT connection...connected
Attempting MQTT connection...connected
Attempting MQTT connection...failed, rc=-4 try again in 5 seconds
Attempting MQTT connection...failed, rc=-4 try again in 5 seconds
Attempting MQTT connection...connected
Attempting MQTT connection...connected
Attempting MQTT connection...connected
Attempting MQTT connection...connected
Attempting MQTT connection...connected
Attempting MQTT connection...connected
Attempting MQTT connection...connected
Attempting MQTT connection...connected
Attempting MQTT connection...failed, rc=-4 try again in 5 seconds
Attempting MQTT connection...failed, rc=-4 try again in 5 seconds
Attempting MQTT connection...connected

Obviously there is a problem but beyond that who knows?  All you have said is that this is an ESP8266 and you get getting an MQTT connection error.  Please add some additional details.

It is not at all clear what you are asking. Does your code make a succesfull MQTT connection, does it not connect, does it connect sometimes or does it disconnect sometimes? Does it work when it's connected? Why did you remove the pinMode() on the ESP32. BTW why do you use the deprecated BUILTIN_LED instead of LED_BUILTIN ?

@StarCat thanks for commenting, about removing pinMode, I do it because I just need to test it for MQTT and BUILTIN_LED makes a compiler error that says that's not declared and that's about LED and not important for connection
and absolutely board doesn't connect to the broker (some times in my tests on another version of Arduino IDE on an older system I got connection successful message but nothing published or subscribed)

rc=-4 means MQTT_CONNECTION_TIMEOUT, rc=-2 means      MQTT_CONNECT_FAILED, given that you are accessing a public-facing MQTT web service site, the chances are you would need to connect it with username and password in addition to the ClinetID, so you might need to change client.connect("ESP8266Client") to (mqttClient.connect(clientID,mqttUserName,mqttPass)).

I found this video as a problem solver, This may help you.
All MQTT Errors explained very well and Suggester Different troubleshooting techniques
https://youtu.be/CbodTTk-D18

Thanks a lot for your answer But as I mentioned that issue was made because I live in a country with network censorship. When I changed my network provider everything worked fine.
Finally after a week the first network provider I tested with fixed that issue and now everything works

all things are OK and the problem is about my network I think there blocked MQTT (cause I couldn't connect any broker and not just hiveMQ) or other related things cause also my notebook doesn't connect I changed my network provider and the problem fixed
if you ran into the same issue, check other stuff and finally check with a computer in your network (don't use things like http://www.hivemq.com/demos/websocket-client/)


text:
How to post image using Arduino HTTPClient
I am using arduino HTTPClient to do the post request in ESP32. Can anyone help me with the part where I will be able to post an image file along with some data.
The below code works perfectly fine with only sending user_name and image_type-
#include <HTTPClient.h>

http.begin("https://www.somelink.com/post-image");

http.addHeader("Content-Type", "application/x-www-form-urlencoded");

String httpRequestData = "user_name=Shidhartha&image_type=Outdoor";

int httpResponseCode = http.POST(httpRequestData);
if(httpResponseCode > 0){
  String response = http.getString();
  Serial.println(response);
}else{
  Serial.print("Error on sending POST: ");
  Serial.println(httpResponseCode);
}

this is not Arduino code. this is C code using esp8266 SDK

Thank you for your comment @Juraj . Can you share any code or link for esp32? It would really help me.

You could use the HttpClient library. but there are only download examples

ESP-IDF specific code is off-topic for this site. You should be asking about ESP-IDF code on the ESP-IDF forums. We deal with the Arduino API abstraction and libraries only.

@Majenko I have edited my post based on your comment. Any more suggestions will be very helpful..

Are you missing void main(void)?

Tutorial from randomnerd is absolutely correct. You can upload multiple types of files like JPEG, TXT, LOG, XML and all others.

Below is the perfectly working code I got from here.
#include <Arduino.h>
#include <WiFi.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_camera.h"

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

String serverName = "192.168.1.XXX";   // REPLACE WITH YOUR Raspberry Pi IP ADDRESS
//String serverName = "example.com";   // OR REPLACE WITH YOUR DOMAIN NAME

String serverPath = "/upload.php";     // The default serverPath should be upload.php

const int serverPort = 80;

WiFiClient client;

// CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

const int timerInterval = 30000;    // time between each HTTP POST image
unsigned long previousMillis = 0;   // last time image was sent

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println();
  Serial.print("ESP32-CAM IP Address: ");
  Serial.println(WiFi.localIP());

  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;

  // init with high specs to pre-allocate larger buffers
  if(psramFound()){
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 10;  //0-63 lower number means higher quality
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_CIF;
    config.jpeg_quality = 12;  //0-63 lower number means higher quality
    config.fb_count = 1;
  }

  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    delay(1000);
    ESP.restart();
  }

  sendPhoto();
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= timerInterval) {
    sendPhoto();
    previousMillis = currentMillis;
  }
}

String sendPhoto() {
  String getAll;
  String getBody;

  camera_fb_t * fb = NULL;
  fb = esp_camera_fb_get();
  if(!fb) {
    Serial.println("Camera capture failed");
    delay(1000);
    ESP.restart();
  }

  Serial.println("Connecting to server: " + serverName);

  if (client.connect(serverName.c_str(), serverPort)) {
    Serial.println("Connection successful!");
    String head = "--RandomNerdTutorials\r\nContent-Disposition: form-data; name=\"imageFile\"; filename=\"esp32-cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
    String tail = "\r\n--RandomNerdTutorials--\r\n";

    uint16_t imageLen = fb->len;
    uint16_t extraLen = head.length() + tail.length();
    uint16_t totalLen = imageLen + extraLen;

    client.println("POST " + serverPath + " HTTP/1.1");
    client.println("Host: " + serverName);
    client.println("Content-Length: " + String(totalLen));
    client.println("Content-Type: multipart/form-data; boundary=RandomNerdTutorials");
    client.println();
    client.print(head);

    uint8_t *fbBuf = fb->buf;
    size_t fbLen = fb->len;
    for (size_t n=0; n<fbLen; n=n+1024) {
      if (n+1024 < fbLen) {
        client.write(fbBuf, 1024);
        fbBuf += 1024;
      }
      else if (fbLen%1024>0) {
        size_t remainder = fbLen%1024;
        client.write(fbBuf, remainder);
      }
    }
    client.print(tail);

    esp_camera_fb_return(fb);

    int timoutTimer = 10000;
    long startTimer = millis();
    boolean state = false;

    while ((startTimer + timoutTimer) > millis()) {
      Serial.print(".");
      delay(100);
      while (client.available()) {
        char c = client.read();
        if (c == '\n') {
          if (getAll.length()==0) { state=true; }
          getAll = "";
        }
        else if (c != '\r') { getAll += String(c); }
        if (state==true) { getBody += String(c); }
        startTimer = millis();
      }
      if (getBody.length()>0) { break; }
    }
    Serial.println();
    client.stop();
    Serial.println(getBody);
  }
  else {
    getBody = "Connection to " + serverName +  " failed.";
    Serial.println(getBody);
  }
  return getBody;
}

I follow this too but I wish we could use the http client for this. Would make life wayy easier


text:
HC-12 problem with reading momentarily strings
I'm new here, so I hope my question is not naive.
I'm using Arduino mega connected with a pulse sensor and a GPS (and other things that are not related to our problem), pulse sensor and GPS data are sent momentarily through HC-12 433 Mhz module to a receiver arduino uno that is only receiving data through HC-12 as well
for processing reasons, I send GPS data with a "G" prefix .. e.g "G11.00,7.45".
and pulse data consist of those three: "S100"
"Q97"
"B22"  // 100,97,22 are just examples, and each one is sent alone
for some reason, the receiver Arduino uno, is reading the data in it's ASCII decimal form and also separate it in a new line.
I can not use Serial.readString(), because it only print data after terminating the Serial communication and I need it momentarily, I tried to configure Serial.setTimeout() , but I couldn't manage to find a suitable time for all data.
please check my code and help me solve my problem, thank you
#include <Adafruit_GPS.h>
// what's the name of the hardware serial port?
#define GPSSerial Serial1
// Connect to the GPS on the hardware port
Adafruit_GPS GPS(&GPSSerial);

String gpsData="";
String pulseData="";
#include <SoftwareSerial.h>
SoftwareSerial mySerial(12, 13); // RX, TX  HC-12
uint32_t timer = millis();
void setup(){  // I think there is no problem here
  Serial.begin(115200);             // we agree to talk fast!
  mySerial.begin(115200);
  interruptSetup();   // initialize timers to read pulse sensor and GPS at fixed intervals
      GPS.begin(9600);
  delay(100);
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  delay(100);
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_100_MILLIHERTZ);
  GPS.sendCommand(PGCMD_ANTENNA);
  delay(1000);
  GPSSerial.println(PMTK_Q_RELEASE);
}
void loop(){
 // that show me if there is a new data, you can skip it
 if (GPS.newNMEAreceived()) {
    // a tricky thing here is if we print the NMEA sentence, or data
    // we end up not listening and catching other sentences!
    // so be very wary if using OUTPUT_ALLDATA and trying to print out data
    GPS.lastNMEA(); // this also sets the newNMEAreceived() flag to false
    if (!GPS.parse(GPS.lastNMEA())) // this also sets the newNMEAreceived() flag to false
      return; // we can fail to parse a sentence in which case we should just wait for another
  }

  //
if (millis() - timer > 10000) { // send GPS data every 10 seconds
    timer = millis(); // reset the timer
    if (GPS.fix) {

      gpsData.concat('G');
      x=GPS.latitude/100;
      gpsData.concat(x);  // I also tried String(x)
      gpsData.concat(',');
      y=GPS.longitude/100;
      gpsData.concat(y);  // I also tried String(y)
      mySerial.println(gpsData);  // here I send GPS  data through HC-12 to the receiver Arduino uno
      gpsData=""; // reset
    }
}
  sendDataToProcessing('S', Signal);     // send Processing the raw Pulse Sensor data
  if (QS == true){                       // Quantified Self flag is true when arduino finds a heartbeat

        sendDataToProcessing('B',BPM);   // send heart rate with a 'B' prefix
        sendDataToProcessing('Q',IBI);   // send time between beats with a 'Q' prefix
        QS = false;                      // reset the Quantified Self flag for next time

  }
  delay(50);
}
void sendDataToProcessing(char symbol, int data ){
 // here I send pulse data through HC-12 to the receiver Arduino uno, and then process it using processing in the receiver arduino
    pulseData.concat(symbol);
    pulseData.concat(data);
    Serial.println(pulseData);  // just for debugging and it was okay
    mySerial.println(pulseData);
    pulseData=""; //reset
  }

interruptSetup() {
// no need to read it, it is just some timer 1 and timer 2 initialization and their ISR, timer 1 read pulse sensor every 2 milliseconds (yeah fast but I guess mega could handle it),and do some calculations to find S, Q, and B.
and timer 2 read GPS coming sentences.
}

the receiver code
void setup() {
  // put your setup code here, to run once:
Serial.begin(115200);  //I will connect HC-12 directly to pin 0,1
}

void loop() {
  // put your main code here, to run repeatedly:
while(Serial.available() >1){
  String input = String (Serial.read());//read string , I need to cast it into String because data comes in ASCII
// I also tried int input = Serial.read() ; //same thing happened
    Serial.println(input);
}
}

waiting for your response.
###edit###
to conclude the problem is that I want to receive data in the uno
as it has been sent from the mega
e.g: I receive sI guess the ascii of the letter and the number also changes to some number
send  |  recive
S490  | 52
        53
Q252  | 10
        83
B160  | 48
        13

I used Serial.write(Serial.read()) instead of
Serial.println, and it worked, does someone know why?

It's hard for me to understand what your problem is, but I think changing Serial.println(input); to Serial.print(input); will remove the added newlines (if that was the problem).

I tried to restate the problem, check it again please

I think, using char input = Serial.read(); would have worked in your old code. Serial.read returns and int with the character/ascii code (or -1 if it gets a read-error). Serial.print doesn't know it's ascii and will interpret it as a integer, and will convert this number to the Ascii representation of that number. Apparently String(...) does the same. Write doesn't try to be clever, and just reads a byte, an sends this byte out over serial. Is your problem solved now?

No, it is now printing the same output but each char is in a new line, for example like this :   B                                                                                1                                                                                2

char input = Serial.read(); Serial.print(input);

oh yeah it worked, I didn't notice, thank you .......

You had to combine both my answers. I wasn't clear about that. Glad you got it working.


text:
SPI transactions in Arduino
I have a task where I should do SPI transactions in interrupt mode. Means I have to handle data in IRQ handler (both for tx and rx bytes). How should I approach?
I have a arduino board (2560) and a CAN shield (seeed studio) with SPI interface.
Edit:
From the website: https://www.arduino.cc/en/reference/SPI

With most SPI devices, after SPI.beginTransaction(), you will write
the slave select pin LOW, call SPI.transfer() any number of times to
transfer data, then write the SS pin HIGH, and finally call
SPI.endTransaction()

My question is - the function SPI.transfer() is handled in what way?
Are the bytes transfered/received in interrupt handler or by polling?

Which Arduino board?  That could make a difference.

There are a lot of libraries. Your question is very broad. There are even multiple SPI and I2C libraries. You need to narrow your question down. What library are you concerned about? What do you mean do a transaction "in interrupt mode"? Do you mean, during an interrupt? Or that the transaction should use interrupts?

Your question is so broad I suggest you read How to ask a good question for Arduino Stack Exchange. The answer to "are these libraries interrupt based or polling based" is, briefly, "it depends". So you need to narrow down the question to get a useful answer.

@Delta_G added in the question

@NickGammon yes. I know there are lot of libraries. That is the problem. I have edited the question. And yes "the transaction should use interrupts". Tell me if I have to narrow it more.

I have a lengthy reference question about SPI which may help you.
To transfer outwards you do not need to use an interrupt. Nor is it polled. The data is simply placed in the SPI register and the hardware clocks the data out at the defined SPI rate.
To transfer inwards you are just reading the register. However to know when you need to read it, you would probably put the reading inside an interrupt routine.
I suggest you read the link above, and then if you want, you might expand your question more.
The source for the SPI transfer which I think applies to the Atmega2560 is as follows:
// Write to the SPI bus (MOSI pin) and also receive (MISO pin)
  inline static uint8_t transfer(uint8_t data) {
    SPDR = data;
    /*
     * The following NOP introduces a small delay that can prevent the wait
     * loop form iterating when running at the maximum speed. This gives
     * about 10% more speed, even if it seems counter-intuitive. At lower
     * speeds it is unnoticed.
     */
    asm volatile("nop");
    while (!(SPSR & _BV(SPIF))) ; // wait
    return SPDR;
  }

You can see that there is brief polling (the "while" line) for the register which the processor maintains to show whether the transmission has ended. Then the register is read and returned. So yes, there is polling there.
Now if you use an interrupt (see link above) then you will know that the flag has been set, and therefore there will be no delay (in the polling).


text:
Is there a limitation of how many instances of the `String` class?
Platform

Attiny85 with AttinyCores
1306 OLED i2c with Tiny4KDisplay

Goal

using a joystick for menu navigation

up/down choose
left enter (not finished yet)
right back (not finished yet)
inverse display the chosen item.

I come from python word which is why I am using a linked list for menu navigation. I found a weird bug that stops me from displaying some of the long text. I found that if the defined Nodes over a certain amount of number, item text over 5 chars will not display. I don't know why this is related to the number of instances. I managed to narrow down the range of the bug. In the code. if those 3 lines are commented, all the items are displayed correct, if not, only up to ccccc but not dddddd.

The flash and RAM consumption of the failure situation is
Sketch uses 5180 bytes (63%) of program storage space. Maximum is 8192 bytes.
Global variables use 280 bytes (54%) of dynamic memory, leaving 232 bytes for local variables. Maximum is 512 bytes.

My code is as below. I broke it into parts to highlighted the problem. But it is a continuous file actually.
Thank you for any insight.
PS: I know there are methods that avoid oop, but I think this weird bug is so close to being fixed, (or proved to be an actual bug in the package/compiler). So I would like to pursue an answer to this question.
Update:
I tried to use another method that uses a List of Strings instead of a class to achieve the same function. The Bug is still there. I guess it is because there are too many instances of String. The question is not changed: "Is there a limitation of how many instances of the String class?".

#include <Tiny4kOLED.h>

// input setup
int x = 512;
int y = 512;
int lastx = 512;
int lasty = 512;

bool left = false;
bool right = false;
bool up = false;
bool down = false;

char input() {
  x = analogRead(A2);
  y = analogRead(A3);
  if( (lastx > 256) & (x <= 256) ){
    left = true;
  }
  if( (lastx < 768) & (x >= 768) ){
    right = true;
  }
  if( (lasty > 256) & (y <= 256) ){
    down = true;
  }
  if( (lasty < 768) & (y >= 768) ){
    up = true;
  }
  lastx = x;
  lasty = y;
}

// item data
class Node
{
  public:
    String text;
    uint8_t id;
    Node * next;
    Node * previous;
    Node * parent;
    Node * child;
    Node(String s, int n){
      text = s;
      id = n;
      next = NULL;
      previous = NULL;
      parent = NULL;
      child = NULL;
    }
    void append_next(Node * other){
      this->next = other;
      other->previous = this;
      other->parent = this->parent;
    }
    void append_child(Node * other){
      this->child = other;
      other->parent = this;
    }
};

Node main_0("aaa", 1);
Node main_1("bbbb", 2);
Node main_2("ccccc", 3);
Node main_3("dddddd", 4);
Node main_4("eeeeeee", 5);
Node main_5("ffffffff", 6);

This is how the error can be repeated.
/* Uncomment The following 3 lines will cause the problem*/
//Node item_0_0("aaa", 7);
//Node item_0_1("bbb", 8);
//Node item_0_2("ccc", 9);

Node * current_sel = (&main_0);
Node * screen_top = (&main_0);

void setup() {
  // oled setup
  oled.begin(0,0);
  oled.enableChargePump();
  oled.setRotation(1);
  // oled.setInternalIref(true);
  oled.enableZoomIn();
  oled.setFont(FONT6X8);
  oled.clear();
  oled.switchRenderFrame();
  oled.clear();
  oled.switchFrame();
  oled.on();
  // oled setup end

  // input setup
  pinMode(A2, INPUT); // X
  pinMode(A3, INPUT); // Y
  // input setup end

  // data
  main_0.append_next(&main_1);
  main_1.append_next(&main_2);
  main_2.append_next(&main_3);
  main_3.append_next(&main_4);
  main_4.append_next(&main_5);
}

void loop() {
  // input read
  input();

  // move current;
  if(up){
    up = false;
    if(current_sel->previous != NULL){
      if(screen_top == current_sel){
        screen_top = screen_top->previous;
      }
      current_sel = current_sel->previous;
    }
  }

  if(down){
    down = false;
    if(current_sel->next != NULL){
      if(screen_top->next->next->next == current_sel){
        screen_top = screen_top->next;
      }
      current_sel = current_sel->next;
    }
  }

  // oled update
  oled.clear();

  oled.setCursor(64, 0);
  oled.print(current_sel->text);

  Node * current_draw = screen_top;
  int i = 0;
  while(true){

    oled.setCursor(0,i);
    if(current_draw == current_sel){
      oled.invertOutput(true);
    }
    oled.print(current_draw->text);
    oled.invertOutput(false);

    if(current_draw->next == NULL){
      break;
    }

    current_draw = current_draw->next;
    i++;
    if(i >= 4){
      break;
    }
  }

  oled.switchFrame();
  delay(50);
}

what is the memory consumption reported be Arduino IDE at the end of the compilation?

@Juraj Thanks for your comment. The report of the failed one is "Sketch uses 5180 bytes (63%) of program storage space. Maximum is 8192 bytes.
Global variables use 280 bytes (54%) of dynamic memory, leaving 232 bytes for local variables. Maximum is 512 bytes.
"

Each instance of your class uses RAM to store its data. There is always a limit to the number of instances; not a fixed number, but a limit imposed by the quantity of RAM available. What Majenko wrote about Strings applies equally to class instances, if instances are constructed and destroyed during the run.
A fixed number of global instances, as you have used, is more efficient but there is still only room for so many. Complicating this is the fact that RAM is a shared resource. Static variables like globals, including global class-instances, are assigned from the bottom of RAM, upward, after all of the compilations are done and before uploading to the chip. The program's run-time stack, which includes each function's automatic local data, builds from the top of RAM, downward, during the run. Stack memory is assigned and released as each function is entered and exited. But when a function calls a function which calls a function, which calls ..., the stack has to keep growing until the final call returns and the previous calls may then return.
If you attempted to define a large number of instances with a small amount of RAM available, the IDE (actually the linker, which puts together all of your code and the libraries you use) would catch the problem before your program gets uploaded.
But in the case where there all of the RAM didn't get assigned at compile- or link-time, then at run time, your stack could still possibly grow downward until it collides with the global- and fixed-data at the bottom of RAM, with (unfortunately) unpredictable results, but definitely unexpected and improper operation.
Update:
I did gloss over some details, as two commenters were kind enough to point out. Yes, the heap - memory allocated dynamically at run-time - occupies the space just above the globals and other static memory allocations. Heap space can grow, the more it is used to allocate and de-allocate memory, and being low in memory, would have to grow upward, toward the stack. It is the heap where String data is allocated and re-allocated and is one of the reason's behind Majenko's warning against using the String type - especially if the strings will be edited at run time, which results in re-allocation that may not be obvious.
It is also worth noting that any class uses memory, whether Strings or user defined classes such as the OP's nodes. They are both classes and their instances will be handled similarly.
Also in OP's case, note that the class instances are allocated 'statically' - all instances are known and allocated during the run setup and not altered during the run. In 'quotes', because the allocation actually does happen during run-time, but at the very start of the run, and prior to the user sketch receiving control.

Great answer. It should probably also mention heap fragmentation though. (It sounds like the OP uses a fixed number of statically allocated objects, so it might no be relevant here, but if you're gonna give a nice complete answer...)

The stack will collide with the heap before reaching .bss or .data.

Do not use String. Ever. Especially not on a chip with such a tiny amount of RAM.
String uses dynamic allocation to store the string data in RAM. This is very inefficient, especially when you are working with string literals.
Those literals must be stored in flash, not RAM, so you need to be working with const char * and PROGMEM, along with the F() macro.
When using a chip with only a few hundred bytes of RAM you need to be as efficient as you possibly can. You need to account for each and every byte you use - and you just can't do that with String.

As an example, let's look at what this does:
Node main_5("ffffffff", 6);

You have a string of 8 characters plus a NULL terminating character. That's 9 bytes.  Those 9 bytes are copied into RAM at boot time. Current total 9 bytes. You then convert that to a String and copy the character data into that temporary object - that's now 18 bytes plus the size of the String object. Then:
text = s;

You allocate 9 bytes inside the text String object and copy the data in.  You're now at 27 bytes plus two String objects (one of which you created earlier in your class).  A little over 5% of your entire memory just to move text around the place.  A third of that you claw back from your heap as the objects leave scope, but then you have a hole in your heap. And this is the last set of operations after you've already made a complete mess of your heap with the earlier ones.
Whereas
const char main_5[] PROGMEM = "ffffffff";

uses just 2 bytes of RAM to store the pointer and nothing else.

Thank you so much for your answer. I accepted the other one because it shows more insight into why that bug is happening. But your answer actually led me in the right direction. I end up writing a python code dealing with the linked list stuff and generates related C code that defines data in the Flash memory.