В предыдущих публикациях (Часть 1 и Часть 2) рассказывалось, как изготовить самодельный счётчик объектов, пересекающих единственный инфракрасный луч (барьер). В счётчике использовался механизм внешних прерываний микроконтроллера. Соответственно, скетч для Arduino выглядит крайне простым.

Теперь мне хочется чуть-чуть пошалить и предложить вашему вниманию альтернативный вариант: странный инфракрасный счётчик с одним лучом. В нём не используются внешние прерывания. И скетч выглядит посложнее.

Зато он может определить, сколько времени объект провёл в инфракрасном луче.

Сенсорная система

Подходящая для странного счётчика сенсорная система (с импульсным излучателем) описана в публикации «Очень самодельная сенсорная система для инфракрасного счётчика людей.»

Вход инфракрасного излучателя следует подключить к цифровому выходу D2 Arduino, выход инфракрасного приёмника - к аналоговому входу A0.

Скетч

// Однолучевой инфракрасный счётчик 
//(с измерением продолжительности прохода через луч)

// Используемые пины Arduino
#define TRANSMITTER  2
#define RECEIVER     A0

// Минимальное значение сигнала на выходе приёмника, означающее: "ИК луч есть"
#define SIGNAL_MIN    50     //соответствует напряжению 250 mV

unsigned long in_time,  //отметка времени входа объекта в луч
              out_time, //отметка времени выхода объекта из луча
              pass_counter; //счётчик прохождений объектов

float time; //продолжительность нахождения объекта в луче

int fone_level, //фоновый уровень на выходе приёмника при выключенном излучателе
    signal,           //сигнал (превышение над фоном) при включенном излучателе
    channel_now,      //состояние сенсорного оптического канала
    channel_before;   //состояние канала в предыдущем опросе

// Инициализация

void setup() {
  
  // Пин излучателя - в режим вывода
  pinMode(TRANSMITTER, OUTPUT);
  // Состояние сенсорного канала априори - открыт
  channel_before = 1;
  // Сброс счётчика прохождений объектов
  pass_counter = 0;
  // Ожидание начальной зарядки буферного конденсатора излучателя до нормы
  delay(100);  // 0.1 сек.
  
  Serial.begin(9600);
  Serial.println(" ");
  Serial.println("----- Start ------");
  
}

// Основной цикл

void loop() {
  
  // Пробуждение сенсорного оптического канала и определение его состояния (250 мксек)
  fone_level = analogRead(RECEIVER);
  digitalWrite(TRANSMITTER, HIGH);
  signal = analogRead(RECEIVER) - fone_level;
  digitalWrite(TRANSMITTER, LOW);

  if (signal >= SIGNAL_MIN) channel_now = 1; else channel_now = 0;

  // Проверка наличия события в канале
  if (channel_now != channel_before) {//событие есть
    
    channel_before = channel_now; //запоминание состояния канала
    
    //Определение типа события и его обработка
    if (channel_now == 0) {//объект вошёл в луч
      in_time =  micros(); //отметка времени входа, мксек.
    }
    else {//объект вышел из луча
      out_time =  micros(); //отметка времени выхода, мксек.
      // Продолжительность нахождения объекта в луче, сек.
      time = 1.0e-6 * (out_time - in_time);
      // Подсчёт очередного прохождения объекта
      pass_counter++;
      Serial.print("  ");
      Serial.print(pass_counter);
      Serial.print("   ");
      Serial.print(time);
      Serial.println(" sec.");
    }
    
  }
  
  delayMicroseconds(750); //задержка для обеспечения периода основного цикла ~1000 мксек
}

Вывод результатов счёта

Чтобы увидеть результаты работы счётчика нужно активировать монитор последовательного порта, встроенный в среду программирования Arduino. При каждом проходе объекта через инфракрасный барьер (луч) в монитор выводится номер прохода и время, проведённое объектом в инфракрасном луче.

Пример реального использования странных счётчиков

Двухлучевые «собратья» странного счётчика круглосуточно несут сетевую совместную «службу» на одном из этажей учебного корпуса вуза. Их работу можно увидеть онлайн.

Комментарии (3)


  1. BSOZ
    27.05.2025 11:45

    Основной цикл никогда не будет 1000 мксек т.к. 250 мксек в нём не будут стабильными и будут зависимыми от задействованной ветви кода. В целом этот подход довольно плохой. Вместо этого следовало опираться на дельту micros(), например, если необходимость ухода от использования прерываний сколько-то обоснована. Если речь о подсчёте времени, то вряд ли стоит делать такие допущения в работе со временем. Когда потребуется подсчитать возможную погрешность, это очень усложнит расчёт.


    1. NutsUnderline
      27.05.2025 11:45

      да ветви кода ладно, там плюс минус, 250мс тут тут analogRead похоже генерирует


      1. BSOZ
        27.05.2025 11:45

        Автор заявляет о микросекундах, не о миллисекундах.