Компоненты · 16 мин чтения

TCRT5000 и Arduino: подключение ИК-датчика, код и тахометр

TCRT5000 с Arduino: ИК-светодиод и фототранзистор, распознавание чёрного и белого, выходы AO/DO, порог, дальность 1–15 мм, FC-51 против TCRT5000 и код для измерения оборотов.

TCRT5000 — маленький инфракрасный отражательный датчик, который в проектах на Arduino замечает чёрную линию на полу, метку на вращающемся валу или поверхность в нескольких миллиметрах перед собой. Подключить TCRT5000 к Arduino просто: готовый модуль соединяется с 5V, GND и одним сигнальным пином; библиотека не нужна, хватает analogRead() или digitalRead(). В одном корпусе стоят и инфракрасный светодиод, который излучает свет, и фототранзистор, который измеряет отражённый свет, поэтому этот датчик служит общим «глазом» для роботов, следующих по линии, принтеров, которые замечают бумагу, и тахометров, которые измеряют скорость вращения.

Из этой статьи ты узнаешь, как ИК-светодиод и фототранзистор внутри TCRT5000 работают вместе, почему датчик так легко отличает чёрные поверхности от белых, чем аналоговый (AO) выход модуля отличается от цифрового (DO) и как настроить порог потенциометром и программно. Шаг за шагом, с кодом для Arduino Uno, ESP32 и Raspberry Pi Pico, разберём рабочее расстояние 1–15 мм, влияние внешнего освещения и способ измерения, который его устраняет, отличие от датчика препятствий FC-51 и сборку тахометра (измерителя оборотов) на TCRT5000.

Инфракрасный отражательный датчик TCRT5000: синий ИК-светодиод и чёрный фототранзистор
TCRT5000: элемент с синей линзой — инфракрасный светодиод на 950 нм, элемент с чёрной линзой — фототранзистор с фильтром дневного света; оба стоят рядом в одном корпусе и разделены светонепроницаемой перегородкой.

Что такое TCRT5000 и как он работает?

TCRT5000 — отражательный оптический датчик компании Vishay. С одной стороны корпуса стоит светодиод, излучающий инфракрасный свет, с другой — светочувствительный фототранзистор, и оба смотрят в одну сторону, вперёд. Пластиковая перегородка между ними не даёт свету светодиода попасть на фототранзистор напрямую; свет регистрируется только тогда, когда он падает на поверхность перед датчиком и отражается обратно. Фототранзистор — это транзистор, который пропускает через коллектор тем больший ток, чем больше света падает на область базы: чем сильнее поверхность отражает, тем больше ток коллектора. Чёрная линза — это фильтр дневного света; она задерживает большую часть видимого света и пропускает только длины волн, близкие к инфракрасным.

ХарактеристикаЗначение (даташит Vishay)
УстройствоИнфракрасный светодиод + фототранзистор, корпус, задерживающий видимый свет
Длина волны светодиода950 нм (невидимый инфракрасный)
Оптимальное рабочее расстояние2,5 мм
Рабочий диапазон0,2–15 мм (сигнал выше 20% от пикового)
Прямое напряжение светодиодаОбычно 1,25 V, максимум 1,5 V (при 60 mA)
Максимальный постоянный ток светодиода60 mA
ФототранзисторVCEO 70 V, ток коллектора до 100 mA
Темновой токОбычно 10 nA, максимум 200 nA
Размеры10,2 × 5,8 × 7 мм; TCRT5000L — версия с длинными выводами (15 мм)
Рабочая температураот −25 до +85 °C

Arduino не может напрямую измерить ток фототранзистора; чтобы превратить ток в напряжение, к коллектору подключают нагрузочный резистор. На готовых модулях он обычно на 10 kΩ и подтягивает коллектор к VCC. Напряжение на коллекторе равно V = VCC − Ic × R. Если над белой поверхностью через фототранзистор течёт около 0,4 mA, на 10 kΩ падает 4 V и выход опускается до 1 V. Если над чёрной поверхностью ток уменьшается до 20 µA, падение составляет всего 0,2 V и выход остаётся на 4,8 V. Значит, на модуле TCRT5000 белое даёт низкое напряжение, а чёрное — высокое; поначалу эта инверсная логика сбивает с толку, но так просто устроена схема. Больший нагрузочный резистор делает датчик чувствительнее, но медленнее; меньший — быстрее, но слабые отражения он уже не различает.

Как TCRT5000 отличает чёрное от белого?

Белая бумага рассеивает обратно во все стороны большую часть падающего на неё инфракрасного света; матовая чёрная краска, тонер или изолента поглощают большую часть света и превращают его в тепло. TCRT5000 превращает эту разницу в большую разницу тока фототранзистора. Но датчик не видит цвета так, как человеческий глаз; для него важно только, насколько сильно поверхность отражает на 950 нм. Отсюда сюрпризы: некоторые струйные отпечатки на глаз угольно-чёрные, но в инфракрасном свете почти прозрачны, и датчик принимает их за белое. Глянцевая чёрная изолента, если смотреть на неё строго сверху, может отражать свет обратно, как зеркало. Красные, оранжевые и жёлтые поверхности часто читаются почти как белые. Поэтому всегда проверяй материал линии и пола датчиком, прежде чем на нём остановиться. В таблице ниже — примерные значения при 5 V и высоте около 3 мм; у твоего датчика и в твоих условиях показания могут отличаться.

