Энкодер на stm32f405 для новичка

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Встал на лапы
Сообщения: 143
Зарегистрирован: Пт май 20, 2022 22:19:02
Откуда: Ижевск

Сообщение Ифторик »

Приобрел я пару месяцев назад платку stm32f405 от WeActStudio в качестве игрушки, а полгода назад набор ардуино от фриновы, но быстро мне стал не интересен, в этом наборе был игрушечный (квадратурный) энкодер.
Мне хочется получить от этого энкодера импульсы и посчитать, но возникла фундаментальная проблема, если подключить только первый канал энкодера - счетчик считает только вверх, если второй канал - только вниз, это означает энкодер не работает, он не должен реагировать на один из каналов, только на оба вместе или никак.
Два канала вместе считают в обоих направлениях, но возникает много ошибок, около 20-30% шагов пропускаются или считают лишнего, фильтры есть программные и физические, информацию вывожу на дисплей ST7796 320x480, перечитал несколько раз Reference manual раздел Advanced-control timers (TIM1 and TIM8), пока больше ничего не читал, мануал крайне сложен для понимания. Использую кубы MX и IDE.
Опыта в программировании у меня нет, совсем, ни в микроконтроллерах, ни в языках Си и прочих, но я почти понимаю что я делаю. Ткните носом почему режим энкодера не работает, перещелкал все возможные настройки, до которых дотянулся мой мозг, моя не понимать где искать.
Основной код прикладываю под спойлер, я смотрю только на него.
код: рабочий цикл while (1)
Спойлер

Код: Выделить всё

  HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);
  while (1)
  {
	if (TIM1->SR & TIM_SR_CC1IF) //Если бит первого канала 1
		{
		PulseDIR1 = TIM1->CNT;								//читаем значение
		snprintf(DIRi, sizeof(DIRi), "%d", PulseDIR1);				//конвертируем PulseDIR1 в массив символов DIRi[16]
		str_dot_out(10, 100, DIRi, strlen(DIRi), 0, 0, SystemFont);	//выводим на экран
		TIM1->SR &= ~TIM_SR_CC1IF;							//обнуляем
		szDIRi0 = strlen(DIRi);								//считаем количество символов
		}
	if (TIM1->SR & TIM_SR_CC2IF) //Если бит второго канала 1
		{
		PulseDIR2 = TIM1->CNT;
		snprintf(DIRi, sizeof(DIRi), "%d", PulseDIR2);
		str_dot_out(10, 100, DIRi, strlen(DIRi), 0, 0, SystemFont);
		TIM1->SR &= ~TIM_SR_CC2IF;
		szDIRi1 = strlen(DIRi);
		}
	if (szDIRi1!=szDIRi0)   //если количество символов меняется,
		{
		lcd_fill_rect(10, 99, 70, 114, 0x001F); //...очищаем область, иначе цифры накладываются друг на друга
		str_dot_out(10, 100, DIRi, strlen(DIRi), 0, 0, SystemFont);
		szDIRi0=0;
		szDIRi1=0;
		}
  }
код: инициализация TIM1
Спойлер

Код: Выделить всё

  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 5;								
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;		// регистр CR1 бит CMS=00 - в какую сторону считает счетчик
  htim1.Init.Period = 1000;							// регистр ARR
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;	// регистр CR1 бит CKD - коэф. деления
  htim1.Init.RepetitionCounter = 0;					// регистр RCR - указывает сколько раз пропустить обновление регистров (UEV)
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  sConfig.EncoderMode = TIM_ENCODERMODE_TI12;		// регистр SMCR бит SMS
  sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;			// регистр CCER бит CC1P
  sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;		// регистр CCMR1 бит CC1S
  sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC1Filter = 0xf;
  sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
  sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC2Filter = 0xf;
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
Вложения
STM32-Timer-Encoder-Mode.jpg
картинка из Reference manual глава 17.3.16
(28.42 КБ) 28 скачиваний
Реклама
Вымогатель припоя
Сообщения: 622
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Ифторик писал(а): Вт июн 16, 2026 19:59:48 мануал крайне сложен для понимания. ... ни в микроконтроллерах, ни в языках Си и прочих, но я почти понимаю что я делаю.
Зачем себя мучить? Займите свою жизнь чем-то другим. Есть и нормальные развлечения - блохерство, тиктохерство, бухло и бабы. Серьезно, без шуток.
Программирование - обязательно требует способность читать и понимать, что делаешь.

