Странный результат измерения длительности цифрового сигнала

Отрабатывался алгоритм определения длительности сигнала (например, получаемого при измерении концентрации углекислоты в воздухе). Для проверки использовалась плата ESP32 DevKitC V4 с процессором ESP32-D0WD-V3 (revision v3.1). Выводящий и приемный пины соединялись на прямую. Квадратный сигнал создавался традиционно High delayMicros Low delayMicros в одном из ядер процессора, прием с заданной частотой осуществлялся в другом ядре процессора так: пропуск “1”, пропуск “0”, включение счетчика, пропуск “1”, остановка счетчика. Созданы две программки, одно простые digital, вторая при прямой работе с пинами (DirectIo.h). Результаты абсолютно одинаковы. Полупериоды от 10000 мкс до 0 мкс определяются в целом верно. Наблюдаются отклонения 1-2 мкс.

Но полупериод 1000 мкс определяется неприемлемо. Получаются значения от 950 до 2002 мкс. Причина этого совершенно не понятна.

Это намек на то, что без приведенного кода задавать подобные вопросы - инфантильный бред!

Не могли бы конкретизировать, что из приведенного текста вам не понятно.

Очень беспокоюсь о твоем здоровье. Вопросы есть у тебя, а не у меня. Это тебе нужно получить на них ответы, а не мне.
Для ответов НЕОБХОДИМО размещать код. Не “похожий” и не намеками, а ровно тот, который загружен в контроллер. Никто не планирует тратить свою жизнь на то, чтобы “понять” что-то в твоем посте. И я в том числе. Разместишь код - кто-то, может и я, заметит ошибку и поможет тебе.
Код. По правилам форума, ТОЧНОЕ название контроллера, версия среды, версия ядра для ЕСП32… может быть еще что-то потом спросят, когда необходимое будет выполнено. Обычно еще и схема нужна, так как новички часто даже при подключении проводочков к кнопке дичь делают.

Вот код:

определитель длительности ВЫСОКОГО

Нужна развязка 4.7ком при работе с сигралом 5в

как завышение так и уменьшение, что странно
Длительность 2000 мкс определяется с точностью 2 мкс
Длительность 1500 мкс определяется с разбросом от 600 до 2000 мкс ??!!

При работе с digitalwrite без Directio.h также возниикают расхожждения 
между задаваемой ддлительностью и определяемой. Примерно такие же как и с Directio
pic=10000 pp=9998/10002
pic= 1000 PP= 999 958  987  1983
pic= 100 PP= 99  101
pic= 10 PP= 9 11
pic= 2 PP= 1 3
pic= 1 pp= 2
pic= 0 PP= 1 иногда редко 6
*/
#include <DirectIO.h>

OutputPin pin(26);
Input<27> my_input;

unsigned long last_m=millis(),tt, pp, tt2, pic=1; // pic длительность высокого в микросек
int period=5000;
bool value;
TaskHandle_t One_task;
TaskHandle_t Two_task;

#define ONE_STACK_SIZE 30000 
#define TWO_STACK_SIZE 30000 


void setup() {
   Serial.begin(115200);
    delay(5000);  
Serial.print("pic= ");Serial.println(pic);
    disableCore0WDT(); // Блокировка прерываний
    disableCore1WDT();
    disableLoopWDT(); // You forgot this one !

    //создаем задачу, которая будет выполняться на ядре 0 с максимальным приоритетом (1)
    xTaskCreatePinnedToCore(
                    Task1code,   /* Функция задачи. */
                    "One_Task",     /* Ее имя. */
                    10000,       /* Размер стека функции */
                    NULL,        /* Параметры */
                    5,           /* Приоритет */
                    &One_task,      /* Дескриптор задачи для отслеживания */
                    0);          /* Указываем пин для данного ядра */                  
    delay(500); 
 
    //Создаем задачу, которая будет выполняться на ядре 1 с наивысшим приоритетом (1)
    xTaskCreatePinnedToCore(
                    Task2code,   /* Функция задачи. */
                    "Two_Task",     /* Имя задачи. */
                    10000,       /* Размер стека */
                    NULL,        /* Параметры задачи */
                    1,           /* Приоритет */
                    &Two_task,      /* Дескриптор задачи для отслеживания */
                    1);          /* Указываем пин для этой задачи */
    delay(500); 
  
}
//Task1code:Создает сигнал из 0 и 1 pic управляет длительностями 0 и 1
void Task1code( void * pvParameters )
{
  Serial.print("Task1 running on core ");
  Serial.println(xPortGetCoreID());
 
  for(;;)
  {
    pin = HIGH;
     delayMicroseconds(pic);
    pin = LOW;
     delayMicroseconds(pic);
      }
}
//Task2code: определяет длительность '1'
void Task2code( void * pvParameters )
{
  Serial.print("Task1 running on core ");
  Serial.println(xPortGetCoreID());
 
  for(;;)
  {
    if(millis()-last_m> period)
    {
        last_m=millis();
      while(my_input == HIGH){} // Пропускаем окончание '1'
     
      while(my_input == LOW){} // Затем надо дождаться '1', пропустив '0'
      tt = micros(); // Начало '1'. На время выполнения этой команды результат уменьшается
      while(my_input == HIGH){} // Ожидаем конца '1'.
      pp = micros() - tt;   // Определяем длину '1'.  На время выполнения этой команды результат увеличивается
          Serial.print("PP= ");Serial.println(pp);
    }
  }
}
void loop() {
  // put your main code here, to run repeatedly:

}

При использовании DirectIO

еще раз - ссылку на DirectIO.h

