Skocz do zawartości
skibos

STM32 F042K6 kontrola PWM

Pomocna odpowiedź

Napisano (edytowany)

Witam.

Chciałbym uzyskać częstotliwość PWM około 31250Hz. Jakie wartości Prescaler, Period oraz Pulse powinienem przypisać aby otrzymać taką częstotliwość. Dodam że chciałbym zarządzać wypełnieniem w zależności od warunku instrukcji warunkowej z wykorzystaniem makra _HAL_TIM_SET_COMPARE, jednakże chciałbym aby były to wartości od 0 do 100 odpowiadające od 0% do 100% wypełnienia. Czy da rade coś takiego zrobić ? Załączam screen z konfiguracji zegarów z MX Cube. Czy zegary są ustawione dobrze ? Dodam że zależy mi na tym aby układ przeliczał wartości z czujników szybciej niż arduino aczkolwiek wolałbym w pełni wykorzystać potencjał tego STMa.

Bez tytułu.png


edit

Poczytałem troszeczkę, zmieniłem ustawienie zegarów na 48 MHz. Podzieliłem częstotliwość zegara czyli 48000000 Hz przez częstotliwość którą chcę  otrzymać czyli 31250Hz i wyszło mi 1536 ( 1535+1) czyli wyszedł mi Prescaler ? Jeśli nie to prosiłbym o dokładne wytłumaczenie, jeśli tak to uważam że nadal nie wiem jak ustawić wartość Period i Pulse.

@edit 2

skorzystałem z tego wzoru

FREQ = TIM_CLK/(ARR+1)(PSC+1)(CKD+1)

i po podstawieniu wyszło 0.. Stwierdziłem więc że wezmę sobie Period z zakresu od 0 do 255 jak w arduino, czyli

31250=48000000/(254+1)(PSC+1)(0+1)

31250*255*(PSC+1)=48000000

PSC+1=48000000/7968750

PSC=5

 

według tego rozumowania przy Prescaler=5, Period=254 otrzymam częstotliwość PWM o wartości 31250Hz tak ? I w Pulse ustawiam wartość początkową z zakresu od 0 do 255 i w kodzie mogę zmieniać wartość _HAL_TIM_SET_COMPARE z zakresu od 0 do 255 ?

 

Edytowano przez skibos

Udostępnij ten post


Link to post
Share on other sites
Dnia 10.03.2019 o 16:53, skibos napisał:

według tego rozumowania przy Prescaler=5, Period=254 otrzymam częstotliwość PWM o wartości 31250Hz tak ? I w Pulse ustawiam wartość początkową z zakresu od 0 do 255 i w kodzie mogę zmieniać wartość _HAL_TIM_SET_COMPARE z zakresu od 0 do 255 ?

Tak, zgadza się.

Dnia 10.03.2019 o 16:53, skibos napisał:

Poczytałem troszeczkę, zmieniłem ustawienie zegarów na 48 MHz. Podzieliłem częstotliwość zegara czyli 48000000 Hz przez częstotliwość którą chcę  otrzymać czyli 31250Hz i wyszło mi 1536 ( 1535+1) czyli wyszedł mi Prescaler ? Jeśli nie to prosiłbym o dokładne wytłumaczenie, jeśli tak to uważam że nadal nie wiem jak ustawić wartość Period i Pulse.

Wyszedł Ci Period.

Żeby maksymalnie uprościć, a jednocześnie nie wprowadzać zbyt dużej karykatury sprowadzając temat do "Arduinów"...
Wzór FREQ = TIM_CLK/(ARR+1)(PSC+1)(CKD+1) na częstotliwość sygnału PWM jest dobry (dla standardowego trybu edge-alligned, który zapewne Cię interesuje).
Zakładam, że ustaliłeś TIM_CLK na 48MHz.
ARR, czyli Period będzie rozdzielczością sygnału PWM. PSC, czyli Prescaler pozwala przeskalować częstotliwość inkrementacji licznika (PSC=1 -> 48MHZ/2 = 24MHz). CKD pomijam.
Dla 31250Hz dobrze Ci wyszło: 1536 ( 1535+1)  - teraz zauważ, że 1535 mieści się w zakresie rejestru 16-bitowego. Więc PSC możesz spokojnie zostawić na 0, a wartość 1535 wpisać do rejestru ARR - uzyskasz w ten sposób maksymalną rozdzielczość sygnału PWM.

Makrem _HAL_TIM_SET_COMPARE ustawiasz rejestr CCRx, czyli Pulse dla danego kanału (z zakresu 0 do ARR).
CCRx/ARR będzie wypełnieniem sygnału PWM. Pamiętaj, że gdy ustawisz CCR na wartość większa niż ARR, wypełnienie będzie wynosić 100%.

