Skocz do zawartości

Enkodery pololu - dziwne odczyty z czujnika


simba92

Pomocna odpowiedź

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.

Link do komentarza
Share on other sites

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.

  • Pomogłeś! 1
Link do komentarza
Share on other sites

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ą.

Link do komentarza
Share on other sites

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

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

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, 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.

  • Lubię! 1
Link do komentarza
Share on other sites

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 :

Link do komentarza
Share on other sites

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!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.