Считать показания с двухразрядного семисегментного LED дисплея.

bigfoot99
Offline
Зарегистрирован: 03.02.2018

Привет!

Очевидно что моя задача снадартная но т.к. я совсем начинающий, то вероятно иду по детским граблямю прошу наставить на путь к решению задачи.

Для личного проекта есть необходимость вмешаться в работу стороннего устройства (конвектор)

Конвектор оснащен двухразрядным семисегментным  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");
    }  

Получается крайне не стабильно т.к. считывание сегментов происходит в рандомный момент тактового импульса. Как бы реализовать считывание только один раз за тактовый импульс на катоде?

Но и может я вообще фигню делаю и такие задачи по другому решать надо?

240265
240265 аватар
Offline
Зарегистрирован: 12.08.2015

попробуйте вот так

void loop() 
{
    while(digitalRead(Display_pin_Ls));  //ждем LOW сигнал на аноде левого(старшего сегмента)
    delayMicroseconds(300);  //даем задержку на дребезг
    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");
       
    }
    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");}
    }  
delay(50);
}

 

 

 

 

 

 

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

del

240265
240265 аватар
Offline
Зарегистрирован: 12.08.2015

   Если ОБЛОМ то че вылез ?

 

 

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Заводите катоды на прерывания, сегменты на один порт или хотя бы два чтобы быстро считать. В обработчике прерывания просто читаете PINx (или два PINx), а потом уже смотрите что там за цифра\буква. Это если портов много, мы не знаем что там за чип у вас. А вообще можно попробовать вклиниться до вывода на индикаторы, там может сдвиговые регистры стоят, можно попробовать еще до них перехватить последовательный код с синхроимпульсами.

bigfoot99
Offline
Зарегистрирован: 03.02.2018

240265 пишет:

попробуйте вот так

Спасибо! Я на самом деле и сам пробывал делать задержку на дребезг и больше и меньше и совсем без нее. И результат иногда очень хороший но к сожалению не стабильный. Как я это понимаю результат зависит от того на сколько ардуинка "синхронизировалась с тактовыми импульсами дисплея"

На самом деле задача delay() (в милисекундах) в программе это всего лишь простой способ заставить программу не так часто писать данные в COM порт и сильно ситуацию наличие или отсутствия делэев не исправляет.

 

bigfoot99
Offline
Зарегистрирован: 03.02.2018

Penni пишет:

Заводите катоды на прерывания, сегменты на один порт или хотя бы два чтобы быстро считать. В обработчике прерывания просто читаете PINx (или два PINx), а потом уже смотрите что там за цифра\буква. Это если портов много, мы не знаем что там за чип у вас.

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

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Под портом я имел ввиду порт микроконтроллера а не конкретный пин. Например, порт B, тогда чтобы считать 8 сегментов Вам надо выпоолнить одну команду PINB и у вас будет 8 бит которые показывают состояние всех сегментов.

bigfoot99
Offline
Зарегистрирован: 03.02.2018

Penni пишет:

А вообще можно попробовать вклиниться до вывода на индикаторы, там может сдвиговые регистры стоят, можно попробовать еще до них перехватить последовательный код с синхроимпульсами.

как я посмотрел - это не получится там стоит микроконтроллер судя по всему который сам на прямую светит дисплей без сдвигового регистра.