ПоверхностьОтражение ИК-светаAO (Uno, 0–1023)DO (у большинства модулей)
Белая бумагаОчень сильноеОколо 30–200LOW, индикатор горит
Светлое дерево или столСильноеОколо 100–400Обычно LOW
Матовая чёрная изолента или лазерная печатьОчень слабоеОколо 600–1000HIGH, индикатор не горит
Глянцевая чёрная изолентаЗависит от углаНестабильноНестабильно
Поверхности нет (дальше 2 см)Отражения нетОколо 1000HIGH, как на чёрном
Не забывай про последнюю строку таблицы: когда перед датчиком ничего нет, он тоже видит чёрное. Поэтому, если поднять робота над столом, моторы робота, следующего по линии, продолжают крутиться, будто линия «найдена». Простое правило «остановить моторы, если все датчики одновременно видят чёрное» бережёт и робота, и стол.

Модуль TCRT5000: аналоговый (AO) и цифровой (DO) выход

Чаще всего вместо голого TCRT5000 используют готовый модуль. Рядом с датчиком на плате модуля стоят компаратор LM393, синий подстроечный потенциометр, резистор, ограничивающий ток ИК-светодиода, нагрузочный резистор фототранзистора на 10 kΩ и два маленьких светодиода: один показывает питание, второй — индикатор состояния выхода DO. Пин AO соединён прямо с коллектором фототранзистора и выдаёт то самое «сырое» напряжение, которое мы рассчитали выше. LM393 сравнивает это напряжение с напряжением на движке потенциометра и выдаёт результат на пин DO. У распространённых модулей над белой поверхностью DO переходит в LOW и индикатор загорается; над чёрной или когда перед датчиком ничего нет — в HIGH, и светодиод гаснет. На некоторых платах логика обратная, поэтому сначала проверь поведение своего модуля в мониторе порта. У большинства одноканальных модулей 4 пина (VCC, GND, DO, AO); бывают и 3-пиновые версии только с DO, а также линейки датчиков линии на 3 и 5 каналов. Один модуль потребляет примерно 15–40 mA при 5 V, в зависимости от резистора ИК-светодиода.

ХарактеристикаAO (аналоговый)DO (цифровой)
Что сообщаетСколько света отражаетсяВыше значение порога или ниже
Чтение на UnoanalogRead(): 0–1023digitalRead(): HIGH или LOW
ПорогЗадаётся в кодеПотенциометр на плате
Над белымНизкое (около 30–200)LOW
Над чёрнымВысокое (около 600–1000)HIGH
Лучше всего подходит дляОценки расстояния, движения по линии с PID, калибровкиПодсчёта оборотов через прерывания, простых решений «да/нет»

Рабочее расстояние: как выжать максимум из диапазона 1–15 мм

По даташиту TCRT5000 сигнал максимален на 2,5 мм и остаётся выше 20% от пика в диапазоне от 0,2 до 15 мм. На практике датчиком можно пользоваться на расстоянии от 1 до 15 мм, но разница между чёрным и белым с ростом расстояния быстро уменьшается. Кривая «расстояние — сигнал» к тому же не монотонна: ближе 2 мм сигнал снова падает, потому что световой конус светодиода и поле зрения фототранзистора пересекаются на поверхности только начиная с определённого расстояния. Если прижать датчик к поверхности, даже белая бумага выглядит тёмной. Поэтому одно и то же аналоговое значение может получиться и на 1 мм, и на 5 мм; для оценки расстояния используй только монотонный участок дальше 3 мм.

РасстояниеЧто происходит?Подходит для
0–1 ммСветовой конус и поле зрения не пересекаются, даже белое читается слабоИзбегать; датчик не должен тереться о пол
2–3 ммСамый сильный сигнал, максимальная разница между чёрным и белымДвижение по линии, обнаружение бумаги и меток
3–8 ммСигнал слабеет, но разница ещё хорошо заметнаНадёжный монтаж под роботом, тахометр
8–15 ммЗамечаются только белые и блестящие поверхностиОбнаружение близости, объект есть / нет
Дальше 15 ммСигнал теряется на фоне внешних помехВыбрать другой датчик, например FC-51 или HC-SR04

С TCRT5000 можно измерять и небольшие расстояния: на одной и той же поверхности аналоговое значение плавно меняется с расстоянием, поэтому можно снять показания в нескольких точках, например на 3, 5, 8 и 12 мм, составить таблицу и линейно интерполировать между ними. Но такое измерение зависит от цвета поверхности: датчик, откалиброванный на белой бумаге, решит, что серая поверхность дальше, чем на самом деле. Поэтому воспринимай TCRT5000 не как линейку, а как датчик приближения, который на одной поверхности отвечает на вопрос «ближе или дальше?». Для измерения сантиметров гораздо лучше подходит ультразвуковой датчик расстояния HC-SR04.

Подключение модуля TCRT5000: Arduino Uno, ESP32 и Pico

Пин модуляArduino UnoESP32Raspberry Pi Pico
VCC5V3V33V3(OUT), пин 36
GNDGNDGNDGND, пин 38
DOD2 (пин прерывания)GPIO 27GP15, пин 20
AOA0GPIO 34 (ADC1)GP26 / ADC0, пин 31
Пины ESP32 и Pico рассчитаны на 3,3 V. На этих платах питай модуль TCRT5000 от пина 3V3, а не от 5V или VBUS: при питании модуля от 5 V выходы AO и DO над чёрным поднимаются почти до 5 V и могут повредить входной пин. При 3,3 V ток ИК-светодиода уменьшается, поэтому дальность обнаружения становится чуть меньше; это нормально. Если без питания 5 V никак не обойтись, поставь на линию AO делитель напряжения. Полную карту пинов своей платы можно посмотреть в утилите распиновки.

