定时器中断实验代码2

Tutorial: 电子电路 Category: 嵌入式 Published: 2026-08-29 08:09:36 Views: 0 Likes: 0 Comments: 0

131.5.3定时器中断实验代码(2)

/* ========================================================================
 * Project: CubeIDE/06TIM
 * File: Core/Inc/main.h
 * ======================================================================== */
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.h
  * @brief          : Header for main.c file.
  *                   This file contains the common defines of the application.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H

#ifdef __cplusplus
extern "C" {
#endif

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

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

/* USER CODE END Includes */

/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */

/* USER CODE END ET */

/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */

/* USER CODE END EC */

/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */

/* USER CODE END EM */

/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);

/* USER CODE BEGIN EFP */

/* USER CODE END EFP */

/* Private defines -----------------------------------------------------------*/
#define LED2_Pin GPIO_PIN_5
#define LED2_GPIO_Port GPIOE
#define LED1_Pin GPIO_PIN_5
#define LED1_GPIO_Port GPIOB

/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

#ifdef __cplusplus
}
#endif

#endif /* __MAIN_H */

/* ========================================================================
 * Project: CubeIDE/06TIM
 * File: Core/Inc/gpio.h
 * ======================================================================== */
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    gpio.h
  * @brief   This file contains all the function prototypes for
  *          the gpio.c file
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __GPIO_H__
#define __GPIO_H__

#ifdef __cplusplus
extern "C" {
#endif

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

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

void MX_GPIO_Init(void);

/* USER CODE BEGIN Prototypes */

/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif
#endif /*__ GPIO_H__ */

/* ========================================================================
 * Project: CubeIDE/06TIM
 * File: Core/Inc/tim.h
 * ======================================================================== */
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    tim.h
  * @brief   This file contains all the function prototypes for
  *          the tim.c file
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __TIM_H__
#define __TIM_H__

#ifdef __cplusplus
extern "C" {
#endif

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

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

extern TIM_HandleTypeDef htim1;

/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

void MX_TIM1_Init(void);

/* USER CODE BEGIN Prototypes */

/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif

#endif /* __TIM_H__ */

/* ========================================================================
 * Project: CubeIDE/06TIM
 * File: Core/Inc/usart.h
 * ======================================================================== */
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.h
  * @brief   This file contains all the function prototypes for
  *          the usart.c file
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USART_H__
#define __USART_H__

#ifdef __cplusplus
extern "C" {
#endif

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

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

extern UART_HandleTypeDef huart1;

/* USER CODE BEGIN Private defines */
extern uint8_t u_buf[256];//printf?


#define printf(...)  HAL_UART_Transmit(&huart1, (uint8_t *)u_buf, sprintf((char*)u_buf, __VA_ARGS__), 0xffff)
/* USER CODE END Private defines */

void MX_USART1_UART_Init(void);

/* USER CODE BEGIN Prototypes */

/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif

#endif /* __USART_H__ */

/* ========================================================================
 * Project: CubeIDE/06TIM
 * File: Core/Inc/stm32f1xx_it.h
 * ======================================================================== */
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    stm32f1xx_it.h
  * @brief   This file contains the headers of the interrupt handlers.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
 ******************************************************************************
  */
/* USER CODE END Header */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F1xx_IT_H
#define __STM32F1xx_IT_H

#ifdef __cplusplus
 extern "C" {
#endif

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

/* USER CODE END Includes */

/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */

/* USER CODE END ET */

/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */

/* USER CODE END EC */

/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */

/* USER CODE END EM */

/* Exported functions prototypes ---------------------------------------------*/
void NMI_Handler(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
void TIM1_UP_IRQHandler(void);
/* USER CODE BEGIN EFP */

/* USER CODE END EFP */

#ifdef __cplusplus
}
#endif

#endif /* __STM32F1xx_IT_H */

/* ========================================================================
 * Project: CubeIDE/06TIM
 * File: Core/Src/main.c
 * ======================================================================== */
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.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 ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint8_t UART_Buf[200];
uint32_t G_TIM_Count = 0;
uint8_t G_UART_Flag = 0;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(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_TIM1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim1);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  if(1 == G_UART_Flag)
	  {
		  printf("MCU stm32 run time is %lus \n",G_TIM_Count);

		  G_UART_Flag = 0;
	  }

    /* USER CODE END WHILE */

    /* 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 RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  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_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

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

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim == &htim1)
	{
		HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
		G_TIM_Count++;
		  if(1 == G_TIM_Count%5)
		  {
			  G_UART_Flag = 1;
		  }
		  if(0 == G_TIM_Count%2)
		  {
			  HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
		  }
	}

}
/* 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 */
  __disable_irq();
  while (1)
  {
  }
  /* 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(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/* ========================================================================
 * Project: CubeIDE/06TIM
 * File: Core/Src/gpio.c
 * ======================================================================== */
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    gpio.c
  * @brief   This file provides code for the configuration
  *          of all used GPIO pins.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

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

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/*----------------------------------------------------------------------------*/
/* Configure GPIO                                                             */
/*----------------------------------------------------------------------------*/
/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/** Configure pins as
        * Analog
        * Input
        * Output
        * EVENT_OUT
        * EXTI
*/
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

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

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);

  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = LED2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LED2_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = LED1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LED1_GPIO_Port, &GPIO_InitStruct);

}

/* USER CODE BEGIN 2 */

/* USER CODE END 2 */

/* ========================================================================
 * Project: CubeIDE/06TIM
 * File: Core/Src/tim.c
 * ======================================================================== */
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    tim.c
  * @brief   This file provides code for the configuration
  *          of the TIM instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "tim.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

TIM_HandleTypeDef htim1;

/* TIM1 init function */
void MX_TIM1_Init(void)
{

  /* USER CODE BEGIN TIM1_Init 0 */

  /* USER CODE END TIM1_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM1_Init 1 */

  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 7199;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 9999;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */

  /* USER CODE END TIM1_Init 2 */

}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspInit 0 */

  /* USER CODE END TIM1_MspInit 0 */
    /* TIM1 clock enable */
    __HAL_RCC_TIM1_CLK_ENABLE();

    /* TIM1 interrupt Init */
    HAL_NVIC_SetPriority(TIM1_UP_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
  /* USER CODE BEGIN TIM1_MspInit 1 */

  /* USER CODE END TIM1_MspInit 1 */
  }
}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspDeInit 0 */

  /* USER CODE END TIM1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM1_CLK_DISABLE();

    /* TIM1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM1_UP_IRQn);
  /* USER CODE BEGIN TIM1_MspDeInit 1 */

  /* USER CODE END TIM1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* ========================================================================
 * Project: CubeIDE/06TIM
 * File: Core/Src/usart.c
 * ======================================================================== */
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */
uint8_t u_buf[256];
/* USER CODE END 0 */

