Перейти к содержанию
    

Добрый день.

Пытаюсь подключить к stm32f103 энкодер. Энкодер планирую опрашивать в прерываниях по таймеру. Написал функцию 


    int encoderCnt;
     int encoderState;

  void readEncoderState(){
     
     if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)!=encoderState){
        if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6)!=encoderState){    
           encoderCnt++;
          printf ("%u \r\n",encoderCnt); 
      }
           else {            
             encoderCnt--;
            printf ("%u \r\n",encoderCnt); 
           }

  }
   encoderState=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7);

   }

она упорно только инкрементирует. Функция вызывается  в прерываниях по таймеру с частотой 4 кГЦ.

Что я делаю не так? За ранее благодарен.  

Изменено пользователем haker_fox
Для оформления кода есть кнопка <>. Для STM32 есть свой подраздел.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

23 минуты назад, reg33 сказал:

Что я делаю не так? За ранее благодарен.

printf() в прерываниях - это вообще зашквар.  :fool:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

а может он нестандартный, с микрореализацией? 🙂 

На STM32F103 есть таймеры. А в таймерах - есть режим аппаратного энкодера! Если эту тему изучить, то будет "вэри гут".

Сигналы энкодера выглядят вот так (сигнал 0DINDX не учитывать) :

95p6.jpg.89da5bc66375937dfd5cb6ad2fe4ea2f.jpg

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

Изменено пользователем EdgeAligned

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если программно:

Надо завести четыре переменные: текущее показание энкодера, прошлое показание энкодера, изменение, положение.

И там и там могут быть 4 состояния. Создается массив результатов 4х4 (HALL[4,4]) всех возможных комбинаций. В этом массиве есть нули, +1, -1 и, допустим, 2(ошибка - энкодер сбился).

изменение = HALL[текущее показание энкодера, прошлое показание энкодера];

if(изменение == 2){ошибка};

положение += изменение;

После опроса и в самом начале прошлое показание энкодера = текущее показание энкодера;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

пару недель назад была тема и было вариантов 5 кода, с разной степенью эффективности посмотрите.

пару недель назад была тема и было вариантов 5 кода, с разной степенью эффективности посмотрите.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 4/20/2023 at 2:55 PM, reg33 said:
        if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6)!=encoderState){    

Вместо этого поставьте

On 4/20/2023 at 2:55 PM, reg33 said:
        if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6)){    

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 4/22/2023 at 1:04 AM, xvr said:

Вместо этого поставьте

 

не помогло.

написал следующую функцию

Spoiler
void  encoderState_1 () {
   
   if ((!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6)) && ( ! HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7))){
   statusEnc=0x00;  
   }
    else if  (HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6) && ( ! HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7))){
   statusEnc=0x10;  
   }
    
    else if  (HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6) && (HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7))){
   statusEnc=0x11; 
   }
   
        else if  ((!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6)) && (HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7))){
   statusEnc=0x01;
   }
 //-----inc
   if ((status_old_Enc == 0x01) && (statusEnc==0x00 )){
   encoderCnt++;
   printf ("st_+00 \r\n");
   }
   
   else  if ((status_old_Enc == 0x00) && (statusEnc==0x10 )){
   encoderCnt++;
   printf ("st_+10 \r\n");
   
   }

   
    else  if ((status_old_Enc == 0x10) && (statusEnc==0x11 )){
   encoderCnt++;
   printf ("st_+11 \r\n");
   }
   
     else  if ((status_old_Enc == 0x11) && (statusEnc==0x01)){
   encoderCnt++;
   printf ("st_+01 \r\n");
   }
   
   //------ dec
   
     else if ((status_old_Enc == 0x00) && (statusEnc==0x01)){
   encoderCnt--;
   printf ("st_-01 \r\n"); 
   }
   
   else  if ((status_old_Enc == 0x10) && (statusEnc==0x00 )){
    encoderCnt--;
   printf ("st_-00\r\n");
   }
   
    else  if ((status_old_Enc == 0x11) && (statusEnc==0x10 )){
    encoderCnt--;
   printf ("st_-10 \r\n");
   }
   
     else  if ((status_old_Enc == 0x01) && (statusEnc==0x11)){
    encoderCnt--;
    printf ("st_-11 \r\n");
   }
   else;
  status_old_Enc=statusEnc;
 }