Как подключить голый TCRT5000 без модуля?

У голого датчика четыре ножки: две с синей стороны — анод и катод ИК-светодиода, две с чёрной стороны — коллектор и эмиттер фототранзистора. Проще всего различить их в режиме проверки диодов мультиметра: на двух ножках синей стороны в одном направлении получится около 1,0–1,2 V, а в другом — ничего; ножка, которой в этот момент касается красный щуп, — анод. Фототранзистор, подключённый наоборот, не повредится, потому что ток ограничивает резистор на 10 kΩ; он просто не будет работать. Если показания не меняются от света, поменяй местами две ножки чёрной стороны.

Ток ИК-светодиода нужно ограничить резистором. Он рассчитывается по формуле R = (VCC − VF) / I: для 5 V, прямого напряжения 1,2 V и 20 mA получается (5 − 1,2) / 0,02 = 190 Ω; ближайший стандартный номинал 220 Ω даёт около 17 mA — такой ток пин Arduino спокойно выдаёт. Этот расчёт можно сделать и в калькуляторе резистора для светодиода. Эмиттер фототранзистора подключи к GND, коллектор — к 5V через резистор 10 kΩ, и этот же коллектор соедини с A0. Чтобы различать более далёкие или более тёмные поверхности, нагрузочный резистор можно увеличить до 47 kΩ; тогда белые поверхности быстро уходят в насыщение, зато мелкие различия в тёмной области становятся заметнее.

Ножка TCRT5000Подключение (Arduino Uno)
Анод (синяя сторона)К 5V через 220 Ω; для измерения внешней засветки — к D7 вместо 5V
Катод (синяя сторона)GND
Коллектор (чёрная сторона)К A0 и через 10 kΩ к 5V
Эмиттер (чёрная сторона)GND

Шаг за шагом: распознавание чёрной и белой поверхности с Arduino

  1. Подключи пин VCC модуля к пину 5V на Arduino, а GND — к GND.
  2. Подключи пин AO к A0, а пин DO — к D2.
  3. Для проверки наклей на лист белой бумаги полоску матовой чёрной изоленты шириной 2 см.
  4. Держи или закрепи датчик примерно в 3 мм над поверхностью, перпендикулярно к ней.
  5. Загрузи код ниже в плату и открой монитор порта на скорости 9600 бод.
  6. В первые 5 секунд несколько раз проведи датчиком туда-обратно над чёрной изолентой и белой бумагой; код найдёт минимальное и максимальное значения и автоматически вычислит порог.
  7. Перемещай датчик между чёрным и белым: светодиод L на плате должен загораться над чёрным и гаснуть над белым.
C++ (Arduino IDE)
1// TCRT5000 ile siyah-beyaz zemin algılama / Black-white surface detection with TCRT5000
2const int SENSOR_AO = A0;      // modülün AO pini / module AO pin
3const int SENSOR_DO = 2;       // modülün DO pini / module DO pin
4const int LED_PIN = 13;        // kart üzerindeki L LED'i / onboard L LED
5const int HYST = 40;           // histerezis payı / hysteresis margin
6
7int threshold = 450;           // varsayılan eşik / default threshold
8bool onBlack = false;
9
10void setup() {
11  Serial.begin(9600);
12  pinMode(SENSOR_DO, INPUT);   // modülde çekme direnci var / the module has its own pull-up
13  pinMode(LED_PIN, OUTPUT);
14
15  Serial.println(F("5 sn: sensoru siyah ve beyazin uzerinden gecir / sweep over black and white"));
16  digitalWrite(LED_PIN, HIGH);                // kalibrasyon sürüyor / calibrating
17  int lo = 1023, hi = 0;
18  unsigned long start = millis();
19  while (millis() - start < 5000) {
20    int v = analogRead(SENSOR_AO);
21    if (v < lo) lo = v;                       // en beyaz / whitest
22    if (v > hi) hi = v;                       // en siyah / blackest
23  }
24  digitalWrite(LED_PIN, LOW);
25  if (hi - lo >= 100) {
26    threshold = (lo + hi) / 2;                // eşik = (beyaz + siyah) / 2 / threshold = (white + black) / 2
27  } else {
28    Serial.println(F("Fark cok az, varsayilan esik / Too little contrast, default threshold"));
29  }
30  Serial.print(F("Beyaz/White: ")); Serial.print(lo);
31  Serial.print(F("  Siyah/Black: ")); Serial.print(hi);
32  Serial.print(F("  Esik/Threshold: ")); Serial.println(threshold);
33}
34
35void loop() {
36  int raw = analogRead(SENSOR_AO);            // beyazda düşük, siyahta yüksek / low on white, high on black
37  bool doBlack = digitalRead(SENSOR_DO) == HIGH;   // çoğu modülde siyahta HIGH / HIGH on black on most modules
38
39  if (!onBlack && raw > threshold + HYST) onBlack = true;    // siyaha geçti / moved onto black
40  if (onBlack && raw < threshold - HYST) onBlack = false;    // beyaza geçti / moved onto white
41
42  digitalWrite(LED_PIN, onBlack ? HIGH : LOW);
43  Serial.print(F("AO: ")); Serial.print(raw);
44  Serial.print(F("  DO: ")); Serial.print(doBlack ? F("SIYAH/BLACK") : F("BEYAZ/WHITE"));
45  Serial.print(F("  Kod/Code: ")); Serial.println(onBlack ? F("SIYAH/BLACK") : F("BEYAZ/WHITE"));
46  delay(100);
47}

