Перейти к содержанию

Arduino некорректное значение micros()


Рекомендуемые сообщения

Я пытаюсь захватить сигнал с ИК-пульта ДУ. Делаю это при помощи Arduino Micro 16 МГц с подключенным к нему фотоприёмником TSOP1736. Код следующий:

const int ARDUINO_MICRO_INTTERRUPT_ON_PIN3 = 0;
const int BUFFER_LEN = 40;

volatile unsigned long periods[BUFFER_LEN];
volatile int i = 0;
volatile unsigned long lastMicros = 0;
volatile unsigned long mcs;
volatile boolean isRunning = false;

void sensorInterruptHandler() {
  isRunning = true;
}

void setup() {
 attachInterrupt(ARDUINO_MICRO_INTTERRUPT_ON_PIN3, sensorInterruptHandler, CHANGE);  
 Serial.begin(9600);
}

void loop() {
  if(!isRunning) {
     return; 
  }
  if(i == BUFFER_LEN) {
    detachInterrupt(ARDUINO_MICRO_INTTERRUPT_ON_PIN3);
    for(int x = 1; x < BUFFER_LEN; ++x) {
       Serial.print(periods[x]);
       Serial.print(" ");
    }
    Serial.println();
    Serial.flush();
    lastMicros = 0;
    delay(1500);
    i = 0;
    attachInterrupt(ARDUINO_MICRO_INTTERRUPT_ON_PIN3, sensorInterruptHandler, CHANGE);
  } else {
    mcs = micros();
    if(lastMicros > mcs) {
       Serial.print("Overflow!"); 
    }
    periods[i] = mcs - lastMicros;
    lastMicros = mcs;
    ++i;
  }
  isRunning = false;
}

Работает следующим образом: всякое изменение уровня на ножке 3 вызывает установку флага isRunning. Главный цикл проверяет установку флага, если он установлен, записывает в буфер periods промежуток времени в микросекундах, в течении которого на ножке не менялся логический уровень. Если буфер заполнен, его содержимое выводится в UART и процесс повторяется. Считываю я всегда один и тот же сигнал, представленный на изображении. И проблема в том, что периодически я получаю совершенно некорректную величину временного промежутка, которую не могу объяснить даже переполнением (для проверки гипотезы о переполнении была вставлена проверка - сообщение о переполнении не печатается). Ниже массив данных, которые я получаю, звездочками отмечены проблемные считывания.

2680 900 496 808 520 376 512 368 468 856 908 428 460 424 468 424 464 416 464 424 464 420 468 420 468 420 460 424 464 424 464 420 468 420 908 416 460 904 876 
2684 896 484 820 520 368 520 368 *1344* *1312* 520 368 528 360 456 428 464 420 468 420 468 420 468 416 464 424 468 420 464 420 468 420 908 416 464 872 904 *83656* 2684 
2680 900 492 816 524 360 520 368 464 860 908 428 460 428 460 424 464 424 468 416 472 416 460 424 464 424 464 424 468 416 460 428 460 424 904 424 468 864 912 
2680 904 492 812 516 372 516 368 *1356* *1304* 516 372 516 368 468 428 460 420 460 424 464 420 468 420 468 420 460 432 456 424 464 424 912 412 468 864 904 *83656* 2684 
2676 904 488 816 524 364 524 364 *1348* *1308* 524 364 524 364 460 424 464 424 468 420 468 416 460 424 464 424 468 420 468 416 460 428 912 412 468 896 880 *83652* 2680 
2676 904 496 812 520 364 524 364 460 864 912 424 468 416 472 416 460 424 464 424 468 420 468 416 460 428 460 428 464 420 468 416 472 424 904 416 464 896 880

Почему я получаю эти странные значения? Эффект повторяется с возмутительным постоянством, и если значения 1344, 1312 ещё как-то можно объяснить, то появления промежутка в 83656 мкс мне совсем не понятно. Что же я делаю не так и откуда берутся столь странные значения? Притом они не случайны и придерживаются какого-то диапазона. Позиция проблемных периодов тоже остаётся неизменной. При подключении датчика вместо микрофона и захвата сигнала при помощи Audacity изменения периода импульсов не наблюдаю.

 

signal.png

Ссылка на комментарий
Поделиться на другие сайты

А почему такая странная проверка флага?

47 минут назад, 1YHAIhwx сказал:

if(!isRunning) { return; }

сразу после return программа выходит из loop(), что-то там ещё делает, потом возвращается обратно в loop(). Вот иногда вне этого loop() программа занята чем-то, и набегает лишнее время.

Лучше так проверять

while(!isRunning) { }

Да, ещё нужно внешний while(1){ текст процедуры} поставить, тогда программа точно не будет вылетать из этого loop() 

Изменено пользователем Yurkin2015
Ссылка на комментарий
Поделиться на другие сайты

Quote

сразу после return программа выходит из loop(), что-то там ещё делает

Выходит куда и делает что? Напоминаю, функция loop() {} в ардуинодиалекте аналогична коду while(true){}. Таким образом, код

void loop() {
    if(!isRunning) {
        return;
    }
    // do something useful here
}

функционально идентичен
 

while(true) {
    if(!isRunning) {
        continue;
    }
}

 

Ссылка на комментарий
Поделиться на другие сайты

Сравнительное тестирование аккумуляторов EVE Energy и Samsung типоразмера 18650

