Просто вспомнил и написал - как когда-то решил проблему быстородействия процедуры опроса энкодера и при этом еще получил эргономику, какую хотел. Давно дело было и было на avr.
Энкодер и STM32
Re: Энкодер и STM32
Если что - я никого ни к чему не призываю. 
Просто вспомнил и написал - как когда-то решил проблему быстородействия процедуры опроса энкодера и при этом еще получил эргономику, какую хотел. Давно дело было и было на avr.
Просто вспомнил и написал - как когда-то решил проблему быстородействия процедуры опроса энкодера и при этом еще получил эргономику, какую хотел. Давно дело было и было на avr.
- Реклама
Re: Энкодер и STM32
[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4101099#p4101099"][uquote="auric",url="/forum/viewtopic.php?p=4101050#p4101050"]и тут на тебе - контроллер считает импульсы - а должен один добавить и тут же по спаду убавить.[/uquote]
Значит, у тебя таймер неправильно настроен. Т.к. в такой ситуации он должен просто на ±1 дрожать!
Я в этих ваших калокубах не понимаю. Поэтому в код и не смотрю. Ну и да: кто сказал, что в самом калокубе нет ошибок?
Привожу код из сниппета:
Фильтрация настроена?[/uquote]
хочу пообсуждать данный код в разрезе эффективности именно этого фильтра ETF для интерфейса энкодера, кто что думает, я лично считаю, что настройка регистра TIM3->SMCR привязана к External тактированию, собственно с этим сигналом фильтр и работает, а также прескалер на него действует. По идее с энкодерными входами должны работать регистры CCMR1(2) в режиме инпут пинов (каналов как входов). Затем после фильтрации получаться TI1FP1 и TI1FP2, которые и являются тактирующими. Вот только не пойму, как в данном случае должен работать прескалер судя по такой картинке

первым работает фильтр выборок, но не совсем понятно, как здесь участвует прескалер, хорошо, если делит частоту таймера по шине и задает этот f_TDS на выборки, а может вообще не делит. Далее выбор фронта или спада (кстати в CIMSIS есть TIM_ICPolarity_BothEdge, который по сути у меня не работает в силу отсутствия аппаратной поддержки).
Почему задумался, да потому что дребезг я отфильтровать расчетным путем не смог, хотел ограничить частотой 70кГц, а в итоге флаг прерывания ловлю даже не досчитав
и это на 72 МГц частоте.
Хотя настройку на ETF тоже делаю из соображений гарантированности и обыкновенного маразма.
ПыСы: короче ICPrescaler вообще убрал от греха, CKD в регистре SR1 сделал свое дело.
Значит, у тебя таймер неправильно настроен. Т.к. в такой ситуации он должен просто на ±1 дрожать!
Я в этих ваших калокубах не понимаю. Поэтому в код и не смотрю. Ну и да: кто сказал, что в самом калокубе нет ошибок?
Привожу код из сниппета:
Код: Выделить всё
static inline void timers_setup(){
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
/* (1) Configure TI1FP1 on TI1 (CC1S = 01)
configure TI1FP2 on TI2 (CC2S = 01) */
/* (2) Configure TI1FP1 and TI1FP2 non inverted (CC1P = CC2P = 0, reset value) */
/* (3) Configure both inputs are active on both rising and falling edges
(SMS = 011), set external trigger filter to f_DTS/8, N=6 (ETF=1000) */
/* (4) Enable the counter by writing CEN=1 in the TIMx_CR1 register. */
TIM3->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0; /* (1)*/
/* (2) */
TIM3->SMCR = TIM_SMCR_ETF_3 | TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1; /* (3) */
// enable update interrupt
TIM3->DIER = TIM_DIER_UIE;
// set ARR to 79 - generate interrupt each 80 counts (one revolution)
TIM3->ARR = 79;
// enable timer
TIM3->CR1 = TIM_CR1_CEN; /* (4) */
NVIC_EnableIRQ(TIM3_IRQn);
}хочу пообсуждать данный код в разрезе эффективности именно этого фильтра ETF для интерфейса энкодера, кто что думает, я лично считаю, что настройка регистра TIM3->SMCR привязана к External тактированию, собственно с этим сигналом фильтр и работает, а также прескалер на него действует. По идее с энкодерными входами должны работать регистры CCMR1(2) в режиме инпут пинов (каналов как входов). Затем после фильтрации получаться TI1FP1 и TI1FP2, которые и являются тактирующими. Вот только не пойму, как в данном случае должен работать прескалер судя по такой картинке

первым работает фильтр выборок, но не совсем понятно, как здесь участвует прескалер, хорошо, если делит частоту таймера по шине и задает этот f_TDS на выборки, а может вообще не делит. Далее выбор фронта или спада (кстати в CIMSIS есть TIM_ICPolarity_BothEdge, который по сути у меня не работает в силу отсутствия аппаратной поддержки).
Почему задумался, да потому что дребезг я отфильтровать расчетным путем не смог, хотел ограничить частотой 70кГц, а в итоге флаг прерывания ловлю даже не досчитав
Код: Выделить всё
if (CNT_EN){
if ((CNT_TIM3_old==1)&&(cnt_dir!=1)&&(TIM3_CNT > 32767))
CNT_Val_Reg = (s32)(CNT_Val_Reg - 65536), CNT_TIM3_old = 65534, cnt_dir = 1;
if ((CNT_TIM3_old==65534)&&(cnt_dir!=2)&&(TIM3_CNT < 32767))
CNT_Val_Reg = (s32)(CNT_Val_Reg + 65536), CNT_TIM3_old = 1, cnt_dir = 2;
}Хотя настройку на ETF тоже делаю из соображений гарантированности и обыкновенного маразма.
ПыСы: короче ICPrescaler вообще убрал от греха, CKD в регистре SR1 сделал свое дело.
Код: Выделить всё
TIM_ICInitTypeDef TIM_ICInitStructure;
//Enter the content in the structure by default
TIM_ICStructInit(&TIM_ICInitStructure);
//выбрать входной терминал IC1
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
//Захват фронт
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
//сопоставлен с TI1
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
//Настроить входное частотное деление замеряемого сигнала, не делим чтоб не потерять
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
//filter value fSAMPLING=fDTS/32, выборка N=8.
TIM_ICInitStructure.TIM_ICFilter = 15;
//Initialize the specified parameters in TIM_ICInitStructure TIM3
TIM_ICInit(TIM3, &TIM_ICInitStructure);Re: Энкодер и STM32
А посмотреть его осциллографом, измерить длительность и отфильтровать с помощью RC-фильтра и триггера Шмитта не пробовал? Глядя на структуру таймера, я не вижу там настоящего фильтра дребезга, поэтому, ИМХО, твои попытки отфильтровать дребезг были априори обречены на неудачу.да потому что дребезг я отфильтровать расчетным путем не смог
- Eddy_Em
- Собутыльник Кота
- Сообщения: 2516
- Зарегистрирован: Пт июл 12, 2019 22:52:01
- Контактная информация:
Re: Энкодер и STM32
По этой SPL'ной мешанине вообще непонятно, что там происходит. Но что-то очень похоже, что таймер вообще не в режиме энкодера инициализирован, а в тупом режиме счета по одному каналу!
Re: Энкодер и STM32
[uquote="tonyk",url="/forum/viewtopic.php?p=4107770#p4107770"]
Ну сейчас получилось, дребезг и так таймером обсчитывается, не могу только "быстрый" настолько, что не успеваю выйти из прерывания, потому и выставил верхнюю границу в 70кГц - ее хватает за глаза. Про осцил - если честно такие частоты надо задавать, а не ловить, осцил есть, а вот генератора нема, потому и шел расчетным путем. По поводу дребезга - и работы с RC и триггерами - все это конечно необходимо НО, если сигнал реально идет с частотой 70 кГц, зачем мне его гасить, система должна справляться, а вот то что не попало в диапазон, можно, но для надежности и программа тоже должна справляться.
Добавлено after 8 minutes 22 seconds:
[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4107799#p4107799"]По этой SPL'ной мешанине вообще непонятно, что там происходит. Но что-то очень похоже, что таймер вообще не в режиме энкодера инициализирован, а в тупом режиме счета по одному каналу![/uquote]
не по одному, а по двум, на втором аналогичная настройка и это никакого отношений к настройке интерфейса энкодера не имеет - это настройка фильтра - она же по совместительству настройка capture. Настройка энкодера идет в битах SMS.
А посмотреть его осциллографом, измерить длительность и отфильтровать с помощью RC-фильтра и триггера Шмитта не пробовал? Глядя на структуру таймера, я не вижу там настоящего фильтра дребезга, поэтому, ИМХО, твои попытки отфильтровать дребезг были априори обречены на неудачу.[/uquote]да потому что дребезг я отфильтровать расчетным путем не смог
Ну сейчас получилось, дребезг и так таймером обсчитывается, не могу только "быстрый" настолько, что не успеваю выйти из прерывания, потому и выставил верхнюю границу в 70кГц - ее хватает за глаза. Про осцил - если честно такие частоты надо задавать, а не ловить, осцил есть, а вот генератора нема, потому и шел расчетным путем. По поводу дребезга - и работы с RC и триггерами - все это конечно необходимо НО, если сигнал реально идет с частотой 70 кГц, зачем мне его гасить, система должна справляться, а вот то что не попало в диапазон, можно, но для надежности и программа тоже должна справляться.
Добавлено after 8 minutes 22 seconds:
[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4107799#p4107799"]По этой SPL'ной мешанине вообще непонятно, что там происходит. Но что-то очень похоже, что таймер вообще не в режиме энкодера инициализирован, а в тупом режиме счета по одному каналу![/uquote]
не по одному, а по двум, на втором аналогичная настройка и это никакого отношений к настройке интерфейса энкодера не имеет - это настройка фильтра - она же по совместительству настройка capture. Настройка энкодера идет в битах SMS.
- Реклама
Re: Энкодер и STM32
Странная логика. У тебя идёт дребезг с энкодера. Не зная параметров дребезга, ни программно, ни аппратно его не возможно подавить. Без подавления дребезга просто не понятно, что там насчитает таймер.
Добавлено after 2 minutes 23 seconds:
Покажи осциллограмму сигналов с энкодера.
Добавлено after 2 minutes 23 seconds:
Покажи осциллограмму сигналов с энкодера.
- Eddy_Em
- Собутыльник Кота
- Сообщения: 2516
- Зарегистрирован: Пт июл 12, 2019 22:52:01
- Контактная информация:
Re: Энкодер и STM32
А у меня вопрос: что в битах CKD регистра TIM3->CR1? Если там по нулям, то fDTS = fCK_INT, т.е. фильтр просто может и не отработать... А вот если туда двоечку записать, то fDTS будет в четыре раза меньше fCK_INT… А это — уже не 48МГц, а 12МГц. Т.е. при фильтрации fDTS/32 N=8 получим, что таймер будет отсекать все шумы выше ~46.9кГц.
И еще: если на PCLK (APB) нет важной периферии, можно APB prescaler загнать в 1/16, в этом случае fCK_INT будет равна HCLK/8, т.е. 6МГц, если AHB шурует на 48 (только учесть это при конфигурации усартов и прочей периферии, сидящей на APB).
Ну и совсем уж в качестве экспериментов, можно AHB притормозить. Правда, при этом затормозится еще и обращение к памяти, DMA и т.д., и т.п.
И еще: если на PCLK (APB) нет важной периферии, можно APB prescaler загнать в 1/16, в этом случае fCK_INT будет равна HCLK/8, т.е. 6МГц, если AHB шурует на 48 (только учесть это при конфигурации усартов и прочей периферии, сидящей на APB).
Ну и совсем уж в качестве экспериментов, можно AHB притормозить. Правда, при этом затормозится еще и обращение к памяти, DMA и т.д., и т.п.
Re: Энкодер и STM32
Eddy_Em, глянь мой код
На плате энкодера еще два резистора по 10кОм впаяны, на подтяжку.
Спойлер
Код: Выделить всё
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; //включить тактирование порта AHB = 48
/** TIM3 GPIO Configuration
PA6 ------> TIM3_CH1
PA7 ------> TIM3_CH2
*/
// настройка вывода PA6
GPIOA->MODER &= ~(GPIO_MODER_MODER6);
GPIOA->MODER |= (GPIO_MODER_MODER6_1); //10 Alternate
GPIOA->PUPDR |= GPIO_PUPDR_PUPDR6_0; //01 Alternate Function PP Pull-up
// настройка вывода PA7
GPIOA->MODER &= ~(GPIO_MODER_MODER7);
GPIOA->MODER |= (GPIO_MODER_MODER7_1);
GPIOA->PUPDR |= GPIO_PUPDR_PUPDR7_0; //01
/*Configure GPIO pin alternate function */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_1);
/*Configure GPIO pin alternate function */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_1);
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; //тактирование таймера
TIM3->CCMR1 |= TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0; //полярность сигнала для каждого входа
TIM3->CCER &= (uint16_t)(~(TIM_CCER_CC1P | TIM_CCER_CC2P)); // PA6 PA7
TIM3->SMCR |= TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1 | TIM_SMCR_ETF; //режим энкодера
TIM3->CR1 |= TIM_CR1_CKD_1;
TIM3->CCMR1 |= TIM_CCMR1_IC1F_3 | TIM_CCMR1_IC1F_2 | TIM_CCMR1_IC1F_1 | TIM_CCMR1_IC1F_0;
TIM3->CCMR1 |= TIM_CCMR1_IC2F_3 | TIM_CCMR1_IC2F_2 | TIM_CCMR1_IC2F_1 | TIM_CCMR1_IC2F_0;
TIM3->ARR = 0xFFFF; //значение, до которого считает CNT
TIM3->CNT = 0x1FFF;
TIM3->CR1 |= TIM_CR1_CEN;- Eddy_Em
- Собутыльник Кота
- Сообщения: 2516
- Зарегистрирован: Пт июл 12, 2019 22:52:01
- Контактная информация:
Re: Энкодер и STM32
Dimon456, и что, все равно не фильтрует?
А если APB prescaler на 1/16?
А если APB prescaler на 1/16?
Re: Энкодер и STM32
Ну как сказать, один тик плохо отрабатывает, особенно при навигации в меню жутко не удобно, может на два три пункта перескочить.Eddy_Em писал(а):и что, все равно не фильтрует?
У меня нет хорошего видео, что нашел
Спойлер
смотреть на нижнюю строку, левые цифры, где 5008, это энкодерНо так и хочется кондерчики поставить, думаю на 1nF сойдет.
не пробовал.Eddy_Em писал(а):А если APB prescaler на 1/16?
- Eddy_Em
- Собутыльник Кота
- Сообщения: 2516
- Зарегистрирован: Пт июл 12, 2019 22:52:01
- Контактная информация:
Re: Энкодер и STM32
Можно вообще по RC-фильтру килогерц на 10 воткнуть.
Re: Энкодер и STM32
Доброго дня. Если не против, вклинюсь со своим вопросом.
Энкодер обычный, алиэкспресс-китайский ЕС11, кажется 15 импульсов на оборот, на синей круглой плате. В его обвязке уже есть резисторы подтяжки к питанию и конденсаторы к земле.
Эксперимент проходит на STM32F103C8.
Таймер настроен для работы с энкодером так:
Значение забирается так:
Тут диапазон счетчика энкодера от 0 до 100, без перехода через 0 или через 100, с шагом 1.
При достижении минимального или максимального значения счетчика, если продолжать вращение в ту же сторону дальше, счетчик начинает колебаться у своего достигнутого значения.
Например, досчитали-докрутили до 0, продолжаем крутить в сторону уменьшения дальше, счетчик меняется в диапазоне 0-1-0-0-0-1-0 и т.п.
Или досчитали до 100, крутим в сторону увеличения дальше, видим 100-99-100-99-98 и т.п.
Скорость вращения вала при этом не важна. Если вал оставить в покое в любом своем положении и любом значении счетчика, то самопроизвольного плавания значения нет.
Параметр Input Filter менять пробовал, результата не видно.
При вращении не на границах счета, этого эффекта нет.
Справочно - этот-же энкодер на ардуине ведет себя адекватно.
Есть-ли решение проблемы такого эффекта у энкодера?
Энкодер обычный, алиэкспресс-китайский ЕС11, кажется 15 импульсов на оборот, на синей круглой плате. В его обвязке уже есть резисторы подтяжки к питанию и конденсаторы к земле.
Эксперимент проходит на STM32F103C8.
Таймер настроен для работы с энкодером так:
Спойлер
Код: Выделить всё
htim3.Instance = TIM3;
htim3.Init.Prescaler = 1;
htim3.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED3;
htim3.Init.Period = 100;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
sConfig.EncoderMode = TIM_ENCODERMODE_TI1;
sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
sConfig.IC1Filter = 15;
sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
sConfig.IC2Filter = 15;
if (HAL_TIM_Encoder_Init(&htim3, &sConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}Спойлер
Код: Выделить всё
encoder_counter = __HAL_TIM_GET_COUNTER(&htim3);При достижении минимального или максимального значения счетчика, если продолжать вращение в ту же сторону дальше, счетчик начинает колебаться у своего достигнутого значения.
Например, досчитали-докрутили до 0, продолжаем крутить в сторону уменьшения дальше, счетчик меняется в диапазоне 0-1-0-0-0-1-0 и т.п.
Или досчитали до 100, крутим в сторону увеличения дальше, видим 100-99-100-99-98 и т.п.
Скорость вращения вала при этом не важна. Если вал оставить в покое в любом своем положении и любом значении счетчика, то самопроизвольного плавания значения нет.
Параметр Input Filter менять пробовал, результата не видно.
При вращении не на границах счета, этого эффекта нет.
Справочно - этот-же энкодер на ардуине ведет себя адекватно.
Есть-ли решение проблемы такого эффекта у энкодера?
- Eddy_Em
- Собутыльник Кота
- Сообщения: 2516
- Зарегистрирован: Пт июл 12, 2019 22:52:01
- Контактная информация:
Re: Энкодер и STM32
U-M, как-то странно у вас настроен энкодер. Не должно такого быть: после 0 должно следовать 99, 98 и так далее; аналогично после 100 должно идти 0, 1, 2 и т.д.
Каловскую портянку вряд ли кто читать будет. Дайте нормальный код инициализации!
P.S. А таймер случаем не в center-aligned mode?
Каловскую портянку вряд ли кто читать будет. Дайте нормальный код инициализации!
P.S. А таймер случаем не в center-aligned mode?
Re: Энкодер и STM32
Да, таймер в aligned mode 3.
Re: Энкодер и STM32
Здрасти
У меня иная проблема, опыта в СТМ пока не много поэтому сильно не пинайте.
Вопрос соединения таймеров, возможно ли такое: я подключил энкодер к таймеру Т4 всё работает, но как то нужно настроить прерывание(допустим через каждых 100 тиков этого таймера), полагаю что прерывание по переполнению делать не вариант, потеряем текущее абсолютное значение (0-0xffff), есть идея параллельно к счётному входу подключить второй таймер который бы и генерил прерывание по переполнению к примеру каждые 100 импульсов?
Или это можно как то иначе реализовать? Но только не через прерывания, прерывание должно быть одно и только после делителя импульсов.
В чём собственно суть: на цепи лежит объект, цепь при этом перемещается, на цепи установлен инкрементальный энкодер, в зоне измерения установлен датчик и через допустим 1-5-10 см нужно считывать значения с датчика при этом запоминается значение счётчика в момент начала и конца объекта чтобы потом вычислить итоговую длину.
У меня иная проблема, опыта в СТМ пока не много поэтому сильно не пинайте.
Вопрос соединения таймеров, возможно ли такое: я подключил энкодер к таймеру Т4 всё работает, но как то нужно настроить прерывание(допустим через каждых 100 тиков этого таймера), полагаю что прерывание по переполнению делать не вариант, потеряем текущее абсолютное значение (0-0xffff), есть идея параллельно к счётному входу подключить второй таймер который бы и генерил прерывание по переполнению к примеру каждые 100 импульсов?
Или это можно как то иначе реализовать? Но только не через прерывания, прерывание должно быть одно и только после делителя импульсов.
В чём собственно суть: на цепи лежит объект, цепь при этом перемещается, на цепи установлен инкрементальный энкодер, в зоне измерения установлен датчик и через допустим 1-5-10 см нужно считывать значения с датчика при этом запоминается значение счётчика в момент начала и конца объекта чтобы потом вычислить итоговую длину.
Re: Энкодер и STM32
У таймеров-счётчиков есть модуль сравнения. Берёшь текущее значение счётчика, добавляешь или вычитаешь из него нужное количество импульсов, разрешеаешь прерывание от этого канала сравнения- и в путь.alex_ писал(а):на цепи лежит объект, цепь при этом перемещается, на цепи установлен инкрементальный энкодер
Управлял конвейером. Энкодера не было, управлял шаговым двигателем, но суть таже самая.
Re: Энкодер и STM32
Ну как вариант, если не получиться таймеры синхронизировать. Пока пытаюсь T4 master->T12 save
Re: Энкодер и STM32
[uquote="alex_",url="/forum/viewtopic.php?p=4434284#p4434284"]Ну как вариант, если не получиться таймеры синхронизировать.[/uquote]
Зачем их синхронизировать? TIM2 и TIM5 имеют аж 32 бита. Впрочем, для большинства задач хватает 16 бит.
Ещё обрати внимание на флаги прерываний. Возможно, тебе понадобиться отключить флаг перехода счётчика через ноль, оставив только сигналы от модуля сравнений.
Зачем их синхронизировать? TIM2 и TIM5 имеют аж 32 бита. Впрочем, для большинства задач хватает 16 бит.
Ещё обрати внимание на флаги прерываний. Возможно, тебе понадобиться отключить флаг перехода счётчика через ноль, оставив только сигналы от модуля сравнений.
Re: Энкодер и STM32
Мне нужно чтобы они работали синхронно, Т4 хранит значение текущего положения цепи(0-0xffff), в Т12 записываем максимальное значение при постижении которого(TIM12_ARR = 20-50-150) счётчик сбрасывается в ноль и формируется прерывание. Хочу сделать всё на аппаратном уровне без заморочки с регистрами сравнения.
Re: Энкодер и STM32
Так ведь если формируется прерывание, то что сложного в нём сбросить счётчик?alex_ писал(а):счётчик сбрасывается в ноль и формируется прерывание. Хочу сделать всё на аппаратном уровне без заморочки с регистрами сравнения.
Если уж так хочется, чтобы всё делалось автоматически, то можно задействовать DMA для записи нуля, хотя, ИМХО, зачем такой изврат?


