Устройство на Ardiuno для контроля пересечения барьера.

Ардуинщики всех стран - объединяйтесь! В этом форуме, конечно.
Ответить
Встал на лапы
Аватара пользователя
Сообщения: 93
Зарегистрирован: Ср июн 03, 2026 18:51:39
Откуда: Воронеж

Сообщение Massaraksh7 »

Zapolyarny писал(а): Пн июн 22, 2026 16:18:59 Почти так же (ровно 40). :beer:
Respect!
Я свой стаж считаю с 1982, когда я закончил факультет прикладной математики ВГУ.
Реклама
Встал на лапы
Аватара пользователя
Сообщения: 93
Зарегистрирован: Ср июн 03, 2026 18:51:39
Откуда: Воронеж

Сообщение Massaraksh7 »

roman.com писал(а): Пн июн 22, 2026 16:02:02 По теме.
Нужно малогабаритные устройство.
Чтобы можно было вмонтировать в дверной проем. Точно так же как простой дверной замок.
Отметили.
Просверлили.
Установили.
Если для коммерческого использования, то да. Но тогда нужно не Arduino, а Atmega в самом маленьком корпусе (если речь об AVR).
И избавляться от крупных деталей, всё переводить на SMD. Единственно, блок питания большой 33x22x15, по-моему, от него как избавиться?
Реклама
Вымогатель припоя
Сообщения: 509
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Massaraksh7 писал(а): Пн июн 22, 2026 15:32:55 . У автора за спиной 40 с лишним лет программирования.
Угу. Мы видим эти "40 с лишним лет" :) Катастрофическое незнание английского языка - путает слова rate и mode, словом DIR обозначает "вперед", словом "Fire" называет нагрузку (которая "Load"), не умеет составлять циклы, плохо владеет языком Си - while(0 == 0) и не может прочесть алгоритм с ветвлениями по if-else.
Так 40 лет программирования на каком языке? На бейсике чтоль? судя по однобуквенным именам переменных.

Любитель или профессионал - но владеть языком программирования хотябы на базовом уровне - он обязан.
roman.com писал(а): Пн июн 22, 2026 16:02:02 Я заметил на этом сайте пишут про все что угодно но только не по теме...
Я писал по теме - автор не понял написанного в силу плохого владения языком программирования. И теперь обвиняет в этом меня :))
Zapolyarny писал(а): Пн июн 22, 2026 16:18:59 Почти так же (ровно 40). :beer:
Тоже - 40 лет??? Мдааа... А чеж до сих пор в трех березах то не разобрались?
roman.com писал(а): Пн июн 22, 2026 16:02:02 По теме.
А это тема про замки чтоль? Почему картинки врезного замка то показываете? :))

Топикстартер вообще хочет установить датчики на уровне пяток (у пола), как он сказал. А ноги то у человека две. И человек не шаркает ногами по полу, а поднимает их.
Последний раз редактировалось Rapra Пн июн 22, 2026 17:08:41, всего редактировалось 1 раз.
Грызет канифоль
Сообщения: 259
Зарегистрирован: Чт май 07, 2026 00:30:38

Сообщение Zapolyarny »

Rapra писал(а): Пн июн 22, 2026 16:53:41 Тоже - 40 лет??? Мдааа... А чеж до сих пор в трех березах то не разобрались?
Если имеются в виду три березы другой ветки, то:
мой опыт - Windows-приложения, последние лет 15 - .Net;
микроконтроллеры - любительство, Ардуино вижу впервые, стиль работы с ней бесит и раздражает;
что профессиональные, что свои любительские, все проекты делаются при полном ТЗ, с оформленными экспериментами и с нормальными отладочными инструментами, а не предполагая что-то за заказчика и не пытаясь мучительно интерпретировать информацию от него, понимая, что наши языки разные.

И что-то никто не стремится помогать.
Ну, хоть не критикуют, как здесь :)
Реклама
Эиком - электронные компоненты и радиодетали
Вымогатель припоя
Сообщения: 509
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Не знаю, про какую соседнюю ветку речь, но я говорю именно об этой ветке.
Я с Ардуиной тоже не работаю. Но за исключением чисто ардуиновских библиотек, здесь всё просто и понятно. Только топикстартер наворотил в этих простых действиях какой-то дичи. Вот на кой черт, объясните мне, нужно трехкратное считывания входа?? Тем более, что написанный алгоритм работает лишь потому, что там нет ложных переключений уровня в заданном интервале.
А на кой черт, объясните мне тоже, отображение цифры на индикаторе закинуто в два цикла for с посегментным отображением? Я ранее показал, как выглядит этот алгоритм "здорового человека".