микроконтроллер так же по I2C общается с памятью куда сохраняет судя по всему выбранный режим работы на случай прерывания питания, первое что я попробовал так это "послушать" I2C для того чтобы понимать какое значение температуры контроллер в память пишет, но стандартная библиотека не дает "подслушивать" а написать обработчик самому - таланта не хватает ((  по этому решил в лоб с индикатора читать.

 

 

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Saleae (я так понимаю по скриншоту у Вас он есть) умеет i2c понимать. Можете для интереса подцепиться и глянуть что там идет и совпадает ли с показаниями на индикаторе.

bigfoot99
Offline
Зарегистрирован: 03.02.2018

Да, анализатор вот только пришел мне китайский китай. попробую им поработать. Но скорее всего не получится нормально считывать из памяти данные. Контроллер  держит i2C на себе и не отпускает. Соттветственно шину придется прослушивать постоянно чтобы не пропустить момент записи который происходит только когда пользователь меняет настройки обогревателя, а постоянно слушать шину не хочется. Моё устройство предуспатривает чтение данных по запросу и переход в standby  Так что пока в приоритете - задача научиться стабильно читать дисплей.

А не существует ли такой штуки как сдвиговый регистр "наоборот"?  или может есть библиотеки заточеные уже под чтение дисплеев?

nik182
Offline
Зарегистрирован: 04.05.2015

Скажите, в чем выражается "Контроллер  держит i2C на себе и не отпускает." ? По протоколу I2C если обе шины в высоком состоянии - то шина свободна и любой ведущий может инициировать обмен. 

bigfoot99
Offline
Зарегистрирован: 03.02.2018

После того как контроллер завершает запись/чтение он притягивает линию к 0. Тоесть в моем случае на линии второго мастера быть не может.

nik182
Offline
Зарегистрирован: 04.05.2015

А отпускает только когда пишет в память? Может быть использовать прерывание при этом событии что бы прочитать, что по шине бежит? А не ждать постоянно. 

bigfoot99
Offline
Зарегистрирован: 03.02.2018

Да именно так, отпускает и дергает шину сам когда ему нужно что то написать или почитать.

Можно и прерывание, но как мне кажется что своим "быдлокодом" я никогда не добьюсь стабильности на скоростях I2C кроме того на мой взгляд это не самое стабильное решение, например при перезапуске ардуинки можно запросто что-то потерять, будет рассинхрон данных. В общем затею с I2C я как то уже не рассматримаю как серьезную. Да и зачем, есть экран и на экране всегда можно увидеть полную информацию о режиме работы.  Надо только научится его стабильно считывать. Пока мой "процент угадывания" числа на экране довольно не высок.

nik182
Offline
Зарегистрирован: 04.05.2015

А какая плата используется?

И попробуйте:

void loop() 
{
    while(digitalRead(Display_pin_Ls));  //ждем LOW сигнал на аноде левого(старшего сегмента)
    while(!digitalRead(Display_pin_Ls));  //ждем HIGH сигнал на аноде левого(старшего сегмента)
    while(digitalRead(Display_pin_Ls));  //ждем LOW сигнал на аноде левого(старшего сегмента)
   delayMicroseconds(50);  //даем задержку на дребезг
    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");
    }  

 

bigfoot99
Offline
Зарегистрирован: 03.02.2018

Китайская UNO, но после того как разработаю "для запуска в продуктив" планировал платку поменьше купить. Nano например.

nik182
Offline
Зарегистрирован: 04.05.2015

Если подключить сегменты к ногам D4-D11, то читать состояние можно командой

byte a= (PIND & 0xF0) & (PINB & 0x0F);
 
Тогда порты будут считаны за время меньше микросекунды. Сейчас они читаются около 900мкс. Биты пременной а будут содержать состояние сегментов по ногам d8,d9,d10,d11,d4,d5,d6,d7 (с меньшего к старшему).      
 
bigfoot99
Offline
Зарегистрирован: 03.02.2018

Для меня это новая штука и переменные типа байт и эта прямая манипуляция с портами.... чуть погуглил,  до конца суть не осознал. попробовал на практике - не сработало. ((

Вот полный код:

//Pins Configuration
int Display_pin_Rs = 12;    //  Rs Right segment common Cathode (LOW)  
int Display_pin_Ls = 13;    //  Ls Left segment common Cathode (LOW) 
int Display_pin_A = 4;    
int Display_pin_B = 5;    
int Display_pin_C = 6;    
int Display_pin_D = 7;    
int Display_pin_E = 8;    
int Display_pin_F = 9;
int Display_pin_G = 10;
int Display_pin_Dp = 11; 

//SETUP   
void setup() {
  // устанавливаем и сбрасываем пины
  pinMode (Display_pin_Rs, INPUT);
  pinMode (Display_pin_Ls, INPUT);
  pinMode (Display_pin_A, INPUT);
  pinMode (Display_pin_B, INPUT);
  pinMode (Display_pin_C, INPUT);
  pinMode (Display_pin_D, INPUT);
  pinMode (Display_pin_E, INPUT);
  pinMode (Display_pin_F, INPUT);
  pinMode (Display_pin_G, INPUT);
  pinMode (Display_pin_Dp, INPUT);
  // запускаем последовательный порт    
  Serial.begin(9600);
  // ждем подключения
  while (! Serial);  
  // сообщаем готовности
  Serial.println("Arduino is ready"); 
}
// MAIN LOOP
void loop() 
{
      byte a = (PIND & 0xF0)&(PINB & 0x0F);
      Serial.println (a);
      Serial.println ("---------");
      delay(700);
}

Вот результат:

bigfoot99
Offline
Зарегистрирован: 03.02.2018

nik182 пишет:

Сейчас они читаются около 900мкс.

Да, вы правы это неприемлемо долго. Это почти милисекунда а у меня тактовый импульс чуть длиннее милисекунды... от того и пляшут показания.

nik182
Offline
Зарегистрирован: 04.05.2015

Конечно несработало. Моя ошибка. a = (PIND & 0xF0)|(PINB & 0x0F); или должно быть а не и.
И три while и делей обязательно надо в начало loop поставить, что бы точно в начале строба читать.
А пляшут из за того, что попадаете на конец строба. При этом условие выполняется, а читается что получится. Поэтому проверяем три раза - низкий высокий низкий уровень, что бы точно попасть в начало.

bigfoot99
Offline
Зарегистрирован: 03.02.2018

Спасибо! нетерпится завтра попробовать. Железо на работе оставил ;)

DeGlucker
Offline
Зарегистрирован: 23.07.2014

Подобную задачу решал 8 лет назад на PIC16F628. Считывал с 4-х  разрядного динамического дисплея и отправлял в ком порт. Работает до сих пор. Есть схема и исходник на MPASM.

Logik
Offline
Зарегистрирован: 05.08.2014

Тоже както пробовал считывание с 4хрозрядного динамического. http://arduino.ru/forum/proekty/polugotovyi-laboratornyi-bp#comment-119537 сильно, глубоко не копал. Впринципе получалось. Но  стабильность не очень иногда, раз в несколько сек мусор проскакивал. И особенно при нажатии кнопок на "чужем" контроллере. Но мне считывание не актуально было, потому и не копал.

bigfoot99
Offline
Зарегистрирован: 03.02.2018

nik182 пишет:
Конечно несработало. Моя ошибка. a = (PIND & 0xF0)|(PINB & 0x0F); или должно быть а не и. И три while и делей обязательно надо в начало loop поставить, что бы точно в начале строба читать. А пляшут из за того, что попадаете на конец строба.

 

Спасибо вам огромное за помощь!  После долгих мучений оно наконец таки заработало. По крайней мере ошибку E1 мигающу. На экране программа читает отлично без сбоев.

Ни через прерывания ни через While работать это не хотело. Работает только так и никак иначе.

Путем экспериментов удолось обнаружить что ардуинка очень плохо притягивает свои цифровые порты на ноль. Выяснил это так:

- читаю состояние портов через PIND и вывожу значение на экран каждые 500ms

- подаю скажем на pin8 логическую единицу проводком на прямую с пинания

- на экране отображаются единички в нужном разряде

- отсоединяю проводок от pin8 а согласно данным на экране единичка держится ещё около секунды

Вобщем, вот код того что работает. Осталось проверить его на полном диапазоне показаний:

//Pins Configuration
/*
Display_pin_A = 7;    
Display_pin_B = 6;    
Display_pin_C = 5;    
Display_pin_D = 4;    
Display_pin_E = 11;    
Display_pin_F = 10;
Display_pin_G = 9;
Display_pin_Dp = 8; */

int Display_pin_Rs = 2;    //  Rs Right segment common Cathode (LOW)  
int Display_pin_Ls = 3;    //  Ls Left segment common Cathode (LOW) 
byte rightSegment;
byte leftSegment;

//SETUP   
void setup() {
  pinMode (Display_pin_Ls, INPUT);
  pinMode (Display_pin_Rs, INPUT);
 // // запускаем последовательный порт    
  Serial.begin(9600);
  while (! Serial);  
  Serial.println("Arduino is ready"); 
}
// MAIN LOOP
void loop() 
{
  if (digitalRead(Display_pin_Rs) == LOW)           //ждем LOW сигнал на аноде правого(младшего разряда)
  {
    delayMicroseconds(70);                          //Задержка на дребезг
    rightSegment = (PIND & 0xF0)|(PINB & 0x0F);     //читаем данные c сегментов
  }
  if (digitalRead(Display_pin_Ls)== LOW)            //ждем LOW сигнал на аноде левого(старшего разряда) 
  {
    delayMicroseconds(10);                          //Задержка на дребезг
    leftSegment = (PIND & 0xF0)|(PINB & 0x0F);      //читаем данные c сегментов
  } 
  String segment_R = Parcer(rightSegment, 0);          //Парсим байт правого(нулевого) сегмента
  String segment_L = Parcer(leftSegment, 1);           //Парсим байт правого(первого) сегмента
  if (segment_R != "NONE" && segment_L != "NONE")   //Если оба сегмента распознаны то выводим результат в COM порт
  {  
  Serial.print (segment_L);
  Serial.print ("     ");
  Serial.print (segment_R);
  Serial.print ("     -     ");
  Serial.print (leftSegment);
  Serial.print ("   ");
  Serial.println (rightSegment);
  Serial.println ("---------"); 
  segment_R = "NONE";                               // обнуляем данные
  segment_L = "NONE";
  rightSegment = 0;
  leftSegment = 0;
  }
}

//FUNCTIONS
String Parcer(byte input_val, boolean seg)                       //Функция парсит результат захвата данных в байт
{
  String result_val = "NONE";
  if (input_val == 158)
  {
    result_val = "E";   
  }
  else if (input_val == 6 || input_val == 96)
  {
    result_val = "1";
  }
  else if (input_val == 218)
  {
    result_val = "2";
  }
  else if (input_val == 242)
  {
    result_val = "3";
  }
  else if (input_val == 102)
  {
    result_val = "4";
  }
  else if (input_val == 182)
  {
    result_val = "5";
  }
  else if (input_val == 190)
  {
    result_val = "6";
  }
  else if (input_val == 14 || input_val == 224)
  {
    result_val = "7";
  }
  else if (input_val == 254)
  {
    result_val = "8";
  }
  else if (input_val == 246)
  {
    result_val = "9";
  }
  else if (input_val == 252)
  {
    result_val = "0";
  }
    else if (input_val == 0 && seg == 1)
  {
    result_val = "0";
  }  
  return result_val;
}

 

 

 

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Я рад за вас,
но только притяжку к "нулю"
нужно делать вручную, внешним резистором.
Висячий в воздухе вход - это не далеко не "0"

bigfoot99
Offline
Зарегистрирован: 03.02.2018

Пробовал притягивать сегменты к нулю - не помогло.

Проверил код на цифрах. Работает но не стабильно. дело в том что по каким то причинам после считывания байта в 50 случаях из 100 возвращается ноль вместо реального числа и я не могу в коде как то обработать это...толи вернулся ноль потому что разряд не горит толи вернулся ошибочный ноль.

Младший разряд горит всегда так что вернувшийся байт 0 для младшего я считаю всегда ошибочным значением.

А вот старший разряд может не гореть если отображается температура ниже 10 градусов например 5.

Как такое можно обработать?

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Ну если не хотите делать нормально, пользуйтесь костылями. В Вашем случае должно помочь инициализация переменных rightSegment и leftSegment не нулём, а например значением русской буквы П на идтикаторах (ну или любого другого символа которого там быть не может) тогда Вы точно будите знать 0 считался или индикатор даже не включался.

bigfoot99
Offline
Зарегистрирован: 03.02.2018

Penni пишет:
Ну если не хотите делать нормально, пользуйтесь костылями. В Вашем случае должно помочь инициализация переменных rightSegment и leftSegment не нулём

Я конечно же хочу сделать нормально, я просто раньше не совсем понимал что вы мне говорите.

Но я уже попробовал вариант с прерыванием - он работает  хуже чем вариант с IFом т.к. в прерывании нельзя использовать ни таймер ни задержку в 20 микросекунд...либо я не умею этого делать.

За совет с инициализацией заведомо неверным значением спасибо - я попробую.

nik182
Offline
Зарегистрирован: 04.05.2015

Покажите что выводит программа.Желательно пару перезапусков.


byte ar[200];
byte i=0;
 
void setup() {
  Serial.begin(9600);
  while (! Serial);  
  Serial.println("Arduino is ready"); 
}
// MAIN LOOP
void loop() 
{
   for (i=0;i<199;i++) { 
   ar[i] = (PIND & 0xFC); 
   delayMicroseconds(50);                          
  } 
  for (i=0;i<199;i++) { 
  Serial.print (ar[i],HEX);
  Serial.print (" ");
  if ((i%10) == 0)   Serial.println(); 
  }
  while(1);
}

 

bigfoot99
Offline
Зарегистрирован: 03.02.2018
Вот результат работы. Программа принципиально не менялась. единственное что исправил это сделал так чтобы выводилось на экран значение только если оно отличается от предыдущего.
  if (segment_R != "NONE" && segment_L != "NONE" && (segment_R != prev_segment_R || segment_L != prev_segment_L)) 

Запуск 1. кнопкой управления обогревателем плавно с задержкой 2сек меняю температуру от 5 до 35.

Жирным курсивом подсветил ошибочные данные:

Arduino ready!

                                  - Значения от 5 до 9 не регистрируются совсем
1  0     -     96   252
                                  - 11 не рапозналось
1  2     -     96   218
1  3     -     96   242
1  4     -     96   102
1  1     -     96   6      - иногда распознается 11 вместо 15
1  5     -     96   182
1  1     -     96   6      - иногда распознается 11 вместо 15
1  5     -     96   182
1  1     -     96   6      - иногда распознается 11 вместо 15
1  5     -     96   182
1  1     -     96   6      - иногда распознается 11 вместо 15
1  5     -     96   182
1  1     -     96   6      - иногда распознается 11 вместо 15
1  6     -     96   190
1  7     -     96   224
1  8     -     96   254
1  9     -     96   246
2  0     -     218   252
                                - 21 не распозналось
2  2     -     218   218
                                - 23 не распозналось
2  4     -     218   102
2  1     -     218   6    - располналось 21 вместо 25
2  6     -     218   190
                                - 27 не распозналось
2  8     -     218   254
2  9     -     218   246
3  0     -     242   252
7  0     -     224   252 - иногда распознается 70 вместо 30 (решаемо т.к. 70 в принципе не валидное значение)
3  0     -     242   252
3  1     -     242   96
3  2     -     242   218
3  3     -     242   242
3  1     -     242   6    иногда распознается31 вместо 34
3  4     -     242   102
3  1     -     242   6
                                - 35 не распозналось
 
 
Запуск 2 (без коментариев):
Arduino ready!
1  0     -     96   252
1  2     -     96   218
1  3     -     96   242
1  1     -     96   6
1  5     -     96   182
1  1     -     96   6
1  5     -     96   182
1  6     -     96   190
1  8     -     96   254
1  9     -     96   246
2  0     -     218   252
2  1     -     218   6
2  6     -     218   190
2  8     -     218   254
2  9     -     218   246
3  0     -     242   252
3  2     -     242   218
3  1     -     242   6
3  4     -     242   102
 

 

bigfoot99
Offline
Зарегистрирован: 03.02.2018

Penni пишет:
В Вашем случае должно помочь инициализация переменных rightSegment и leftSegment не нулём, а например значением русской буквы П на идтикаторах (ну или любого другого символа которого там быть не может) тогда Вы точно будите знать 0 считался или индикатор даже не включался.

Увы но не помогло ((  '0' возвращается именно в результате считывания портов.

nik182
Offline
Зарегистрирован: 04.05.2015

Моя программа должна была вывести 20 НЕХ строк по 10 значений.  Это нужно для отладки. Иначе не понять почему считывается неправильно. 

bigfoot99
Offline
Зарегистрирован: 03.02.2018

Прошу прощения, я не увидел сперва что Вы мне свою программу дали.

Вот результат вашей программы когда на дисплее цифра 20:

ЗАПУСК1

Arduino is ready
D8 
D8 C CC C4 C4 C4 C4 C4 C4 C4 
C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 
C4 C4 C4 C4 C4 DC C C C C 
C C C C C C C C C C 
C C C C C C C C C C 
C EC C C C C C C C C 
C C C C C C C C C C 
C C C C C C 2C F8 F8 F8 
F8 F8 F8 F8 F8 F8 F8 F8 F8 F8 
F8 F8 F8 F8 F8 F8 F8 F8 F8 F8 
C CC C4 C4 C4 C4 C4 C4 C4 C4 
C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 
C4 C4 C4 C4 C4 C C C C C 
C C C C C C C C C C 
C C C C C C C C C C 
EC EC C C C C C C C C 
C C C C C C C C C C 
C C C C C 2C EC F8 F8 F8 
F8 F8 F8 F8 F8 F8 F8 F8 F8 F8 
F8 F8 F8 F8 F8 F8 F8 F8 

ЗАПУСК2

Arduino is ready
C4 
C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 
C4 C4 C4 C4 C4 C C C C C 
C C C C C C C C C C 
C C C C C C C C C C 
EC C C C C C C C C C 
C C C C C C C C C C 
C C C C C AC F8 F8 F8 F8 
F8 F8 F8 F8 F8 F8 F8 F8 F8 F8 
F8 F8 F8 E8 F8 F8 F8 F8 F8 C 
8C C4 4 4 4 4 4 4 4 4 
4 4 4 4 4 4 4 4 4 4 
4 4 4 4 C C C C C C 
C C C C C C C C C C 
C C C C C C C C C EC 
EC C C C C C C C C C 
C C C C C C C C C C 
C C C C 2C FC C8 C8 C8 C8 
C8 C8 C8 C8 C8 C8 C8 C8 C8 C8 
C8 C8 C8 C8 C8 C8 C8 C8 C C 
C4 C4 C4 C4 C4 C4 C4 C4

А вот такой результат когда цифра 21:

ЗАПУСК3

Arduino is ready
C C C C C C C C C 2C 
8 8 8 8 8 8 8 8 8 8 
8 8 8 8 8 8 8 8 8 8 
8 8 8 C 8C C4 C4 C4 C4 C4 
C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 
C4 C4 C4 C4 C4 C4 C4 C4 C C 
C C C C C C C C C C 
C C C C C C C C C C 
C C C EC C C C C C C 
C C C C C C C C C C 
C C C C C C C C 2C 8 
8 8 8 8 8 8 8 8 8 8 
8 8 8 8 8 8 8 8 8 8 
8 8 C 8C C4 C4 C4 C4 C4 C4 
C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 
C4 C4 C4 C4 C4 C4 C4 C C C 
C C C C C C C C C C 
C C C C C C C C C C 
C C EC EC C C C C C C 
C C C C C C C C 

ЗАПУСК4

Arduino is ready

8 8 8 8 8 8 C CC C4 C4 
C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 
C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 
C4 C C C C C C C C C 
C C C C C C C C C C 
C C C C C C EC EC C C 
C C C C C C C C C C 
C C C C C C C C C C 
C 2C 8 8 8 8 8 8 8 8 
8 8 8 8 8 8 8 8 8 8 
8 8 8 8 8 C 8C 4 4 4 
4 4 4 4 4 4 4 4 4 4 
4 4 4 4 4 4 4 4 4 4 
C C C C C C C C C C 
C C C C C C C C C C 
C C C C C EC EC C C C 
C C C C C C C C C C 
C C C C C C C C C C 
C 6C 8 8 8 8 8 8 8 8 
8 8 8 8 8 8 8 8 
Datak
Offline
Зарегистрирован: 09.10.2014

bigfoot99, так попробуйте, по-моему должно работать.

// MAIN LOOP
void loop() 
{
  while( digitalRead( Display_pin_Rs ) == LOW );    // ждем HIGH сигнал на аноде правого(младшего разряда)

  while( digitalRead( Display_pin_Rs ) != LOW );    // ждем LOW сигнал на аноде правого(младшего разряда)
  delayMicroseconds( 20 ) ;
  
  rightSegment = (PIND & 0xF0)|(PINB & 0x0F);       // читаем данные c правого сегмента
  
  while( digitalRead( Display_pin_Ls ) != LOW );    // ждем LOW сигнал на аноде левого(старшего разряда)
  delayMicroseconds( 20 );
  
  leftSegment = (PIND & 0xF0)|(PINB & 0x0F);        // читаем данные c левого сегмента

  char segment_R = Parcer( rightSegment );          // Парсим байт правого(нулевого) сегмента
  char segment_L = Parcer( leftSegment );           // Парсим байт левого(первого) сегмента
 
  Serial.print (segment_L);
  Serial.print ( ( leftSegment & 0x01 ) ? '.' : ' ' );
  Serial.print (segment_R);
  Serial.print ( ( rightSegment & 0x01 ) ? '.' : ' ' );
  Serial.print ("     -     ");
  Serial.print (leftSegment);
  Serial.print ("   ");
  Serial.println (rightSegment);
  Serial.println ("---------"); 
  }
}

//FUNCTIONS
char Parcer( byte input_val )                       //Функция парсит результат захвата данных в байт
{
  char result;
  
  input_val &= 0xFE; // обнулить бит DP (десятичная точка)
  
  switch( input_val )
  {
  case 158: result = 'E'; break;

  case  96: result = '1'; break;
  case 218: result = '2'; break;
  case 242: result = '3'; break;
  case 102: result = '4'; break;
  case 182: result = '5'; break;
  case 190: result = '6'; break;
  case 224: result = '7'; break;
  case 254: result = '8'; break;
  case 246: result = '9'; break;
  case 152: result = '0'; break;
  case   0: result = ' '; break;

  default:  result = '?'; break;
  }
  
  return result;
}

А вообще, да, наверно правильней повеситься на прерывания по LEFT_DIG и RIGHT_DIG, как Penni советовал.

nik182
Offline
Зарегистрирован: 04.05.2015

Ну собственно из четырёх запусков вылез один единственный дребезг. Т.е два while сначала на низкий а потом на высокий уровень и потом делей на 40 микросекунд должны 100% читать правильно дисплей. В этих цифрах нижний разряд С - нет строба. 8 -одна цифра, 4 другая. Ряд через 50 мкс. 22 одинаковых значения вподряд при цифрах 4 и 8. Завтра подпрвлю прграмму и попробуем.

nik182
Offline
Зарегистрирован: 04.05.2015

Да. Должна работать. Только задержку не 20, а 200 мкс. Один раз через 50 мкс вылазила ошибка. 200 мкс ни разу.

 

bigfoot99
Offline
Зарегистрирован: 03.02.2018

В общем что я только не пробовал но пока удовлетворительного результата не получаю.

Конструкция с тремя while работает хуже чем чем с одним. делэй больше 5 микросекунд тоже не айс. Кроме того я посмотрел анализатором на сигнал - он при подключенной ардуинке сильно зашумленный получается(много дребезга)

Так что пока я в поисках алгоритма.

На текущий момент считываю данные в массив, вопрос роявился а не существует ли какой то простой функции которая смогла бы мне вернуть из массива моду(наиболее часто встречающееся значение)

вот текущий код:

void loop() 
{   
int Strobe_pin = Display_pin_Rs;    // определяем какой строб считать. Для начала тренируемся на младшем сегменте
int Segment = 0;                    // говорим какой это сегмент 0-младший или 1-страший (нужно для парсинга)                

// получить не ошибочное значение сегмента 100 раз и записать в массив
    for (int i=0;i<49;i++) 
    { 
      int val = Get_Segment(Strobe_pin, Segment);  // Функция Get_Segment возвращает цифру которая светится разряде или число 88 в случае ошибки парсера
      if (val != 88)      
      {
         ar[i] = val;     
      }
      else              // если значение 88 - это ошибка парсинга - такое значение отбрасываем и цикл отбрасываем на шаг назад
      {
          i = i - 1;         
      }
    } 

// получить наиболее часто встречающееся число в массиве
      // ?? нужна трезвая голова и светлый ум а гдеж это взять ;)
      
// печать результата  (пока просто печатаем массив целиком)
    for (int i=0;i<49;i++) 
    { 
      Serial.print (ar[i]); 
      Serial.print (" - ");          
    } 
    Serial.println ("");
    delay(10);
}
nik182
Offline
Зарегистрирован: 04.05.2015

Про шум очень странно. В том выводе, что вы показали по моей программе никакого шума не было.

While должно быть два сначала и третий после чтения первой цифры. Кстати. Есть ещё варианты. Два while первый на низкий уровень, второй на высокий, потом задержка на 500 мкс и чтение первой цифры, потом задержка на 1000 мкс и чтение второй цифры. Без while: if - читаем цифру, ещё раз if - если всё ещё низкий уровень - цифре верим - иначе пробуем читать снова. Можно ещё набросать варианты.

Попробуйте это.

void loop() 
{
  while(!(PIND & 0x4));    // ждем пока LOW  сигнал первой цифрфы
  while( (PIND & 0x4));    // ждем пока HIGH сигнал первой цифрфы
  delayMicroseconds( 500 ) ;
 
  rightSegment = (PIND & 0xF0)|(PINB & 0x0F);       // читаем данные c правого сегмента
  
  delayMicroseconds( 1200 );
  
  leftSegment = (PIND & 0xF0)|(PINB & 0x0F);        // читаем данные c левого сегмента

  char segment_R = Parcer( rightSegment );          // Парсим байт правого(нулевого) сегмента
  char segment_L = Parcer( leftSegment );           // Парсим байт левого(первого) сегмента
 
  Serial.print (segment_L);
  Serial.print ( ( leftSegment & 0x01 ) ? '.' : ' ' );
  Serial.print (segment_R);
  Serial.print ( ( rightSegment & 0x01 ) ? '.' : ' ' );
  Serial.print ("     -     ");
  Serial.print (leftSegment);
  Serial.print ("   ");
  Serial.println (rightSegment);

  }

 

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

bigfoot99 пишет:

На текущий момент считываю данные в массив, вопрос роявился а не существует ли какой то простой функции которая смогла бы мне вернуть из массива моду(наиболее часто встречающееся значение)

Есть "стандартные", некоторые меньше памят расходуют, но более медленные, некоторые наоборот. Вот одна из реализаций.

// global variables and constants
const int mass_size = 50;
int mass[mass_size];

int moda()
{
  int num = mass[0];
  int max_frq = 1;
  int frq = 0;
  for (int i = 0; i < mass_size - 1; i++)
  {
    frq = 1;
    for (int k = i + 1; k < mass_size; k++)
      if (mass[i] == mass[k])
        frq += 1;
    if (frq > max_frq)
    {
      max_frq = frq;
      num = mass[i];
    }
  }
  return num;
}

 

Datak
Offline
Зарегистрирован: 09.10.2014

Вот интересный подход - чуть что, сразу программно фильтровать помехи.

А то что помехи вообще появились, там где им появиться неоткуда, никого не беспокоит?

bigfoot99, как там всё подключено? Уверены что правильно?

Какие уровни сигнала, снятого с сегментов? Если есть возможность, неплохо бы ткнуть аналоговым осциллографом. То есть, не обязательно аналоговым, но с аналоговым входом.

Проверьте, например, не подключились ли Вы к точке между сегментом-светодиодом и его токоограничивающим резистором - вполне возможная ошибка, я так часто делаю. :)

А пытаться восстановить искаженный сигнал - можно, конечно, но какой смысл, если проще его не искажать.

bigfoot99
Offline
Зарегистрирован: 03.02.2018

Datak пишет:

Вот интересный подход - чуть что, сразу программно фильтровать помехи.

А то что помехи вообще появились, там где им появиться неоткуда, никого не беспокоит?

bigfoot99, как там всё подключено? Уверены что правильно?

Вот очень верный коментарий. Сам чую что подход с фильтрацией скорее похож на подгонку под результат.

Да, меня беспокоит, что появились помехи, просто я не посчитал нужным высказать эти беспокойства на форуме )).

Подключаюсь я непосредственно к дисплею, но подключение "коленочное"  с помощью наспех припаеных к дисплею проводков вставленых в разъемы ардуинки где от частых подключений разьемчики уже болтаются.

Я допускаю что дребезг  возникает именно из-за фигового монтажа, но не уверен в этом на 100%

В общем, что я планирую делать в качестве работы над ошибками, я для начала сделаю правильный монтаж распаеный нормальным шлейфом (от старых FDD/HDD). 

После того как вопрос монтажа закрою - продолжу эксперименты.

Осцилографа аналогового у меня к сожалению нету.  Есть только цифровой анализатор-китаец на 8 портов.

Logik
Offline
Зарегистрирован: 05.08.2014

Datak пишет:

А то что помехи вообще появились, там где им появиться неоткуда, никого не беспокоит?

Чего ж не беспокоит. Меня  беспокоил в свое время. И мысли были разные. Вот сигналы на сегменты и на строб. Их выдают не одномоментно (в смысле не одной машинной командой), а фигзнает каким загадочным образом в зависимости от реализации. Может побитово, по одному сегменту устанавливают, а может сразу все или по группам(на разных портах если). И строб можна активировать после установки сегментов, а можна и до. А ежели прерывания не запрещать в это время, то интервалы  процесса могут гулять оч интересным образом, на десяток микросекунд - глаз не заметит, а софт сбивается. И софт считывающий должен все это учесть. Если не учитывать - будут помехи.  Еще вопрос - переключение показаний, не факт что оно синхронизировано с стробированием и уж точно асинхронно нашей работе. Вот и можем получить часть от одних показаний, а часть от других.

Или вот про электричество - уровни снимаемые с индикатора могут быть сильно просажены (ну тут от схемы зависит, у меня так вобще без резисторов было )). Еще про электричество - каждый светодиод еще и емкость имеет, её тоже надо учесть. И как возможность затяжки фронта и как возможность скчков напряжения на сегментах при переключении строба. А может и еще как.