Код вычисляет порог как (минимум + максимум) / 2: если на белом получается 80, а на чёрном 820, порог равен 450. Вместо одного порога используются две границы: переход на «чёрное» происходит, когда значение поднимается выше 490, а обратно на «белое» — когда опускается ниже 410. Благодаря такому гистерезису выход не мерцает, когда датчик стоит ровно на краю линии. Если во время калибровки разница остаётся меньше 100, код берёт порог по умолчанию 450 и выводит предупреждение; обычно это значит, что датчик слишком высоко или его провели только над одним цветом. Столбец DO показывает то же решение, принятое потенциометром модуля; если смотреть на оба значения рядом, удобно проверять настройку потенциометра.

Настройка порога: потенциометр или программа?

Если используется выход DO, порог задаёт потенциометр на плате. Напряжение на движке потенциометра — опорное для компаратора; в момент, когда напряжение AO пересекает его, DO меняет состояние. Для хорошей настройки выполни эти шаги:

  1. Поставь датчик над белой поверхностью на той высоте, на которой он будет работать, и крути потенциометр, пока не загорится индикатор.
  2. Сдвинь датчик на чёрную линию и проверь, что светодиод гаснет; если нет, немного поверни потенциометр обратно.
  3. Найди два крайних положения, при которых светодиод уверенно горит над белым и уверенно гаснет над чёрным, и установи потенциометр посередине между ними.
  4. Для более точной настройки измерь мультиметром AO над белым и над чёрным и выставь напряжение на движке потенциометра посередине между этими значениями; например, около 2,4 V для 0,6 V и 4,2 V.
  5. Всегда настраивай там, где будет работать робот или установка, при том же освещении.
Программный порог обычно гибче: можно заново откалибровать датчик при изменении освещения или напряжения батареи и задать каждому из нескольких датчиков собственный порог. Настоящее преимущество выхода DO — скорость: компаратор принимает решение за микросекунды, и его выход можно подать прямо на пин прерывания. Поэтому используй DO для быстрых задач вроде подсчёта оборотов, а AO — для тонких задач вроде движения по линии и оценки расстояния.

Влияние внешнего освещения и как с ним справиться

Фильтр дневного света в чёрной линзе задерживает видимый свет, но не может задержать инфракрасный, ведь датчик как раз работает в инфракрасном диапазоне. Солнце, лампы накаливания и галогенные лампы сильно излучают в инфракрасной области около 950 нм; когда этот свет попадает на фототранзистор, даже чёрная поверхность читается как белая. На прямом солнце фототранзистор может полностью войти в насыщение, и датчик вообще ничего не различает. А вот светодиодные и люминесцентные лампы дают очень мало инфракрасного света, поэтому один и тот же робот может отлично ездить в классе и путаться у окна. Вот решения, от простых к сложным:

  • Затени датчик: надень вокруг него чёрную «юбку», термоусадочную трубку или чёрный поролон; они задерживают свет сбоку.
  • Держи датчик низко: опусти его на 2–4 мм от поверхности; отражённый свет станет сильнее, а доля внешнего света — меньше.
  • Калибруй на месте: всегда задавай порог в реальных условиях, а если освещение меняется, измеряй заново при запуске.
  • Измеряй разницу: с голым датчиком управляй ИК-светодиодом с пина Arduino и делай два измерения: при выключенном и при включённом светодиоде. Внешний свет в обоих измерениях одинаков, поэтому разница — это только отражение светодиода.
C++ (Arduino IDE)
1// Ortam ışığını çıkaran ölçüm (çıplak TCRT5000) / Ambient-light-cancelling reading (bare TCRT5000)
2const int IR_LED = 7;          // 220 Ω üzerinden IR LED anoduna / to the IR LED anode via 220 Ω
3const int SENSOR = A0;         // kolektör, 10 kΩ ile 5V'a / collector, 10 kΩ pull-up to 5V
4const int SETTLE_US = 500;     // fototransistörün oturma süresi / phototransistor settling time
5
6int readReflection() {
7  digitalWrite(IR_LED, LOW);
8  delayMicroseconds(SETTLE_US);
9  int ambient = analogRead(SENSOR);           // yalnız ortam ışığı / ambient light only
10  digitalWrite(IR_LED, HIGH);
11  delayMicroseconds(SETTLE_US);
12  int lit = analogRead(SENSOR);               // ortam + yansıma / ambient + reflection
13  digitalWrite(IR_LED, LOW);
14  return ambient - lit;                       // ışık arttıkça gerilim düşer / voltage drops as light rises
15}
16
17void setup() {
18  Serial.begin(115200);
19  pinMode(IR_LED, OUTPUT);
20}
21
22void loop() {
23  long sum = 0;
24  for (int i = 0; i < 8; i++) sum += readReflection();   // 8 ölçümün ortalaması / average of 8 readings
25  int reflection = sum / 8;
26  Serial.println(reflection);                 // büyük değer = beyaz ya da yakın / large = white or near
27  delay(50);
28}

Фототранзистор реагирует не мгновенно; с нагрузочным резистором 10 kΩ ему может понадобиться несколько сотен микросекунд, чтобы установиться на новом значении, поэтому код ждёт 500 µs перед каждым измерением. Если показания нестабильны, увеличь SETTLE_US до 1000. Чем больше разница, тем белее или ближе поверхность. Полностью победить солнце этот способ не может: если внешний свет уже ввёл фототранзистор в насыщение, включение светодиода ничего не меняет и разница падает до нуля; тогда остаётся только затенить датчик. Пульты от телевизора используют ту же идею гораздо быстрее: они посылают свет пачками с частотой 38 kHz, а приёмник слушает только эту частоту; подробнее — в статье ИК-приёмник и пульт.

