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 — отражательный оптический датчик компании 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–200 | LOW, индикатор горит |
| Светлое дерево или стол | Сильное | Около 100–400 | Обычно LOW |
| Матовая чёрная изолента или лазерная печать | Очень слабое | Около 600–1000 | HIGH, индикатор не горит |
| Глянцевая чёрная изолента | Зависит от угла | Нестабильно | Нестабильно |
| Поверхности нет (дальше 2 см) | Отражения нет | Около 1000 | HIGH, как на чёрном |
Модуль 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 (цифровой) |
|---|---|---|
| Что сообщает | Сколько света отражается | Выше значение порога или ниже |
| Чтение на Uno | analogRead(): 0–1023 | digitalRead(): 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 Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| VCC | 5V | 3V3 | 3V3(OUT), пин 36 |
| GND | GND | GND | GND, пин 38 |
| DO | D2 (пин прерывания) | GPIO 27 | GP15, пин 20 |
| AO | A0 | GPIO 34 (ADC1) | GP26 / ADC0, пин 31 |
Как подключить голый 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
- Подключи пин VCC модуля к пину 5V на Arduino, а GND — к GND.
- Подключи пин AO к A0, а пин DO — к D2.
- Для проверки наклей на лист белой бумаги полоску матовой чёрной изоленты шириной 2 см.
- Держи или закрепи датчик примерно в 3 мм над поверхностью, перпендикулярно к ней.
- Загрузи код ниже в плату и открой монитор порта на скорости 9600 бод.
- В первые 5 секунд несколько раз проведи датчиком туда-обратно над чёрной изолентой и белой бумагой; код найдёт минимальное и максимальное значения и автоматически вычислит порог.
- Перемещай датчик между чёрным и белым: светодиод L на плате должен загораться над чёрным и гаснуть над белым.
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 меняет состояние. Для хорошей настройки выполни эти шаги:
- Поставь датчик над белой поверхностью на той высоте, на которой он будет работать, и крути потенциометр, пока не загорится индикатор.
- Сдвинь датчик на чёрную линию и проверь, что светодиод гаснет; если нет, немного поверни потенциометр обратно.
- Найди два крайних положения, при которых светодиод уверенно горит над белым и уверенно гаснет над чёрным, и установи потенциометр посередине между ними.
- Для более точной настройки измерь мультиметром AO над белым и над чёрным и выставь напряжение на движке потенциометра посередине между этими значениями; например, около 2,4 V для 0,6 V и 4,2 V.
- Всегда настраивай там, где будет работать робот или установка, при том же освещении.
Влияние внешнего освещения и как с ним справиться
Фильтр дневного света в чёрной линзе задерживает видимый свет, но не может задержать инфракрасный, ведь датчик как раз работает в инфракрасном диапазоне. Солнце, лампы накаливания и галогенные лампы сильно излучают в инфракрасной области около 950 нм; когда этот свет попадает на фототранзистор, даже чёрная поверхность читается как белая. На прямом солнце фототранзистор может полностью войти в насыщение, и датчик вообще ничего не различает. А вот светодиодные и люминесцентные лампы дают очень мало инфракрасного света, поэтому один и тот же робот может отлично ездить в классе и путаться у окна. Вот решения, от простых к сложным:
- Затени датчик: надень вокруг него чёрную «юбку», термоусадочную трубку или чёрный поролон; они задерживают свет сбоку.
- Держи датчик низко: опусти его на 2–4 мм от поверхности; отражённый свет станет сильнее, а доля внешнего света — меньше.
- Калибруй на месте: всегда задавай порог в реальных условиях, а если освещение меняется, измеряй заново при запуске.
- Измеряй разницу: с голым датчиком управляй ИК-светодиодом с пина Arduino и делай два измерения: при выключенном и при включённом светодиоде. Внешний свет в обоих измерениях одинаков, поэтому разница — это только отражение светодиода.
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 равномерно расположенные метки на диске улучшают разрешение метода подсчёта; не забудь изменить число меток в формуле.
- Покрась вал или колесо, которое нужно измерить, матовой чёрной краской или обмотай матовой чёрной изолентой.
- Наклей на него белую бумажную наклейку размером около 5 × 5 мм; метка должна быть шире пятна, на которое смотрит датчик.
- Закрепи датчик в 3–5 мм от метки так, чтобы он не вибрировал.
- Медленно поверни вал рукой и проверь, что светодиод DO мигает каждый раз, когда проходит метка; при необходимости подстрой потенциометр.
- Подключи пин DO к одному из пинов прерывания Uno (D2 или D3) и загрузи код ниже в плату.
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.
TCRT5000 с ESP32
На ESP32 работает та же логика, но есть три отличия. Во-первых, модуль питается от 3V3. Во-вторых, аналоговый вход 12-битный и выдаёт значения от 0 до 4095; подключай AO только к пинам ADC1 (GPIO 32–39), потому что пины ADC2 нельзя читать при включённом Wi-Fi. В-третьих, обработчик прерывания помечается IRAM_ATTR, а поскольку у ESP32 два ядра, общие переменные защищаются критической секцией portMUX. Код ниже считает две метки на диске и каждые полсекунды выводит обороты и аналоговое значение. Если ESP32 для тебя в новинку, сначала загляни в статью Что такое ESP32?.
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?.
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
С маленьким датчиком, который служит глазом роботов, едущих по линии, можно узнать, чёрный пол или белый. TCRT5000 светит на пол невидимым светом и проверяет, сколько его отражается обратно; на белом

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

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

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

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

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

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

Счётчик на семисегментном индикаторе с кнопками
Простой счётчик с тремя кнопками: нажми одну — цифра на индикаторе увеличится на единицу, нажми другую — уменьшится, а третья возвращает её к нулю. Одноразрядный семисегментный индикатор считает от 0
Другие статьи
Приложение BlueGrays
Собери эту схему шаг за шагом в телефоне
Схема подключения, код и список деталей на одном экране. 200+ проектов на Arduino, ESP32 и Pico готовы к сборке.
Наведи камеру телефона
Наведи камеру на код — откроется магазин приложений на телефоне.
или открыть магазин

