Как работает энкодер?

… так сразу и танцуй )))

Смотрю дискуссия пошла по новому кругу))

Ещё одна мысль пришла. Может покажется смешной.
Я ESP32 не юзаю, лишь по верхам. Понял, что много чего знать надо.
Возможно, дело во времени обработки прерывания.

Может ли RTOS как то это замедлить?
В таком случае, логично, что уровень на пине успеет измениться.
Если есть уно/нано мой совет, проверьте на них.

Стащил у сына Uno. Загрузил код из #41 (с необходимыми правками)
Там почти всегда 0 (т.е. ожидаемое поведение). Иногда проскакивает 1, но это я вполне могу объяснить дребезгом. Тем более что она проскакивает и “влево” и “вправо”, что тоже логично.
Значит, в итоге разбираться нужно с esp, а не с энкодером. Но там факторов, которые могут повлиять много (включая конкретный экземпляр esp), это не энкодер с двумя контактами. В рамках форума, пожалуй, будет сложновато.
Если кто-то знает, какой конкретно фактор в данном случае влияет, буду благодарен.

@MMM , не подскажете, на чем проверяли?

Классик Нано

1 лайк

ТС, посмотри уже пример в этой библиотеке и сделай так же:

Здесь есть спецы по ESP32, может ответят.
Моя версия дилетанта - эти ардуино- прерывания, не совсем прерывания , они обрабатываются операционкой.
Как напрямую к железу обратиться не знаю, да и надо ли.
Ведь можно и без прерываний решить эту задачу.
А выше ещё писали про встроенный модуль энкодера…

2 лайка

Дельная мысль.
Я тоже не спец по ЕСП32, но “где-то слышал”, что для использования хардварных прерываний ЕСП32 обработчик должен начинаться с ключевого слова IRAM_ATTR:

// Обработчик прерывания по нажатию кнопки
static void IRAM_ATTR isrButtonPress(void* arg)
{
  // Что-то делаем..
}

А у ТС в коде этого нет:

1 лайк

Звучит как заклинание. ))

спасибо , переделал стенд , и на нем сейчас все проверю

у меня есть многое что нужно для разработки домашнего хобита.
могу многое . CAM ,. инженерия . владения всеми инструментами. . ну и конечно 3 д принтером не проффесианально но все же . нет осцилогрофа .
не умею паять хотя все есть . не умею писать код. но что то из кусков собрать и поправить под свои задачи могу .
можете по необходимости спросить я постараюсь проверить ваши хотелки .

Это заклинание переносит процедуру в оперативную память. В противном случае она будет исполняться так же, как и всё остальное - подгружаясь со SPI EEPROM со всеми вытекающими накладными расходами.

1 лайк

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

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

volatile int enc;
#define STEP_PIN         2
#define DIR_PIN          5
#define ENABLE_PIN       8


void setup() {
   Serial.begin(230400);
   pinMode(A0,INPUT_PULLUP);
   pinMode(A1,INPUT_PULLUP);
   PCIFR=PCIFR; PCICR=1<<PCIE1; //разрешить прерывание
   PCMSK1=1<<PCINT8 | 1<<PCINT9; //выбрать вход на котором сработает прерывание 
   pinMode(2, OUTPUT);   
   pinMode(5, OUTPUT);
   pinMode(8, OUTPUT);
}

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

//Энкодер на пинах А0, А1. Используется внутренняя подтяжка.
volatile int enc, motor_position;

#define STEP_PIN         2
#define DIR_PIN          5
#define ENABLE_PIN       8

void setup(){                
Serial.begin(9600);
pinMode(A0,INPUT_PULLUP);
pinMode(A1,INPUT_PULLUP);
PCIFR=PCIFR; PCICR=1<<PCIE1; //разрешить прерывание
PCMSK1=1<<PCINT8 | 1<<PCINT9; //выбрать вход на котором сработает прерывание
pinMode(2, OUTPUT);   
pinMode(5, OUTPUT);
pinMode(8, OUTPUT);
}

ISR(PCINT1_vect){
static char EncPrev=0;      //предыдущее состояние энкодера
static char EncPrevPrev=0;  //пред-предыдущее состояние энкодера
 char EncCur = 0;
 if(!(PINC & (1 << PC0))){EncCur  = 1;} //опрос фазы 1 энкодера
 if(!(PINC & (1 << PC1))){ EncCur |= 2;} //опрос фазы 2 энкодера
 if(EncCur != EncPrev)             //если состояние изменилось,
 {
   if(EncPrev == 3 &&        //если предыдущее состояние 3
      EncCur != EncPrevPrev )      //и текущее и пред-предыдущее не равны,
   {
     if(EncCur == 2) 
       enc++;
       digitalWrite(DIR_PIN    , LOW);
   	digitalWrite(ENABLE_PIN , LOW);
       digitalWrite(STEP_PIN    , HIGH);
       if(EncPrev%2) {
       digitalWrite(STEP_PIN    , LOW);
       ++motor_position; 
     }
   } 		
   	
     else                    
       enc--;
       digitalWrite(DIR_PIN    ,HIGH );
   	digitalWrite(ENABLE_PIN , LOW);
       digitalWrite(STEP_PIN    , HIGH);
       if(EncPrev%2) {
       digitalWrite(STEP_PIN    , LOW);
       ++motor_position;		
   }
   EncPrevPrev = EncPrev;          //сохранение пред-предыдущего состояния
   EncPrev = EncCur;               //сохранение предыдущего состояния
 }
 


 }