При настройке таймера в режим энкодера не требуется никаких прерываний или флагов CCxIF. В счетчике CNT напрямую отображается число посчитанных шагов.
Реклама
Мудрый кот
Сообщения: 1770
Зарегистрирован: Вт авг 15, 2017 10:51:13

Сообщение jcxz »

Ифторик писал(а): Вт июн 16, 2026 19:59:48

Код: Выделить всё

...
		snprintf(DIRi, sizeof(DIRi), "%d", PulseDIR1);				//конвертируем PulseDIR1 в массив символов DIRi[16]
		str_dot_out(10, 100, DIRi, strlen(DIRi), 0, 0, SystemFont);	//выводим на экран
		TIM1->SR &= ~TIM_SR_CC1IF;							//обнуляем
		szDIRi0 = strlen(DIRi);								//считаем количество символов

...

		snprintf(DIRi, sizeof(DIRi), "%d", PulseDIR2);
		str_dot_out(10, 100, DIRi, strlen(DIRi), 0, 0, SystemFont);
		TIM1->SR &= ~TIM_SR_CC2IF;
		szDIRi1 = strlen(DIRi);

...

		lcd_fill_rect(10, 99, 70, 114, 0x001F); //...очищаем область, иначе цифры накладываются друг на друга
		str_dot_out(10, 100, DIRi, strlen(DIRi), 0, 0, SystemFont);
...
Это не "код", это ужас!
Погуглите в инете учебники на тему программирования микроконтроллеров и почитайте что такое "обработчики прерываний" (ISR) и почему в них нельзя делать то, что вы тут наворотили. Это объясняется уже в основах.
ISR должен быть минимальным. И тем более не должен содержать каких-то выводов куда-то, куда вы сами не знаете.
Про любую функцию из какого-либо Куба или любой другой мурзилки - нужно сперва почитать что она такое, и где её можно вызывать. И не пользоваться чужим кодом, работы которого вы не понимаете.
Ифторик писал(а): Вт июн 16, 2026 19:59:48я почти понимаю что я делаю.
По "коду" видно, что совершенно не понимаете.
Вымогатель припоя
Сообщения: 622
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Там нет обработчика прерываний :) Это написано внутри цикла while(1). Но проблема непонимания работы, тем не менее, есть в самом ярком виде. Автору вообще не следует заниматься программированием. Либо выбрать для себя самый минимальный уровень, как для младших школьников.
Реклама
Эиком - электронные компоненты и радиодетали
Встал на лапы
Сообщения: 142
Зарегистрирован: Вс авг 23, 2015 08:14:05

Сообщение Denis82 »

jcxz писал(а): Ср июн 17, 2026 13:58:19 Погуглите в инете учебники на тему программирования микроконтроллеров и почитайте что такое "обработчики прерываний" (ISR) и почему в них нельзя делать то, что вы тут наворотили. Это объясняется уже в основах.
а где вы увидели что тс на прерываниях работает ? я вижу while(1){ } :)
Реклама
Мудрый кот
Сообщения: 1770
Зарегистрирован: Вт авг 15, 2017 10:51:13

Сообщение jcxz »

Denis82 писал(а): Ср июн 17, 2026 14:55:04а где вы увидели что тс на прерываниях работает ? я вижу while(1){ } :)
Да, точно. Чё-то не доглядел. Но один фиг - он обрабатывает такие быстрые процессы, а вызывает тяжёлые функции при этом.
Да и работать с энкодером нужно именно в прерываниях. А не в суперлупе main().
Особенно глядя на это:
Ифторик писал(а): Вт июн 16, 2026 19:59:48 TIM1->SR &= ~TIM_SR_CC1IF; //обнуляем
Это само по себе неправильно (ТС - читать мануал!), так ещё и делается с большой и непредсказуемой задержкой относительно события. Что тоже неправильно.
Потому и глючит оно безбожно.