Так что где здесь "40 лет опыта программирования" то, коль выглядит как у двухмесячного новичка?
Последний раз редактировалось Rapra Пн июн 22, 2026 17:19:22, всего редактировалось 1 раз.
Реклама
Грызет канифоль
Сообщения: 259
Зарегистрирован: Чт май 07, 2026 00:30:38

Сообщение Zapolyarny »

Rapra писал(а): Пн июн 22, 2026 17:11:37 Не знаю, про какую соседнюю ветку речь, но я говорю именно об этой ветке.
Эту я прочитал в самом начале, середину большей частью пропустил (сложно читать всё, особенно с картинками каких-то замков). Причины особенности конструкции были автором объяснены. Потом глянул, что всё успешно. А потом, зайдя уже от скуки, увидел, что автор, оказывается, всё сделал плохо, но не увидел, почему.

Посегментное могло прийти из другого проекта, где оно было актуально.
Реклама
Вымогатель припоя
Сообщения: 509
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Ну так если у вас так же "40 лет опыта программирования" - просто посмотрите код. Ардуиновские функции типа digitalWrite можно не читать.
Zapolyarny писал(а): Пн июн 22, 2026 17:19:03 Посегментное могло прийти из другого проекта, где оно было актуально.
А вот что, имея "40 лет опыта за плечами" - так сложно чтоль не копипастить, а написать именно подходящую к конкретному проекту версию? Объем работы - несколько строчек.

И я уже объяснял дважды, что даже говнокод может работать при некоторых условиях благодаря взаимной нейтрализации ошибок. Но, как правило, при изменении условий такой код крашится.
Вот сейчас у топикстартера новые условия:
Massaraksh7 писал(а): Пн июн 22, 2026 01:45:39 ставить придётся, где-то, на уровне щиколоток.
А это уже другой алгоритм. Потому что ноги у человека две. И сенсор может зафиксировать две ноги, одну или ни одной, в зависимости от случайной постановки ног при шаге :))
Грызет канифоль
Сообщения: 259
Зарегистрирован: Чт май 07, 2026 00:30:38

Сообщение Zapolyarny »

Rapra писал(а): Пн июн 22, 2026 17:22:21 Ну так если у вас так же "40 лет опыта программирования" - просто посмотрите код. Ардуиновские функции типа digitalWrite можно не читать.
Посмотрел. Так же глянул и Ваши замечания.
Ну... что тут сказать... мой стиль отличается и от Вашего:
не пишу очевидные сдвиги 1<< 2 и т.д., на мой взгляд неудобно увеличивают листинг;
и от автора:
не сравниваю явно с нулём и выражения if (sign1==0) digitalWrite(FB1,LOW); else digitalWrite(FB1,HIGH);
написал бы тернарно: digitalWrite(FB1,(sign1)?HIGH:LOW);
Ну, в циклах бы стремился по возможности приводить условие к сравнению с нулём, но сейчас подобное вряд ли актуально.

То есть, я - круче всех? :) Нет. Просто некоторая деформация от .Net (когда в основном работал в Delphi - да, были и константные сдвиги, и if..else)

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

Работает? Работает. (... "тогда ничего не трогай и не меняй!" ;) )
Вымогатель припоя
Сообщения: 509
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Zapolyarny писал(а): Пн июн 22, 2026 17:44:09 на мой взгляд неудобно увеличивают листинг;
0x04 и 1 << 2 - где здесь увеличение листинга? К тому же, запись 1 << 2 логически показывает, что это позиция бита, а не какое-то число.
Zapolyarny писал(а): Пн июн 22, 2026 17:44:09 любительские и профессиональные проекты - это разное.
Вовсе нет. Они отличаются только объемом кода и/или сложностью задачи. А вот говнокод от "кода здорового человека" как раз и отличается тем, что рассматривается в этой теме.
Zapolyarny писал(а): Пн июн 22, 2026 17:44:09 Работает? Работает. (... "тогда ничего не трогай и не меняй!" ;) )
Хорошо, когда ничего не надо менять. А вот у топикстартера сейчас начнутся изменения из-за нового места установки датчиков.
Грызет канифоль
Сообщения: 259
Зарегистрирован: Чт май 07, 2026 00:30:38

Сообщение Zapolyarny »

Rapra писал(а): Пн июн 22, 2026 17:53:31 А вот говнокод от "кода здорового человека"
вот я написал на днях (тоже работа с индикатором и подсчёт):