TCRT5000 против датчика препятствий FC-51: в чём разница?

Их часто путают: оба состоят из инфракрасного светодиода и приёмника, измеряющего отражённый свет, и у обоих есть компаратор LM393. Разница в назначении: у TCRT5000 излучатель и приёмник объединены в одном корпусе и нацелены на маленькое пятно в нескольких миллиметрах перед ними. FC-51 же использует отдельный ИК-светодиод и отдельный приёмник, стоящие рядом, и ловит свет, отражённый от препятствия на расстоянии нескольких сантиметров. Поэтому FC-51 не может надёжно выделить тонкую линию на полу, а TCRT5000 не видит стену в 10 см.

ХарактеристикаМодуль TCRT5000Датчик препятствий FC-51
УстройствоСветодиод и фототранзистор в одном корпусе, между ними перегородкаОтдельный ИК-светодиод и отдельный приёмник рядом
Дальность обнаруженияОколо 1–15 мм (лучше всего на 2,5 мм)Около 2–30 см (регулируется)
Зона обнаруженияУзкое пятноКонус около 35°
ВыходыОбычно AO + DOТолько DO (LOW при наличии препятствия)
Типичное применениеДвижение по линии, тахометр, обнаружение бумаги и метокРобот, объезжающий препятствия, обнаружение руки или предмета
Внешнее освещениеУстойчивее благодаря малому расстояниюНа солнце дальность заметно падает

Подсчёт оборотов с TCRT5000 (тахометр)

Одна из самых полезных, но малоизвестных задач TCRT5000 — измерять скорость вращения; даже в даташите Vishay первым в списке применений стоит датчик положения для энкодеров вала (position sensor for shaft encoders). Идея простая: на диск или вал, окрашенный в чёрный цвет, наклеивается белая метка; каждый раз, когда метка проходит мимо датчика, выход DO один раз переходит в LOW. По числу этих импульсов скорость можно вычислить двумя способами:

  • Метод подсчёта: об/мин = число импульсов × 60 / (число меток × время измерения в секундах). Если за 1 секунду насчитано 25 импульсов, а на диске 1 метка, результат 25 × 60 = 1500 об/мин. На высоких скоростях метод очень точен, но с окном в 1 секунду и одной меткой его разрешение — 60 об/мин.
  • Метод периода: об/мин = 60 000 000 / (микросекунды между двумя импульсами × число меток). Если между двумя импульсами проходит 40 000 µs (40 мс), результат 60 000 000 / 40 000 = 1500 об/мин. Он даёт свежий точный результат на каждом импульсе, даже на малых скоростях.
  • Число меток: 2 или 4 равномерно расположенные метки на диске улучшают разрешение метода подсчёта; не забудь изменить число меток в формуле.
  1. Покрась вал или колесо, которое нужно измерить, матовой чёрной краской или обмотай матовой чёрной изолентой.
  2. Наклей на него белую бумажную наклейку размером около 5 × 5 мм; метка должна быть шире пятна, на которое смотрит датчик.
  3. Закрепи датчик в 3–5 мм от метки так, чтобы он не вибрировал.
  4. Медленно поверни вал рукой и проверь, что светодиод DO мигает каждый раз, когда проходит метка; при необходимости подстрой потенциометр.
  5. Подключи пин DO к одному из пинов прерывания Uno (D2 или D3) и загрузи код ниже в плату.
C++ (Arduino IDE)
1// TCRT5000 ile takometre (devir ölçer) / Tachometer with TCRT5000
2const byte SENSOR_DO = 2;                // DO -> D2 (kesme pini / interrupt pin)
3const byte MARKS = 1;                    // diskteki beyaz işaret sayısı / white marks on the disc
4const unsigned long MIN_GAP_US = 500;    // daha sık darbeler titreşimdir / closer pulses are glitches
5
6volatile unsigned long pulseCount = 0;
7volatile unsigned long lastPulseUs = 0;
8volatile unsigned long periodUs = 0;
9
10void onPulse() {
11  unsigned long now = micros();
12  unsigned long gap = now - lastPulseUs;
13  if (gap < MIN_GAP_US) return;          // sınırdaki titreşimi ele / filter edge chatter
14  if (lastPulseUs != 0) periodUs = gap;  // iki darbe arası süre / time between pulses
15  lastPulseUs = now;
16  pulseCount++;
17}
18
19void setup() {
20  Serial.begin(115200);
21  pinMode(SENSOR_DO, INPUT);
22  attachInterrupt(digitalPinToInterrupt(SENSOR_DO), onPulse, FALLING);   // beyaz işarette LOW olur / goes LOW on the white mark
23}
24
25void loop() {
26  static unsigned long lastPrint = 0;
27  if (millis() - lastPrint < 1000) return;   // saniyede bir hesapla / calculate once per second
28  lastPrint = millis();
29
30  noInterrupts();                        // paylaşılan değişkenleri güvenle kopyala / copy shared variables safely
31  unsigned long count = pulseCount;
32  pulseCount = 0;
33  unsigned long period = periodUs;
34  unsigned long last = lastPulseUs;
35  interrupts();
36
37  float rpmCount = count * 60.0 / MARKS;                 // sayma yöntemi / counting method
38  float rpmPeriod = 0;
39  if (period > 0 && micros() - last < 2000000UL) {       // 2 sn darbe yoksa durmuş say / stopped after 2 s without pulses
40    rpmPeriod = 60000000.0 / (period * (float)MARKS);    // periyot yöntemi / period method
41  }
42  Serial.print(F("Sayma/Count: "));
43  Serial.print(rpmCount, 0);
44  Serial.print(F(" rpm   Periyot/Period: "));
45  Serial.print(rpmPeriod, 1);
46  Serial.println(F(" rpm"));
47}

