Счетчик кабеля на энкодере.

artur_fcsm
Offline
Зарегистрирован: 12.02.2015

Решил собрать счетчик кабеля на энкодере, 28ми сегментном индикаторе и Ардуино Uno.

Энкодер у меня 12ти позиционный. Ниже код:

001int dig1, dig2, dig3, dig4=0; // Цифры, которые будут последовательно вводиться
002int keys[10] = { 39, 30, 31, 32, 33, 34, 35, 36, 37, 38 }; // Массив с ASCII кодами цифер от 0 до 9 соответственно
003int s = 0;
004unsigned long Counter = 0;
005unsigned long k=0;
006unsigned long currentTime;
007unsigned long loopTime;
008const int pin_A = 13;       // pin 12
009const int pin_B = 12;       // pin 11
010unsigned char encoder_A;
011unsigned char encoder_B;
012unsigned char encoder_A_prev=0;
013 
014void setup()
015{
016 // pinMode(9, OUTPUT);         // устанавливаем pin 9 как выход
017  pinMode(pin_A, INPUT);
018  pinMode(pin_B, INPUT);
019  currentTime = millis();
020  loopTime = currentTime;
021 
022   
023  pinMode(2, OUTPUT); // G
024  pinMode(3, OUTPUT); // F
025  pinMode(4, OUTPUT); // E
026  pinMode(5, OUTPUT); // D
027  pinMode(6, OUTPUT); // C
028  pinMode(7, OUTPUT); // B
029  pinMode(8, OUTPUT); // A
030  pinMode(9, OUTPUT); // D4
031  pinMode(10, OUTPUT); // D3
032  pinMode(11, OUTPUT); // D2
033  pinMode(1, OUTPUT); // D1
034 
035 
036// Выключаем все сегменты:
037 
038  digitalWrite(1, HIGH);
039  digitalWrite(11, HIGH);
040  digitalWrite(10, HIGH);
041  digitalWrite(9, HIGH);
042  delay(100); // Пауза, чтобы «клавиатура» успела определиться в системе
043 
044}
045 
046void loop()
047{
048 
049  currentTime = millis();
050  if(currentTime >= (loopTime + 5))
051    { // проверяем каждые 5мс (200 Гц)
052      encoder_A = digitalRead(pin_A);     // считываем состояние выхода А энкодера
053      encoder_B = digitalRead(pin_B);     // считываем состояние выхода B энкодера   
054      if((!encoder_A) && (encoder_A_prev))
055        {    // если состояние изменилось с положительного к нулю
056          if(encoder_B)
057            {
058              k=k+133;            
059            }  
060          else
061            {
062              k=k-133;              
063            }  
064 
065          // digLED(9, k);
066        }  
067    Counter = k; // 131 микрометра
068    if (Counter < 1000)
069      {
070        dig1=0; dig2=0; dig3=0; dig4=Counter/100;
071      }
072  
073    if ((Counter < 10000)&(Counter > 999))
074      {
075        dig1=0; dig2=0; dig3=Counter / 1000; dig4=(Counter / 100)%10 ;
076      }
077    if ((Counter < 100000)&(Counter > 9999))
078      {
079        dig1=0; dig2=Counter / 10000; dig3=(Counter / 1000) % 10; dig4=(Counter / 100)%10;
080      }
081    if ((Counter < 1000000)&(Counter > 99999))
082      {
083        dig1=Counter/1000000; dig2=(Counter / 10000) %10; dig3=(Counter / 1000) % 10; dig4=(Counter / 100)%10;
084      };
085 
086    digLED(1, dig1);
087    digLED(11, dig2);
088    digLED(10, dig3);
089    digLED(9, dig4);
090     
091    encoder_A_prev = encoder_A;     // сохраняем значение А для следующего цикла
092    loopTime = currentTime;
093    }
094}
095 
096 
097void digLED(int pin, int dig) // Функция отображения цифер на индикаторе
098{
099     
100  digitalWrite(pin, LOW);
101  switch(dig)
102  {
103  case 0:
104    digitalWrite(8, HIGH);
105    digitalWrite(7, HIGH);
106    digitalWrite(6, HIGH);
107    digitalWrite(5, HIGH);
108    digitalWrite(4, HIGH);
109    digitalWrite(3, HIGH);
110    digitalWrite(2, LOW);
111    break;
112  case 1:
113    digitalWrite(8, LOW);
114    digitalWrite(7, HIGH);
115    digitalWrite(6, HIGH);
116    digitalWrite(5, LOW);
117    digitalWrite(4, LOW);
118    digitalWrite(3, LOW);
119    digitalWrite(2, LOW);
120    break;
121  case 2:
122    digitalWrite(8, HIGH);
123    digitalWrite(7, HIGH);
124    digitalWrite(6, LOW);
125    digitalWrite(5, HIGH);
126    digitalWrite(4, HIGH);
127    digitalWrite(3, LOW);
128    digitalWrite(2, HIGH);
129    break;
130  case 3:
131    digitalWrite(8, HIGH);
132    digitalWrite(7, HIGH);
133    digitalWrite(6, HIGH);
134    digitalWrite(5, HIGH);
135    digitalWrite(4, LOW);
136    digitalWrite(3, LOW);
137    digitalWrite(2, HIGH);
138    break;
139  case 4:
140    digitalWrite(8, LOW);
141    digitalWrite(7, HIGH);
142    digitalWrite(6, HIGH);
143    digitalWrite(5, LOW);
144    digitalWrite(4, LOW);
145    digitalWrite(3, HIGH);
146    digitalWrite(2, HIGH);
147    break;
148  case 5:
149    digitalWrite(8, HIGH);
150    digitalWrite(7, LOW);
151    digitalWrite(6, HIGH);
152    digitalWrite(5, HIGH);
153    digitalWrite(4, LOW);
154    digitalWrite(3, HIGH);
155    digitalWrite(2, HIGH);
156    break;
157  case 6:
158    digitalWrite(8, HIGH);
159    digitalWrite(7, LOW);
160    digitalWrite(6, HIGH);
161    digitalWrite(5, HIGH);
162    digitalWrite(4, HIGH);
163    digitalWrite(3, HIGH);
164    digitalWrite(2, HIGH);
165    break;
166  case 7:
167    digitalWrite(8, HIGH);
168    digitalWrite(7, HIGH);
169    digitalWrite(6, HIGH);
170    digitalWrite(5, LOW);
171    digitalWrite(4, LOW);
172    digitalWrite(3, LOW);
173    digitalWrite(2, LOW);
174    break;
175  case 8:
176    digitalWrite(8, HIGH);
177    digitalWrite(7, HIGH);
178    digitalWrite(6, HIGH);
179    digitalWrite(5, HIGH);
180    digitalWrite(4, HIGH);
181    digitalWrite(3, HIGH);
182    digitalWrite(2, HIGH);
183    break;
184  case 9:
185    digitalWrite(8, HIGH);
186    digitalWrite(7, HIGH);
187    digitalWrite(6, HIGH);
188    digitalWrite(5, HIGH);
189    digitalWrite(4, LOW);
190    digitalWrite(3, HIGH);
191    digitalWrite(2, HIGH);
192    break;
193  }
194  delay(3);
195  digitalWrite(pin, HIGH);
196 
197}