Инженеры КОМПЭЛ провели сравнительное тестирование аккумуляторов EVE и Samsung популярного для бытовых и индустриальных применений типоразмера 18650. 

Для теста были выбраны аккумуляторы литий-никельмарганцевой системы: по два образца одного наименования каждого производителя – и протестированы на двух значениях тока разряда: 0,5 А и 2,5 А. Испытания проводились в нормальных условиях на электронной нагрузке EBD-USB от ZKEtech, а зарядка осуществлялась от лабораторного источника питания в режиме CC+CV в соответствии с рекомендациями в даташите на определенную модель. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

При выходе из loop() программа занимается отправкой байтов по Serial интерфейсу

#include <Arduino.h>

int main(void)
{
 init();

#if defined(USBCON)
 USBDevice.attach();
#endif
 
 setup();
    
 for (;;) {
 loop();
 if (serialEventRun) serialEventRun();
 }
        
 return 0;
}

 

Поэтому предлагаю, пока не выполнилось условие

if(i == BUFFER_LEN)

оставаться в пределах loop(), а уже при выполнении условия посылать данные по UART и выходить из loop()

Ссылка на комментарий
Поделиться на другие сайты

Новый аккумулятор EVE серии PLM для GSM-трекеров, работающих в жёстких условиях (до -40°С)

Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре. 

Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств. Подробнее параметры и результаты тестов новой серии PLM по ссылке.

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

void loop() {
  while(true) {
    if(i == BUFFER_LEN) {
      detachInterrupt(ARDUINO_MICRO_INTTERRUPT_ON_PIN3);
      for(int x = 1; x < BUFFER_LEN; ++x) {
          Serial.print(periods[x]);
          Serial.print(" ");
       }
        Serial.println();
        Serial.flush();
        lastMicros = 0;
        delay(1500);
        i = 0;
        attachInterrupt(ARDUINO_MICRO_INTTERRUPT_ON_PIN3, sensorInterruptHandler, CHANGE);
    } else {
      if(!isRunning) {
        continue; 
      }
      byte oldSREG = SREG;
      noInterrupts ();
      mcs = micros();
      periods[i] = mcs - lastMicros;
      lastMicros = mcs;
      ++i;
      SREG = oldSREG;
    }
    isRunning = false;
  }
}

Нет, это не помогло. Также стал заполнять массив периодов с отключенными прерываниями. Притом даже если я просто буду печатать в UART текущее значение микросекунд, видно, что иногда между соседними значениями проскакиевает большой промежуток (более 3мс). Не понимаю, откуда они берутся.

Ссылка на комментарий
Поделиться на другие сайты

Литиевые батарейки и аккумуляторы от мирового лидера  EVE в Компэл

Компания Компэл, официальный дистрибьютор EVE Energy, бренда №1 по производству химических источников тока (ХИТ) в мире, предлагает продукцию EVE как со склада, так и под заказ. Компания EVE широко известна в странах Европы, Америки и Юго-Восточной Азии уже более 20 лет. Недавно EVE была объявлена поставщиком новых аккумуляторных элементов круглого формата для электрических моделей «нового класса» компании BMW.

Продукция EVE предназначена для самого широкого спектра применений – от бытового до промышленного. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Отвчечаю на бегу, последний вариант ещё не разглядел, но можно сделать по-простому:

оставить Ваш первый вариант, только увеличить и сделать массив достаточного размера BUFFER_LEN для записи всех шести входных пакетов. И только после записи всего, что нужно, уже тогда спокойно отправлять данные по UART.

Ссылка на комментарий
Поделиться на другие сайты

Уже пробовал, результат аналогичен. Обновление арудиноиде тоже не спасло. Инициализация UART уже после отправки данных не помогла тоже. Девятый и десятый отчёт всё равно периодически становится равным ~1300 мкс вместо положенных 400-900.

Ссылка на комментарий
Поделиться на другие сайты

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

void sensorInterruptHandler() {
    mcs = micros();
    periods[i] = mcs - lastMicros;
    lastMicros = mcs;
    ++i;
}

а в loop() проверять i == BUFFER_LEN  и отправлять по UART когда наберётся нужное число байтов.

Ссылка на комментарий
Поделиться на другие сайты

А причина-то очевидна - с micros() всё в порядке, ровно как и с кодом. Таки дело в пульте. Я подключил фотоприёмник вместо микрофона ещё раз и настрелял десятки последовательностей. Да, пульт иногда производит импульс 9 и 10 в ~1300 мкс вместо ~900. Просто в первый раз я очень удачно нащёлкал и в запись такие последовательности не попали. И последняя чиселка тоже вполне объяснима: пульт пакет передал, встал на паузу, затем снова передавать начал, я же прерывание на изменение логического уровня повесил, вот он длину пребывания на выходе лог. 0 и считал.

Таким образом:

- с ардуиной и функцией micros() всё в порядке;

- код работает удовлетворительно;

- неправильная постановка эксперимента ведёт к потере времени.

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

const int LED_PIN = 13;
const int LED_PIN_CARRIER = 12;

void setup() {
  pinMode(LED_PIN, OUTPUT);
  pinMode(LED_PIN_CARRIER, OUTPUT);
}

void loop() {
  tone(LED_PIN_CARRIER, 38000);
  while(true) {
    delay(10);
    digitalWrite(LED_PIN, 0);
    delay(10);
    digitalWrite(LED_PIN, 1);
  }
}

 

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы публикуете как гость. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...