Импульсы ловятся с помощью attachInterrupt(): чем бы ни был занят процессор в loop(), onPulse() выполняется в момент спада DO, поэтому ни один импульс не теряется. Переменные, общие для обработчика прерывания и loop(), объявлены как volatile, а loop() копирует их между noInterrupts() и interrupts(); иначе прерывание может сработать посреди чтения 4-байтного числа и получится наполовину обновлённое значение. На границе чёрного и белого выход LM393 может несколько раз дребезжать; MIN_GAP_US отфильтровывает это, игнорируя импульсы, пришедшие с интервалом меньше 500 µs. С одной меткой этот фильтр допускает показания до 120 000 об/мин, так что для моторов из хобби-проектов на практике ограничения нет. Подробнее о прерываниях — в статье Прерывания в Arduino.

Проверь установку на моторе с известной скоростью: например, жёлтый мотор-редуктор TT без нагрузки при 6 V крутится примерно на 200 об/мин. Если показание выходит ровно вдвое больше, на диске есть второе блестящее пятно, которое осталось незамеченным; головки винтов, металлические ступицы и блестящие кромки тоже считаются метками.

TCRT5000 с ESP32

На ESP32 работает та же логика, но есть три отличия. Во-первых, модуль питается от 3V3. Во-вторых, аналоговый вход 12-битный и выдаёт значения от 0 до 4095; подключай AO только к пинам ADC1 (GPIO 32–39), потому что пины ADC2 нельзя читать при включённом Wi-Fi. В-третьих, обработчик прерывания помечается IRAM_ATTR, а поскольку у ESP32 два ядра, общие переменные защищаются критической секцией portMUX. Код ниже считает две метки на диске и каждые полсекунды выводит обороты и аналоговое значение. Если ESP32 для тебя в новинку, сначала загляни в статью Что такое ESP32?.

C++ (Arduino IDE)
1// ESP32 + TCRT5000: devir ölçer ve analog okuma / tachometer and analog reading
2const int SENSOR_DO = 27;                // DO -> GPIO 27
3const int SENSOR_AO = 34;                // AO -> GPIO 34 (ADC1)
4const int MARKS = 2;                     // diskteki beyaz işaret sayısı / white marks on the disc
5const uint32_t MIN_GAP_US = 300;         // daha sık darbeler titreşimdir / closer pulses are glitches
6
7volatile uint32_t pulseCount = 0;
8volatile uint32_t lastPulseUs = 0;
9portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
10
11void IRAM_ATTR onPulse() {               // kesme kodu IRAM'de durur / ISR lives in IRAM
12  uint32_t now = micros();
13  portENTER_CRITICAL_ISR(&mux);
14  if (now - lastPulseUs >= MIN_GAP_US) {
15    lastPulseUs = now;
16    pulseCount++;
17  }
18  portEXIT_CRITICAL_ISR(&mux);
19}
20
21void setup() {
22  Serial.begin(115200);
23  pinMode(SENSOR_DO, INPUT);
24  analogReadResolution(12);              // 0-4095
25  attachInterrupt(digitalPinToInterrupt(SENSOR_DO), onPulse, FALLING);
26}
27
28void loop() {
29  static uint32_t lastMs = 0;
30  uint32_t nowMs = millis();
31  if (nowMs - lastMs < 500) return;      // yarım saniyede bir / every half second
32  uint32_t elapsed = nowMs - lastMs;
33  lastMs = nowMs;
34
35  portENTER_CRITICAL(&mux);              // iki çekirdeğe karşı koruma / protection across both cores
36  uint32_t pulses = pulseCount;
37  pulseCount = 0;
38  portEXIT_CRITICAL(&mux);
39
40  float rpm = pulses * 60000.0 / (elapsed * (float)MARKS);   // dev/dk / revolutions per minute
41  int raw = analogRead(SENSOR_AO);       // siyahta yüksek, beyazda düşük / high on black, low on white
42  Serial.printf("RPM: %.0f   AO: %d\n", rpm, raw);
43}

Окно измерения — полсекунды, поэтому код точно измеряет прошедшее время с помощью millis() и подставляет его в формулу: об/мин = импульсы × 60 000 / (прошедшие мс × число меток). Показывать скорость на веб-странице по Wi-Fi или присылать уведомление на телефон, когда она падает ниже заданного значения, — вот что ESP32 на самом деле добавляет к этому проекту. Поскольку одновременно читается и аналоговое значение, можно следить, меняется ли расстояние от диска до датчика, то есть не бьёт ли вал.

TCRT5000 с Raspberry Pi Pico и MicroPython

На Pico питай модуль от пина 3V3(OUT), AO подключи к GP26 (ADC0), а DO — к GP15. read_u16() возвращает значение от 0 до 65535; над белым оно низкое, над чёрным высокое. Код ниже распознаёт поверхность и заодно вычисляет обороты, считая импульсы на линии DO с помощью прерывания. Прерывания в MicroPython не такие быстрые, как в C; они надёжно работают до нескольких сотен импульсов в секунду, поэтому для очень быстрых моторов лучше выбрать Arduino или ESP32. Установка и первые шаги описаны в статье Что такое Raspberry Pi Pico?.