UART_HandleTypeDef huart1;

/* USART1 init function */

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* ========================================================================
 * Project: CubeIDE/06TIM
 * File: Core/Src/stm32f1xx_it.c
 * ======================================================================== */
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    stm32f1xx_it.c
  * @brief   Interrupt Service Routines.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f1xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */

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

/* USER CODE END TD */

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

/* USER CODE END PD */

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

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

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

/* USER CODE END 0 */

/* External variables --------------------------------------------------------*/
extern TIM_HandleTypeDef htim1;
/* USER CODE BEGIN EV */

/* USER CODE END EV */

/******************************************************************************/
/*           Cortex-M3 Processor Interruption and Exception Handlers          */
/******************************************************************************/
/**
  * @brief This function handles Non maskable interrupt.
  */
void NMI_Handler(void)
{
  /* USER CODE BEGIN NonMaskableInt_IRQn 0 */

  /* USER CODE END NonMaskableInt_IRQn 0 */
  /* USER CODE BEGIN NonMaskableInt_IRQn 1 */
  while (1)
  {
  }
  /* USER CODE END NonMaskableInt_IRQn 1 */
}

/**
  * @brief This function handles Hard fault interrupt.
  */
void HardFault_Handler(void)
{
  /* USER CODE BEGIN HardFault_IRQn 0 */

  /* USER CODE END HardFault_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_HardFault_IRQn 0 */
    /* USER CODE END W1_HardFault_IRQn 0 */
  }
}

/**
  * @brief This function handles Memory management fault.
  */
void MemManage_Handler(void)
{
  /* USER CODE BEGIN MemoryManagement_IRQn 0 */

  /* USER CODE END MemoryManagement_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
    /* USER CODE END W1_MemoryManagement_IRQn 0 */
  }
}

/**
  * @brief This function handles Prefetch fault, memory access fault.
  */
void BusFault_Handler(void)
{
  /* USER CODE BEGIN BusFault_IRQn 0 */

  /* USER CODE END BusFault_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_BusFault_IRQn 0 */
    /* USER CODE END W1_BusFault_IRQn 0 */
  }
}

/**
  * @brief This function handles Undefined instruction or illegal state.
  */
void UsageFault_Handler(void)
{
  /* USER CODE BEGIN UsageFault_IRQn 0 */

  /* USER CODE END UsageFault_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_UsageFault_IRQn 0 */
    /* USER CODE END W1_UsageFault_IRQn 0 */
  }
}