PS: Так что совет остаётся прежним - изучать что такое прерывания и делать работу на них.
Реклама
Вымогатель припоя
Сообщения: 622
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Вообще, всё зависит от соотношения частот - системной МК и скорости поворота энкодера.
Ну а режим энкодера у таймера вообще не предполагает обязательного использования флагов CC1IF. Счетчик увеличивается или уменьшается на единицу при распознавании последовательности фронтов от энкодера. Значение счетчика отражает число зафиксированных шагов энкодера и прочитать его можно в любое время.
Флаг CC1IF в рассматриваемом режиме работы будет возникать лишь при достижении счетчиком импульсов установленного в CCR1 значения. А на направление вращения энкодера будет указывать бит TIM_CR1_DIR.
Последний раз редактировалось Rapra Ср июн 17, 2026 15:55:16, всего редактировалось 1 раз.
Опытный кот
Аватара пользователя
Сообщения: 721
Зарегистрирован: Пн сен 15, 2025 08:43:23
Откуда: Маленький СССР посреди террористов

Сообщение linux_rulezz »

jcxz писал(а): Ср июн 17, 2026 15:13:16 Да и работать с энкодером нужно именно в прерываниях.
Не нужно!
Просто когда надо - проверять значение регистра CNT, а в прерываниях нужно лишь счетчик переполнений инкрементировать/декрементировать…
Например, вот так:

Код: Выделить всё

void tim1_brk_up_trg_com_isr(){
    encoders_UPD(0);
}
void tim2_isr(){
    encoders_UPD(1);
}
void tim3_isr(){
    encoders_UPD(2);
}
...
void encoders_UPD(uint8_t i){
    if(enctimers[i]->SR & TIM_SR_UIF){
        int8_t d = 1; // positive (-1 - negative)
        if(enctimers[i]->CR1 & TIM_CR1_DIR) d = -d; // negative
        if(the_conf.motflags[i].encreverse) d = -d;
        if(d == 1) encpos[i] += the_conf.encrev[i];
        else encpos[i] -= the_conf.encrev[i];
    }
    enctimers[i]->SR = 0;
}
Windows must die!
Контактная информация:
Вымогатель припоя
Сообщения: 622
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Таймер в режиме энкодера автоматически считает число шагов от энкодера и отражает их в регистре CNT! Направление вращения энкодера отражается битом TIM_CR1_DIR.
Таймер в режиме энкодера получает счетные импульсы от входов канала 1 и канала 2, распознавая последовательность фронтов.
Кто-нить вообще читал в мануале параграф Encoder interface mode?


14.3.16 Режим интерфейса энкодера
Для выбора режима интерфейса энкодера запишите SMS=‘001’ в регистр TIMx_SMCR, если счетчик считает только по фронтам TI2, SMS=’010’, если он считает только по фронтам TI1, и SMS=’011’, если он считает как по фронтам TI1, так и по фронтам TI2.

Выберите полярность TI1 и TI2, запрограммировав биты CC1P и CC2P в регистре TIMx_CCER. При необходимости пользователь также может запрограммировать входной фильтр.
Два входа TI1 и TI2 используются для подключения к инкрементальному энкодеру. См. Таблицу 81. Счетчик тактируется каждым допустимым переходом на TI1FP1 или TI2FP2 (TI1 и TI2 после входного фильтра и выбора полярности, TI1FP1=TI1, если фильтр не отфильтрован и не инвертирован, TI2FP2=TI2, если фильтр не отфильтрован и не инвертирован), при условии, что он включен (бит CEN в
регистре TIMx_CR1 записан в «1»). Последовательность переходов двух входов оценивается и генерирует импульсы счета, а также сигнал направления. В зависимости от последовательности счета счетчика вверх или вниз, бит DIR в регистре TIMx_CR1 изменяется аппаратно соответственно. Бит DIR вычисляется при каждом переходе на любом входе (TI1 или TI2), независимо от того, считает ли счетчик только на TI1, только на TI2 или на обоих TI1 и TI2.

