реклама на сайте
подробности

 
 
> stm32 + абсолютный энкодер
Alexsandr000
сообщение Oct 20 2014, 13:56
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 97
Регистрация: 23-10-12
Пользователь №: 74 054



Здравствуйте уважаемые форумчане!

Хотел спросить у вас совета. Есть абсолютный энкодер с 1024 отсчетами угла поворота и stm32 работающий на 72 МГц, данные с энкодера передаются на МК через 10 выводов. Вал энкодера соединен с валом двигателя через шестерню с передаточным числом 1/7. Была написана программа для определения угла поворота и передачи его на ПК через UART. Тут возникло две проблемы:
1. Данные на ПК иногда передаются не корректно;
2. Как преобразовать угол поворота энкодера в угол поворота двигателя.
вот код:
CODE
#include "main.h"
//////////////////////////////////////////////////////////////////////
int main(void){
init_timer();
init_gpio();
init_clock();
init_uart();
for(i = 0; i < 200000; i++);
if(!RCC_CFGR_SWS_HSE){ GPIOA->ODR ^= GPIO_Pin_0; }
Usart2_Send_String("Hello, world!"); //Передаем строку, сообщающую о готовности микроконтроллера к обмену данными
NVIC_SetPriority(TIM3_IRQn, 1);
while(1){
if(State == 1){
NVIC_DisableIRQ(TIM3_IRQn);
State = 0;
D0 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
D1 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11);
D2 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10);
D3 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_9);
D4 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8);
D5 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_15);
D6 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14);
D7 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
D8 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);
D9 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
pos = D0 | (D1 << 1) | (D2 << 2) | (D3 << 3) | (D4 << 4) | (D5 << 5) | (D6 << 6) | (D7 << 7) | (D8 << 8) | (D9 << 9);

if(pos <= convert.INT){
while(!(USART2->SR & USART_SR_TC)); //Проверяем установку флага TC - завершения предыдущей передачи
USART_SendData(USART2, convert.CHAR[0]);
for(i = 0; i < 100; i++);
while(!(USART2->SR & USART_SR_TC)); //Проверяем установку флага TC - завершения предыдущей передачи
USART_SendData(USART2, convert.CHAR[1]);
pos = convert.INT;
}
NVIC_EnableIRQ(TIM3_IRQn);
}
for(i = 0; i < 100000; i++);
}
return 0;
}
void init_gpio(void){
GPIO_InitTypeDef gpio_cfgA, gpio_cfgB, gpio_cfgLED;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_StructInit(&gpio_cfgA);
GPIO_StructInit(&gpio_cfgB);
GPIO_StructInit(&gpio_cfgLED);
gpio_cfgA.GPIO_Mode = GPIO_Mode_IN_FLOATING; //GPIO_Mode_Out_PP;
gpio_cfgA.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_11| GPIO_Pin_10 | GPIO_Pin_9 | GPIO_Pin_8 | GPIO_Pin_6;
gpio_cfgA.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio_cfgA);
gpio_cfgB.GPIO_Mode = GPIO_Mode_IN_FLOATING; //GPIO_Mode_Out_PP;
gpio_cfgB.GPIO_Pin = GPIO_Pin_15 | GPIO_Pin_14| GPIO_Pin_13 | GPIO_Pin_12 | GPIO_Pin_11;
gpio_cfgB.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_cfgB);
gpio_cfgLED.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_cfgLED.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
gpio_cfgLED.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA, &gpio_cfgLED);
}
void init_timer(){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); /* Не забываем затактировать таймер */
TIM_TimeBaseInitTypeDef timer_base;
TIM_TimeBaseStructInit(&timer_base);
timer_base.TIM_Prescaler = 720 - 1; /* Делитель учитывается как TIM_Prescaler + 1, поэтому отнимаем 1 */
timer_base.TIM_Period = 1;
TIM_TimeBaseInit(TIM3, &timer_base);
/* Настраиваем захват сигнала: - канал: 1 - счёт: по нарастанию - источник: напрямую со входа - делитель: отключен - фильтр: отключен */
TIM_ICInitTypeDef timer_ic;
timer_ic.TIM_Channel = TIM_Channel_1;
timer_ic.TIM_ICPolarity = TIM_ICPolarity_BothEdge; //TIM_ICPolarity_Rising;
timer_ic.TIM_ICSelection = TIM_ICSelection_DirectTI;
timer_ic.TIM_ICPrescaler = TIM_ICPSC_DIV1;
timer_ic.TIM_ICFilter = 2;
TIM_PWMIConfig(TIM3, &timer_ic); /* Эта функция настроит канал 1 для захвата периода, а канал 2 - для захвата заполнения. */
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); /* Выбираем источник для триггера: вход 1 (PA6) */
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); /* По событию от триггера счётчик будет сбрасываться. */
TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable); /* Включаем события от триггера */
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE); /* Разрешаем таймеру генерировать прерывание по захвату */
TIM_Cmd(TIM3, ENABLE); /* Включаем таймер */
NVIC_EnableIRQ(TIM3_IRQn); /* Разрешаем прерывания таймера TIM3 */
}
void TIM3_IRQHandler(){
if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET) {
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1); /* Даём знать, что обработали прерывание */
State = 1;
GPIOA->ODR ^= GPIO_Pin_1;
}
}


