Der STM32-Timer kann im Ein-Impuls-Modus mit ST HAL nicht initialisiert werden

Ich verwende ein STM32F401C-Discovery-Board mit STM32F401VCT6-Mikrocontroller und möchte einen Timer in einem Impulsmodus einrichten, der nach Ablauf einer Zeitspanne einen Interrupt generiert. Der Interrupt-Handler soll einen der Ausgangszustände umschalten.

Ich habe das Projekt mit STM32CubeMX generiert, den Code zum Starten des Timers und einen Callback hinzugefügt, der aufgerufen wird, wenn ein Interrupt ausgelöst wird.

Der Rückruf:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  UNUSED(htim);
  HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
}

Die Zeile, die den Timer-Betrieb im Ein-Impuls-Modus startet:

HAL_TIM_OnePulse_Start_IT(&htim10, TIM_CHANNEL_ALL);

Leider funktioniert das Programm nicht wie gewünscht - der Zustand der Ausgänge wird nicht umgeschaltet.

Der gesamte Code meiner main.c-Datei ist unten angehängt. Taktkonfiguration: APB1 Timer-Takte: 25 MHz APB2 Timer-Takte: 50 MHz

Können Sie mir bitte sagen, ob ich etwas in meinem Programm verpasst habe?

Haupt c:

#include "main.h"
#include "stm32f4xx_hal.h"

TIM_HandleTypeDef htim10;

void SystemClock_Config(void);
void Error_Handler(void);
static void MX_GPIO_Init(void);
static void MX_TIM10_Init(void);

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  //This code is never reached
  UNUSED(htim);
  HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
}

int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_TIM10_Init();

  HAL_TIM_OnePulse_Start_IT(&htim10, TIM_CHANNEL_ALL);

  while (1)
  {

  }
}

void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 50;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

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

  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

static void MX_TIM10_Init(void)
{
  htim10.Instance = TIM10;
  htim10.Init.Prescaler = 50000;
  htim10.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim10.Init.Period = 1000;
  htim10.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  if (HAL_TIM_Base_Init(&htim10) != HAL_OK)
  {
    Error_Handler();
  }

  if (HAL_TIM_OnePulse_Init(&htim10, TIM_OPMODE_SINGLE) != HAL_OK)
  {
    Error_Handler();
  }

}

static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;

  __HAL_RCC_GPIOD_CLK_ENABLE();

  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);

  GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}

void Error_Handler(void)
{
  while(1) 
  {
  }
}

Bearbeiten: Ich hänge den Rest des Codes an, den ich für relevant halte.

stm32f4xx_hal_msp.c:

#include "stm32f4xx_hal.h"

extern void Error_Handler(void);

void HAL_MspInit(void)
{
  //This function is called

  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);

  /* System interrupt init*/
  /* MemoryManagement_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(MemoryManagement_IRQn, 0, 0);
  /* BusFault_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(BusFault_IRQn, 0, 0);
  /* UsageFault_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(UsageFault_IRQn, 0, 0);
  /* SVCall_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SVCall_IRQn, 0, 0);
  /* DebugMonitor_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DebugMonitor_IRQn, 0, 0);
  /* PendSV_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(PendSV_IRQn, 0, 0);
  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
  //This function is called

  if(htim_base->Instance==TIM10)
  {
     __HAL_RCC_TIM10_CLK_ENABLE();
    HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
  }

}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
  //This function is not called
  if(htim_base->Instance==TIM10)
  {
    __HAL_RCC_TIM10_CLK_DISABLE();

    HAL_NVIC_DisableIRQ(TIM1_UP_TIM10_IRQn);

  }
}

stm32f4xx_it.c:

#include "stm32f4xx_hal.h"
#include "stm32f4xx.h"
#include "stm32f4xx_it.h"

extern TIM_HandleTypeDef htim10;

void SVC_Handler(void)
{

}

void PendSV_Handler(void)
{

}

void SysTick_Handler(void)
{
  HAL_IncTick();
  HAL_SYSTICK_IRQHandler();
}

void TIM1_UP_TIM10_IRQHandler(void)
{
  //This code is never reached
  HAL_TIM_IRQHandler(&htim10);
}

Antworten (2)

Ich habe endlich herausgefunden, was in meinem Code gefehlt hat.

Neben muss HAL_TIM_OnePulse_Start_IT()auch HAL_TIM_Base_Start()aufgerufen werden, um den Timerbetrieb im Einpulsmodus einzurichten.

Jetzt sieht meine Hauptfunktion wie unten aus und der Interrupt wird ausgelöst, wenn nach der eingestellten Zeit.

int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_TIM10_Init();

  HAL_TIM_Base_Start(&htim10);
  HAL_TIM_OnePulse_Start_IT(&htim10, TIM_CHANNEL_1);

  while (1)
  {

  }
}
Bist du dir da sicher, denn bei mir funktioniert es nur, wenn ich HAL_TIM_Base_Start_IT(&htim10);statt verwendeHAL_TIM_Base_Start(&htim10);

Sie haben uns nicht den gesamten Code gezeigt. Wo sind beispielsweise die Timer- und GPIO-Peripherie aktiviert? Und wo wird der Timer-Interrupt aktiviert?

Typischerweise rufen bei STM32Cube-HAL-Anwendungen die Funktionen wie HAL_TIM_Base_Init()eine andere Funktion wie auf HAL_TIM_Base_MspInit(), für die Sie möglicherweise eine Implementierung bereitstellen müssen. Die xxx_MspInit()Funktionen sind typischerweise in einer Datei namens stm32xxxx_hal_msp.c implementiert. ST stellt eine Vorlage für diese Datei mit dem HAL bereit, aber ich glaube, die Erwartung ist, dass Sie die Vorlage in Ihre Projektdatei kopieren und anpassen. (Ich bin mit dem STM32CubeMX-Tool nicht vertraut, das einiges davon möglicherweise automatisch erledigt.)

Normalerweise aktivieren Sie in HAL_TIM_Base_MspInit() in stm32xxxx_hal_msp.c den Timer und den Timer-Interrupt. Dieser Code sieht in etwa so aus:

    // Enable the peripheral clock.
    __HAL_RCC_TIM10_CLK_ENABLE();

    // NVIC configuration for the TIM10 interrupt.
    HAL_NVIC_SetPriority(TIM10_IRQn, 3, 0);
    HAL_NVIC_EnableIRQ(TIM10_IRQn);

Dann müssen Sie auch eine Implementierung für den Timer-Interrupt-Handler bereitstellen. Normalerweise geschieht dies in einer Datei namens stm32xxxx_it.c. Dies ist eine weitere Datei, die als Vorlage mit der HAL bereitgestellt wird, aber es wird erwartet, dass Sie sie in Ihrem Projektverzeichnis anpassen. (Und wieder kann STM32CubeMX einiges davon automatisch erledigen.)

/**
* @brief  This function handles TIM10_IRQHandler interrupt request.
* @param  None
* @retval None
*/
void TIM10_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&htim10);
}