Режим интерфейса энкодера работает просто как внешний тактовый сигнал с выбором направления. Это означает, что счетчик непрерывно считает от 0 до значения автоперезагрузки в регистре TIMx_ARR (от 0 до ARR или от ARR до 0 в зависимости от направления). Поэтому пользователь должен настроить TIMx_ARR перед началом работы. Аналогичным образом, функции захвата, сравнения, делителя частоты, счетчика повторений и вывода триггера продолжают работать в обычном режиме. Режим энкодера и режим внешнего тактового сигнала 2 несовместимы и не должны выбираться одновременно.
В этом режиме счетчик автоматически изменяется в соответствии со скоростью и направлением инкрементного энкодера, и его содержимое, следовательно, всегда представляет положение энкодера. Направление счета соответствует направлению вращения подключенного датчика.

Внешний инкрементальный энкодер можно подключить непосредственно к микроконтроллеру без внешней интерфейсной логики. Однако для преобразования дифференциальных выходов энкодера в цифровые сигналы обычно используются компараторы. Это значительно повышает помехоустойчивость. Третий выход энкодера, указывающий на механическое нулевое положение, может быть подключен к внешнему входу прерывания и запускать сброс счетчика.

Таймер, настроенный в режиме интерфейса энкодера, предоставляет информацию о текущем положении датчика. Пользователь может получать динамическую информацию (скорость, ускорение, замедление), измеряя период между двумя событиями энкодера с помощью второго таймера, настроенного в режиме захвата. Для этой цели можно использовать выходной сигнал энкодера, указывающий на механический ноль. В зависимости от времени между двумя событиями, показания счетчика также можно считывать через равные промежутки времени. Это можно сделать, зафиксировав значение счетчика в третьем входном регистре захвата, если он доступен (в этом случае сигнал захвата должен быть периодическим и может генерироваться другим таймером). При наличии также можно считывать его значение через запрос DMA, генерируемый часами реального времени.
Последний раз редактировалось Rapra Ср июн 17, 2026 16:13:45, всего редактировалось 1 раз.
Встал на лапы
Сообщения: 143
Зарегистрирован: Пт май 20, 2022 22:19:02
Откуда: Ижевск

Сообщение Ифторик »

Да, вы правы, я только начинаю изучать алфавит, до прерываний я еще не дошел, понятия не имею что это. Первые буквы, которые я напечатал, сильно не ругайтесь))
Цифирки сами бегают, мне уже радостно. Почему вы решили что чужой код использую? Библиотеку на дисплей от кейла в сети нашел, это да, да и то там только функция очистки дисплея и отправки текста, остальное не работает, в кейле библиотека ХАЛ чуть другая, я замучался ее переписывать и обрезать под куб, понятно что для вас это дело двух с половиной минут, а мне аж кажется что пентагон взломал, но перевод переменной в массив помог гугл, мне аж стыдно что я нашел такую функцию с помощью ИИ.
Вымогатель припоя
Сообщения: 622
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Да не нужны здесь никакие прерывания, мало ли чего там jcxz напишет, он сам не понял, как работает таймер в режиме энкодера. Правильно настроенный таймер будет считать шаги энкодера и без прерываний. Достаточно через какие-то промежутки времени читать счетный регистр CNT таймера и всё.
Выше я вставил в сообщение гуглоперевод параграфа из мануала, там всё написано.
Опытный кот
Аватара пользователя
Сообщения: 721
Зарегистрирован: Пн сен 15, 2025 08:43:23
Откуда: Маленький СССР посреди террористов

Сообщение linux_rulezz »

