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