/**
  * @brief This function handles System service call via SWI instruction.
  */
void SVC_Handler(void)
{
  /* USER CODE BEGIN SVCall_IRQn 0 */

  /* USER CODE END SVCall_IRQn 0 */
  /* USER CODE BEGIN SVCall_IRQn 1 */

  /* USER CODE END SVCall_IRQn 1 */
}

/**
  * @brief This function handles Debug monitor.
  */
void DebugMon_Handler(void)
{
  /* USER CODE BEGIN DebugMonitor_IRQn 0 */

  /* USER CODE END DebugMonitor_IRQn 0 */
  /* USER CODE BEGIN DebugMonitor_IRQn 1 */

  /* USER CODE END DebugMonitor_IRQn 1 */
}

/**
  * @brief This function handles Pendable request for system service.
  */
void PendSV_Handler(void)
{
  /* USER CODE BEGIN PendSV_IRQn 0 */

  /* USER CODE END PendSV_IRQn 0 */
  /* USER CODE BEGIN PendSV_IRQn 1 */

  /* USER CODE END PendSV_IRQn 1 */
}

/**
  * @brief This function handles System tick timer.
  */
void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}

/******************************************************************************/
/* STM32F1xx Peripheral Interrupt Handlers                                    */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file (startup_stm32f1xx.s).                    */
/******************************************************************************/

/**
  * @brief This function handles TIM1 update interrupt.
  */
void TIM1_UP_IRQHandler(void)
{
  /* USER CODE BEGIN TIM1_UP_IRQn 0 */

  /* USER CODE END TIM1_UP_IRQn 0 */
  HAL_TIM_IRQHandler(&htim1);
  /* USER CODE BEGIN TIM1_UP_IRQn 1 */

  /* USER CODE END TIM1_UP_IRQn 1 */
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

一、定时器中断实验

1.1 统计单片机上电时间

TIM1 已配置为每秒产生一次更新中断,因此可在周期回调中把 32 位全局变量加一:

volatile uint32_t G_TIM_Count = 0;

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM1)
    {
        G_TIM_Count++;
    }
}

变量单位是“秒”,前提是定时器实际更新周期确实为 1 秒。uint8_t 只能表示 0~255,约 255 秒就会回绕;uint32_t 会在 2^32 秒后回绕,约为 136 年。整数回绕通常不会让单片机“死机”,但会让累计时间从 0 重新开始,所以长时间运行的系统仍应设计溢出处理。

G_TIM_Count 同时被中断和主循环访问,应使用 volatile,避免编译器把主循环看到的值长期缓存在寄存器中。volatile 只保证每次都实际读写内存,不等同于线程安全;本例 Cortex-M3 对对齐的 32 位读写可作为单次访问完成,复杂共享结构仍需要临界区。

1.2 打印单片机上电时间

先用缓冲区格式化,再调用阻塞式串口发送:

uint8_t UART_Buf[200];
int len = snprintf((char *)UART_Buf,
                   sizeof(UART_Buf),
                   "MCU stm32 run time is %lus\r\n",
                   (unsigned long)G_TIM_Count);

if (len > 0)
{
    uint16_t send_len = (len < (int)sizeof(UART_Buf))
                      ? (uint16_t)len
                      : (uint16_t)(sizeof(UART_Buf) - 1U);
    HAL_UART_Transmit(&huart1, UART_Buf, send_len, 1000);
}

snprintfsprintf 多一个缓冲区上限,可避免输出超过 200 字节。若已经正确生成以 '\0' 结尾的字符串,也可用 strlen((char *)UART_Buf) 取得实际长度。不能使用 sizeof(UART_Buf) 作为有效字符串长度,否则会把数组中未使用的尾部字节也发送出去。

HAL_UART_Transmit 是阻塞调用,发送期间 CPU 会等待,因此它应位于主循环,不应放在定时器中断回调中。

1.3 编译并观察效果

若把格式化与发送直接写在 while (1) 中,主循环会以 CPU 和串口允许的最高速度反复打印,并不是每秒打印一次。即使主循环判断:

if ((G_TIM_Count % 5U) == 0U)
{
    printf(...);
}

也仍有逻辑问题:G_TIM_Count 在一整秒内都保持 5、10、15 等值,而主循环在这一秒内会运行成千上万次,于是相同时间会被重复打印。

取余运算只说明“当前秒数能被 5 整除”,不能自动把代码限制为只执行一次。需要检测一次性事件,或使用由中断置位、主循环清零的标志。

1.4 观察效果