MicroPython
1# Raspberry Pi Pico: TCRT5000 ile zemin algılama ve devir sayma
2# Raspberry Pi Pico: surface detection and RPM counting with TCRT5000
3from machine import Pin, ADC
4import machine
5import time
6
7ao = ADC(26)                     # AO -> GP26 (ADC0)
8do = Pin(15, Pin.IN)             # DO -> GP15
9led = Pin("LED", Pin.OUT)        # kart üzerindeki LED / onboard LED
10
11MARKS = 1                        # diskteki beyaz işaret sayısı / white marks on the disc
12MIN_GAP_US = 500                 # daha sık darbeler titreşimdir / closer pulses are glitches
13count = 0
14last_us = time.ticks_us()
15
16def on_pulse(pin):
17    global count, last_us
18    now = time.ticks_us()
19    if time.ticks_diff(now, last_us) < MIN_GAP_US:
20        return                   # sınırdaki titreşimi ele / filter edge chatter
21    last_us = now
22    count += 1
23
24do.irq(trigger=Pin.IRQ_FALLING, handler=on_pulse)   # beyaz işarette DO LOW olur / DO goes LOW on white
25
26while True:
27    time.sleep(1)
28    state = machine.disable_irq()   # sayacı güvenle oku / read the counter safely
29    pulses = count
30    count = 0
31    machine.enable_irq(state)
32
33    raw = ao.read_u16()             # 0-65535: beyazda düşük, siyahta yüksek / low on white, high on black
34    on_white = do.value() == 0      # çoğu modülde beyazda LOW / LOW on white on most modules
35    led.value(on_white)
36    rpm = pulses * 60 / MARKS
37    print("AO:", raw, "Zemin/Surface:", "BEYAZ/WHITE" if on_white else "SIYAH/BLACK", "RPM:", rpm)

Идеи проектов с TCRT5000

  • Робот, следующий по линии: робот, который едет по чёрной линии с линейкой из 2, 3 или 5 датчиков; расположение датчиков и настройка PID разобраны в статье Робот, следующий по линии.
  • Робот, который замечает край стола: поставь спереди робота TCRT5000, направленный вниз; на краю стола сигнал становится «чёрным», и робот останавливается, не успев упасть. Шасси и моторы описаны в руководстве Робот-машинка на Arduino своими руками.
  • Индикатор скорости мотора: объедини код тахометра с OLED-дисплеем и выводи обороты крупными цифрами.
  • Энкодер колеса и одометр: наклей на внутреннюю сторону колеса 8–20 чёрных и белых сегментов, считай импульсы, дели на число сегментов и умножай на длину окружности колеса — получится пройденное расстояние. Если нужно ещё и направление, поставь два датчика со сдвигом на полсегмента, как в поворотном энкодере.
  • Счётчик предметов: считай белые коробки или листы бумаги, проезжающие по маленькому конвейеру, и выводи итог на дисплей.
  • Сигнал об окончании бумаги: направь датчик на обратную сторону рулона этикеток или бумаги для принтера; как только бумага заканчивается, отражение пропадает и звучит зуммер.
  • Тот же принцип, но в закрытом корпусе: сравни TCRT5000 с оптопарой, где светодиод и фототранзистор запечатаны вместе в светонепроницаемом корпусе, чтобы лучше понять, как сигналы передаются светом.

Частые ошибки и как их исправить

СимптомВероятная причинаРешение
AO держится около 1000 и не меняетсяДатчик слишком далеко от поверхности, ИК-светодиод не светит или AO подключён не к тому пинуОпусти датчик на 3 мм, проверь ИК-светодиод камерой телефона, перепроверь подключение
Чёрные поверхности читаются как белыеСолнце или лампа накаливания, глянцевая изолента или краска, пропускающая инфракрасный светЗатени датчик, используй матовую изоленту или лазерную печать, задавай порог на месте
Светодиод DO никогда не меняет состояниеПотенциометр выкручен в крайнее положениеНайди точку, где светодиод переключается, и выставь потенциометр по ней
Тахометр показывает вдвое больше реальных оборотовВторое блестящее пятно на диске или дребезг на границеСделай диск полностью матовым, увеличь MIN_GAP_US, проверь значение MARKS
На ESP32 аналоговое значение всегда 0 или нестабильноAO на пине ADC2, а Wi-Fi включёнПеренеси AO на пин ADC1 в диапазоне GPIO 32–39
Моторы продолжают крутиться, если поднять роботаКогда под датчиком нет поверхности, он видит чёрноеДобавь защитное правило: остановить моторы, если все датчики одновременно видят чёрное
Работает ли ИК-светодиод, глазом не увидеть, а вот камера телефона это покажет: открой камеру и направь её на синюю сторону датчика — на экране должно быть видно фиолетово-белое свечение. На некоторых телефонах у основной камеры стоит инфракрасный фильтр, поэтому, если свечения не видно, попробуй фронтальную камеру.

TCRT5000 — дешёвый, маленький и очень поучительный датчик: на одной детали можно разобраться с фототранзисторами, компараторами, порогами и гистерезисом, прерываниями и борьбой с внешней засветкой. Начни с того, чтобы узнать значения своего датчика с помощью кода распознавания поверхности, затем измерь скорость тахометром, а в конце объедини несколько датчиков под роботом. Если интересен ещё один простой способ измерять светом, загляни и в статью Фоторезистор (LDR). В приложении BlueGrays есть проекты «Распознавание чёрной и белой поверхности на TCRT5000» и «Измерение расстояния на TCRT5000», а также «Машинка с управлением по Bluetooth на L298N» и «Робот, объезжающий препятствия», у каждого пошаговые схемы подключения и код.