Skoro do tej pory nie udało Ci się rozwiązać problemu, zakładam, że technika mikroprocesorowa, czy bardziej co się dzieje w środku mikrokontrolera, Cię nie interesuje i rozumiem - nie wszystko na raz. Jeśli to Twoje początku radzę więcej grzebać, próbować, testować i szukać. Jest pełno poradników, kursów i na pewno, jeśli pojawia się problem, to ktoś już się z tym spotkał. Dla podobnych problemów forum ST może być dobrą alternatywą dla forbota 🙂

Jeśli chcesz popróbować z licznikami to warto pod sygnał PWM podłączyć diodę (z opornikiem oczywiście) i tak jak tutaj, wyliczyłeś ARR dla 31250Hz. Zmieniasz PSC z 0 na 31250-1 i patrzysz, czy dioda będzie zapalać się co 1 sekundę na długość ustawionego Pulse (_HAL_TIM_SET_COMPARE ). Łatwo wówczas wyłapać błędy, jeśli dioda zapala się co 0.5s, lub 2s, to znaczy, że np. TIM_CLK nie jest 48Mhz. 🙂

  • Lubię! 2

Udostępnij ten post


Link to post
Share on other sites

Podłączyłem diodę, napisałem fora żeby wypełnienie sygnału rosło od 0 do 100%, a następnie malało od 100% do 0%. Działa to bo dioda się płynnie rozjaśnia i gaśnie. Jednakże po przełączeniu się na silniki i mostek TB6612FNG nie działa to jak dioda. Korzystam z CubeMX i generalnie tylko dopisałem to i dioda działała tak jak miała:

  /* USER CODE BEGIN 2 */

  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);

  /* USER CODE END 2 */

for:

for (int pwm=0;pwm<=255;pwm++)
	   {
	   __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm); 
	   HAL_Delay(10);
	   }
	  HAL_Delay(400); 
	  for (int pwm=255;pwm>=0;pwm--)  
	   {
		  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm);
	   HAL_Delay(10);
	   }
	  HAL_Delay(400);

Czy trzeba coś jeszcze dopisać aby odnośnie PWM'a żeby silniki ruszyły ? Oczywiście stany zadeklarowałem ain1 i bin1 na SET ( wysoki ) natomiast ain2 i bin2 na RESET ( czyli niski ) co powinno dawać nam ruch silników zgodny ze wskazówkami zegara, jednak silniki stoją w miejscu i nie ruszają się.

Udostępnij ten post


Link to post
Share on other sites

Z arduino silniki ruszają? Może kwestia błędu w schemacie. Standby jest podłączony do stanu wysokiego?

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

Tak na arduino wszystko działa perfekcyjnie, stby ustawiony na wysoki zaraz na początku.

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;

UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_TIM2_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_TIM2_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // stby

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5|GPIO_PIN_6, GPIO_PIN_SET); // ain1 bin1
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4|GPIO_PIN_7, GPIO_PIN_RESET); // ain2 bin2
	  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 200);
	  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 200);

	  /*for (int pwm=0;pwm<=255;pwm++)
	  	   {
		  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5|GPIO_PIN_6, GPIO_PIN_SET);
		  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4|GPIO_PIN_7, GPIO_PIN_RESET);
	  	   __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm);
	  	   __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, pwm);
	  	   HAL_Delay(10);
	  	   }
	  	  HAL_Delay(400);
	  	  for (int pwm=255;pwm>=0;pwm--)
	  	   {
			  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5|GPIO_PIN_6, GPIO_PIN_SET);
			  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4|GPIO_PIN_7, GPIO_PIN_RESET);
	  		  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm);
	  		  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, pwm);
	  	   HAL_Delay(10);
	  	   }
	  	  HAL_Delay(400);*/

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48;
  RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI48;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief TIM2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 5;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 254;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */
  HAL_TIM_MspPostInit(&htim2);

}

/**
  * @brief USART2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);

  /*Configure GPIO pins : PA4 PA5 PA6 PA7 */
  GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PB0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(char *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

w za komentowanej pętli też sprawdzałem również nie działa.

Edytowano przez skibos

Udostępnij ten post


Link to post
Share on other sites

@skibos rozumiem, że próbujesz rozwiązać swój problem, ale naprawdę nie trzeba wklejać regularnie  linków do tematu na chatcie, pisać "podbijam" itd. Jeśli ktoś będzie chciał i będzie mógł to na pewno udzieli Ci pomocy bez takiego ponaglania 🙂

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »

×