Arduino pro micro + оптический энкодер + 7 сегментный индикатор

colorit
Offline
Зарегистрирован: 06.07.2016

Доброго времени суток!

Подскажите, пожалуйста, в чем затык? Написал скетч для считывания показаний энкодера и отображения на 7-ми сегментном индикаторе на сдвиговых регистрах 74HC595

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

Не стправляется Ардуина с потоком данных?

#include <Encoder.h>
#define ENCODER_OPTIMIZE_INTERRUPTS
Encoder knobLeft(5, 6);
int buttonPin = 7;
#define SCLK 2  // пины ардуины
#define RCLK 3     
#define DIO 4    
byte digitBuffer[4];

void setup() {
  Serial.begin(9600);
  Serial.println("TwoKnobs Encoder Test:");
  pinMode(buttonPin, INPUT);
  pinMode(RCLK, OUTPUT);
  pinMode(SCLK, OUTPUT);
  pinMode(DIO, OUTPUT);  
}

long positionLeft  = -999;
void loop() {
  long newLeft;
  int x1;
  int x2;
  int x3;
  int x4;
  newLeft = knobLeft.read();
  if (newLeft != positionLeft) {
    Serial.print("Left = ");
    Serial.print(newLeft);
    Serial.println();
    positionLeft = newLeft;
   }

  x4 = (newLeft / 1000) % 10;
  x3 = (newLeft / 100) % 10;
  x2 = (newLeft / 10) % 10;
  x1 = newLeft % 10;
  
  digitBuffer[0] = x4; 
  digitBuffer[1] = x3;
  digitBuffer[2] = x2;
  digitBuffer[3] = x1;

  showDisplay(); 
}
void showDisplay(){
  
  const byte digit[10] = {  // маска для 7 сигментного индикатора  
      0b11000000, // 0
      0b11111001, // 1
      0b10100100, // 2
      0b10110000, // 3
      0b10011001, // 4
      0b10010010, // 5
      0b10000010, // 6
      0b11111000, // 7
      0b10000000, // 8
      0b10010000, // 9 
  };

  const byte chr[4] = { // маска для разряда
      0b00001000,  
      0b00000100,  
      0b00000010,  
      0b00000001  
  };

  // отправляем в цикле по два байта в сдвиговые регистры
  for(byte i = 0; i <= 3; i++){ 
    digitalWrite(RCLK, LOW); // открываем защелку
      shiftOut(DIO, SCLK, MSBFIRST, digit[digitBuffer[i]]);  // отправляем байт с "числом"
      shiftOut(DIO, SCLK, MSBFIRST, chr[i]);   // включаем разряд
    digitalWrite(RCLK, HIGH); // защелкиваем регистры
    delay(1); // ждем немного перед отправкой следующего "числа"
  }
}

 

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

Что такое "медленно" и что такое "быстрее" ведомо только Вам.

Записать два байта в сдвиговый регистр - это примерно 360-370 мкс, а вот с какой частотой у Вас идут импульсы с энкодеров, лично мне неизвестно. Поэтому сравнить два числа и сделать на основании этого вывод я не могу.

reticular
Offline
Зарегистрирован: 09.06.2016

что бы не терять тики от энкодера вешайте его на внешнее прерывание

reticular
Offline
Зарегистрирован: 09.06.2016

или уберите SERIAL из LOOP

он конкретно тормозит

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

reticular пишет:

или уберите SERIAL из LOOP

он конкретно тормозит

Поддерживаю, или хотя бы на 115200 скорость поменять. Как то раз тоже долго не мог понять, почему всё тормозит.. :)

colorit
Offline
Зарегистрирован: 06.07.2016

убрал SERIAL - вывожу только на индикатор - то же самое. 

если закомментить void showDisplay(), и выводить на монитор - то ничего не тормозит при любой скорости вращения энкодера..и тики не теряются...

 

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

Уберите последнюю строку в подпрограмме индикации delay(1) и посмотрите, что получится.

Если не поможет, то сделайте вывод на дисплей в условии.

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

colorit
Offline
Зарегистрирован: 06.07.2016

убрал delay - не помогло

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

весь затык, кажется, в этом куске кода

 for(byte i = 0; i <= 3; i++){ 
    digitalWrite(RCLK, LOW); // открываем защелку
      shiftOut(DIO, SCLK, MSBFIRST, digit[digitBuffer[i]]);  // отправляем байт с "числом"
      shiftOut(DIO, SCLK, MSBFIRST, chr[i]);   // включаем разряд
    digitalWrite(RCLK, HIGH); // защелкиваем регистры
   // delay(1); // ждем немного перед отправкой следующего "числа"

Как думаете. если поменять 7 сегментник на LCD дисплей - изменится ситуация?

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

Извините, не обратил внимания, что индикация динамическая. Тогда лучше будет сделать индикацию 1 разряда после очередного считывания энкодера. Что-то вроде

В начале программы прописываете

byte Number =0;

Там, где индикация пишете

i=Number;

// дальше собственно индикация одного разряда с номером i без  задержки в конце

if (Number >3 ) Number=0 else Number++;

Ну а если и это не поможет, то надо ускорять работы подпрограмм загрузки значения в сдвиговые регистры, если она сделана на DigitalWrite, то это может быть ОЧЕНЬ долго.

reticular
Offline
Зарегистрирован: 09.06.2016

вам помогут прерывания

на внешнее прерывание вешаете одну ногу энкодера

а на таймере 2 организуете динамическую индикацию

имхо

colorit
Offline
Зарегистрирован: 06.07.2016

Почитал про библиотеку Encoder.h - повесил ноги энкодера на пины ардуино, поддерживающие прерывания (2, 3) и все нормально заработало.

спасибо всем за помощь!