Заранее спасибо!!!

Сообщение отредактировал IgorKossak - Oct 20 2014, 14:13
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!


--------------------
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
_3m
сообщение Oct 20 2014, 14:07
Сообщение #2


Знающий
****

Группа: Участник
Сообщений: 745
Регистрация: 28-12-06
Пользователь №: 23 960



Цитата(Alexsandr000 @ Oct 20 2014, 17:56) *
Хотел спросить у вас совета. Есть абсолютный энкодер с 1024 отсчетами угла поворота и stm32 работающий на 72 МГц, данные с энкодера передаются на МК через 10 выводов.

Все 10 бит с энкодера необходимо считывать одновременно (одной командой чтения) потому что в процессе чтения код может измениться и в таком случае побитовое чтение даст неправильный результат.
Go to the top of the page
 
+Quote Post
net
сообщение Oct 20 2014, 16:21
Сообщение #3


Знающий
****

Группа: Свой
Сообщений: 858
Регистрация: 9-08-04
Пользователь №: 473



QUOTE (_3m @ Oct 20 2014, 18:07) *
Все 10 бит с энкодера необходимо считывать одновременно (одной командой чтения) потому что в процессе чтения код может измениться и в таком случае побитовое чтение даст неправильный результат.

и до тех пор пока два раза не станет одинаковыми smile3046.gif
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Oct 20 2014, 18:30
Сообщение #4


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(net @ Oct 20 2014, 18:21) *
и до тех пор пока два раза не станет одинаковыми smile3046.gif

Я бы сказал более обще: применить к получаемым данным подходящий алгоритм фильтрации.
А для конкретного примера распиновки порекомендовал бы еще не собирать данные побитово, а прочитать сразу все содержимое портов A и B и лишь потом рассортировать биты.
Go to the top of the page
 
+Quote Post
net
сообщение Oct 21 2014, 07:35
Сообщение #5


Знающий
****

Группа: Свой
Сообщений: 858
Регистрация: 9-08-04
Пользователь №: 473



QUOTE (KnightIgor @ Oct 20 2014, 22:30) *
Я бы сказал более обще: применить к получаемым данным подходящий алгоритм фильтрации.
А для конкретного примера распиновки порекомендовал бы еще не собирать данные побитово, а прочитать сразу все содержимое портов A и B и лишь потом рассортировать биты.

я имел ввиду что считывание может попасть на момент переключения - если запись в регистр данных с устройства не стробируется
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Oct 21 2014, 09:05
Сообщение #6


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(net @ Oct 21 2014, 09:35) *
я имел ввиду что считывание может попасть на момент переключения - если запись в регистр данных с устройства не стробируется

Вопрос в том, каково соотношение частот переключения и опроса. Можно ограничиться конкретным случаем и решить, что соотношение разительное, и процессор сто раз успеет. Вполне допустимый подход. Можно, однако, подойти обще и применить фильтрацию, которая исключит сбои и в случае, если завтра моторчик шустро раскрутится, а процессор будет напевать MP3 песенку. Мне в этой связи вспоминается статья (кажется на Хабре) об упавшей ракете Ariane: когда стали разбираться, нашли, что самоликвидация произошла из-за старого участка кода управления, который посчитал более выское ускорение модифицированных двигателей ракеты отклонением от нормы.

