STM32F1与STM32CubeIDE快速入门-定时器计数模式
定时器计数模式
1、定时器计数模式介绍
在计数器模式下,定时器模块从外部源(定时器输入引脚)获得时钟。 因此定时器在外部输入的每个上升沿或下降沿向上或向下计数。 当需要在不轮询输入引脚或定期读取 GPIO 或连续中断 CPU(如果选择将其连接到 EXTI 引脚)的情况下实现数字计数器时,这种模式在许多情况下非常有用。
实际上可以监视每个时间间隔的计数器值差异,以了解确实发生了多少个脉冲或其频率。 这种模式在很多情况下都是有利的。
正如我们在之前的文章中所讨论的,定时器模块可以在计数器模式下运行。 定时器从外部源(输入引脚)获得时钟并计算脉冲数。 但是,STM32 定时器模块对于计数模式本身确实有多种模式。

1)递增计数(Up-Counting)模式
在向上计数模式下,计数器从 0 计数到自动重载值(TIMx_ARR 寄存器的内容),然后从 0 重新开始并产生计数器溢出事件。 可以在每次计数器溢出时或通过设置 TIMx_EGR 寄存器中的 UG 位(通过软件或使用从模式控制器)生成更新事件。
2)递减计数( Down-counting)模式
在向下计数模式下,计数器从自动重载值(TIMx_ARR 寄存器的内容)向下计数到 0,然后从自动重载值重新开始并产生计数器下溢事件。 可以在每次计数器下溢时或通过设置 TIMx_EGR 寄存器中的 UG 位(通过软件或使用从模式控制器)生成更新事件。
3)中心对齐模式(上/下)
在中心对齐模式下,计数器从 0 计数到自动重载值(TIMx_ARR 寄存器的内容)- 1,产生计数器溢出事件,然后从自动重载值向下计数到 1 并产生计数器下溢 事件。 然后从 0 重新开始计数。在这种模式下,不能写入方向位(来自 TIMx_CR1 寄存器的 DIR)。 它由硬件更新并给出计数器的当前方向。
2、定时器计数模式配置
第一步、创建工程:

第二步、选择芯片:

第三步、配置系统时钟


第三步、配置定时器
1)配置TIM2功能

2)配置TIM2中断

第四步、配置串口

串口通信具体配置请参考:USART/UART串口通信
第五步、开启系统调试

保存配置并生成代码。
3、生成代码及功能实现
配置工程生成的代码如下:
1)定时器TIM2初始化
在main.c文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| /\*\* \* @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_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0};
/\* USER CODE BEGIN TIM2\_Init 1 \*/
/\* USER CODE END TIM2\_Init 1 \*/ htim2.Instance = TIM2; htim2.Init.Prescaler = 0; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 20; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL\_TIM\_Base\_Init(&htim2) != HAL_OK) { Error\_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_ETRMODE2; sClockSourceConfig.ClockPolarity = TIM_CLOCKPOLARITY_NONINVERTED; sClockSourceConfig.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1; sClockSourceConfig.ClockFilter = 15; if (HAL\_TIM\_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) { Error\_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL\_TIMEx\_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error\_Handler(); } /\* USER CODE BEGIN TIM2\_Init 2 \*/
/\* USER CODE END TIM2\_Init 2 \*/
}
|
2)定时器TIM2中断开启
在main.c文件中
1 2 3 4 5 6 7 8 9 10 11
| /\*\* \* @brief NVIC Configuration. \* @retval None \*/ static void MX\_NVIC\_Init(void) { /\* TIM2\_IRQn interrupt configuration \*/ HAL\_NVIC\_SetPriority(TIM2_IRQn, 0, 0); HAL\_NVIC\_EnableIRQ(TIM2_IRQn); }
|
3)串口UART1初始化
在main.c文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| /\*\* \* @brief USART1 Initialization Function \* @param None \* @retval None \*/ static 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 \*/
}
|
4)定时器TIM2中断处理
在stm32f1xx_it.c文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| /\*\* \* @brief This function handles TIM2 global interrupt. \*/ void TIM2\_IRQHandler(void) { /\* USER CODE BEGIN TIM2\_IRQn 0 \*/
/\* USER CODE END TIM2\_IRQn 0 \*/ HAL\_TIM\_IRQHandler(&htim2); /\* USER CODE BEGIN TIM2\_IRQn 1 \*/
/\* USER CODE END TIM2\_IRQn 1 \*/ }
|
5)定时器TIM2中断回调处理实现
在stm32f1xx_it.c文件中添加如下代码:
1 2 3 4 5 6 7 8 9
| /\* USER CODE BEGIN 1 \*/ // Counter Overflow ISR Handler void HAL\_TIM\_PeriodElapsedCallback(TIM_HandleTypeDef \*htim) { if (htim->Instance == TIM2) { HAL\_UART\_Transmit(&huart1, END_MSG, sizeof(END_MSG), 100); } } /\* USER CODE END 1 \*/
|
6)主程序入口
在main.c文件中添加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| /\* Private typedef -----------------------------------------------------------\*/ /\* USER CODE BEGIN PTD \*/ uint8_t MSG[20] = { '\0' }; uint16_t CounterTicks = 0; uint8_t END_MSG[35] = "Overflow Reached! Counter Reset!\n\r"; uint8_t RX_Buffer[1]; const uint8_t __r_chr[] = { '\r' }; /\* USER CODE END PTD \*/ /\*\* \* @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\_TIM2\_Init(); MX\_USART1\_UART\_Init();
/\* Initialize interrupts \*/ MX\_NVIC\_Init(); /\* USER CODE BEGIN 2 \*/ HAL\_TIM\_Base\_Start\_IT(&htim2); /\* USER CODE END 2 \*/
/\* Infinite loop \*/ /\* USER CODE BEGIN WHILE \*/ printf("Timer Counter Demo\n"); while (1) { /\* USER CODE END WHILE \*/
/\* USER CODE BEGIN 3 \*/ // Read The Counter Ticks Register CounterTicks = TIM2->CNT; // Print The Ticks Count Via UART1 sprintf(MSG, "Ticks = %d\n\r", CounterTicks); HAL\_UART\_Transmit(&huart1, MSG, sizeof(MSG), 100); HAL\_Delay(100); } /\* USER CODE END 3 \*/ }
|
4、程序运行结果

文章来源: https://iotsmart.blog.csdn.net/article/details/123305266
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!