Энкодер подключал по этой схеме:

Вал у меня такого размера, что 1 щелчок энкодера это 13мм.

Проблема следующая: При быстрой прокрутке (50см/сек), счетчик не успевает считать. При медленной прокрутке (10см/сек) считает идеально.

В чем может быть причина? Спасибо большое!

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

artur_fcsm, в коде. возьмите нормальный обработчик энкодера на прерываниях.

artur_fcsm
Offline
Зарегистрирован: 12.02.2015

dimax пишет:

artur_fcsm, в коде. возьмите нормальный обработчик энкодера на прерываниях.

Спасибо! С вашим кодом энкодер работает на моного стабильнее и отлично выводит инфу через команду serial

Но после того, как я подключаю индикатор, через команду serial ничего не выходит (иероглифы)

Код:

001#include <Encoder.h>
002 
003int dig1, dig2, dig3, dig4=0; // Цифры, которые будут последовательно вводиться
004int keys[10] = { 39, 30, 31, 32, 33, 34, 35, 36, 37, 38 }; // Массив с ASCII кодами цифер от 0 до 9 соответственно
005int s = 0;
006unsigned long Counter = 0;
007unsigned long k=0;
008 
009Encoder knobLeft(12, 13);
010//   avoid using pins with LEDs attached
011 
012void setup() {
013  Serial.begin(9600);
014  Serial.println("TwoKnobs Encoder Test:");
015 
016      pinMode(2, OUTPUT); // G
017  pinMode(3, OUTPUT); // F
018  pinMode(4, OUTPUT); // E
019  pinMode(5, OUTPUT); // D
020  pinMode(6, OUTPUT); // C
021  pinMode(7, OUTPUT); // B
022  pinMode(8, OUTPUT); // A
023  pinMode(9, OUTPUT); // D4
024  pinMode(10, OUTPUT); // D3
025  pinMode(11, OUTPUT); // D2
026  pinMode(1, OUTPUT); // D1
027 
028// Выключаем все сегменты:
029    digitalWrite(1, HIGH);
030  digitalWrite(11, HIGH);
031  digitalWrite(10, HIGH);
032  digitalWrite(9, HIGH);
033  delay(100); // Пауза, чтобы «клавиатура» успела определиться в системе
034}
035 
036long positionLeft  = -999;
037 
038void loop() {
039  long newLeft;
040  newLeft = knobLeft.read();
041  if (newLeft != positionLeft) {
042    Serial.print("Left = ");
043    Serial.print(newLeft);
044    Serial.println();
045    positionLeft = newLeft;
046 
047 
048Counter = positionLeft*200; // 131 микрометра
049    if (Counter < 10000)
050      {
051        dig1=0; dig2=0; dig3=0; dig4=Counter/1000;   ////
052      }
053  
054    if ((Counter < 100000)&(Counter > 9999))
055      {
056        dig1=0; dig2=0; dig3=Counter / 10000; dig4=(Counter / 1000)%10 ;
057      }
058    if ((Counter < 1000000)&(Counter > 99999))
059      {
060        dig1=0; dig2=Counter / 100000; dig3=(Counter / 10000) % 10; dig4=(Counter / 1000)%10;
061      }
062    if ((Counter < 10000000)&(Counter > 999999))
063      {
064        dig1=Counter/10000000; dig2=(Counter / 100000) %10; dig3=(Counter / 10000) % 10; dig4=(Counter / 1000)%10;
065      }
066    digLED(1, dig1);
067    digLED(11, dig2);
068    digLED(10, dig3);
069    digLED(9, dig4); 
070  }
071}
072 
073void digLED(int pin, int dig) // Функция отображения цифер на индикаторе
074{
075     
076  digitalWrite(pin, LOW);
077  switch(dig)
078  {
079  case 0:
080    digitalWrite(8, HIGH);
081    digitalWrite(7, HIGH);
082    digitalWrite(6, HIGH);
083    digitalWrite(5, HIGH);
084    digitalWrite(4, HIGH);
085    digitalWrite(3, HIGH);
086    digitalWrite(2, LOW);
087    break;
088  case 1:
089    digitalWrite(8, LOW);
090    digitalWrite(7, HIGH);
091    digitalWrite(6, HIGH);
092    digitalWrite(5, LOW);
093    digitalWrite(4, LOW);
094    digitalWrite(3, LOW);
095    digitalWrite(2, LOW);
096    break;
097  case 2:
098    digitalWrite(8, HIGH);
099    digitalWrite(7, HIGH);
100    digitalWrite(6, LOW);
101    digitalWrite(5, HIGH);
102    digitalWrite(4, HIGH);
103    digitalWrite(3, LOW);
104    digitalWrite(2, HIGH);
105    break;
106  case 3:
107    digitalWrite(8, HIGH);
108    digitalWrite(7, HIGH);
109    digitalWrite(6, HIGH);
110    digitalWrite(5, HIGH);
111    digitalWrite(4, LOW);
112    digitalWrite(3, LOW);
113    digitalWrite(2, HIGH);
114    break;
115  case 4:
116    digitalWrite(8, LOW);
117    digitalWrite(7, HIGH);
118    digitalWrite(6, HIGH);
119    digitalWrite(5, LOW);
120    digitalWrite(4, LOW);
121    digitalWrite(3, HIGH);
122    digitalWrite(2, HIGH);
123    break;
124  case 5:
125    digitalWrite(8, HIGH);
126    digitalWrite(7, LOW);
127    digitalWrite(6, HIGH);
128    digitalWrite(5, HIGH);
129    digitalWrite(4, LOW);
130    digitalWrite(3, HIGH);
131    digitalWrite(2, HIGH);
132    break;
133  case 6:
134    digitalWrite(8, HIGH);
135    digitalWrite(7, LOW);
136    digitalWrite(6, HIGH);
137    digitalWrite(5, HIGH);
138    digitalWrite(4, HIGH);
139    digitalWrite(3, HIGH);
140    digitalWrite(2, HIGH);
141    break;
142  case 7:
143    digitalWrite(8, HIGH);
144    digitalWrite(7, HIGH);
145    digitalWrite(6, HIGH);
146    digitalWrite(5, LOW);
147    digitalWrite(4, LOW);
148    digitalWrite(3, LOW);
149    digitalWrite(2, LOW);
150    break;
151  case 8:
152    digitalWrite(8, HIGH);
153    digitalWrite(7, HIGH);
154    digitalWrite(6, HIGH);
155    digitalWrite(5, HIGH);
156    digitalWrite(4, HIGH);
157    digitalWrite(3, HIGH);
158    digitalWrite(2, HIGH);
159    break;
160  case 9:
161    digitalWrite(8, HIGH);
162    digitalWrite(7, HIGH);
163    digitalWrite(6, HIGH);
164    digitalWrite(5, HIGH);
165    digitalWrite(4, LOW);
166    digitalWrite(3, HIGH);
167    digitalWrite(2, HIGH);
168    break;
169  }
170  delay(3);
171  digitalWrite(pin, HIGH);
172 
173}

