Відповісти

Введіть повідомлення і натисніть Надіслати
Параметри

Назад

Огляд теми (нові повідомленні вгорі)

jokeR
Сьогодні 15:21:42

Довелось вимірювати швидкість обертання за допомогою такої штуки E6B2-CWZ6C
хттпс://www.rcscomponents.kiev.ua/datasheets/e6b2-c-datasheet.pdf

Зіткнувся з неочевидними не перший погляд речами, може комусь буде корисно.
По перше, енкодер хоч і оптичний, але тригерів Шмідта всередині немає. На малих швидкостях фронти імпульсів виглядають так:
photo_2026-06-08_14-40-35.jpg

І в зв"язку з цим, по 2 імпульсах рахувати швидкість не варто, бажано по хоча б 1 повному оберту.

По друге, результат вимірювання бажано отримувати актуальний зразу, а не після повного оберту.

Для компенсації кривих фронтів є таке рішення: по переходу 0-1 - лічильник інкрементується, по переходу 1-0 - декрементується. Після закінчення перехідного процесу залишиться +1 (чи -1, в залежності від напрямку обертання). Лічильник клацає по фронту і спаду кожної фази, тобто в 4 рази швидше - це треба врахувати.

Для підрахунку середньої швидкості обертання - інформацію про кожен імпульс (timestamp і покази лічильника) писати у кільцевий буфер. Тоді швидкість буде просто розраховуватись з різниці між початком і кінцем буфера. Якщо в початку буфері ці покази вже є - просто переписати поверх, щоб не зберігати непотрібний брязкіт.

Недоліки такого рішення:
Треба досить багато тактів процесора і пам"яті. Великі оберти Atmega328 не витягне.
Всі зовнішні interrupts, доступні для Atmega328, зайняті.
Не до будь-якої ноги можна підключити енкодер.


#define OMRON_PIN_A 2
#define OMRON_PIN_B 3
#define OMRON_PULSES_2_ROTATE 10

#define COUNT_OF_MEASURES 20
struct MEASURE_S {
   unsigned long ts;
   int ticks;
};
volatile MEASURE_S measures[COUNT_OF_MEASURES];
volatile int measures_head=COUNT_OF_MEASURES-1;
volatile int measures_tail=0;
long int ticks = 0;


const int increment[16] = {0,-1,1,0, 1,0,0,-1, -1,0,0,1, 0,1,-1,0};
volatile char ABprev = 0;
void isr_omron()
{
  char AB = (PIND >> 2) & 3; // PORT D bits 2,3
  ticks += increment[AB+ABprev*4];

  unsigned long now = micros();
  if (measures[measures_head].ticks == ticks 
    || measures[(measures_head-1)% COUNT_OF_MEASURES].ticks == ticks
    || measures[(measures_head-2)% COUNT_OF_MEASURES].ticks == ticks
    || measures[(measures_head-3)% COUNT_OF_MEASURES].ticks == ticks) // bounce
  {
  measures[measures_head].ts = now;
  measures[measures_head].ticks = ticks;

  } else {
  measures_head = (measures_head+1) % COUNT_OF_MEASURES;
  measures[measures_head].ts = now;
  measures[measures_head].ticks = ticks;
  measures_tail = (measures_head+1) % COUNT_OF_MEASURES;
  };
  
  ABprev = AB;
}

int calc_rpm() //оберти за хвилину
{
  int res = 0;
  unsigned long dt;
  int d_cont;
  int head, tail;
  int t;
  noInterrupts();
  t = ticks;
  head = measures_head; tail = measures_tail;
  if (measures_head != measures_tail)
  {
    dt = measures[measures_head].ts - measures[measures_tail].ts;
    d_cont = abs(measures[measures_head].ticks - measures[measures_tail].ticks);
    if (micros() > measures[measures_head].ts + dt)
    {
      dt = micros() - measures[measures_tail].ts;
    };
  };
;
  interrupts();
      if (dt == 0)
      {
        res = 0;
      }
      else
      {
        res = 60 * 1000000 * d_cont / dt / OMRON_PULSES_2_ROTATE / 4;
      };
  return res;
}

void setup() {
  pinMode(OMRON_PIN_A, INPUT_PULLUP);
  pinMode(OMRON_PIN_B, INPUT_PULLUP);
  ABprev = (PIND >> 2) & 3; // PORT D bits 2,3
  int _interrupt = digitalPinToInterrupt(OMRON_PIN_A);
  attachInterrupt(_interrupt, isr_omron, CHANGE);
  Serial.print(F("Use interrupt A ")); Serial.println(_interrupt);
  _interrupt = digitalPinToInterrupt(OMRON_PIN_B);
  attachInterrupt(_interrupt, isr_omron, CHANGE);
}

Підвал форуму