Код: Выделить всё

  // Получение сегментов соответственно цифрам:
  uint8_t seg3 = Segments[d3];
  uint8_t seg2 = Segments[d2];
  uint8_t seg1 = Segments[d1];

  // Добавление точки к нужному разряду:
#ifdef DISPLAY_COMMON_CATHODE
  if (dot == 2) seg3 |= 0x02;
  if (dot == 1) seg2 |= 0x02;
  if (dot == 0) seg1 |= 0x02;
#else
  if (dot == 2) seg3 &= ~0x02;
  if (dot == 1) seg2 &= ~0x02;
  if (dot == 0) seg1 &= ~0x02;
#endif

  // Обновление массива дисплея новыми данными:
  cli();
  display[pos + 2] = seg1;
  display[pos + 1] = seg2;
  display[pos + 0] = seg3;
  sei();
Это можно написать нормально, и увидев у кого-то другого я бы сказал "говнокод", но... у меня в этом месте Ардуина вела себя не так, как должна. И я расписал в индийском стиле, а потом так и оставил. Это не делает меня неумехой, просто так вышло.
Кстати, перепишу ща.
---------
Во, красота, компактно и читаемость не особо упала:

Код: Выделить всё

// Обновление буфера дисплея новыми данными из массива сегментов;
//добавление точки, если разряд совпадает:
  cli();
#ifdef DISPLAY_COMMON_CATHODE
  display[pos + 2] = Segments[d1] | ((dot == 0) << 1);
  display[pos + 1] = Segments[d2] | ((dot == 1) << 1);
  display[pos + 0] = Segments[d3] | ((dot == 2) << 1);
#else
  display[pos + 2] = Segments[d1] & ~((dot == 0) << 1);
  display[pos + 1] = Segments[d2] & ~((dot == 1) << 1);
  display[pos + 0] = Segments[d3] & ~((dot == 2) << 1);
#endif
  sei();
Последний раз редактировалось Zapolyarny Пн июн 22, 2026 18:32:20, всего редактировалось 3 раза.
Вымогатель припоя
Сообщения: 509
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Отобразить цифры на семисегментнике - это второй "хелловорлд" после "блинка" в электронике. И издревле, еще до Ардуины, это решалось показанным выше способом - составить распиновку пинов для сегментов и разрядов, составить таблицу сегментов для цифр, и уложить полученную таблицу в массив. При отображении цифры она выбирается из массива по индексу. Десятичная точка добавляется к полученному значению. И всё это передается в порт. Выходной порт для сегментов выбирали один, а распиновка сегментов в нем могла быть произвольной.
Грызет канифоль
Сообщения: 259
Зарегистрирован: Чт май 07, 2026 00:30:38

Сообщение Zapolyarny »

Издревле - это не догма.
Я издревле использовал готовый массив:
const uint8_t Segments[...] = { 0xFC, 0x18, 0x6D, 0x3D, 0x99, 0xB5, 0xF5, 0x1C, 0xFD, 0xBD, 0x00, ... };
и, честно говоря, совершенно не понимаю, зачем писать в листинге что-то ещё. Лучше потрачу буквы на комментарии к коду, но увеличить листинг здесь на десяток строк, там на десяток строк... в итоге лишняя сотня строк, а потом невольно всё это читать? Для констант вряд ли это нужно.

Но это же субъективно, и компилятор, скорее всего даже с напрочь выключенной оптимизацией, обернёт и то и то одинаково. А потому не буду доказывать, что мой подход правильный, а другой - нет.
Грызет канифоль
Сообщения: 259
Зарегистрирован: Чт май 07, 2026 00:30:38

Сообщение Zapolyarny »

кстати, спасибо за диалог - переписал пару мест ;)
Вымогатель припоя
Сообщения: 509
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Zapolyarny писал(а): Пн июн 22, 2026 18:24:16 Для констант вряд ли это нужно.
А вот для возможности перепиновки индикатора - очень даже нужно. То есть, если сегменты по пинам распределены не последовательно. Это может быть необходимо для разводки платы.
#define - это препроцессор, поэтому оптимизация компилятора не влияет.

Ну а когда появились STM32 с их непоследовательной распиновкой ног, стало сложнее подбирать пины из одного порта. И если это не получалось, приходилось усложнять код. Полноценно и аккуратно с этим вопросом справляется только С++, когда список пинов передается в шаблон класса виртуального порта: VPort<GpioA::Pin4, GpioB::Pin0, GpioB::Pin7 и так далее
Грызет канифоль
Сообщения: 259
Зарегистрирован: Чт май 07, 2026 00:30:38