Проблема возникает, когда я добавляю вот этот код:

1digLED(1, dig1);
2digLED(11, dig2);
3digLED(10, dig3);
4digLED(9, dig4);

Как мне кажется, проблема в спсобе вывода значения на индикатор.

Подскажит пожалуйста, в какую сторону копать. Спасибо!

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

artur_fcsm пишет:

Проблема возникает, когда я добавляю вот этот код:

1digLED(1, dig1);
2digLED(11, dig2);
3digLED(10, dig3);
4digLED(9, dig4);

Как мне кажется, проблема в спсобе вывода значения на индикатор.

Подскажит пожалуйста, в какую сторону копать. Спасибо!

Вы же на эти ноги энкодер подключили, судя по схеме... :)  Посмотрите на строки 076 и 151 - в них пишется прямо в ногу, переданную для digLED, соответственно и порты энкодера коцаются.

artur_fcsm
Offline
Зарегистрирован: 12.02.2015

Да нет, схема взята с интернета. Энкодер у меня подключен к ножкам 12 и 13

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

artur_fcsm пишет:

Да нет, схема взята с интернета. Энкодер у меня подключен к ножкам 12 и 13

А, так Вы же жалуетесь на пропадание вывода serial при  подключении того куска... Та же проблема, что я предположил в прошлый раз: дёргаете вручную ногу 1, на котрой сериал сидит. :)

