Ви не увійшли.
Довелось вимірювати швидкість обертання за допомогою такої штуки E6B2-CWZ6C
хттпс://www.rcscomponents.kiev.ua/datasheets/e6b2-c-datasheet.pdf
Зіткнувся з неочевидними не перший погляд речами, може комусь буде корисно.
По перше, енкодер хоч і оптичний, але тригерів Шмідта всередині немає. На малих швидкостях фронти імпульсів виглядають так:
І в зв"язку з цим, по 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);
}Неактивний