Сообщение Zapolyarny »

Согласен. Но тогда просто перепишу этот массив заново.
Однажды написал программку, которая делала его автоматически плюс можно было свои символы накликать по сегментам, потом увидел, что многие такие программки уже написали ))
А потом обнаружил, что это совершенно несложно в уме.
(#define - каюсь, забыл, что он там был написан, пока отвечал)
Когда попадутся случаи а-ля STM32, где Ваш вариант удобнее - конечно же, буду использовать его.
Друг Кота
Сообщения: 9225
Зарегистрирован: Вт мар 13, 2012 12:16:13
Откуда: .ru

Сообщение roman.com »

Рано вы занялись кодом. У вас ещё схемы нормальной нет.
:tea:
Сначала передатчик подключите к мк.
А для этого один таймер освободите.
Семисегментник там вообще нафиг не нужен. Количество людей в ванной не может быть больше трёх. Хотя и три никогда не бывает. Это ванная комната а не басейн )) Поэтому три светодиода достаточно для отображения количества людей.
Встал на лапы
Аватара пользователя
Сообщения: 93
Зарегистрирован: Ср июн 03, 2026 18:51:39
Откуда: Воронеж

Сообщение Massaraksh7 »

roman.com писал(а): Пн июн 22, 2026 19:12:35 Рано вы занялись кодом. У вас ещё схемы нормальной нет.
Сначала передатчик подключите к мк.
А для этого один таймер освободите.
Так это связано. Тогда время прерывания таймера0 делаем 30мкс, и в обработчике по каждому прерыванию генерируем меандр, скажем, на на ноге D7, которую подключаем к IR-светодиоду + резистор (номинал?) + на землю. А в каждом 10 прерывании занимаемся обработкой, как было.
Или не меандр, а скажем 1:10, но тогда какой номинал резистора?
Друг Кота
Сообщения: 9225
Зарегистрирован: Вт мар 13, 2012 12:16:13
Откуда: .ru

Сообщение roman.com »

Напряжение питагия пять вольт минус прямое напряжение диода полтора-два вольта при максимальном допустимой токе порта ардуина сорок миллиампер получаем резистор не должен быть меньше ста Ом.
Точный номинал подбирается экспериментально до получения достаточной мощности передатчика для четкоко срабатывания приемника с одной стороны и не настолько мощного чтобы приёмник ловил отраженный сигнал от стен и других посторонних объектов ))

Таймер... Я бы выделил отдельный таймер для передатчика. А программу бы всю переписал ))
Грызет канифоль
Сообщения: 259
Зарегистрирован: Чт май 07, 2026 00:30:38

Сообщение Zapolyarny »

40 мА это из Absolute Maximum Ratings. Несколько глупо брать это значение, и крайне глупо рекомендовать другим. В спецификации указано испытательное значение 20 мА для 5 В и 10 мА для 3 В и ограничение в 100/150 мА в сумме для нижних/верхних транзисторов портов.

Диод может выйти из строя, и они предпочитают это делать в виде КЗ, что как бэ уменьшает падение напряжения до нуля.
Исходя из выше сказанного, а также из здравомыслия и рекомендаций производителей микроконтроллеров:
IR необходимо подключать через транзистор. Это обезопасит вывод порта, снизит нагрузку на
цепи питания микроконтроллера вообще, при необходимости позволит увеличить мощность IR-диода или подключить альтернативную функцию (если она не буферизована транзисторами GPIO, что вполне возможно, в том числе для вывода таймера).
roman.com писал(а): Пн июн 22, 2026 21:42:16 и не настолько мощного чтобы приёмник ловил отраженный сигнал от стен и других посторонних объектов ))
Значит, во всех бытовых устройствах пульты работают от случая к случаю. Кому как повезёт.
roman.com писал(а): Пн июн 22, 2026 21:42:16 Таймер... Я бы выделил отдельный таймер для передатчика.
Зачем? В подобной задаче достаточно вообще одного таймера на всё. Или даже ноль таймеров.

И самое главное: почему без зелёной чашки?
Встал на лапы
Аватара пользователя
Сообщения: 93
Зарегистрирован: Ср июн 03, 2026 18:51:39
Откуда: Воронеж

Сообщение Massaraksh7 »

roman.com писал(а): Пн июн 22, 2026 21:42:16 Таймер... Я бы выделил отдельный таймер для передатчика. А программу бы всю переписал ))
Да без проблем.
Sa1.png
(92.26 КБ) 3 скачивания

Код: Выделить всё