Сообщение отредактировал KnightIgor - Oct 21 2014, 09:06
Go to the top of the page
 
+Quote Post
net
сообщение Oct 21 2014, 10:41
Сообщение #7


Знающий
****

Группа: Свой
Сообщений: 858
Регистрация: 9-08-04
Пользователь №: 473



QUOTE (KnightIgor @ Oct 21 2014, 13:05) *
Вопрос в том, каково соотношение частот переключения и опроса. Можно ограничиться конкретным случаем и решить, что соотношение разительное, и процессор сто раз успеет. Вполне допустимый подход.

нееее - так нельзя - потому как будет сбоить один раз в год, но в самымй неподходящий момент


Go to the top of the page
 
+Quote Post
Alexsandr000
сообщение Oct 21 2014, 10:58
Сообщение #8


Частый гость
**

Группа: Участник
Сообщений: 97
Регистрация: 23-10-12
Пользователь №: 74 054



Цитата(net @ Oct 21 2014, 14:41) *
нееее - так нельзя - потому как будет сбоить один раз в год, но в самымй неподходящий момент

И сбоит, каждые 2-3 периода


--------------------
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Oct 21 2014, 17:53
Сообщение #9


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(Alexsandr000 @ Oct 21 2014, 16:58) *
И сбоит, каждые 2-3 периода

Вы не в разных прерываниях по таймеру читайте два раза, а прямо подряд, в одном прерывании:
Код
uint16_t ReadEncoder()
{
    uint16_t PA, PB;
    PA = ~GPIOA->IDR;
    PB = ~GPIOB->IDR;
    return 0
        | ((PA & 0b0000000000100000) >> (6 - 0))
        | ((PA & 0b0000010000000000) >> (11 - 1))
        | ((PA & 0b0000001000000000) >> (10 - 2))
        | ((PA & 0b0000000100000000) >> (9 - 3))
        | ((PA & 0b0000000010000000) >> (8 - 4))
        | ((PB & 0b1000000000000000) >> (15 - 5))
        | ((PB & 0b0100000000000000) >> (14 - 6))
        | ((PB & 0b0010000000000000) >> (13 - 7))
        | ((PB & 0b0001000000000000) >> (12 - 8))
        | ((PB & 0b0000100000000000) >> (11 - 9));
}


И в прерывании:
Код
void TIM3_IRQHandler()
{
    uint16_t enc1, enc2;
    if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
        do
        {
            enc1 = ReadEncoder();
            enc2 = ReadEncoder();
        } while (enc1!=enc2);
        // здесь используем правильное значение enc1.
    }
}


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- Alexsandr000   stm32 + абсолютный энкодер   Oct 20 2014, 13:56
|- - KnightIgor   Цитата(net @ Oct 21 2014, 12:41) нееее - ...   Oct 22 2014, 07:29
- - Alexsandr000   Это я сделал CODE#include "main.h" /////...   Oct 21 2014, 05:14
|- - KnightIgor   Цитата(Alexsandr000 @ Oct 21 2014, 07:14)...   Oct 21 2014, 07:07
- - Alexsandr000   сделал так, но теперь не пойму почему данные с UAR...   Oct 21 2014, 09:14
- - Alexsandr000   Огромное всем спасибо!!! Ну сбоить буд...   Oct 22 2014, 08:13
- - Golikov A.   что за бред? если у вас на столе сбоит, на объекте...   Oct 22 2014, 08:35
|- - AHTOXA   Цитата(Golikov A. @ Oct 22 2014, 14:35) Е...   Oct 22 2014, 09:59
- - Alexsandr000   добавил проверку ошибки исчезли Кодconvert.INT = p...   Oct 22 2014, 09:59


Closed TopicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 17:07
Рейтинг@Mail.ru


Страница сгенерированна за 0.01475 секунд с 7
ELECTRONIX ©2004-2016