Ифторик писал(а): Ср июн 17, 2026 16:11:55ХАЛ
Самая грубая ошибка - начинать со всякого кала!
Начинать нужно с полного нуля! Разве что, чтобы время не тратить, не самому заполнять все эти заголовочные файлы CMSIS с регистрами и флагами, а взять готовое (например, здесь).
Стартап, линкер-скрипт и т.п. лучше всего самому написать, чтобы понимание пришло. Ну и, естественно, весь базовый код писать самому...
Чужие "библиотеки" - это лишняя возможность добавить в свой код непонятных ошибок. Код для МК пишется достаточно быстро - вообще нет нужды привлекать что-то чужое.

P.S. У некоторых таймеров есть возможность быть "связанными" друг с другом. В таком случае два 16-битных таймера можно аппаратно "превратить" в один 32-битный, и не нужно будет вообще прерывания дергать, чтобы считать переполнения CNT. А в некоторых задачах и 16-битного счетчика шагов за глаза хватит: например, если диапазон перемещения контролируемой каретки меньше, чем 65535 отсчетов энкодера.
Последний раз редактировалось linux_rulezz Ср июн 17, 2026 16:22:41, всего редактировалось 1 раз.
Windows must die!
Контактная информация:
Вымогатель припоя
Сообщения: 622
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Грубая ошибка - не читать мануалов. А ХАЛ - использовать можно. По крайней мере, для новичков это быстрый способ. Тем более, что топикстартер, как он сам признался, не блещет скилами.

Стартап и линкер-скрипт самому писать - тоже излишне для такого простого и стандартного случая. Просто нет смысла в этом.

Про 32-битный таймер. В F405 - это TIM2 и TIM5, они аппаратно 32-битные.
Опытный кот
Аватара пользователя
Сообщения: 721
Зарегистрирован: Пн сен 15, 2025 08:43:23
Откуда: Маленький СССР посреди террористов

Сообщение linux_rulezz »

Rapra писал(а): Ср июн 17, 2026 16:22:10топикстартер, как он сам признался, не блещет скилами.
Ну так ТСу и нужно начинать с чтения документации и написания "blink". А никак не с таймеров в режиме энкодера!
Естественно, еще и английский надо до нужного уровня подтянуть, если его еще нет.

Это же точь то же самое, что и компьютер: нельзя к компьютеру подпускать человека, пока он не освоит линукс и английский язык. И LQFP144 тоже люди не садятся с нуля паять: сначала учатся пайке более крупных деталей. И т.д., и т.п...

А то привыкли, паимашь, что за них "ИИ" думает. А после третьей мировой как они жить будут? Тоже им "ИИ" еду добудет или огонь разожжет?
Windows must die!
Контактная информация:
Вымогатель припоя
Сообщения: 622
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Есть мнение, что третью мировую развяжет сам ИИ, и в ней он сам и победит :)) В целом, показанный в "Терминахтере" 40 лет назад сюжет может иметь место быть, учитывая возможность саморазвития ИИ без участия человека. Уже сейчас ИИ может самомодифицировать собственный программный код. Есть мнение, что темпы развития ИИ уже сейчас начинают опережать способность человека понимать механизмы ИИ.
Это не хвост, это антенна
Сообщения: 1339
Зарегистрирован: Вт ноя 19, 2019 06:10:18

Сообщение tonyk »

linux_rulezz писал(а):нельзя к компьютеру подпускать человека, пока он не освоит линукс
Хм, а как осваивать Линукс, когда тебя не подпускают к нему? :))
Мы изучали компьютеры, когда Линукс ещё не существовало. Нам надо было подождать, пока он появиться, чтобы, так сказать, осваивать комьютер по фэншую? :))

И вообще, Линукс не лучшая реализация *nix, чтобы зацикиваться на ней.
Встал на лапы
Сообщения: 142
Зарегистрирован: Вс авг 23, 2015 08:14:05

Сообщение Denis82 »

tonyk писал(а): Чт июн 18, 2026 09:44:26
linux_rulezz писал(а):нельзя к компьютеру подпускать человека, пока он не освоит линукс
Хм, а как осваивать Линукс, когда тебя не подпускают к нему? :))
Мы изучали компьютеры, когда Линукс ещё не существовало. Нам надо было подождать, пока он появиться, чтобы, так сказать, осваивать комьютер по фэншую? :))