void loop() {
Serial.println(enc);

}

есть проблема , этот код считывает только в минус -1,-120
пины на энкодере менял и по одному пину ставил все идет в минус
этот код нужно исправлять .

этого не может быть

блин , не может это я что то понаписал
буду перепроверять
спасибо а то я уже дальше переписывать начал

у тебя концептуальная ошибка:

  1. должен быть датчик нулевого положения каретки
  2. в струйных принтерах не просто так установлен оптический датчик и линейка
  3. если нужна точность, а у тебя вижу в схеме индикатор, смотри как сделано в струйном принтере

А твк?

Спойлер
ISR(PCINT1_vect)
{
static char EncPrev=0;      //предыдущее состояние энкодера
static char EncPrevPrev=0;  //пред-предыдущее состояние энкодера
 char EncCur = 0;
 if(!(PINC & (1 << PC0))){EncCur  = 1;} //опрос фазы 1 энкодера
 if(!(PINC & (1 << PC1))){ EncCur |= 2;} //опрос фазы 2 энкодера
 if(EncCur != EncPrev)             //если состояние изменилось,
 {
  if ((EncPrev == 0 && EncCur == 1) || (EncPrev == 3 && EncCur == 2))
  { 
       enc++;
       digitalWrite(DIR_PIN    , LOW);
   	digitalWrite(ENABLE_PIN , LOW);
       digitalWrite(STEP_PIN    , HIGH);
       if(EncPrev%2) {
       digitalWrite(STEP_PIN    , LOW);
       ++motor_position; 
       }
   } 		
   	
  if ((EncPrev == 1 && EncCur == 0) || (EncPrev == 2 && EncCur == 3))
    {                    
       enc--;
       digitalWrite(DIR_PIN    ,HIGH );
   	digitalWrite(ENABLE_PIN , LOW);
       digitalWrite(STEP_PIN    , HIGH);
       if(EncPrev%2) {
       digitalWrite(STEP_PIN    , LOW);
       ++motor_position;	
       }	
   }
   EncPrevPrev = EncPrev;          //сохранение пред-предыдущего состояния
   EncPrev = EncCur; 
   }              //сохранение предыдущего состояния
 }

все , раскидал
теперь двигатель крутится куда и энкодер
сейчас погоняем на всех скоростях. и посмотрим шим

я пока с делей сделал погоняю переделаю немного по другому
такмка будет точнее показывать

//Энкодер на пинах А0, А1. Используется внутренняя подтяжка.
volatile int enc, motor_position;

#define STEP_PIN         2
#define DIR_PIN          5
#define ENABLE_PIN       8

void setup(){                
Serial.begin(9600);
pinMode(A0,INPUT_PULLUP);
pinMode(A1,INPUT_PULLUP);
PCIFR=PCIFR; PCICR=1<<PCIE1; //разрешить прерывание
PCMSK1=1<<PCINT8 | 1<<PCINT9; //выбрать вход на котором сработает прерывание
pinMode(2, OUTPUT);   
pinMode(5, OUTPUT);
pinMode(8, OUTPUT);
}

ISR(PCINT1_vect){
static char EncPrev=0;      //предыдущее состояние энкодера
static char EncPrevPrev=0;  //пред-предыдущее состояние энкодера
  char EncCur = 0;
  if(!(PINC & (1 << PC0))){EncCur  = 1;} //опрос фазы 1 энкодера
  if(!(PINC & (1 << PC1))){ EncCur |= 2;} //опрос фазы 2 энкодера
  if(EncCur != EncPrev)             //если состояние изменилось,
  {
    if(EncPrev == 3 &&        //если предыдущее состояние 3
       EncCur != EncPrevPrev )      //и текущее и пред-предыдущее не равны,
       
	   
    {
      if  (EncCur == 2)          //если текущее состояние 2,
        (enc++,    digitalWrite(DIR_PIN , 1),  Step());
        
      else                          //иначе
        (enc--,    digitalWrite(DIR_PIN , 0),  Step());
    }
    EncPrevPrev = EncPrev;          //сохранение пред-предыдущего состояния
    EncPrev = EncCur;               //сохранение предыдущего состояния
  }


  }

 void Step() {		
	    digitalWrite(ENABLE_PIN , LOW);
        digitalWrite(STEP_PIN    , HIGH);
	    delay(1);
        digitalWrite(STEP_PIN    , LOW);
        ++motor_position;
} 

void loop() {
Serial.println(enc);
}