//
// Shirokov V.V. aka Massaraksh7, 23.06.2026
//
#define IN1   2
#define IN2   3
#define FIRE  4
#define FB1   5
#define FB2   6
#define IR    7

#define R_WAIT 0
#define R_DIR  1
#define R_BACK 2
#define R_DO_DIR  3
#define R_DO_BACK 4
#define MAX_VIS  3      //---Максимальное число посетителей 
#define DEL 700  

byte count,rate,gen;

volatile byte sign1,sign2; //---Сигнал 0 или 1
volatile byte imp1,imp2;   //---Число импульсов
volatile int tim0;        //---счётчик основного цикла

//---Прочитать состояние входов
void ReadSignals() {
if (imp1<3) sign1=1; else sign1=0; imp1=0;
if (imp2<3) sign2=1; else sign2=0; imp2=0;
if (sign1==0) digitalWrite(FB1,LOW); else digitalWrite(FB1,HIGH);
if (sign2==0) digitalWrite(FB2,LOW); else digitalWrite(FB2,HIGH);
}

//---Подключить нагрузку
void fireON() {
digitalWrite(FIRE,HIGH);  
}

//---Отключить нагрузку
void fireOFF() {
digitalWrite(FIRE,LOW);  
}

//---Прерывание по переднему фронту 1 канала
void cannal_1() {
imp1++;
}

//---Прерывание по переднему фронту 2 канала
void cannal_2() {
imp2++;
}

//---1 мс - основной цикл
void startTimer0() {
cli();
TCCR0A = 0;
TCCR0B = 0;
TCNT0  = 0;
TCCR0A |= (1 << WGM01);
TCCR0B |= (1 << CS01) | (1 << CS00);
OCR0A = 249;
TIMSK0 |= (1 << OCIE0A);
sei();
}

//---25 мкс - генератор
void startTimer1() {
cli(); // Отключаем прерывания на время настройки
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << CS11) | (1 << CS10);
OCR1A = 399;
TIMSK1 |= (1 << OCIE1A);
sei();
}

ISR(TIMER1_COMPA_vect) {
if (gen==0) digitalWrite(IR,LOW); else digitalWrite(IR,HIGH);
gen=1-gen;
}

//---Инициализация
void setup() {
  pinMode(IN1,INPUT);pinMode(IN2,INPUT);
  pinMode(FIRE,OUTPUT);pinMode(FB1,OUTPUT);pinMode(FB2,OUTPUT);
  pinMode(IR,OUTPUT);
  digitalWrite(FIRE,LOW);digitalWrite(FB1,LOW);digitalWrite(FB2,LOW);
  count=0;rate=R_WAIT;
  sign1=1;sign2=1;gen=0;
//---Запустить таймеры  
  tim0=1;imp1=0;imp2=0;
  startTimer0();
  startTimer1();
//---Запустить внешние прерывания
  attachInterrupt(digitalPinToInterrupt(IN1),cannal_1,RISING);  
  attachInterrupt(digitalPinToInterrupt(IN2),cannal_2,RISING);    
}

//---Основной цикл по таймеру 0
ISR(TIMER0_COMPA_vect) {
tim0--;if (tim0!=0) return;
tim0=1;
  if (rate==R_WAIT) //---Режим ожидания основной
     {
     ReadSignals();
     if (sign1==0 && sign2==1){rate=R_BACK;return;}
     if (sign1==1 && sign2==0){rate=R_DIR;return;}
     return;
     }
  if (rate==R_DIR) //---Режим возможного пересечения вперёд
     {
     ReadSignals();
     if (sign1==0 && sign2==0){rate=R_WAIT;return;}
     if (sign1==1 && sign2==1){rate=R_DO_DIR;return;}      
     return;
     }
  if (rate==R_BACK) //---Режим возможного пересечения назад
     {
     ReadSignals(); 
     if (sign1==0 && sign2==0){rate=R_WAIT;return;}
     if (sign1==1 && sign2==1){rate=R_DO_BACK;return;}
     return;
     }     
  if (rate==R_DO_DIR) //---Точно пересечение вперёд
     {
     if (count<MAX_VIS) count++;
     if (count==1) fireON();
     tim0=DEL;
     rate=R_WAIT;
     return;
     }
  if (rate==R_DO_BACK) //---Точно пересечение назад
     {
     if (count>0) count--;
     if (count==0) fireOFF();
     tim0=DEL;
     rate=R_WAIT;
     return;
     }    
}

void loop() {
while (0==0) {};
}
Ответить

Вернуться в «Arduino»