Счетчик кабеля на энкодере.
- Войдите на сайт для отправки комментариев
Ср, 02/03/2016 - 16:37
Решил собрать счетчик кабеля на энкодере, 28ми сегментном индикаторе и Ардуино Uno.
Энкодер у меня 12ти позиционный. Ниже код:
int dig1, dig2, dig3, dig4=0; // Цифры, которые будут последовательно вводиться
int keys[10] = { 39, 30, 31, 32, 33, 34, 35, 36, 37, 38 }; // Массив с ASCII кодами цифер от 0 до 9 соответственно
int s = 0;
unsigned long Counter = 0;
unsigned long k=0;
unsigned long currentTime;
unsigned long loopTime;
const int pin_A = 13; // pin 12
const int pin_B = 12; // pin 11
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;
void setup()
{
// pinMode(9, OUTPUT); // устанавливаем pin 9 как выход
pinMode(pin_A, INPUT);
pinMode(pin_B, INPUT);
currentTime = millis();
loopTime = currentTime;
pinMode(2, OUTPUT); // G
pinMode(3, OUTPUT); // F
pinMode(4, OUTPUT); // E
pinMode(5, OUTPUT); // D
pinMode(6, OUTPUT); // C
pinMode(7, OUTPUT); // B
pinMode(8, OUTPUT); // A
pinMode(9, OUTPUT); // D4
pinMode(10, OUTPUT); // D3
pinMode(11, OUTPUT); // D2
pinMode(1, OUTPUT); // D1
// Выключаем все сегменты:
digitalWrite(1, HIGH);
digitalWrite(11, HIGH);
digitalWrite(10, HIGH);
digitalWrite(9, HIGH);
delay(100); // Пауза, чтобы «клавиатура» успела определиться в системе
}
void loop()
{
currentTime = millis();
if(currentTime >= (loopTime + 5))
{ // проверяем каждые 5мс (200 Гц)
encoder_A = digitalRead(pin_A); // считываем состояние выхода А энкодера
encoder_B = digitalRead(pin_B); // считываем состояние выхода B энкодера
if((!encoder_A) && (encoder_A_prev))
{ // если состояние изменилось с положительного к нулю
if(encoder_B)
{
k=k+133;
}
else
{
k=k-133;
}
// digLED(9, k);
}
Counter = k; // 131 микрометра
if (Counter < 1000)
{
dig1=0; dig2=0; dig3=0; dig4=Counter/100;
}
if ((Counter < 10000)&(Counter > 999))
{
dig1=0; dig2=0; dig3=Counter / 1000; dig4=(Counter / 100)%10 ;
}
if ((Counter < 100000)&(Counter > 9999))
{
dig1=0; dig2=Counter / 10000; dig3=(Counter / 1000) % 10; dig4=(Counter / 100)%10;
}
if ((Counter < 1000000)&(Counter > 99999))
{
dig1=Counter/1000000; dig2=(Counter / 10000) %10; dig3=(Counter / 1000) % 10; dig4=(Counter / 100)%10;
};
digLED(1, dig1);
digLED(11, dig2);
digLED(10, dig3);
digLED(9, dig4);
encoder_A_prev = encoder_A; // сохраняем значение А для следующего цикла
loopTime = currentTime;
}
}
void digLED(int pin, int dig) // Функция отображения цифер на индикаторе
{
digitalWrite(pin, LOW);
switch(dig)
{
case 0:
digitalWrite(8, HIGH);
digitalWrite(7, HIGH);
digitalWrite(6, HIGH);
digitalWrite(5, HIGH);
digitalWrite(4, HIGH);
digitalWrite(3, HIGH);
digitalWrite(2, LOW);
break;
case 1:
digitalWrite(8, LOW);
digitalWrite(7, HIGH);
digitalWrite(6, HIGH);
digitalWrite(5, LOW);
digitalWrite(4, LOW);
digitalWrite(3, LOW);
digitalWrite(2, LOW);
break;
case 2:
digitalWrite(8, HIGH);
digitalWrite(7, HIGH);
digitalWrite(6, LOW);
digitalWrite(5, HIGH);
digitalWrite(4, HIGH);
digitalWrite(3, LOW);
digitalWrite(2, HIGH);
break;
case 3:
digitalWrite(8, HIGH);
digitalWrite(7, HIGH);
digitalWrite(6, HIGH);
digitalWrite(5, HIGH);
digitalWrite(4, LOW);
digitalWrite(3, LOW);
digitalWrite(2, HIGH);
break;
case 4:
digitalWrite(8, LOW);
digitalWrite(7, HIGH);
digitalWrite(6, HIGH);
digitalWrite(5, LOW);
digitalWrite(4, LOW);
digitalWrite(3, HIGH);
digitalWrite(2, HIGH);
break;
case 5:
digitalWrite(8, HIGH);
digitalWrite(7, LOW);
digitalWrite(6, HIGH);
digitalWrite(5, HIGH);
digitalWrite(4, LOW);
digitalWrite(3, HIGH);
digitalWrite(2, HIGH);
break;
case 6:
digitalWrite(8, HIGH);
digitalWrite(7, LOW);
digitalWrite(6, HIGH);
digitalWrite(5, HIGH);
digitalWrite(4, HIGH);
digitalWrite(3, HIGH);
digitalWrite(2, HIGH);
break;
case 7:
digitalWrite(8, HIGH);
digitalWrite(7, HIGH);
digitalWrite(6, HIGH);
digitalWrite(5, LOW);
digitalWrite(4, LOW);
digitalWrite(3, LOW);
digitalWrite(2, LOW);
break;
case 8:
digitalWrite(8, HIGH);
digitalWrite(7, HIGH);
digitalWrite(6, HIGH);
digitalWrite(5, HIGH);
digitalWrite(4, HIGH);
digitalWrite(3, HIGH);
digitalWrite(2, HIGH);
break;
case 9:
digitalWrite(8, HIGH);
digitalWrite(7, HIGH);
digitalWrite(6, HIGH);
digitalWrite(5, HIGH);
digitalWrite(4, LOW);
digitalWrite(3, HIGH);
digitalWrite(2, HIGH);
break;
}
delay(3);
digitalWrite(pin, HIGH);
}
Энкодер подключал по этой схеме:
Вал у меня такого размера, что 1 щелчок энкодера это 13мм.
Проблема следующая: При быстрой прокрутке (50см/сек), счетчик не успевает считать. При медленной прокрутке (10см/сек) считает идеально.
В чем может быть причина? Спасибо большое!
artur_fcsm, в коде. возьмите нормальный обработчик энкодера на прерываниях.
artur_fcsm, в коде. возьмите нормальный обработчик энкодера на прерываниях.
Спасибо! С вашим кодом энкодер работает на моного стабильнее и отлично выводит инфу через команду serial
Но после того, как я подключаю индикатор, через команду serial ничего не выходит (иероглифы)
Код:
#include <Encoder.h> int dig1, dig2, dig3, dig4=0; // Цифры, которые будут последовательно вводиться int keys[10] = { 39, 30, 31, 32, 33, 34, 35, 36, 37, 38 }; // Массив с ASCII кодами цифер от 0 до 9 соответственно int s = 0; unsigned long Counter = 0; unsigned long k=0; Encoder knobLeft(12, 13); // avoid using pins with LEDs attached void setup() { Serial.begin(9600); Serial.println("TwoKnobs Encoder Test:"); pinMode(2, OUTPUT); // G pinMode(3, OUTPUT); // F pinMode(4, OUTPUT); // E pinMode(5, OUTPUT); // D pinMode(6, OUTPUT); // C pinMode(7, OUTPUT); // B pinMode(8, OUTPUT); // A pinMode(9, OUTPUT); // D4 pinMode(10, OUTPUT); // D3 pinMode(11, OUTPUT); // D2 pinMode(1, OUTPUT); // D1 // Выключаем все сегменты: digitalWrite(1, HIGH); digitalWrite(11, HIGH); digitalWrite(10, HIGH); digitalWrite(9, HIGH); delay(100); // Пауза, чтобы «клавиатура» успела определиться в системе } long positionLeft = -999; void loop() { long newLeft; newLeft = knobLeft.read(); if (newLeft != positionLeft) { Serial.print("Left = "); Serial.print(newLeft); Serial.println(); positionLeft = newLeft; Counter = positionLeft*200; // 131 микрометра if (Counter < 10000) { dig1=0; dig2=0; dig3=0; dig4=Counter/1000; //// } if ((Counter < 100000)&(Counter > 9999)) { dig1=0; dig2=0; dig3=Counter / 10000; dig4=(Counter / 1000)%10 ; } if ((Counter < 1000000)&(Counter > 99999)) { dig1=0; dig2=Counter / 100000; dig3=(Counter / 10000) % 10; dig4=(Counter / 1000)%10; } if ((Counter < 10000000)&(Counter > 999999)) { dig1=Counter/10000000; dig2=(Counter / 100000) %10; dig3=(Counter / 10000) % 10; dig4=(Counter / 1000)%10; } digLED(1, dig1); digLED(11, dig2); digLED(10, dig3); digLED(9, dig4); } } void digLED(int pin, int dig) // Функция отображения цифер на индикаторе { digitalWrite(pin, LOW); switch(dig) { case 0: digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, HIGH); digitalWrite(5, HIGH); digitalWrite(4, HIGH); digitalWrite(3, HIGH); digitalWrite(2, LOW); break; case 1: digitalWrite(8, LOW); digitalWrite(7, HIGH); digitalWrite(6, HIGH); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, LOW); break; case 2: digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, LOW); digitalWrite(5, HIGH); digitalWrite(4, HIGH); digitalWrite(3, LOW); digitalWrite(2, HIGH); break; case 3: digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, HIGH); digitalWrite(5, HIGH); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, HIGH); break; case 4: digitalWrite(8, LOW); digitalWrite(7, HIGH); digitalWrite(6, HIGH); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, HIGH); digitalWrite(2, HIGH); break; case 5: digitalWrite(8, HIGH); digitalWrite(7, LOW); digitalWrite(6, HIGH); digitalWrite(5, HIGH); digitalWrite(4, LOW); digitalWrite(3, HIGH); digitalWrite(2, HIGH); break; case 6: digitalWrite(8, HIGH); digitalWrite(7, LOW); digitalWrite(6, HIGH); digitalWrite(5, HIGH); digitalWrite(4, HIGH); digitalWrite(3, HIGH); digitalWrite(2, HIGH); break; case 7: digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, HIGH); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, LOW); break; case 8: digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, HIGH); digitalWrite(5, HIGH); digitalWrite(4, HIGH); digitalWrite(3, HIGH); digitalWrite(2, HIGH); break; case 9: digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, HIGH); digitalWrite(5, HIGH); digitalWrite(4, LOW); digitalWrite(3, HIGH); digitalWrite(2, HIGH); break; } delay(3); digitalWrite(pin, HIGH); }Проблема возникает, когда я добавляю вот этот код:
digLED(1, dig1); digLED(11, dig2); digLED(10, dig3); digLED(9, dig4);Как мне кажется, проблема в спсобе вывода значения на индикатор.
Подскажит пожалуйста, в какую сторону копать. Спасибо!
Проблема возникает, когда я добавляю вот этот код:
digLED(1, dig1); digLED(11, dig2); digLED(10, dig3); digLED(9, dig4);Как мне кажется, проблема в спсобе вывода значения на индикатор.
Подскажит пожалуйста, в какую сторону копать. Спасибо!
Вы же на эти ноги энкодер подключили, судя по схеме... :) Посмотрите на строки 076 и 151 - в них пишется прямо в ногу, переданную для digLED, соответственно и порты энкодера коцаются.
Да нет, схема взята с интернета. Энкодер у меня подключен к ножкам 12 и 13
Да нет, схема взята с интернета. Энкодер у меня подключен к ножкам 12 и 13
А, так Вы же жалуетесь на пропадание вывода serial при подключении того куска... Та же проблема, что я предположил в прошлый раз: дёргаете вручную ногу 1, на котрой сериал сидит. :)
Да нет, схема взята с интернета. Энкодер у меня подключен к ножкам 12 и 13
А, так Вы же жалуетесь на пропадание вывода serial при подключении того куска... Та же проблема, что я предположил в прошлый раз: дёргаете вручную ногу 1, на котрой сериал сидит. :)
мда. действительно, мне не хватало ножек и я использовал ножку 1.
В итоге, у меня проблема, что ардуино пропускает импульсы от энкодера. 20 имп на оборот. Если крутить медленно - все ок. Если крутануть быстро, то от 20 остаётся 4-7 импульсов.
Что же я не так делаю (((
Да нет, схема взята с интернета. Энкодер у меня подключен к ножкам 12 и 13
А, так Вы же жалуетесь на пропадание вывода serial при подключении того куска... Та же проблема, что я предположил в прошлый раз: дёргаете вручную ногу 1, на котрой сериал сидит. :)
мда. действительно, мне не хватало ножек и я использовал ножку 1.
В итоге, у меня проблема, что ардуино пропускает импульсы от энкодера. 20 имп на оборот. Если крутить медленно - все ок. Если крутануть быстро, то от 20 остаётся 4-7 импульсов.
Что же я не так делаю (((
а) Вам уже советовали использовать библиотеку энкодера на прерываниях;
б) дребезг контактов, который оооочень зависит от качества энкодера, тоже необходимо учитывать программно или RC цепочкой.
а) Вам уже советовали использовать библиотеку энкодера на прерываниях;
б) дребезг контактов, который оооочень зависит от качества энкодера, тоже необходимо учитывать программно или RC цепочкой.
Я воспользовался советом:
void loop() { long newLeft; newLeft = knobLeft.read(); if (newLeft != positionLeft) { Serial.print("Left = "); Serial.print(newLeft); Serial.println(); positionLeft = newLeft;Или я что то не так понял?
Проблема была в delay
Проблема была в delay
Вот видите - и самостоятельно можете разобраться. Это очень хорошо! Теперь ёщё громодкий case замените на разумное, исползуя массив keys. :)
да. спасибо вам большое за помощь. Я уже многое изменил и убрал. Завтра выложу свой код.
Вот мой конечный вариант:
int val; int encoder0PinA = 13; int encoder0PinB = 12; unsigned long encoder0Pos = 0; int encoder0PinALast = LOW; int n = LOW; const int numeral[10] = { //ABCDEFG /dp B11111100, // 0 B01100000, // 1 B11011010, // 2 B11110010, // 3 B01100110, // 4 B10110110, // 5 B00111110, // 6 B11100000, // 7 B11111110, // 8 B11100110, // 9 }; // pins for decimal point and each segment // DP,G,F,E,D,C,B,A const int segmentPins[] = { 13,2,3,4,5,6,7,8 }; //dig 0 1 2 3 const int digitPins[4] = { 1,11,10,9 }; unsigned long Counter = 0; void setup() { pinMode (encoder0PinA,INPUT); pinMode (encoder0PinB,INPUT); // Выключаем все сегменты: digitalWrite(1, HIGH); digitalWrite(11, HIGH); digitalWrite(10, HIGH); digitalWrite(9, HIGH); delay(100); // Пауза, чтобы «клавиатура» успела определиться в системе for(int i=1; i < 8; i++) { pinMode(segmentPins[i], OUTPUT); // set segment and DP pins to output } for(int i=0; i < 4; i++) { pinMode(digitPins[i], OUTPUT); } } unsigned long positionLeft = 0; void loop() { n = digitalRead(encoder0PinA); if ((encoder0PinALast == LOW) && (n == HIGH)) { if (digitalRead(encoder0PinB) == LOW) { encoder0Pos--; } else { encoder0Pos++; } } encoder0PinALast = n; Counter = (encoder0Pos * 900) / 10000 ; showNumber(Counter); } void showNumber( long number) { if(number == 0) { showDigit( 0, 3); } else { for( int digit = 3; digit >= 0; digit--) { if(number > 0) { showDigit( number % 10, digit) ; number = number / 10; } } } } void showDigit( int number, int digit) { digitalWrite( digitPins[digit], LOW ); for(int segment = 1; segment < 8; segment++) { boolean isBitSet = bitRead(numeral[number], segment); digitalWrite( segmentPins[segment], isBitSet); } delayMicroseconds(750); digitalWrite( digitPins[digit], HIGH ); }Все отлично работает! Проверил! Отправил на производство.
Звонит заказчик, говорит счетчик считает сам по себе - я не поверил его словам. Поехал посмотреть сам.
И вот, что происходит. Когда включается станок - счетчик начинает самопроизвольно считать. И считает он только, когда запитан от БП 12В. Если он запитан от компа через usb, то все нормально. Что за чудеса?
Подскажите пожалуйста. БП менял.
Очевидно, помехи на входах. Это не совсем простая тема, чтобы дать точное и простое решение. Если учесть нормальную работу от БП нотбука, то можно сделать вывод, что энкодер не имеет электрического контакта с тем местом, куда установлен. Когда питаете от изолированного источника, наводкам, попадающим на жилу кабеля некуда стикать и, если эта же наводка не попадёт на другую жилу со сдвигом фазы, то она полетит дальше по своим делам, ничего не дав Вашему устройству. Когда включаете БП, он через общую сеть (через землю) даёт возможность помехам течь через вход на гальваническую свять с источником помехи - на землю. У Вас энкодер, как я полагаю, без всыких фильтров и защит включен в порт МК. Где Вы настраивали его входы в коде не видно, схемы тоже нет (или я забыл её). Если не использовали внутренние подтягивающие резистор и не ставили внешние, то в 10МОм вход МК может очень хорошо лететь помеха. В общем случае, необходимо отделить вход МК от энкодера резистором около 1кОм, приятнуть вход к земле или к VCC (в зависимости от того, куда второй конец энкодера подключен) резистором около 50кОм, и повесить конденсатор 0.1мкФ на землю, расположив его рядом со входом МК.