重复输出的真实时序如下:

中断时刻:     4s           5s                         6s
G_TIM_Count:   4  ───────── 5  ─────────────────────── 6
主循环判断:                  真 真 真 真 真 ...         假
串口输出:                    连续输出许多次“5s”

定时器仍然只是一秒中断一次;重复打印来自这一秒内主循环多次满足相同条件,不是定时器一秒触发了很多次。解决办法是让 ISR 在目标时刻只产生一个通知。

1.5 更换思路

第一步可以先把“五秒到了”的判断移到定时器回调中:

G_TIM_Count++;
if ((G_TIM_Count % 5U) == 0U)
{
    /* 五秒事件只在这次中断里出现一次 */
}

因为回调每秒只进入一次,所以 5、10、15 秒各命中一次。但不要因此直接在回调里发送串口;判断可以留在 ISR,耗时工作仍交给主循环。

1.6 注释主函数

调试时可以暂时注释主循环里的打印代码,先确认计数和中断判断能正常编译运行。更可靠的验证方式是:

  • 在调试器 Watch 窗口观察 G_TIM_Count
  • 在回调入口设置断点,但不要长时间停住,以免改变系统时序。
  • 临时翻转一个 GPIO,用示波器或逻辑分析仪测量周期。

注释代码只是一种定位手段,最终实现仍应保留“ISR 通知、主循环处理”的完整通路。

1.7 观察效果

如果把打印直接放进回调,确实能得到 5、10、15 秒各一次的表面效果,但阻塞式 UART 会延长 ISR:

TIM1更新中断
  ├─ 秒计数与条件判断       很短
  └─ 格式化 + UART阻塞发送  较慢,不适合ISR

ISR 执行期间,同级或更低优先级中断可能无法及时响应;如果 HAL 超时依赖 SysTick,而当前中断优先级又阻止 SysTick 运行,还可能出现超时计数不前进的问题。因此回调只保留计数、GPIO 和标志操作。

1.8 问题优化

增加一个全局事件标志:

volatile uint8_t G_UART_Flag = 0;

职责划分为:

sequenceDiagram
    participant T as TIM1中断回调
    participant F as G_UART_Flag
    participant M as 主循环
    T->>T: G_TIM_Count++
    T->>F: 到指定秒数时置1
    M->>F: 轮询标志
    F-->>M: 标志为1
    M->>M: printf/HAL_UART_Transmit
    M->>F: 清0

这与操作系统里“快速中断处理 + 延后处理”的思想相似,不过本例没有真正创建两个 Linux 式上下半部,只是用标志把耗时工作移出硬件中断上下文。

1.9 增加变量

全局变量放在用户代码区域,并标明其含义:

volatile uint32_t G_TIM_Count = 0U; /* 上电秒数 */
volatile uint8_t  G_UART_Flag = 0U; /* 串口打印事件 */

uint8_t 足够保存 0/1 标志。变量名应表达用途,避免使用 jy1 等离开课堂上下文后难以理解的名称。

单一标志只能表示“至少发生过一次事件”。如果主循环可能阻塞十几秒,期间多个五秒事件会合并成一次。对不能丢失的事件,应改用递增的待处理计数器、环形队列或 RTOS 消息机制。

1.10 初始化变量

静态存储期的全局变量即使不显式赋值也会被初始化为 0,但写出 = 0U 能让意图更清楚。每次复位后:

G_TIM_Count = 0
G_UART_Flag = 0
TIM1启动后,每次更新中断令 G_TIM_Count 加1

在中断回调中,到达打印时刻只置位:

if ((G_TIM_Count % 5U) == 0U)
{
    G_UART_Flag = 1U;
}

不要在主循环每次迭代开头把标志清零,否则中断刚产生的事件可能在检查前就被覆盖。

1.11 注释之前判断

主循环不再直接根据 G_TIM_Count % 5 判断,而是消费标志:

if (G_UART_Flag == 1U)
{
    G_UART_Flag = 0U;
    printf("MCU stm32 run time is %lus\r\n",
           (unsigned long)G_TIM_Count);
}

先清标志再执行慢速打印,可缩短“旧事件尚未清除”的窗口。如果必须让打印值严格对应产生事件时的 5、10、15,而不是主循环稍后读到的时间,可在 ISR 中把当时的计数值复制到另一个共享变量,再置位标志。

1.12 观察效果

中断与主循环的最终分工如下:

位置适合执行不适合执行
TIM1 回调加计数、置标志、短 GPIO 操作printf、阻塞串口、HAL_Delay、复杂计算
主循环格式化、串口发送、业务处理长时间关中断或无界阻塞

