• Объявления

    • admin

      Просьба всем принять участие!   24.11.2017

      На форуме разыгрывается спектроанализатор Arinst SSA-TG LC (цена 18500 руб). Просьба всем перейти по ссылке ниже и принять участие!
1YHAIhwx

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

9 сообщений в этой теме

1YHAIhwx    3

Я пытаюсь захватить сигнал с ИК-пульта ДУ. Делаю это при помощи 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

Поделиться сообщением


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

Быстрый заказ печатных плат

Полный цикл производства PCB по низким ценам!

  • x
    мм
Заказать Получить купон на $5.00
Yurkin2015    273

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

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

if(!isRunning) { return; }

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

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

while(!isRunning) { }

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

Изменено пользователем Yurkin2015

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1YHAIhwx    3
Quote

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

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

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

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Yurkin2015    273

При выходе из 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()

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1YHAIhwx    3
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мс). Не понимаю, откуда они берутся.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Yurkin2015    273

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1YHAIhwx    3

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Yurkin2015    273

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1YHAIhwx    3

А причина-то очевидна - с 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);
  }
}

 

Поделиться сообщением


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

Ваша публикация должна быть проверена модератором

Гость
Вы не авторизованы. Если у вас есть аккаунт, пожалуйста, войдите.
Ответить в тему...

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

  Разрешено не более 75 смайлов.

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

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

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

Загрузка...

  • Похожие публикации

    • Автор: winice
      Подскажите как можно сделать программку на андроид для обмена данными с контроллером?
      Например дергать выводами arduino со смарта по wi-fi (само собой через соответствующий шилд) 
      Накидать кнопок ползунков... и задать им соответствие каким-то байтам в памяти контроллера. 
      С разработкой на андроид связываться не хочется)))
    • Автор: megauserr895877
      Добрый день уважаемые!
      хотелось бы вашего совета по блоку питания!
      Суть проблемы такова, имеется прибор на Arduino с 3 датчиками и несколькими кнопками (если быть совсем честным и точным это контроллер джойстика). У большинства народа и у меня в частности этот прибор имеет нестабильности в работе датчиков, так как собственного питания ардуины на датчики хватает с некоторым натягом и более того, склонен я думать что питание ардуины от USB имеет "некоторые" проблемы с помехами и скачками питания- отчего возникают шумы в показаниях. Решение проблемы я вижу в 3 вариантах: 1 шумы датчиков, 2 шумы контроллера, 3 шумы источника питания. Не вдаваясь, пока что, в первые две, хочу решить 3 проблему.
      Моя цель собрать или купить готовый блок, модуль или комплектующие и собрать сетевой(желательно безтрансформаторный-трудно добыть, еще сложней перемотать) качественный блок питания с стабилизированным DC напряжением 5 V на небольшую мощность- 200-500 mA
      Возможно я параноик и питание ардуины стабильно и все "затыки" в первых 2 моментах,
      возможно для датчиков хватит стандартного ардуиновского внешнего подключаемого питалова...
      возможно блок питания от мобилки с лихвой заменит по качеству и всему прочему большинство самоделок,
      возможно и  взять какой нить 9 вольтовый зарядник и стабилизировать его какой нибудь 7805 или AMS1117( но 7805 это печка а не стаб- у меня батарея есть квартиру греть, а 1117 какие то подозрительные милипусичные и обвязка на смд меня смущает- будет ли оно ловить внешние помехи и отдавать их в выходное напряжение да и смысл, если они же в ардуиновской питалке стоят?)
      но я же параноик... и потому прошу совета Отцов:
      пару схемок:
      одну простую и надежную как автомат Михаила Тимофеевича
      и вторую что-нить экстравагантно шизофреничное а ля золотые транзисторы навесным монтажом в корпусе оклеенном серебряными пулями крестами, чесноком и святой водой, с наклейкой HighEnd и обмотанное кабелем ODIN или Sommer
      Ну или валенков, что суету попусту развел , вот только в гугл не отправляйте, видели там-знаем
    • Автор: NORD905
      Здравствуйте уважаемые форумчане.
      Суть: нужно изменить голос в реальном времени, создав устройство компактных размеров на базе arduino, которое можно было бы встроить в маску/шлем. 
      С горем пополам, товарищи мне собирали аналоговые схемы, которые меняли голос, но меняли, мягко говоря, ужасно. Качество было на уровне детских игрушек. Заказывал с али подобные вещи - тоже плачевные результаты.
      Но программы справляются с этим прекрасно. Поэтому нужно сделать на arduino. Я не представляю как это делается, заказывать на стороне не хочу, т.к.: 1) будет дорого, 2) хотелось бы самому научиться делать это.
      Помогите пожалуйста. Может у вас есть уже такой проект. Что мне надо купить и где. Схемы если есть (свежие, не на древних компонентах). Советы, может обратиться к какому-нибудь умельцу местному (в Москве живу), чтобы показал/рассказал как что и где.
      Спасибо за внимание.
    • Автор: Prozac
      Здравствуйте! С МК я знаком достаточно давно, теперь вот возникло желание заказать и немножечко помучить Ардуину (а точнее, ее китайский аналог Funduino Nano - но это не суть важно) - просто, чтобы понять, что это за зверь такой. Как известно, классической средой для написания программ ("скетчей") и прошивания Ардуины является Arduino IDE, язык которой - СИ. Но вот беда - не люблю я этот язык, за невменяемый и плохочитаемый синтаксис (писать вместо опрятного Паскалевского AND крякозябру &&, например - это нечто), и знаю его плохо (могу с некоторым усилием прочесть не очень сложный чужой код, и только). Зато Pascal очень нравится, и с Delphi сталкивался. Отсюда вопрос: существуют ли интегрированные программные комплексы для Ардуины, имеющие Пакскальский синтаксис и, так же как и Arduino IDE, имеющие встроенную функцию прошивальщика (т.е., построенные по принципу "все в одном"). Ну, и если такая среда существует, где взять для нее библиотеки - такие же удобные, как и у Arduino IDE? Или, может быть, существует какой-то плагин или патч для классической Arduino IDE, переводящий ее синтаксис на Паскальский?
       
      P.S. Я знаю-знаю, что СИ учить нужно (хотя, с AVRками до сих пор общаюсь на Ассемблере, а если совсем сложный проект - то беру MicroPascal). Я знаю, что в Arduino IDE используется очень упрощенная версия СИ - для домохозяек. И я знаю, что переучится с Паскаля на СИ (тем более упрощенный) - не так уж и сложно (главное - знать общие принципы программирования). Но... как-нибудь в другой раз: сейчас лениво что-то...
       
      P.P.S. СИшнки, только без холиворов, ладно? Обидеть никого не хотел!
       
    • Автор: hardbar
      Есть проект СГУ на AVR. Музой проекта послужил не безызвестный проект  СГУ на PIC.
      Хотел сделать его ещё в 2012 но знаний не хватало. А вот сейчас знаний хватает, вот и сбылась моя мечта. 
      Пока что прикреплю видео, когда напишу статью о нем, ждите публикацию на ГЛ странице сайта. 
      В качестве динамика использовал колонку от Соньки музыкалки.