simba92 Napisano Lipiec 12, 2017 Udostępnij Napisano Lipiec 12, 2017 Witam! Aktualnie realizuje projekt dwukołowego robota mobilnego o napędzie różnicowym z enkoderami magnetycznymi na każdym z kół, konstrukcja mechaniczna została już zrealizowana, elektronika obejmująca projekt plytki drukowanej też, aktualnie programuje. Robot jest sterowany procesorem STM32f103vc i enkodery są podpięte pod TIMER3 tj. sygnały 1A(kanał CH4) i 1B ( CH3) oraz 2A (CH1) i 2B(CH2). Moje pytanie do forumowiczów jest następujące : czy istnieje możliwość pomiaru ilości impulsów + kierunku obrotu dla każdego koła przy użyciu JEDNEGO TIMERA, jeśli tak to jak ? 🙁 Chyba nie przewidziałem opcji sterowania dwoma Timerami, na upartego mogę podpiąć się pod inny timer zmieniając połączenia kabli na płytce, wówczas miałbym do dyspozycji TIM3 + TIM2. 1 Cytuj Link do komentarza Share on other sites More sharing options...
ps19 Lipiec 13, 2017 Udostępnij Lipiec 13, 2017 Encoder mode jest tylko na dwóch kanałach, ale możesz na pozostałych dwóch odpalić przerwanie zewnętrzne EXTI i na nim liczyć zbocza. Mam tak zrobione u siebie i działa bez problemowo Cytuj Link do komentarza Share on other sites More sharing options...
simba92 Lipiec 17, 2017 Autor tematu Udostępnij Lipiec 17, 2017 ps19 napisałem poniższy kod do obsługi enkoderów, założenia są następujące: 1) kanały 1A i 1B obsługiwane są przez timer TIM8 w trybie Encoder Mode na kanałach CH1 i CH2 2) kanały 2A i 2B obsługiwane są przez timer TIM3 w trybie Encoder Mode na kanałach CH1 i CH2 i kod, który niestety nie działa to znaczy w pętli while() w main() robot powinien obrócić się dokładnie o 90 stopni po zliczeniu 585 impulsów przez jakikolwiek enkoder. ps19 mógłbyś rzucić okiem czy czegoś nie brakuje w kodzie ???? #include <stdint.h> #include "stm32f10x.h" #include "rcc_konfiguracja.h" #include "init.h" #include "silniki_sterowanie.h" //definicje enkodera dla silnika1 - LEWY #define silnik1_ENKODERY_GPIO_PORT GPIOC #define silnik1_ENKODERY_TIMER TIM8 #define enkoder_1A_PIN GPIO_Pin_6 #define enkoder_1B_PIN GPIO_Pin_7 //definicje enkodera dla silnika2 - PRAWY #define silnik2_ENKODERY_GPIO_PORT GPIOA #define silnik2_ENKODERY_TIMER TIM3 #define enkoder_2A_PIN GPIO_Pin_6 #define enkoder_2B_PIN GPIO_Pin_7 //zmienne do obslugi enkoderow static volatile int16_t old_silnik1_Enkoder; static volatile int16_t old_silnik2_Enkoder; static volatile int16_t silnik1_Enkoder; static volatile int16_t silnik2_Enkoder; static volatile int16_t enkoder_Suma; volatile int16_t silnik1_Count; volatile int16_t silnik2_Count; volatile int32_t silnik1_Total; volatile int32_t silnik2_Total; void delay(int time) { int i; for (i = 0; i < time * 4000; i++) {} } void Enkodery_Init(void) { GPIO_InitTypeDef gpio; TIM_TimeBaseInitTypeDef tim; TIM_ICInitTypeDef incapture; /*------ KONFIGURACJA kanałów 2A i 2B w trybie Encoder_Mode dla timera TIM3------ */ GPIO_StructInit(&gpio); gpio.GPIO_Pin = enkoder_2A_PIN| enkoder_2B_PIN; gpio.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(silnik2_ENKODERY_GPIO_PORT, &gpio); TIM_TimeBaseStructInit(&tim); tim.TIM_CounterMode = TIM_CounterMode_Up; tim.TIM_Prescaler = 0x0; tim.TIM_Period = 0xffff; TIM_TimeBaseInit(TIM3, &tim); TIM_ICStructInit(&incapture); incapture.TIM_Channel = TIM_Channel_1; incapture.TIM_ICPolarity = TIM_ICPolarity_Rising; incapture.TIM_ICPrescaler = TIM_ICPSC_DIV1; incapture.TIM_ICSelection = TIM_ICSelection_DirectTI; incapture.TIM_ICFilter = 0; TIM_ICInit(TIM3, &incapture); incapture.TIM_Channel = TIM_Channel_2; TIM_ICInit(TIM3, &incapture); TIM_EncoderInterfaceConfig(silnik2_ENKODERY_TIMER, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); TIM_SetAutoreload(silnik2_ENKODERY_TIMER,0xffff); TIM_Cmd(silnik2_ENKODERY_TIMER, ENABLE); /*----------------------------------------------------------------------------------*/ /*------ KONFIGURACJA kanałów 1A i 1B w trybie Encoder_Mode dla timera TIM8------ */ gpio.GPIO_Pin = enkoder_1A_PIN| enkoder_1B_PIN; gpio.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(silnik1_ENKODERY_GPIO_PORT, &gpio); tim.TIM_CounterMode = TIM_CounterMode_Up; tim.TIM_Prescaler = 0x0; tim.TIM_Period = 0xffff; TIM_TimeBaseInit(TIM8, &tim); incapture.TIM_Channel = TIM_Channel_1; incapture.TIM_ICPolarity = TIM_ICPolarity_Rising; incapture.TIM_ICPrescaler = TIM_ICPSC_DIV1; incapture.TIM_ICSelection = TIM_ICSelection_DirectTI; incapture.TIM_ICFilter = 0; TIM_ICInit(TIM8, &incapture); incapture.TIM_Channel = TIM_Channel_2; TIM_ICInit(TIM8, &incapture); TIM_EncoderInterfaceConfig(silnik1_ENKODERY_TIMER, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); TIM_SetAutoreload(silnik1_ENKODERY_TIMER,0xffff); TIM_Cmd(silnik1_ENKODERY_TIMER, ENABLE); /*----------------------------------------------------------------------------------*/ Enkodery_Reset(); } void Enkodery_Reset(void) { __disable_irq(); old_silnik1_Enkoder = 0; old_silnik1_Enkoder = 0; silnik1_Enkoder = 0; //POPRAWIONE silnik2_Enkoder = 0; silnik1_Total = 0; silnik2_Total = 0; TIM_SetCounter(silnik1_ENKODERY_TIMER, 0); TIM_SetCounter(silnik2_ENKODERY_TIMER, 0); __enable_irq(); } void Enkodery_Read(void) { old_silnik1_Enkoder = silnik1_Enkoder; //POPRAWIONE silnik1_Enkoder = TIM_GetCounter(silnik1_ENKODERY_TIMER); old_silnik2_Enkoder = silnik2_Enkoder; silnik2_Enkoder = TIM_GetCounter(silnik2_ENKODERY_TIMER); silnik1_Count = silnik1_Enkoder - old_silnik1_Enkoder; silnik2_Count = silnik2_Enkoder - old_silnik2_Enkoder; silnik1_Total = silnik1_Total + silnik1_Count; //zmienne okreslajace sume zliczonych impulsow przez silnik2_Total = silnik2_Total + silnik2_Count; } int main(void) { RCC_Conf(); RCC_Periph_Conf(); //FUNKCJA wlaczajaca wszystkie potrzebne zegary Gpio_Init(); while(1) { Enkodery_Init(); while((silnik1_Total <= 585) && (silnik2_Total <= 585)) { robot_jazda(40,-40); //funkcja odpowiedzialna za obrot robota, PS : napewno działa, robot obraca sie w kolko Enkodery_Read(); } } } 1 Cytuj Link do komentarza Share on other sites More sharing options...
Elvis Lipiec 18, 2017 Udostępnij Lipiec 18, 2017 silnik1_Enkoder = TIM_GetCounter(silnik1_ENKODERY_TIMER); old_silnik1_Enkoder = silnik1_Enkoder; silnik1_Count = silnik1_Enkoder - old_silnik1_Enkoder; Czy to przypadkiem nie zwraca zawsze zera? Cytuj Link do komentarza Share on other sites More sharing options...
Polecacz 101 Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Produkcja i montaż PCB - wybierz sprawdzone PCBWay! • Darmowe płytki dla studentów i projektów non-profit • Tylko 5$ za 10 prototypów PCB w 24 godziny • Usługa projektowania PCB na zlecenie • Montaż PCB od 30$ + bezpłatna dostawa i szablony • Darmowe narzędzie do podglądu plików Gerber Zobacz również » Film z fabryki PCBWay
simba92 Lipiec 18, 2017 Autor tematu Udostępnij Lipiec 18, 2017 Elvis tak wartość zwracana zawsze byłaby zerowa, poprawiłem to. Efekt działania programu jest taki, że pętla while((silnik2_Total <= 585)) { Enkodery_Read(); robot_jazda(40,-40); } wykonuję się w nieskończoność, a silniki na dodatek przyspieszają !!!???. Funkcja robot_jazda(40,-40) wysterowuję mostki TB6612 z wypełnieniem PWM 40 i - 40 , gdzie max. wypełnienie wynosi 200 - 1, a znak oznacza kierunek obrotów. Piszę program do obsługi już kilka dni na podstawie m.in obsluga_enkoderów F4 , powinno działać 🙁 1 Cytuj Link do komentarza Share on other sites More sharing options...
Elvis Lipiec 18, 2017 Udostępnij Lipiec 18, 2017 A sprawdzałeś czy same enkodery działają? Może warto sprawdzić za pomocą debuggera czy zmienne mają oczekiwane wartości, ewentalnie wysyłać dane testowe przez port szeregowy? Inna sprawa, to nie wiem czego oczekujesz po zliczeniu 585 impulsów, bo program który wkleiłeś po prostu zresetuje liczniki i będzie kręcił silnikami od początku Cytuj Link do komentarza Share on other sites More sharing options...
simba92 Lipiec 18, 2017 Autor tematu Udostępnij Lipiec 18, 2017 Elvis sprawdzę działanie enkoderów wykorzystując port szeregowy i terminal, tak będzie najlepiej. Swoje pytanie odnośnie kodu wrzuciłem, bo liczyłem ,że może robię jakiś podstawowy błąd i ktoś mi go wytknie. Inna sprawa, to nie wiem czego oczekujesz po zliczeniu 585 impulsów, bo program który wkleiłeś po prostu zresetuje liczniki i będzie kręcił silnikami od początku Zgł Po osiągnięciu wartości 585 impulsów robot obróci się w miejscu o dokładnie 90 stopni, obliczałem to na podstawie długości łuku po jakim porusza się koło o danej średnicy i obwodzie z nią związanym. 1 Cytuj Link do komentarza Share on other sites More sharing options...
Elvis Lipiec 18, 2017 Udostępnij Lipiec 18, 2017 Chodziło mi o to, że pętla zliczająca do 585 jest wewnątrz kolejnej pętli. Więc nawet jeśli enkodery działają ok, to doliczasz do 585 i co dalej? Nie masz instrukcji zatrzymującej silniki, zakładam, że robot_jazda() wystarczy wywołać raz i później PWM steruje silnikami do zatrzymania. Więc nawet po zakończeniu wewnętrznej pętli silniki się kręcą, a kilka mikrosekund później program wraca do głównej pętli, wywołuje Enkodery_Init() i od początku liczy do 585. Może dlatego wygląda jakby ta pętla się nie kończyła? 🙂 Wydaje mi się, że robot_jazda(40, -40) wystarczy wywołać raz, później w pętli możesz poczekać na enkodery i zatrzymać silniki - może wywołując robot_jazda(0,0)? Po zatrzymaniu silników musisz trochę poczekać, inaczej nawet nie zauważysz zmiany - możesz poczekać określony czas, albo i nieskończoność ale bez opóźnienia na pewno nie będzie działało zgodnie z oczwkiwaniami. Cytuj Link do komentarza Share on other sites More sharing options...
simba92 Sierpień 15, 2017 Autor tematu Udostępnij Sierpień 15, 2017 Elvis poprawiłem i uprościłem program do minimum, generalnie chcę po prostu tylko uruchomić tryb enkoderów na liczniku TIM3 i funkcją printf("wartosc=%d\r\n",TIM_GetCounter(TIM3)); wyświetlić na terminalu wartość w liczniku. Przy pisaniu programu posługiwałem się m.in kursem STM32 F4, gdzie konfiguracja licznika w trybie enkodera https://forbot.pl/blog/artykuly/programowanie/kurs-stm32-f4-8-zaawansowane-funkcje-licznikow-id13473 jest banalna i zawiera ustawienie kilku parametrów nic więcej co w analogi do standardowej biblioteki powinno wyglądać tak samo. Poniżej kod programu obejmujący funkcje sterującą silnikami, konfiguracje transmisji przez interfejs UART i wspomnianych enkoderów tj. enkodera na silniku nr 2 #include "stm32f10x.h" #include "math.h" #include "stdint.h" #include "stdio.h" #define silnik1_IN1 GPIO_Pin_14 #define silnik1_IN2 GPIO_Pin_15 #define silnik1_IN_GPIO GPIOD #define silnik1_PWM GPIO_Pin_8 #define silnik2_IN1 GPIO_Pin_15 #define silnik2_IN2 GPIO_Pin_14 #define silnik2_IN_GPIO GPIOE #define silnik2_PWM GPIO_Pin_9 #define silniki_PWM_GPIO GPIOA #define licznik_max 199 #define enkoder_2A_Pin GPIO_Pin_6 #define enkoder_2B_Pin GPIO_Pin_7 #define silnik2_ENKODERY_GPIO_Port GPIOA void robot_jazda(int lewy, int prawy) { if(lewy >= 0 ) { if(lewy > licznik_max) lewy = licznik_max; GPIO_SetBits(silnik1_IN_GPIO, silnik1_IN1); //jazda do przodu lewe koło GPIO_ResetBits(silnik1_IN_GPIO, silnik1_IN2); } else { if(lewy < -licznik_max) lewy = -licznik_max; GPIO_ResetBits(silnik1_IN_GPIO, silnik1_IN1); GPIO_SetBits(silnik1_IN_GPIO, silnik1_IN2); } if(prawy >= 0) //jazda do przodu prawe koło { if(prawy > licznik_max) prawy = licznik_max; GPIO_SetBits(silnik2_IN_GPIO, silnik2_IN2); GPIO_ResetBits(silnik2_IN_GPIO, silnik2_IN1); } else { if(prawy < -licznik_max) prawy = -licznik_max; GPIO_ResetBits(silnik2_IN_GPIO, silnik2_IN2); GPIO_SetBits(silnik2_IN_GPIO, silnik2_IN1); } TIM_SetCompare1(TIM1, fabs(lewy)); TIM_SetCompare2(TIM1, fabs(prawy)); } int main(void) { GPIO_InitTypeDef gpio; TIM_TimeBaseInitTypeDef tim; TIM_OCInitTypeDef channel; USART_InitTypeDef uart; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD| RCC_APB2Periph_GPIOC| RCC_APB2Periph_GPIOE, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); GPIO_StructInit(&gpio); gpio.GPIO_Pin = silnik1_IN1 | silnik1_IN2; // silnik1 wejscia sterujace IN_1 i IN_2 gpio.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(silnik1_IN_GPIO, &gpio); gpio.GPIO_Pin = silnik2_IN1 | silnik2_IN2; // silnik2 wejscia sterujace IN_1 i IN_2 gpio.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(silnik2_IN_GPIO, &gpio); gpio.GPIO_Pin = GPIO_Pin_5; // led test gpio.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &gpio); gpio.GPIO_Pin = silnik1_PWM | silnik2_PWM; // konfiguracja pinow dla trybu pwm gpio.GPIO_Speed = GPIO_Speed_50MHz; gpio.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(silniki_PWM_GPIO, &gpio); TIM_TimeBaseStructInit(&tim); tim.TIM_CounterMode = TIM_CounterMode_Up; tim.TIM_Prescaler = 800 - 1; //80khz tim.TIM_Period = 200 - 1; TIM_TimeBaseInit(TIM1,&tim); TIM_OCStructInit(&channel); channel.TIM_OCMode = TIM_OCMode_PWM1; channel.TIM_OutputState = TIM_OutputState_Enable; channel.TIM_OCNPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM1, &channel); TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); channel.TIM_OCMode = TIM_OCMode_PWM1; channel.TIM_OutputState = TIM_OutputState_Enable; channel.TIM_OCNPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM1, &channel); TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM1, ENABLE); TIM_CtrlPWMOutputs(TIM1, ENABLE); TIM_Cmd(TIM1, ENABLE); /*--------------Konfiguracja UART4---------------------*/ gpio.GPIO_Pin = GPIO_Pin_10; gpio.GPIO_Mode = GPIO_Mode_AF_PP; gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &gpio); gpio.GPIO_Pin = GPIO_Pin_11; gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING; gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &gpio); USART_StructInit(&uart); uart.USART_BaudRate = 9600; uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; uart.USART_WordLength = USART_WordLength_8b; uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None; uart.USART_Parity = USART_Parity_No; uart.USART_StopBits = USART_StopBits_1; USART_Init(UART4, &uart); USART_Cmd(UART4, ENABLE); /*------------Konfiguracja uart---------------------------*/ /*--------------KONFIGURACJA ENKODERA - prawy silnik(silnik2) - licznik TIM3 ---------------------*/ gpio.GPIO_Pin = enkoder_2A_Pin | enkoder_2B_Pin; gpio.GPIO_Mode = GPIO_Mode_AF_PP; gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(silnik2_ENKODERY_GPIO_Port, &gpio); tim.TIM_CounterMode = TIM_CounterMode_Up; tim.TIM_Period = 0xffff; //wartość po której licznik się przepełnia TIM_TimeBaseInit(TIM3,&tim); TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); TIM_Cmd(TIM3, ENABLE); /*--------------------------------------------------------*/ while(1) { robot_jazda(40,40); //wypełnienie PWM wynosi 40 dla obu silników, funkcja działa w momencie jej wywolania i koła kręcą się w nieskończoność printf("wartosc=%d\r\n",TIM_GetCounter(TIM3)); //wyswietlana wartość wynosi 0, licznik nic nie zlicza, a powinnien ?! } } Poniżej zdjęcie z terminala : Podsumowując : 1) licznik nic nie zlicza, może brakuje jakieś linijki kodu, etc ?! 2) połączenie fizyczne kanałów jest poprawne [ Dodano: 15-08-2017, 19:16 ] Uruchomiłem tryb enkoderów, brakowało konfiguracji kilku peryferiów m.in kontrolera przerwań i ustawienia wejść jako gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING; , później wrzucę pełen kod może komuś się przyda 🙂 Cytuj Link do komentarza Share on other sites More sharing options...
Pomocna odpowiedź
Dołącz do dyskusji, napisz odpowiedź!
Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!