Так что беспокоило. Но не волновало ;)  Есть откуда взятся помехам.

А фильтровать тут действительно слабенький подход. Может лучше многократный повторный опрос состояния сегментов при активном стробе через небольшие интервалы времени с отбросом непохожих значений или хотяб алгоритм 2подряд или 2из3.

Datak
Offline
Зарегистрирован: 09.10.2014

Logik пишет:

Так что беспокоило. Но не волновало ;)  Есть откуда взятся помехам.

Ну да, тоже правильно. Раз появились - значит есть откуда. :)

Но я имел в виду, что желательно выяснить причину, и по возможности устранить, ещё на аппаратном уровне.

Кстати, вспомнилось - извините если уже писали, не хочется всё перечитывать.
Возможно, нужны подтягивающие резисторы - на сигналах стробов и/или сигналах сегментов.

Управляющие индикатором выходы, когда они не активны, вполне могут оставаться в неопределённом состоянии, и тогда всякие случайные помехи вполне объяснимы.

bigfoot99
Offline
Зарегистрирован: 03.02.2018

Datak пишет:

Возможно, нужны подтягивающие резисторы - на сигналах стробов и/или сигналах сегментов.

Логгер не фиксирует дребезга на "пустых" значениях.

Но поддтягивать я пробовал - это не сказалось на работе совсем никак.