Все равно считает только в плюс.  Подключил лог.анализатор к PIN 7 порта_A к GLK энкодера и PIN 6 порта_А к DT энкодера. Скрин с лог анализатора прилагаю 

image.thumb.png.f13b350da910fb994542177ddf80b402.png

 

 

Изменено пользователем haker_fox
Код нужно прятать в теги. А длинный код ещё и помещать в спойлер.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

const uint16_t StepDir = 0x2442;

uint16_t tmp = (EncState ^ ((GPIOA ->IDR) >> 6)) & 0b11;
if((tmp == 0b01) || (tmp == 0b10))
{
    if(StepDir & (1<<(tmp | (EncState << 2))))
        StepD++;
    else
        StepD--;
}

EncState ^= tmp;

Этот код решительно не нравится из той темы?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

не помогло. написал следующую функцию ...Все равно считает только в плюс.
Ну а какая проблема под отладчиком смотреть, что читается с порта, как меняется состояние и куда ветвится подпрограмма? Не надо быстро крутить, каждый переход будет виден.
Кстати, зачем 4 раза (HAL_GPIO_ReadPin(GPIOA,..) читаются входы: один раз считал - получил "00" или "01", или "10", или "11".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 минут назад, Obam сказал:

Кстати, зачем 4 раза (HAL_GPIO_ReadPin(GPIOA,..) читаются входы: один раз считал - получил "00" или "01", или "10", или "11".

Как зачем? Неужто не поняли? Естественно - чтобы в каких-то случаях (когда звёзды так сложились) в statusEnc получать случайное значение. Так как локальная автоматическая неинициализированная переменная внутри функции, имеет такое пакостное свойство.  :sarcastic:

А если statusEnc - глобальная (хотя - на кой??? :wacko2: ), иногда получать предыдущее значение.

 

PS: А printf() внутри ISR в этом коде недоразумении вас значит - нисколько не смутил?  :sarcastic:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как зачем? Неужто не поняли? Естественно - чтобы в каких-то случаях (когда звёзды так сложились) в statusEnc получать случайное значение. Так как локальная автоматическая неинициализированная переменная внутри функции, имеет такое пакостное свойство.
Как-то, возможно, по простоте душевной, считал, что два бита из одного и того же порта вычитываются одной операцией, и пытался намекнуть об сём...

И простите, (((-8Ж в
void encoderState_1 () {бла-бла-бла}
- не наблюдаю признаков обработчика прерывания ;-)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Obam сказал:

- не наблюдаю признаков обработчика прерывания 😉

Пронаблюдайте в первом сообщении.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще, да... но прошла, считай, неделя - и концепция ТСа могла смениться, и просветление нагрянуть (-;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 26.04.2023 в 23:17, Obam сказал:

Кстати, зачем 4 раза (HAL_GPIO_ReadPin(GPIOA,..) читаются входы: один раз считал - получил "00" или "01", или "10", или "11".

Кажется в хале нет ReadPort целиком :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 hours ago, Obam said:

Вообще, да... но прошла, считай, неделя - и концепция ТСа могла смениться, и просветление нагрянуть (-;

Вроде все сложилось. На мой взгляд самый объективный получился считает без пропусков, функция юзается в прерываниях  4кГц.  

  void readEncoderState(){
     
     if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)!=encoderState){
        if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6)!=encoderState){    
           encoderCnt++;
          printf ("%u \r\n",encoderCnt); 
      }
           else {            
             encoderCnt--;
            printf ("%u \r\n",encoderCnt); 
           }

  }
  encoderState=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7);
  if(encoderCnt<=1) 
       {encoderCnt=0;}
       if(encoderCnt>=30)
           {encoderCnt=30;}
  
   }

опыта написания кода у меня мало, поэтому использовал printf (); для вывода в консоль. 

Изменено пользователем haker_fox
Для оформления кода есть кнопка <>.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...