И вообще, Линукс не лучшая реализация *nix, чтобы зацикиваться на ней.
да слушайте его больше, давно известно что воинствующий красноглазик :)) нахер винду, только линукс, нахер ИД, только командная строка, нахер библиотеки, только регистры и никак иначе, тот кто этому не следует лузер и чмо :))
Потрогал лапой паяльник
Сообщения: 398
Зарегистрирован: Чт май 07, 2026 00:30:38

Сообщение Zapolyarny »

Rapra писал(а): Ср июн 17, 2026 05:08:54 Зачем себя мучить? Займите свою жизнь чем-то другим... Программирование - обязательно требует способность читать и понимать, что делаешь.
Только для профессионального уровня. А в хобби можно всё. И этим оно и прекрасно: можно открывать для себя новое, добиваться каких-то побед, не смотря на то, что для опытного всё это крайне просто и элементарно, и получать положительные эмоции. К тому же, способность понимать не требует понимания с первого раза. Можно с любого. В хобби сроки несколько иные.
Прорезались зубы
Аватара пользователя
Сообщения: 240
Зарегистрирован: Пн июл 04, 2016 16:51:22
Откуда: Россия, Омск

Сообщение AlanDrakes »

Делал прототип устройства и тоже использовал энкодер. Разве что на F407, но не должно быть принципиально.

Кусочки моего кода:
Спойлер

Код: Выделить всё

	// Пины GPIOC[6-7] подключаются к таймеру TIM3 на каналы CH1, CH2
	GPIOC->MODER &= ~(GPIO_MODER_MODER6 | GPIO_MODER_MODER7);	// GPIOC[6-7] -> Input
	GPIOC->MODER |= (GPIO_MODER_MODER6_1 | GPIO_MODER_MODER7_1);	// GPIOC[6-7] -> Alternate
	GPIOC->AFR[0] &= 0x00FFFFFF;
	GPIOC->AFR[0] |= 0x22000000;	// GPIOC[6-7] -> TIM3-CH1-2

	// TIM3 SMCR -> SMS = 011
	// TIM3 CCER -> CC1P + CC2P
	TIM3->ARR = 402; // Предел
	TIM3->SMCR = (TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0); // Режим Encoder mode 3
	TIM3->CCER = (TIM_CCER_CC2P | TIM_CCER_CC1P); // Ведомый, режим приёма энкодера - полярность на пинах 1 и 2 обратная.
	//  Почему-то было нужно так.
	TIM3->CNT = 200; // Начальное значение
	TIM3->CR1 = TIM_CR1_CEN; // Разрешаем работу.
И функция-поллер кнопок (вызывается каждую милисекунду, НЕ планировщиком заздач, а при пробуждении от SysTick'а, но в основном цикле (не в прерывании!):
Спойлер

Код: Выделить всё

// EncVal - Глобальная переменная. Помнит предыдущее значение энкодера.
	if (EncVal != (TIM3->CNT >> 2)) { // Для фильтрации шума убираем младший значащий бит. Если значение счётчика изменилось - было вражение.
		if (EncVal < (TIM3->CNT >> 2)) { // Проверяем, куда сдвинули
			OnKeyDown(9); // В одну сторону
		} else {
			OnKeyDown(10); // В другую
		}
		EncVal = (TIM3->CNT >> 2); // Запоминаем новое значение.
	}
AUGHTUNG! Так как это был именно концепт - проверку на переполнение я не произвожу.
В крайнем случае после перехода через какие-нибудь значения можно возвращать регистр TIM3->CNT к середине и делать вид, что ничего не было. Это тоже сработает.
Вымогатель припоя
Сообщения: 622
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Если поставить на середину 16-битного счетчика, то для обычного 24-щелчкового энкодера до переполнения будет порядка 700 оборотов непрерывно в одну сторону. Так что вряд ли кто за раз будет столько крутить в одну сторону.
В программе при вызове функционала ввода по энкодеру сбрасывайте счетчик таймера на середину диапазона и будет вам щщястье.
Ответить

Вернуться в «ARM»