Es HAL_TIM_IRQHandler()ruft dann Ihre HAL_TIM_PeriodElapsedCallback()Funktion auf.

Stellen Sie also sicher, dass Sie den Timer und den Timer-Interrupt in aktiviert haben HAL_TIM_Base_MspInit(). Stellen Sie dann sicher, dass Sie eine Implementierung bereitgestellt haben, für TIM10_IRQHandler()die HAL_TIM_IRQHandler(). Verwenden Sie dann den Debugger, um den Code schrittweise zu durchlaufen. Setzen Sie Haltepunkte in HAL_TIM_Base_MspInit()und TIM10_IRQHandler()und HAL_TIM_PeriodElapsedCallback()um herauszufinden, was funktioniert und was nicht funktioniert.

Ich habe den Rest des Codes, den ich wichtig fand, an den ersten Beitrag angehängt. Ich habe auch Kommentare hinzugefügt, die markieren, ob eine bestimmte Funktion aufgerufen wurde oder nicht. Alle von Ihnen erwähnten Funktionen wurden von dem mit CubeMX generierten Code korrekt aufgerufen.
@Deoksyryboza Sie haben sowohl Anrufe HAL_TIM_Base_Init()als auch HAL_TIM_OnePulse_Init(). Ich denke, Sie sollten nur das eine oder das andere verwenden. Versuchen Sie, den Anruf zu entfernen HAL_TIM_Base_Init(). Hat der Anruf HAL_TIM_OnePulse_Init()Erfolg? Wird HAL_TIM_Base_MspInit()immer noch angerufen von HAL_TIM_OnePulse_Init()?
@Deoksyryboza Nach weiterer Überprüfung sieht es so aus, als ob es ein HAL_TIM_OnePulse_MspInit() gibt, das in stm32f4xx_hal_msp.c anstelle von HAL_TIM_Base_MspInit() implementiert werden sollte.
Das Entfernen des Aufrufs von HAL_TIM_Base_Init() hat nicht geholfen. Der Aufruf von HAL_TIM_OnePulse_Init() war erfolgreich. HAL_TIM_Base_MspInit() wurde nicht aufgerufen. Die Implementierung von HAL_TIM_OnePulse_MspInit() anstelle von HAL_TIM_Base_MspInit() in stm32f4xxx_hal_msp.c hat auch nicht geholfen.
@Deoksyryboza Hier ist eine andere Idee. Ich denke, Sie müssen möglicherweise anrufen, HAL_TIM_OnePulse_ConfigChannel()um den Timer im Ein-Impuls-Modus zu verwenden. Siehe die HAL-Dokumentation.
Der Aufruf von HAL_TIM_OnePilse_ConfigChannel() hat nicht geholfen.