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

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


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

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

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    297

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

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

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

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


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

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

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


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

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

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 смайлов.

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

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

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

Загрузка...

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

    • Автор: Lost13
      помогите с простиньким скетчом для ардуино уно
      задача :
      на вход (А0) подается логический сигнал короткими импульсами, и если  промежуток между сигналами меньше 2-х секунд , то на выходе (d2) загорается светодиод на 3 секунды, если промежуток между сигналами больше 2-х секунд то он игнорируется 
    • Автор: SaintYGL
      Здравствуйте!
      Данная тема посвящена разработке устройства, имеющего название "Лампа с беспроводным управлением на Arduino".
      Краткая предыстория: я - студент последнего курса техникума, а данная тема - мой дипломный проект. Выбран был в спешке, далеко не самое дальновидное решение, как показала практика, особенно с учётом того, что тема была взята здесь же, на сайте паяльник, в этой статье, и имела незаконченное состояние, из-за чего сейчас и возникают большие неприятности. 
      Концепция: устройство имеет Bluetooth-модуль, по которому соединяется с телефоном, посредством чего и осуществляется беспроводное управление. Также к Arduino подключено двухканальное реле, которое переключает ток, идущий к патронам, в которые вкручены лампы. По команде, переданной по bluetooth, реле переключается в одно из положений (обе выкл.  / 1 вкл, 2 выкл. / 1 выкл, 2 вкл. / обе вкл.)
      Загвоздки: 1) В статье всё осуществляется с помощью отдельного микроконтроллера ATMega 328p, расположенного на макетной плате, в то время как Arduino используется лишь как программатор. Мне же необходимо, чтобы данное устройство работало не с отдельным микроконтроллером, а с самой Arduino. Кварцевый резонатор в ней есть, кнопка есть, диоды есть, bluetooth-модуль и реле докуплены.
      2) Если копировать код из статьи (а точнее перепечатать его со скриншота) и вставить в Arduino IDE, то появятся следующие ошибки: 
      Lamp: 5: error: a function-definition is not allowed here before '{' token
      D: \ Saint \ \ \ \ \ \ \ "\ \ \ \ \ \ \ \ \ Lamp \ Lamp.ino: In function 'void loop ()':
      Lamp: 16: error: 'incomingInt' was not declared in this scope
      Lamp: 27: error: 'class HardwareSerial' has no member named 'printIn'
      Lamp: 30: error: expected '}' at end of input
       
      Сам код, чтобы его не нужно было также перепечатывать со скриншота:
      #include <Wire.h>  int incomingInt = 0  void setup ( )  {  Serial.begin (9600) ;  Serial.setTimeout (1000) ;  pinMode (7, OUTPUT) ;  pinMode (5, OUTPUT) ;  }  void loop ( )  {  if (Serial.available ( ) > 0)  {  incomingInt = Serial.parseInt ();  if (incomingInt = 500)  {  digitalWrite (5, HIGH) ;  }  else digitalWrite (5, LOW) ;  if (incomingInt == 422)  {  digitalWrite (7, HIGH) ;  }  else digitalWrite (7, LOW) ;  Serial.printIn(incomingInt) ;  }  }   
      На данный момент это всё, по мере развития проекта тема будет мной дополняться. Также я буду рад любому совету, который поможет разобраться с этим устройством. Связаться со мной можно через ВКонтакте: vk.com/sainty_gl
    • Автор: mefi73
      Кроме классических Arduino с микроконтроллерами Atmel существуют так же платы, в основе которых лежат другие микроконтроллеры. Одной из таких ардуин является модель 101, в основе которой находится Intel Curie. Выглядит она так:

      Поскольку ардуино это проект открытый, то изготавливать совместимые платы может кто угодно, иногда изменяя схему.
      Так вот, у компании DFrobot свой взгляд на arduino 101. Представляю вашему вниманию DFRobot Curie Nano.


      Для сравнения приведу фото этой платы с некоторыми другими (леонардо, esp32, NodeMCU). Плата довольно компактна.

      Не вижу смысла перепечатывать характеристики микроконтроллера из даташита , просто приведу содержимое первой страницы.

      расположение и назначение выводов DFRobot Curie Nano представлено на следующем изображении.

      Итак, на борту 32-битный микроконтроллер, работающий на частоте 32 мегагерца. Есть встроенный 6-осевой акселерометр, Bluetooth, часы реального времени. То есть микроконтроллер изначально задуман для создания носимых умных устройств. К тому же DFRobot Curie Nano меньше по размеру, чем arduino 101.
      Для программирования DFRobot Curie Nano можно использовать фирменную IDE от Intel (но я её не прбовал), либо ArduinoIDE. На ArduinoIDE я и остановлюсь.
      Что бы ArduinoIDE могла работать с Curie, необходимо добавить поддержку этого микроконтроллера в «менеджере плат».

      Всего необходимо скачать чуть менее 200 мегабайт. На скриншоте только один из скачиваемых пакетов.

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

      Вот и вся установка.
      Стоит отметить, что работа с ардуино 101 (и соответственно с DFRobot Curie Nano) ничем не отличается от других плат ардуино, построенных на микроконтроллерах AVR. Дело в том, что с "ядром" Intel Curie Boards устанавливаются библиотеки, которые заменяют встроенные в ArduinoIDE библиотеки (Wire, SPI, EEPROM, servo и так далее). Кроме того, в комплект пакета поддержки входят библиотеки, специально предгазначенные для микроконтроллера Intel Curie - CurieBLE для работы с bluetooth, CurieI2S, CurieIMU для работы со встроенным датчиком положения, power для спящего режима, CurieTime для работы со встроенным RTC, CurieTimerOne в пояснениях не нуждается.
      Для прошивки микроконтроллера отведено 155682 байт, это больше чем у большинства микроконтроллеров AVR, используемых в платах ардуино. Но, одна и та же программа может занимать разный объем в микроконтроллерах разной архитектуры.  Я решил сравнить объем программ, компмллируемых для Intel Curie и ATmega 328p (arduino nano). Итак...

      С ATmega328p всё закономерно, больше объем скетча - больше памяти занимает скомпилированный код. А вот с Intel Curie не все так просто. Даже пустой скетч занимает 31% памяти. Но далее с ростом скетча рост скомпилированной программы значительно меньше, чем у ATmega328p.
      На данном примере я покажу совместную работу встроенной в ядро Intel Curie библиотеки и библиотеки U8g2. Это скетч простых часов, которые выводят данные на дисплей.
      #include <CurieTime.h> #include <U8g2lib.h> U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0,U8X8_PIN_NONE); char c_time[10]; void setup() {   u8g2.begin(); } void loop() { int i_hour=hour(); //получаем время: час, int i_minute=minute(); //минуты, int i_second=second(); //секунды и помещаем их в соответствующие переменные String s_time = String(i_hour) + ":" + String(i_minute) + ":" + String(i_second); //конактенация и одновременный пере s_time.toCharArray(c_time, 10); //преобразование переменной типа string в тип char   u8g2.firstPage(); //вывод данных на дисплей   do {   u8g2.setFont(u8g2_font_ncenB14_tr); //выбор шрифта   u8g2.drawStr(30, 36, c_time); //эта функция может вывести только значение переменной типа char   }     while ( u8g2.nextPage() ); }
      Создатели arduino 101 хорошо поработали над совместимостью исходного кода, предназначенного для микроконтроллеров AVR, с микроконтроллером Intel Curie. То есть,  большинство сторонних библиотек, написанных для arduino, совместимы так же и с DFRobot Curie Nano.
      Подробно рассматривать библиотеки, поставляемые с ядром Intel Curie, я не буду. Так как примеров, поставляемых с ядром, достаточно для понимания их работы. Отдельного внимания заслуживает библиотека CurieBLE и собственно работа с BLE, но это тема отдельной статьи.
      Кроме того, на базе Curie Nano можно построить нейронную сеть при помощи Curie's neuron SDK, вот только библиотека платная и стоит 19$.
      P.S. DFRobot Curie Nano мне очень понравилась. Уже есть огромный план по использованию этой платы по назначению, то есть для создания носимого устройства с применением возможностей микроконтроллера Intel Curie (часы с навигацией и расчетом астрономических событий для туристов и фотографов)
      Отдельная благодарность магазину dfrobot.com за предоставленную на обзор DFRobot Curie Nano.
       
    • Автор: MolodoyElectrik
      Всем привет.
      Пишу скетч для ардуины, нужно чтоб 1 светодиод мигал постоянно, и 4 светодиода включались и выключались поочередно. Все должно происходить в одно время разумеется и Delay здесь не катит. Вот пример как должно быть только с delay:
       
      Сделал такой скетч:
      Тот который 1 светодиод мигает все хорошо, а вот с 4, которые должны подряд включаться какая то лажа) Где напортачил?
      Предыдущую тему не в том разделе создал, удалите пожалуйста. 
    • Гость izakom
      Автор: Гость izakom
      Добрый день,
      Никак не могу, подключить АЦП к микроконтроллеру. Будет здраво, если кто-нибудь сможет подсказать где моя ошибка или хотя бы где ее искать.
      Я подключаю ADS1240 к arduino UNO. Описание АЦП слишком тяжелое, поэтому прикрепляю ссылку
      http://www.ti.com/lit/ds/sbas173f/sbas173f.pdf
      Также во вложении прикрепил 2 схемы подключения, которые побывал.
      Контроллер общается с АЦП по SPI, где D10 -SS, D11 - MOSI, D12 - MISO, D13 - SCLK.

      Сейчас моя задача, измерять напряжение на потенциометре с достаточной точностью. 
      К сожалению внутренний АЦП arduino 10 разрядный, поэтому пытаюсь подключить внешний.

      Также прикрепляю программу, при помощи которой пытаюсь снимать показания. Но к сожалению на контроллер приходит только "0".
      Схема_2.pdf
      Схема_1.pdf
      Тестова программа.txt
      Схема_2.pdf
      Схема_1.pdf
      Тестова программа.txt
  • Сообщения

    • Выключение модуля осуществляется ровно также, как и его включение. Только обратной операцией.
      Как его включить (или выключить) - подробно описано в документации на камень.
    • Плату от трансформатора немного отодвинуть бы
    • В общем, я подумал и сейчас развожу плату под корпус SO-8 (3 шт), иначе плата большой получится, в каждом корпусе по 2 полевика, по габаритам получается как пара SOT23 в сумме, но зато SOT23 можно раскинуть проводками, если что. Эти полевики обычно стоят в мониторах LCD, у них сопротивление 20-50-100 мОм, но купить можно в магазе, даже по 7-12-25 мОм, по деньгам 15-25-40 руб каждый корпус.  2 полевика (1 корпус) точно надо на 20-50 мОм (1000-10 000мкф), остальные - некритично, ток мало играет роли, можно и по 1 Ом. По напряжению - наверное 30 В и ток 5-10 А, чтобы точно выдержал напругу на щупах. Ну и по затвору 1.5-2.5 В открытия, 3.7 В питания конечно все убивает, приходится буферы ставить. Биполярники по току на базе не смогут прокачать, так что полевики рулят.
    • проходили, мочили, фанерка того, расклеивается...потом клеил лепестки 3мм фанеры в пресе (так же изготавливать пресс форму и тут надо всё равно) изгибал по 5шт вроде или 4 (непомню), и ничего круто. А вот потом как состыковать то и идеальо нарезать торцы под углом точным чтоб сошлось скажем 6 или 8 граней? я пока не смог. Есть вариант на чпу лепескти вырезать из дерва, я рисовал и сдавал, оценили 8 лепестков - 1 рупор под 1.5 евро. Не кисло так. Но зато там только слекиваешь и всё. Есть где то видео где так делают рупор. Но очень дорого это за 2 рупора только за чпу отдать 3 евро. 
    • Собрал фильтр по данной схеме. Подключаю только через высокоуровневый вход, т.е. источник с выхода китайского усилителя 4х10 вт. Проблема вот в чем: Когда подключаю оба канала - все работает нормально только на низкой громкости, а совсем чуть повысив - звук "обрывается" в китайском УМ, как буд то защита какая то срабатывает... Как только отключаю один из каналов и оставляю любой другой - все играет отлично даже на самой максимальной громкости. Кто что думает? В чем может быть проблема? Схему фильтра взял отсюда, но чуток обрезал.
    • Неужели фанерку тяжелее отмочить-изогнуть-склеить, нежели прессом гнуть 20кг железа и варить?
    • Сегодня послушали усилитель с разными источниками (с внешним цапом тоже игрались) и на разной акустике. Кендайлы положил в ящик на хранение. С самвой АМ звук приятней. На мои уши - звук приятней и ВЧ естественней, что ли, на ВЧ с кендайлами каша. Заметно с любой акустикой и любым источником. Вот такие вот дела. В архивчике "бардачок" из разных источников и колонок.   Photos.rar