Считать показания с двухразрядного семисегментного LED дисплея.
- Войдите на сайт для отправки комментариев
Привет!
Очевидно что моя задача снадартная но т.к. я совсем начинающий, то вероятно иду по детским граблямю прошу наставить на путь к решению задачи.
Для личного проекта есть необходимость вмешаться в работу стороннего устройства (конвектор)
Конвектор оснащен двухразрядным семисегментным LED дисплеем с общим катодом
На дисплей выводятся показания установвленой и текущей температуры а так же код ошибки в случае неисправности (ошибка мигает)
Задача время от времени обращатьться к обогревателю и получать данные выводимые на дисплей чтобы удаленно мониторить показания.
Посмотрев на сигнал анализатором вижу такую картину:
т.е. устройство сначала светит младший разряд в течении ~1ms затем через микроскопическую паузу светит старший разряд в течении милисекунды. Потом пауза 2 милисекунды и цикл повторяется.
Мигание дисплея реализовано таким образом что тактовые импульсы разрядов(катодов) продалжают поступать своим чередом а адресс выставленый на сегментах(a,b,c..) равен нулю.
На текущий момент мне не пришло в голову ничего умнее как занять на ардуинке 10 цифровых входов и пытаться считывать сигналы методом тыка:
void loop() { while(digitalRead(Display_pin_Ls)); //ждем LOW сигнал на аноде левого(старшего сегмента) delayMicroseconds(10); //даем задержку на дребезг segment_A = digitalRead(Display_pin_A); //читаем данные с сегментов segment_B = digitalRead(Display_pin_B); segment_C = digitalRead(Display_pin_C); segment_D = digitalRead(Display_pin_D); segment_E = digitalRead(Display_pin_E); segment_F = digitalRead(Display_pin_F); segment_G = digitalRead(Display_pin_G); segment_Dp = digitalRead(Display_pin_Dp); //проверяем есть ли совпадения с известными символами if (segment_A == HIGH && segment_B == LOW && segment_C == LOW && segment_D == HIGH && segment_E == HIGH && segment_F == HIGH && segment_G == HIGH && segment_Dp == LOW) { Serial.println("E - Detected"); delay(50); } else if (segment_A == LOW && segment_B == HIGH && segment_C == HIGH && segment_D == LOW && segment_E == LOW && segment_F == LOW && segment_G == LOW && segment_Dp == LOW) { Serial.println("ONE - Detected"); }
Получается крайне не стабильно т.к. считывание сегментов происходит в рандомный момент тактового импульса. Как бы реализовать считывание только один раз за тактовый импульс на катоде?
Но и может я вообще фигню делаю и такие задачи по другому решать надо?
попробуйте вот так
del
Если ОБЛОМ то че вылез ?
Заводите катоды на прерывания, сегменты на один порт или хотя бы два чтобы быстро считать. В обработчике прерывания просто читаете PINx (или два PINx), а потом уже смотрите что там за цифра\буква. Это если портов много, мы не знаем что там за чип у вас. А вообще можно попробовать вклиниться до вывода на индикаторы, там может сдвиговые регистры стоят, можно попробовать еще до них перехватить последовательный код с синхроимпульсами.
попробуйте вот так
Спасибо! Я на самом деле и сам пробывал делать задержку на дребезг и больше и меньше и совсем без нее. И результат иногда очень хороший но к сожалению не стабильный. Как я это понимаю результат зависит от того на сколько ардуинка "синхронизировалась с тактовыми импульсами дисплея"
На самом деле задача delay() (в милисекундах) в программе это всего лишь простой способ заставить программу не так часто писать данные в COM порт и сильно ситуацию наличие или отсутствия делэев не исправляет.
Заводите катоды на прерывания, сегменты на один порт или хотя бы два чтобы быстро считать. В обработчике прерывания просто читаете PINx (или два PINx), а потом уже смотрите что там за цифра\буква. Это если портов много, мы не знаем что там за чип у вас.
День добрый. Что то я не пойму. Сегментов у меня 8(вместе с дробной точкой) как их можно завести на один или два порта?
Под портом я имел ввиду порт микроконтроллера а не конкретный пин. Например, порт B, тогда чтобы считать 8 сегментов Вам надо выпоолнить одну команду PINB и у вас будет 8 бит которые показывают состояние всех сегментов.
А вообще можно попробовать вклиниться до вывода на индикаторы, там может сдвиговые регистры стоят, можно попробовать еще до них перехватить последовательный код с синхроимпульсами.
как я посмотрел - это не получится там стоит микроконтроллер судя по всему который сам на прямую светит дисплей без сдвигового регистра.
микроконтроллер так же по I2C общается с памятью куда сохраняет судя по всему выбранный режим работы на случай прерывания питания, первое что я попробовал так это "послушать" I2C для того чтобы понимать какое значение температуры контроллер в память пишет, но стандартная библиотека не дает "подслушивать" а написать обработчик самому - таланта не хватает (( по этому решил в лоб с индикатора читать.
Saleae (я так понимаю по скриншоту у Вас он есть) умеет i2c понимать. Можете для интереса подцепиться и глянуть что там идет и совпадает ли с показаниями на индикаторе.
Да, анализатор вот только пришел мне китайский китай. попробую им поработать. Но скорее всего не получится нормально считывать из памяти данные. Контроллер держит i2C на себе и не отпускает. Соттветственно шину придется прослушивать постоянно чтобы не пропустить момент записи который происходит только когда пользователь меняет настройки обогревателя, а постоянно слушать шину не хочется. Моё устройство предуспатривает чтение данных по запросу и переход в standby Так что пока в приоритете - задача научиться стабильно читать дисплей.
А не существует ли такой штуки как сдвиговый регистр "наоборот"? или может есть библиотеки заточеные уже под чтение дисплеев?
Скажите, в чем выражается "Контроллер держит i2C на себе и не отпускает." ? По протоколу I2C если обе шины в высоком состоянии - то шина свободна и любой ведущий может инициировать обмен.
После того как контроллер завершает запись/чтение он притягивает линию к 0. Тоесть в моем случае на линии второго мастера быть не может.
А отпускает только когда пишет в память? Может быть использовать прерывание при этом событии что бы прочитать, что по шине бежит? А не ждать постоянно.
Да именно так, отпускает и дергает шину сам когда ему нужно что то написать или почитать.
Можно и прерывание, но как мне кажется что своим "быдлокодом" я никогда не добьюсь стабильности на скоростях I2C кроме того на мой взгляд это не самое стабильное решение, например при перезапуске ардуинки можно запросто что-то потерять, будет рассинхрон данных. В общем затею с I2C я как то уже не рассматримаю как серьезную. Да и зачем, есть экран и на экране всегда можно увидеть полную информацию о режиме работы. Надо только научится его стабильно считывать. Пока мой "процент угадывания" числа на экране довольно не высок.
А какая плата используется?
И попробуйте:
Китайская UNO, но после того как разработаю "для запуска в продуктив" планировал платку поменьше купить. Nano например.
Если подключить сегменты к ногам D4-D11, то читать состояние можно командой
Для меня это новая штука и переменные типа байт и эта прямая манипуляция с портами.... чуть погуглил, до конца суть не осознал. попробовал на практике - не сработало. ((
Вот полный код:
Вот результат:
Сейчас они читаются около 900мкс.
Да, вы правы это неприемлемо долго. Это почти милисекунда а у меня тактовый импульс чуть длиннее милисекунды... от того и пляшут показания.
Конечно несработало. Моя ошибка. a = (PIND & 0xF0)|(PINB & 0x0F); или должно быть а не и.
И три while и делей обязательно надо в начало loop поставить, что бы точно в начале строба читать.
А пляшут из за того, что попадаете на конец строба. При этом условие выполняется, а читается что получится. Поэтому проверяем три раза - низкий высокий низкий уровень, что бы точно попасть в начало.
Спасибо! нетерпится завтра попробовать. Железо на работе оставил ;)
Подобную задачу решал 8 лет назад на PIC16F628. Считывал с 4-х разрядного динамического дисплея и отправлял в ком порт. Работает до сих пор. Есть схема и исходник на MPASM.
Тоже както пробовал считывание с 4хрозрядного динамического. http://arduino.ru/forum/proekty/polugotovyi-laboratornyi-bp#comment-119537 сильно, глубоко не копал. Впринципе получалось. Но стабильность не очень иногда, раз в несколько сек мусор проскакивал. И особенно при нажатии кнопок на "чужем" контроллере. Но мне считывание не актуально было, потому и не копал.
Спасибо вам огромное за помощь! После долгих мучений оно наконец таки заработало. По крайней мере ошибку E1 мигающу. На экране программа читает отлично без сбоев.
Ни через прерывания ни через While работать это не хотело. Работает только так и никак иначе.
Путем экспериментов удолось обнаружить что ардуинка очень плохо притягивает свои цифровые порты на ноль. Выяснил это так:
- читаю состояние портов через PIND и вывожу значение на экран каждые 500ms
- подаю скажем на pin8 логическую единицу проводком на прямую с пинания
- на экране отображаются единички в нужном разряде
- отсоединяю проводок от pin8 а согласно данным на экране единичка держится ещё около секунды
Вобщем, вот код того что работает. Осталось проверить его на полном диапазоне показаний:
Я рад за вас,
но только притяжку к "нулю"
нужно делать вручную, внешним резистором.
Висячий в воздухе вход - это не далеко не "0"
Пробовал притягивать сегменты к нулю - не помогло.
Проверил код на цифрах. Работает но не стабильно. дело в том что по каким то причинам после считывания байта в 50 случаях из 100 возвращается ноль вместо реального числа и я не могу в коде как то обработать это...толи вернулся ноль потому что разряд не горит толи вернулся ошибочный ноль.
Младший разряд горит всегда так что вернувшийся байт 0 для младшего я считаю всегда ошибочным значением.
А вот старший разряд может не гореть если отображается температура ниже 10 градусов например 5.
Как такое можно обработать?
Ну если не хотите делать нормально, пользуйтесь костылями. В Вашем случае должно помочь инициализация переменных rightSegment и leftSegment не нулём, а например значением русской буквы П на идтикаторах (ну или любого другого символа которого там быть не может) тогда Вы точно будите знать 0 считался или индикатор даже не включался.
Я конечно же хочу сделать нормально, я просто раньше не совсем понимал что вы мне говорите.
Но я уже попробовал вариант с прерыванием - он работает хуже чем вариант с IFом т.к. в прерывании нельзя использовать ни таймер ни задержку в 20 микросекунд...либо я не умею этого делать.
За совет с инициализацией заведомо неверным значением спасибо - я попробую.
Покажите что выводит программа.Желательно пару перезапусков.
Запуск 1. кнопкой управления обогревателем плавно с задержкой 2сек меняю температуру от 5 до 35.
Жирным курсивом подсветил ошибочные данные:
Arduino ready!
Увы но не помогло (( '0' возвращается именно в результате считывания портов.
Моя программа должна была вывести 20 НЕХ строк по 10 значений. Это нужно для отладки. Иначе не понять почему считывается неправильно.
Прошу прощения, я не увидел сперва что Вы мне свою программу дали.
Вот результат вашей программы когда на дисплее цифра 20:
ЗАПУСК1
ЗАПУСК2
А вот такой результат когда цифра 21:
ЗАПУСК3
ЗАПУСК4
Arduino is ready
bigfoot99, так попробуйте, по-моему должно работать.
А вообще, да, наверно правильней повеситься на прерывания по LEFT_DIG и RIGHT_DIG, как Penni советовал.
Ну собственно из четырёх запусков вылез один единственный дребезг. Т.е два while сначала на низкий а потом на высокий уровень и потом делей на 40 микросекунд должны 100% читать правильно дисплей. В этих цифрах нижний разряд С - нет строба. 8 -одна цифра, 4 другая. Ряд через 50 мкс. 22 одинаковых значения вподряд при цифрах 4 и 8. Завтра подпрвлю прграмму и попробуем.
Да. Должна работать. Только задержку не 20, а 200 мкс. Один раз через 50 мкс вылазила ошибка. 200 мкс ни разу.
В общем что я только не пробовал но пока удовлетворительного результата не получаю.
Конструкция с тремя while работает хуже чем чем с одним. делэй больше 5 микросекунд тоже не айс. Кроме того я посмотрел анализатором на сигнал - он при подключенной ардуинке сильно зашумленный получается(много дребезга)
Так что пока я в поисках алгоритма.
На текущий момент считываю данные в массив, вопрос роявился а не существует ли какой то простой функции которая смогла бы мне вернуть из массива моду(наиболее часто встречающееся значение)
вот текущий код:
Про шум очень странно. В том выводе, что вы показали по моей программе никакого шума не было.
While должно быть два сначала и третий после чтения первой цифры. Кстати. Есть ещё варианты. Два while первый на низкий уровень, второй на высокий, потом задержка на 500 мкс и чтение первой цифры, потом задержка на 1000 мкс и чтение второй цифры. Без while: if - читаем цифру, ещё раз if - если всё ещё низкий уровень - цифре верим - иначе пробуем читать снова. Можно ещё набросать варианты.
Попробуйте это.
На текущий момент считываю данные в массив, вопрос роявился а не существует ли какой то простой функции которая смогла бы мне вернуть из массива моду(наиболее часто встречающееся значение)
Есть "стандартные", некоторые меньше памят расходуют, но более медленные, некоторые наоборот. Вот одна из реализаций.
Вот интересный подход - чуть что, сразу программно фильтровать помехи.
А то что помехи вообще появились, там где им появиться неоткуда, никого не беспокоит?
bigfoot99, как там всё подключено? Уверены что правильно?
Какие уровни сигнала, снятого с сегментов? Если есть возможность, неплохо бы ткнуть аналоговым осциллографом. То есть, не обязательно аналоговым, но с аналоговым входом.
Проверьте, например, не подключились ли Вы к точке между сегментом-светодиодом и его токоограничивающим резистором - вполне возможная ошибка, я так часто делаю. :)
А пытаться восстановить искаженный сигнал - можно, конечно, но какой смысл, если проще его не искажать.
Вот интересный подход - чуть что, сразу программно фильтровать помехи.
А то что помехи вообще появились, там где им появиться неоткуда, никого не беспокоит?
bigfoot99, как там всё подключено? Уверены что правильно?
Вот очень верный коментарий. Сам чую что подход с фильтрацией скорее похож на подгонку под результат.
Да, меня беспокоит, что появились помехи, просто я не посчитал нужным высказать эти беспокойства на форуме )).
Подключаюсь я непосредственно к дисплею, но подключение "коленочное" с помощью наспех припаеных к дисплею проводков вставленых в разъемы ардуинки где от частых подключений разьемчики уже болтаются.
Я допускаю что дребезг возникает именно из-за фигового монтажа, но не уверен в этом на 100%
В общем, что я планирую делать в качестве работы над ошибками, я для начала сделаю правильный монтаж распаеный нормальным шлейфом (от старых FDD/HDD).
После того как вопрос монтажа закрою - продолжу эксперименты.
Осцилографа аналогового у меня к сожалению нету. Есть только цифровой анализатор-китаец на 8 портов.
А то что помехи вообще появились, там где им появиться неоткуда, никого не беспокоит?
Чего ж не беспокоит. Меня беспокоил в свое время. И мысли были разные. Вот сигналы на сегменты и на строб. Их выдают не одномоментно (в смысле не одной машинной командой), а фигзнает каким загадочным образом в зависимости от реализации. Может побитово, по одному сегменту устанавливают, а может сразу все или по группам(на разных портах если). И строб можна активировать после установки сегментов, а можна и до. А ежели прерывания не запрещать в это время, то интервалы процесса могут гулять оч интересным образом, на десяток микросекунд - глаз не заметит, а софт сбивается. И софт считывающий должен все это учесть. Если не учитывать - будут помехи. Еще вопрос - переключение показаний, не факт что оно синхронизировано с стробированием и уж точно асинхронно нашей работе. Вот и можем получить часть от одних показаний, а часть от других.
Или вот про электричество - уровни снимаемые с индикатора могут быть сильно просажены (ну тут от схемы зависит, у меня так вобще без резисторов было )). Еще про электричество - каждый светодиод еще и емкость имеет, её тоже надо учесть. И как возможность затяжки фронта и как возможность скчков напряжения на сегментах при переключении строба. А может и еще как.
Так что беспокоило. Но не волновало ;) Есть откуда взятся помехам.
А фильтровать тут действительно слабенький подход. Может лучше многократный повторный опрос состояния сегментов при активном стробе через небольшие интервалы времени с отбросом непохожих значений или хотяб алгоритм 2подряд или 2из3.
Так что беспокоило. Но не волновало ;) Есть откуда взятся помехам.
Ну да, тоже правильно. Раз появились - значит есть откуда. :)
Но я имел в виду, что желательно выяснить причину, и по возможности устранить, ещё на аппаратном уровне.
Кстати, вспомнилось - извините если уже писали, не хочется всё перечитывать.
Возможно, нужны подтягивающие резисторы - на сигналах стробов и/или сигналах сегментов.
Управляющие индикатором выходы, когда они не активны, вполне могут оставаться в неопределённом состоянии, и тогда всякие случайные помехи вполне объяснимы.
Возможно, нужны подтягивающие резисторы - на сигналах стробов и/или сигналах сегментов.
Логгер не фиксирует дребезга на "пустых" значениях.
Но поддтягивать я пробовал - это не сказалось на работе совсем никак.
темв ременем успел сегодня сделать монтаж нормальным шлейфом. Буду тестировать.
Возможные причины помех
1) Разность земель
2) броски потребления и из за этого разность земель
3) если смотрим сегменты на индикаторе, то низкий уровень (2.5В) высокого сигнала, при этом если питание Ардуины 5В, то может не хватать для четкого определения единицы.
К моему сожалению, качественный монтаж не дал значительных улучшенийб ардуинка по прежнему фиксирует много мусора.
1) Разность земель -> Земли связаны хорошим толстым проводом
2) броски потребления и из за этого разность земель -> Потребления светодиодом?
3) если смотрим сегменты на индикаторе, то низкий уровень (2.5В) высокого сигнала, при этом если питание Ардуины 5В, то может не хватать для четкого определения единицы. -> Я померял питание самой платы где дисплей и его контроллер - там четко 5в. А как можно померить напряжение импульсов на поданные на дисплей без аналогового осцилографа?
Ну откуда шум? Не было шума на выводе. Уберите из моей программы while(1) и она непрерывно будет сыпать значения. Посмотрите много ли будут прыгать верхние цифры при нижних 4 и 8.
А как можно померить напряжение импульсов на поданные на дисплей без аналогового осцилографа?
Элементарно, Ватсон! Цифровым осциллографом.
Вообще мне ситуация, когда кто-то справшивает, как наладить схему без осциллографа, напоминает ситуацию, когда кто-то на кулинарном форуме, где люди обсуждают особенности применения специй, температурного режима и пр. вдруг появляется человек и справшивает: А как мне приготовить борщ ьез кастрюли, ведра, тазика и т.п. посуды.
IMHO этот вопрос должен звучать на форуме повыживанию в экстремальных ситуациях, но никак не на кулинарном форуме.
Точно так же и здесь: IMHO вопрос по наладке схемы без осциллографа следует счтитать оффтопиком для данного форума и вообще - проявлением неуважения к его участникам.
PS. В конце концов, существует DSO 138, который способен закрыть 90-95% потребностей в осциллографе.