А вот судя по приведенному персонажу - это самое то! Потому что человек, который называет себя «доктор КТО» именно на инфальтильные темы «и падок» :smiley:

url=GitHub - mmarchetti/DirectIO: Fast, simple I/O library for Arduino

вы в библиотеку смотрели? там нет ESP32

У меня библиотека по предыдущей ссылке работает с ESP32.
Кроме того все проблемы поименованные в первом тексте наблюдаются и при работе без привлечения DirectIO. Скетч прилагается

/*
определитель длительности ВЫСОКОГО

Нужна развязка 4.7ком при работе с сигралом 5в

При работе с digitalwrite возниикают расхожждения между задаваемой ддлительностью и определяемой
как завышение так и уменьшение, что странно
pic=10000 PP= 10001 
pic=1000 PP= 2002 !! независимо от частоты измерения. Это таймеры!!
pic=500 PP= 501
pic=100 PP= 101
pic=50 PP= 51
pic=10 PP= 10/11
pic=5 PP= 5/6  5- редко
pic=2 PP= 2/3
pic=1 PP= 1/2 1 - редко
without pic pp=1 
*/
#define Pin 27  // 
#define Pin2 26  // 


unsigned long tt, pp, tt2, pic=5; // pic длительность высокого в микросек

TaskHandle_t One_task;
TaskHandle_t Two_task;

#define ONE_STACK_SIZE 40000   //  4 Кб
#define TWO_STACK_SIZE 30000  // 30 Кб


void setup() {
  // put your setup code here, to run once:

pinMode(Pin, INPUT_PULLDOWN);//, INPUT_PULLUP);INPUT_PULLDOWN);
pinMode(Pin2,  OUTPUT);

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

    Serial.print("pic= ");Serial.println(pic);
    disableCore0WDT(); // Блокировка прерываний
    disableCore1WDT();
    disableLoopWDT(); // You forgot this one !

    //создаем задачу, которая будет выполняться на ядре 0 с максимальным приоритетом (1)
    xTaskCreatePinnedToCore(
                    Task1code,   /* Функция задачи. */
                    "One_Task",     /* Ее имя. */
                    10000,       /* Размер стека функции */
                    NULL,        /* Параметры */
                    5,           /* Приоритет */
                    &One_task,      /* Дескриптор задачи для отслеживания */
                    0);          /* Указываем пин для данного ядра */                  
    delay(500); 
 
    //Создаем задачу, которая будет выполняться на ядре 1 с наивысшим приоритетом (1)
    xTaskCreatePinnedToCore(
                    Task2code,   /* Функция задачи. */
                    "Two_Task",     /* Имя задачи. */
                    10000,       /* Размер стека */
                    NULL,        /* Параметры задачи */
                    1,           /* Приоритет */
                    &Two_task,      /* Дескриптор задачи для отслеживания */
                    1);          /* Указываем пин для этой задачи */
    delay(500); 
  
}
//Task1code: мигает светодиодом 
void Task1code( void * pvParameters )
{
  Serial.print("Task1 running on core ");
  Serial.println(xPortGetCoreID());
 
  for(;;)
  {
  digitalWrite(Pin2,HIGH);
	delayMicroseconds(pic);
   digitalWrite(Pin2,LOW);
   delayMicroseconds(pic);
  }
}
//Task2code: отслеживает длительность высокого
void Task2code( void * pvParameters )
{
  Serial.print("Task1 running on core ");
  Serial.println(xPortGetCoreID());
 
  for(;;)
  {
    while(digitalRead(Pin) == HIGH){} // Ожидаем конец высокого
    while(digitalRead(Pin) == LOW){} // Затем надо дождаться высокого
    tt = micros(); // Начало высокого
    while(digitalRead(Pin) == HIGH){} // Ожидаем конца высокого
    pp = micros() - tt;   // Определяем длину цуга
    Serial.print("PP= ");Serial.println(pp);
      delay(2000);
  }
}
void loop() {
  // put your main code here, to run repeatedly:

}

Я бы попробовал повысить приоритет Task2code.
Полностью кода нет, возможно , Serial мешает

Почему код у вас не открывается полностью стрелкой сверху окна справа

Да почему-то в последнее время больше 95 строк не влезает, приходится на части разбивать

У меня после нажатия на стрелку справа открывается в отдельном окне оба мои скетча

Увидел. Ещё раз спрашиваю: приоритет меняли?

Прости, я не вникал подробно. Но в глаза бросается неаккуратность. Поясню: неаккуратность приводит читателя к мысли о общей неправильности, уж прости.
Итак про неаккуратность:

  1. Нахрена стек 10000?
  2. Нахрена дескрипторы, если в Ардуино они не поддерживаются?

Это не влияет на описанный тобой эффект, но просто выглядит странно.

Вы правы, если бы программа составлялась сама по себе. Здесь же для скорости была взята большая двух-ядерная программа пригодной структуры, из нее выкинута начинка и вставлена новая из элементов интернетовских примеров, соответствующих поставленной задаче.

Ради интереса, запустил в WOKWI.

Я в ESP32 совсем зелёный, но, по моему скромному мнению, отслеживать микросекунды - не та задача для операционной системы.

P.S. Интересно услышать комментарий сведущих людей

Второй ваш результат практически совпал с моим. Что касается первого, то надо бы просчитать с другими исходными, например большими 1000. Возможно добавка к ожидаемому результату будет постоянная. А что касается ES32? то я использую двух-ядерную плату для устранения влияния всех используемых задержек, которые могли бы искажать результаты.

При использовании прерываний количество ядер не является доминирующем свойством влияющим на задержки.