artur_fcsm
Offline
Зарегистрирован: 12.02.2015

faeton пишет:

artur_fcsm пишет:

Да нет, схема взята с интернета. Энкодер у меня подключен к ножкам 12 и 13

А, так Вы же жалуетесь на пропадание вывода serial при  подключении того куска... Та же проблема, что я предположил в прошлый раз: дёргаете вручную ногу 1, на котрой сериал сидит. :)

мда. действительно, мне не хватало ножек и я использовал ножку 1. 

В итоге, у меня проблема, что ардуино пропускает импульсы от энкодера. 20 имп на оборот. Если крутить медленно - все ок. Если крутануть быстро, то от 20 остаётся 4-7 импульсов. 

Что же я не так делаю (((

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

artur_fcsm пишет:

faeton пишет:

artur_fcsm пишет:

Да нет, схема взята с интернета. Энкодер у меня подключен к ножкам 12 и 13

А, так Вы же жалуетесь на пропадание вывода serial при  подключении того куска... Та же проблема, что я предположил в прошлый раз: дёргаете вручную ногу 1, на котрой сериал сидит. :)

мда. действительно, мне не хватало ножек и я использовал ножку 1. 

В итоге, у меня проблема, что ардуино пропускает импульсы от энкодера. 20 имп на оборот. Если крутить медленно - все ок. Если крутануть быстро, то от 20 остаётся 4-7 импульсов. 

Что же я не так делаю (((

а) Вам уже советовали использовать библиотеку энкодера на прерываниях;
б) дребезг контактов, который оооочень зависит от качества энкодера, тоже необходимо учитывать программно или RC цепочкой.

artur_fcsm
Offline
Зарегистрирован: 12.02.2015

faeton пишет:

а) Вам уже советовали использовать библиотеку энкодера на прерываниях;

б) дребезг контактов, который оооочень зависит от качества энкодера, тоже необходимо учитывать программно или RC цепочкой.

Я воспользовался советом: 

 
1void loop() {
2  long newLeft;
3  newLeft = knobLeft.read();
4  if (newLeft != positionLeft) {
5    Serial.print("Left = ");
6    Serial.print(newLeft);
7    Serial.println();
8    positionLeft = newLeft;
 

Или я что то не так понял? 

artur_fcsm
Offline
Зарегистрирован: 12.02.2015

Проблема была в delay

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

artur_fcsm пишет:

Проблема была в delay

Вот видите - и самостоятельно можете разобраться. Это очень хорошо! Теперь ёщё громодкий case замените на разумное, исползуя массив keys. :)

artur_fcsm
Offline
Зарегистрирован: 12.02.2015

да. спасибо вам большое за помощь. Я уже многое изменил и убрал. Завтра выложу свой код. 

artur_fcsm
Offline
Зарегистрирован: 12.02.2015

Вот мой конечный вариант:

01int val;
02 int encoder0PinA = 13;
03 int encoder0PinB = 12;
04unsigned long encoder0Pos = 0;
05 int encoder0PinALast = LOW;
06 int n = LOW;
07 
08const int numeral[10] = {
09   //ABCDEFG /dp
10   B11111100, // 0
11   B01100000, // 1
12   B11011010, // 2
13   B11110010, // 3
14   B01100110, // 4
15   B10110110, // 5
16   B00111110, // 6
17   B11100000, // 7
18   B11111110, // 8
19   B11100110, // 9
20};
21// pins for decimal point and each segment
22// DP,G,F,E,D,C,B,A
23const int segmentPins[] = { 13,2,3,4,5,6,7,8 };
24//dig 0 1 2 3
25const int digitPins[4] = { 1,11,10,9 };
26 
27unsigned long Counter = 0;
28 
29void setup() {
30   pinMode (encoder0PinA,INPUT);
31   pinMode (encoder0PinB,INPUT);
32 
33// Выключаем все сегменты:
34  digitalWrite(1, HIGH);
35  digitalWrite(11, HIGH);
36  digitalWrite(10, HIGH);
37  digitalWrite(9, HIGH);
38  delay(100); // Пауза, чтобы «клавиатура» успела определиться в системе
39   
40   for(int i=1; i < 8; i++) {
41      pinMode(segmentPins[i], OUTPUT); // set segment and DP pins to output
42   }
43   for(int i=0; i < 4; i++) {
44      pinMode(digitPins[i], OUTPUT);
45   }
46}
47 
48unsigned long positionLeft  = 0;
49 
50void loop() {
51  n = digitalRead(encoder0PinA);
52  if ((encoder0PinALast == LOW) && (n == HIGH))
53  {
54     if (digitalRead(encoder0PinB) == LOW)
55     {
56       encoder0Pos--;
57     } else {
58       encoder0Pos++;
59     }
60   }
61  encoder0PinALast = n;
62  Counter = (encoder0Pos * 900) / 10000 ;
63  showNumber(Counter);
64}
65 
66void showNumber( long number)
67{
68   if(number == 0)
69   {
70      showDigit( 0, 3);
71   }
72   else
73   {
74      for( int digit = 3; digit >= 0; digit--)  {
75         if(number > 0) 
76         {
77            showDigit( number % 10, digit) ;
78            number = number / 10;
79         }
80      }
81   }
82}
83 
84void showDigit( int number, int digit)
85{
86  digitalWrite( digitPins[digit], LOW );
87  for(int segment = 1; segment < 8; segment++) 
88  {
89    boolean isBitSet = bitRead(numeral[number], segment);
90    digitalWrite( segmentPins[segment], isBitSet);
91  }
92   delayMicroseconds(750);
93   digitalWrite( digitPins[digit], HIGH );
94}

Все отлично работает! Проверил! Отправил на производство.

Звонит заказчик, говорит счетчик считает сам по себе - я не поверил его словам. Поехал посмотреть сам.

И вот, что происходит. Когда включается станок - счетчик начинает самопроизвольно считать. И считает он только, когда запитан от БП 12В. Если он запитан от компа через usb, то все нормально. Что за чудеса? 

Подскажите пожалуйста. БП менял.

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

Очевидно, помехи на входах. Это не совсем простая тема, чтобы дать точное и простое решение. Если учесть нормальную работу от БП нотбука, то можно сделать вывод, что энкодер не имеет электрического контакта с тем местом, куда установлен. Когда питаете от изолированного источника, наводкам, попадающим на жилу кабеля некуда стикать и, если эта же наводка не попадёт на другую жилу со сдвигом фазы, то она полетит дальше по своим делам, ничего не дав Вашему устройству. Когда включаете БП, он через общую сеть (через землю) даёт возможность помехам течь через вход на гальваническую свять с источником помехи - на землю. У Вас энкодер, как я полагаю, без всыких фильтров и защит включен в порт МК. Где Вы настраивали его входы в коде не видно, схемы тоже нет (или я забыл её). Если не использовали внутренние подтягивающие резистор и не ставили внешние, то в 10МОм вход МК может очень хорошо лететь помеха. В общем случае, необходимо отделить вход МК от энкодера резистором  около 1кОм, приятнуть вход к земле или к VCC (в зависимости от того, куда второй конец энкодера подключен) резистором около 50кОм, и повесить конденсатор 0.1мкФ на землю, расположив его рядом со входом МК.