这样既能保证每五秒只产生一次打印事件,也能让中断尽快返回。主循环每消费一次标志就将其清零,为下一次事件做准备。

1.13 观察窗口

调试器 Watch/Expressions 窗口可以同时观察:

G_TIM_Count:每秒递增
G_UART_Flag:目标时刻由0变1,主循环处理后恢复0
TIM1->CNT:在0到9999之间循环
TIM1->SR 的 UIF:更新时置位,HAL中断处理后清除

复位后计数回到 0;启动 TIM1 后约一秒变为 1。调试器暂停 CPU 时,定时器是否继续计数取决于调试冻结配置,所以断点期间的观察结果可能与脱机运行不同。

1.14 加小人化更改

配套最终代码把条件写成:

if ((G_TIM_Count % 5U) == 1U)
{
    G_UART_Flag = 1U;
}

这样输出时刻是 1、6、11、16……秒,而不是 1 秒后再等到 5 秒输出。它提供了更快的首次反馈,但相邻两次输出仍相隔 5 秒。若业务定义要求严格在 5、10、15……秒输出,就应使用 % 5U == 0U,而不是把两种时间序列混称为同一行为。

1.15 让第二个灯每隔两秒翻转一次

在同一个每秒回调中增加:

if ((G_TIM_Count % 2U) == 0U)
{
    HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
}

LED2 在第 2、4、6……秒翻转。由于一次翻转只改变一个状态,灯保持亮 2 秒、再保持灭 2 秒,完整亮灭周期为 4 秒。

LED 板载电路为低电平有效:

3.3 V ── LED ── 1 kΩ ── PE5
                            │
                         GPIO输出级

PE5=0:GPIO灌电流,LED2亮
PE5=1:没有足够压差,LED2灭

这不影响 TogglePin 的时间规律,只会影响哪个逻辑电平对应“亮”。

1.16 问题优化

多个定时器共用 HAL_TIM_PeriodElapsedCallback 时必须区分句柄:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM1)
    {
        /* TIM1任务 */
    }
    else if (htim->Instance == TIM2)
    {
        /* TIM2任务 */
    }
}

不能只因为当前工程只有 TIM1 就永久忽略参数,否则以后增加定时器会让所有分支重复执行。

串口输出可从“snprintf + HAL_UART_Transmit”简化为 printf,但 printf 并不会天然知道要使用哪个 UART,必须实现底层字符输出重定向。

1.17 粘贴内容并更改

常见的 GCC/newlib 重定向方式是在 usart.c 或独立文件中实现 _write

#include <stdio.h>

int _write(int file, char *ptr, int len)
{
    (void)file;

    if (HAL_UART_Transmit(&huart1,
                          (uint8_t *)ptr,
                          (uint16_t)len,
                          1000) == HAL_OK)
    {
        return len;
    }

    return -1;
}

若使用 Keil/Arm Compiler,重定向入口可能是 fputc;应根据当前工具链选择一种实现,不要同时复制多套互相冲突的桩函数。还要确认:

  • huart1 在当前源文件中可见,必要时使用 extern UART_HandleTypeDef huart1;
  • 头文件声明、函数签名和工具链匹配。
  • 重定向函数不在 ISR 中被调用。
  • 量产代码按需要处理超时与返回错误。

1.18 回到主函数里更改

完成重定向后,主循环可直接写:

if (G_UART_Flag == 1U)
{
    G_UART_Flag = 0U;
    printf("MCU stm32 run time is %lus\r\n",
           (unsigned long)G_TIM_Count);
}

配套 06TIM 工程的完整逻辑可以概括为:

volatile uint32_t G_TIM_Count = 0U;
volatile uint8_t G_UART_Flag = 0U;

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM1)
    {
        HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
        G_TIM_Count++;

        if ((G_TIM_Count % 5U) == 1U)
            G_UART_Flag = 1U;

        if ((G_TIM_Count % 2U) == 0U)
            HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
    }
}

/* 初始化完成后 */
HAL_TIM_Base_Start_IT(&htim1);

while (1)
{
    if (G_UART_Flag == 1U)
    {
        G_UART_Flag = 0U;
        printf("MCU stm32 run time is %lus\r\n",
               (unsigned long)G_TIM_Count);
    }
}

编译、烧录并打开串口后,应看到 1、6、11……秒的运行时间;LED1 每秒翻转,LED2 每两秒翻转。若希望输出 5、10、15……秒,只需把打印条件改为 G_TIM_Count % 5U == 0U。整个设计的重点不是某个具体余数,而是“硬件定时器产生稳定节拍,中断快速记录事件,主循环处理耗时任务”。