bigfoot99
Offline
Зарегистрирован: 03.02.2018

темв ременем успел сегодня сделать монтаж нормальным шлейфом. Буду тестировать.

GarryC
Offline
Зарегистрирован: 08.08.2016

Возможные причины помех
1) Разность земель
2) броски потребления и из за этого разность земель
3) если смотрим сегменты на индикаторе, то низкий уровень (2.5В) высокого сигнала, при этом если питание Ардуины 5В, то может не хватать для четкого определения единицы.

bigfoot99
Offline
Зарегистрирован: 03.02.2018

К моему сожалению, качественный монтаж не дал значительных улучшенийб ардуинка по прежнему фиксирует много мусора.

bigfoot99
Offline
Зарегистрирован: 03.02.2018

GarryC пишет:
Возможные причины помех

1) Разность земель  -> Земли связаны хорошим толстым проводом

2) броски потребления и из за этого разность земель -> Потребления светодиодом?

3) если смотрим сегменты на индикаторе, то низкий уровень (2.5В) высокого сигнала, при этом если питание Ардуины 5В, то может не хватать для четкого определения единицы. -> Я померял питание самой платы где дисплей и его контроллер - там четко 5вА как можно померить напряжение импульсов на поданные на дисплей без аналогового осцилографа? 

nik182
Offline
Зарегистрирован: 04.05.2015

Ну откуда шум? Не было шума на выводе. Уберите из моей программы while(1) и она непрерывно будет сыпать значения. Посмотрите много ли будут прыгать верхние цифры при нижних 4 и 8.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

bigfoot99 пишет:

 А как можно померить напряжение импульсов на поданные на дисплей без аналогового осцилографа? 

Элементарно, Ватсон! Цифровым осциллографом.

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

IMHO этот вопрос должен звучать на форуме повыживанию в экстремальных ситуациях, но никак не на кулинарном форуме.

Точно так же и здесь: IMHO вопрос по наладке схемы без осциллографа следует счтитать оффтопиком для данного форума и вообще - проявлением неуважения к его участникам.

 

PS. В конце концов, существует DSO 138, который способен закрыть 90-95% потребностей в осциллографе.