Частые вопросы

Для чего нужен датчик TCRT5000?

TCRT5000 — отражательный датчик, в одном корпусе которого объединены инфракрасный светодиод и фототранзистор. Он измеряет, сколько инфракрасного света отражает поверхность в нескольких миллиметрах перед ним, поэтому может отличать чёрное от белого, считать метки на вращающемся диске или замечать очень близкий объект. Чаще всего его используют в роботах, следующих по линии, тахометрах и для обнаружения бумаги.

Какая дальность обнаружения у TCRT5000?

TCRT5000 работает на расстояниях в миллиметры, а не в сантиметры. По даташиту самый сильный сигнал — на 2,5 мм, а пользоваться датчиком можно примерно от 0,2 до 15 мм; на практике самый надёжный диапазон — 2–8 мм. Для больших расстояний выбирай инфракрасный датчик препятствий FC-51 или ультразвуковой датчик расстояния HC-SR04.

TCRT5000 выдаёт HIGH или LOW на чёрном?

У распространённых модулей TCRT5000 выход DO над белым переходит в LOW и индикатор загорается; над чёрным или когда перед датчиком нет поверхности — в HIGH. Выход AO так же даёт низкое значение над белым и высокое над чёрным. На некоторых платах логика обратная, поэтому лучше проверить свой модуль в мониторе порта.

Чем TCRT5000 отличается от FC-51?

TCRT5000 — отражательный датчик с излучателем и приёмником в одном корпусе, который работает на очень малых расстояниях, примерно 1–15 мм; он идеален для движения по линии и подсчёта оборотов. FC-51 использует отдельные ИК-светодиод и приёмник, обнаруживает препятствия на расстоянии около 2–30 см и имеет только цифровой выход. Коротко: TCRT5000 смотрит в пол, а FC-51 — вперёд.

Может ли TCRT5000 распознавать цвета?

Нет, TCRT5000 измеряет только, сколько инфракрасного света около 950 нм отражается; цвет он определить не может. Некоторые цвета в инфракрасном свете ведут себя неожиданно: красные и жёлтые поверхности часто читаются почти как белые, а некоторые чёрные струйные отпечатки почти прозрачны. Чтобы различать цвета, используй датчик цвета, например TCS3200 или TCS34725.

Работает ли TCRT5000 с ESP32 и при 3,3 V?

Да, модули TCRT5000 работают от 3,3 до 5 V, а на ESP32 и Raspberry Pi Pico их нужно питать от пина 3V3. Тогда выходы AO и DO никогда не превышают 3,3 V, и пины платы в безопасности. При 3,3 V ИК-светодиод потребляет меньший ток, поэтому дальность обнаружения становится чуть меньше; на ESP32 не забудь подключить AO к пину ADC1.

Все проекты
Определение чёрной и белой поверхности с TCRT5000
#78Средний
Premium

Определение чёрной и белой поверхности с TCRT5000

С маленьким датчиком, который служит глазом роботов, едущих по линии, можно узнать, чёрный пол или белый. TCRT5000 светит на пол невидимым светом и проверяет, сколько его отражается обратно; на белом

4.7(40)
49
Чтение отражения (приближения) с TCRT5000
#77Средний
Premium

Чтение отражения (приближения) с TCRT5000

С маленьким датчиком, который посылает невидимый свет и измеряет, сколько его отражается обратно, можно определить поверхность перед ним. Чем ближе предмет или светлая поверхность, тем больше света во

4.6(33)
43
Измерение освещённости с LDR
#11Новичок

Измерение освещённости с LDR

Хочешь увидеть яркость своей комнаты в виде числа? LDR — маленькая деталь, реагирующая на свет, — измеряет освещённость вокруг, а Arduino каждые полсекунды выводит значение на экран компьютера. Закрой

4.6(81)
139
Измерение расстояния HC-SR04 (вывод в порт)
#27Новичок

Измерение расстояния HC-SR04 (вывод в порт)

Датчик HC-SR04 работает совсем как летучая мышь, которая находит дорогу в темноте: он посылает звук, которого ты не слышишь, слушает эхо и измеряет, насколько далеко предмет перед ним. Arduino каждые

4.6(46)
71
Машинка на L298N с управлением по Bluetooth
#80Продвинутый
Premium

Машинка на L298N с управлением по Bluetooth

Преврати телефон в пульт и управляй своей машинкой-роботом. Arduino получает команды из приложения-пульта на телефоне через Bluetooth-модуль и вращает колёса через драйвер моторов; машинка едет вперёд

5.0(38)
65
Робот, объезжающий препятствия
#81Продвинутый
Premium

Робот, объезжающий препятствия

Как насчёт того, чтобы собрать умную машину, которая сама находит дорогу? Робот, объезжающий препятствия, постоянно осматривает всё вокруг благодаря ультразвуковому датчику спереди. Встретив препятств

5.0(38)
49
Лазерная сигнализация
#22Средний
Premium

Лазерная сигнализация

Ты ставишь невидимую лучевую ограду, совсем как в кино. Лазер светит на датчик освещённости с другой стороны; как только кто-то проходит и прерывает луч, загорается светодиод и звучит зуммер, а когда

4.8(64)
83
Счётчик на семисегментном индикаторе с кнопками
#43Продвинутый
Premium

Счётчик на семисегментном индикаторе с кнопками

Простой счётчик с тремя кнопками: нажми одну — цифра на индикаторе увеличится на единицу, нажми другую — уменьшится, а третья возвращает её к нулю. Одноразрядный семисегментный индикатор считает от 0

4.6(35)
47