simba92 Napisano Sierpień 16, 2017 Udostępnij Napisano Sierpień 16, 2017 Witam! Zrealizowałem program do obsługi czujników tj. enkoderów na STM32, poniżej zamieszczam kod : #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) //funkcja do zadawania kierunku i prędkosci kół (PWM) { if(lewy >= 0 ) { if(lewy > licznik_max) lewy = licznik_max; GPIO_SetBits(silnik1_IN_GPIO, silnik1_IN1); //jazda do przodu 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) { if(prawy > licznik_max) prawy = licznik_max; GPIO_SetBits(silnik2_IN_GPIO, silnik2_IN2); //jazda do przodu 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 silników 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 enkoderu dla silnika nr 2 i TIM3 ---------------------*/ gpio.GPIO_Pin = enkoder_2A_Pin | enkoder_2B_Pin; gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING; gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(silnik2_ENKODERY_GPIO_Port, &gpio); tim.TIM_CounterMode = TIM_CounterMode_Up; tim.TIM_Period = 100 - 1; TIM_TimeBaseInit(TIM3,&tim); TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); TIM_SetCounter(TIM3, 0); TIM_Cmd(TIM3, ENABLE); /*--------------------------------------------------------*/ /*------------Konfiguracja uart---------------------------*/ 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); /*--------------------------------------------------------*/ while(1) { robot_jazda(15,15); //funkcja odpowiedzialna za sterowanie kołami (znak okresla kierunek obrotu) robota z parametrem PWM z zakresu 0-200 printf("Wartosc z licznika TIM3 = %d\r\n",TIM_GetCounter(TIM3)); } } Silniki mają przekładnie 75 : 1 , rozdzielczość czujnika enkoder_magnetyczny wynosi 12 * 75 (przekładnia) = 900 impulsów na obrót. Uruchomiłem komunikacje UART i wyświetlam to co jest w liczniku dzięki funkcji TIM_GetCounter(TIM3) na terminalu i nie rozumiem skąd biorą się te wartości co przedstawiam na poniższym zdjęciu Czy ktoś z forumowiczów mógłby mi pomóc ??? PS : przeglądałem Reference Manual i przebiegi w trybie enkoder mode i analizując to co tam jest nie rozumiem czemu w liczniku są takie bzdury i nie otrzymuje 900 impulsów na obrót. Cytuj Link do komentarza Share on other sites More sharing options...
Treker (Damian Szymański) Sierpień 18, 2017 Udostępnij Sierpień 18, 2017 simba92, zacząłbym od tego, aby ograniczyć transmisje przez UART. Jeśli dobrze widzę, to wysyłasz informacje do PC w każdym obiegu pętli. To generuje gigantyczne ilości danych i Tera Term nie radzi sobie z odczytaniem wszystkiego, co jest wysyłane więc widzisz tylko jakieś szczątkowe informacje. 1 Cytuj Link do komentarza Share on other sites More sharing options...
simba92 Sierpień 19, 2017 Autor tematu Udostępnij Sierpień 19, 2017 Treker tylko nie rozumiem czemu wysyłając dane przez UART, kiedy koła kręcą się bardzo wolno wypełnienie PWM wynosi 15 na zakresie 0-200 TeraTerm nie miałby dać rady zliczać tych impulsów 🙁 Korzystałeś kiedyś z tych enkoderów ??? pisałeś program ??? przeglądałem wiele rozwiązań w internecie, czytałem dokumentacje i właściwie konfiguracja trybu ENCODER MODE sprowadza się do kilku linijek kodu tak samo jak w kursie STM32 F4 przez analogie tylko z inną biblioteką. Cytuj Link do komentarza Share on other sites More sharing options...
Lukaszm Sierpień 19, 2017 Udostępnij Sierpień 19, 2017 Hej,Ja ostatnio uruchamiałem aplikację z tymi enkoderami które linkujesz. Dwa enkodery, jeden podłączony do TIM1, drugi do TIM2. MCU to STM32F103C8T6. Konfigurację niestety robiłem przez CubeMX, ale podrzucam Ci wygenerowany kod z konfiguracją /* TIM1 init function */ static void MX_TIM1_Init(void) { TIM_Encoder_InitTypeDef sConfig; TIM_MasterConfigTypeDef sMasterConfig; htim1.Instance = TIM1; htim1.Init.Prescaler = 0; htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 65535; htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 0; htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; sConfig.EncoderMode = TIM_ENCODERMODE_TI12; sConfig.IC1Polarity = TIM_ICPOLARITY_RISING; sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI; sConfig.IC1Prescaler = TIM_ICPSC_DIV1; sConfig.IC1Filter = 2; sConfig.IC2Polarity = TIM_ICPOLARITY_RISING; sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI; sConfig.IC2Prescaler = TIM_ICPSC_DIV1; sConfig.IC2Filter = 2; if (HAL_TIM_Encoder_Init(&htim1, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } } /* TIM2 init function */ static void MX_TIM2_Init(void) { TIM_Encoder_InitTypeDef sConfig; TIM_MasterConfigTypeDef sMasterConfig; htim2.Instance = TIM2; htim2.Init.Prescaler = 0; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 65535; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; sConfig.EncoderMode = TIM_ENCODERMODE_TI12; sConfig.IC1Polarity = TIM_ICPOLARITY_RISING; sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI; sConfig.IC1Prescaler = TIM_ICPSC_DIV1; sConfig.IC1Filter = 2; sConfig.IC2Polarity = TIM_ICPOLARITY_RISING; sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI; sConfig.IC2Prescaler = TIM_ICPSC_DIV1; sConfig.IC2Filter = 2; if (HAL_TIM_Encoder_Init(&htim2, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } } Może to Ci jakoś pomoże 1 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
Elvis Sierpień 19, 2017 Udostępnij Sierpień 19, 2017 simba92, używasz jednej zmiennej tim do konfiguracji kilku timerów. Nie ma w tym nic złego, ale jeśli nie wywołasz TIM_TimBaseStructInit przed każdym użyciem zmiennej do kolejnego timera to ryzykujesz, że ustawienia z poprzedniego mogą niechcący "przejść" do kolejnego. Zobacz jak ustawiasz pole TIM_Prescaler - wpisujesz do niego 800 dla TIM1, ale później już nie zmieniasz tej wartości. Więc i TIM3 ma taki preskaler, co może tłumaczyć działanie programu. 1 Cytuj Link do komentarza Share on other sites More sharing options...
simba92 Sierpień 21, 2017 Autor tematu Udostępnij Sierpień 21, 2017 Elvis bardzo dziękuje za cenne uwagi, cały czas poznaję i uczę się programowania STM32. Napewno poprawie parę rzeczy w kodzie i zobaczę jak to wpłynie na działanie programu. Dzięki!!! [ Dodano: 21-08-2017, 18:05 ] Elvis wywołałem inicjalizacje struktury TIM_TimBaseStructInit dla każdego z timerów z osobna i wszystko działa, miałeś rację prescaler TIM3 niestety też był ustawiony na wcześniejszą wartość 800. Poniżej zamieszczam działający kod : #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 delay(int time) { int i; for (i = 0; i < time * 4000; i++) {} } 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 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) { 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_StructInit(&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_StructInit(&gpio); gpio.GPIO_Pin = GPIO_Pin_5; // led test gpio.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &gpio); GPIO_StructInit(&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 enkoderu---------------------*/ GPIO_StructInit(&gpio); gpio.GPIO_Pin = enkoder_2A_Pin | enkoder_2B_Pin; gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING; gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(silnik2_ENKODERY_GPIO_Port, &gpio); TIM_TimeBaseStructInit(&tim); //poprawiony błąd tim.TIM_CounterMode = TIM_CounterMode_Up; tim.TIM_Period = 0xffff; //900 impulsow na 1 obrot kola TIM_TimeBaseInit(TIM3,&tim); TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); TIM_SetCounter(TIM3, 0); TIM_Cmd(TIM3, ENABLE); /*--------------------------------------------------------*/ GPIO_StructInit(&gpio); gpio.GPIO_Pin = GPIO_Pin_10; gpio.GPIO_Mode = GPIO_Mode_AF_PP; gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &gpio); GPIO_StructInit(&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---------------------------*/ while(1) { robot_jazda(-15,15); //funkcja sterujaca mostkami silników, robot obraca się w miejscu GPIO_SetBits(GPIOA, GPIO_Pin_5); // włączenie diody delay(400); GPIO_ResetBits(GPIOA, GPIO_Pin_5); // wyłączenie diody delay(100); printf("Wartosc z licznika TIM3 = %d\r\n",TIM_GetCounter(TIM3) ); } } Lukaszm jeszcze będą optymalizował kod i napewno zajrzę do Twojej implementacji trybu encoder mode, dzięki !!! Poprawne odczyty z terminala : 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!