STM32 基本定时器实验

1、基本定时器简介

在这里插入图片描述

  1. 时钟源
    时钟挂载在APB1总线下,中间有一个倍频器,sys_stm32_clock_init时钟已经设置APB1总线时钟频率为36M,预分频器分频系数为2,所以挂载在APB1总线的定时器时钟频率为72Mhz,图中对应的时钟信号为CK_INT。
  2. 控制器
    能够控制定时器复位、使能、计数,还能触发DAC转换。
  3. 时基单元
    时基单元包括:计数器寄存器、预分频寄存器、自动重载寄存器。预分频寄存器的输入来源于CK_PSC,也就是CK_INT,输出为CK_CNT,CK_CNT是通过预分频器分频后的信号。预分频寄存器和自动重载寄存器都有影子寄存器,影子寄存器就是当写入新的值的时候,这个值不会直接写进影子寄存器,会在寄存器中缓冲,在下一个更新事件出现的时候,才会写入,区别在于自动重载寄存器是否有缓冲作用还受到ARPE位控制。
  4. 更新事件
    一由软件产生,将TIMx_EGR寄存器的位UG置1,产生更新事件后,硬件会自动将UG位清零。
    二由硬件产生,当计数器的值等于自动重装载寄存器影子寄存器的值时。

2、寄存器

  • 控制寄存器(TIMx_CR1)

在这里插入图片描述

  • DMA/中断使能寄存器(TIMx_DIER) 位0控制使能或者禁止更新中断
  • 状态寄存器(TIMx_SR) 位0是中断更新的标志位,需要软件清零
  • 计数器寄存器(TIMx_CNT) [15:0]计数器的实时计数值
  • 预分频寄存器(TIMx_PSC) [15:0]预分频数值
  • 自动重载寄存器(TIMx_ARR) [15:0]自动重载数值

3、硬件

(1)功能
LED0用来指示程序运行,每200ms翻转一次。我们在更新中断中,将LED1的状态取反。 LED1用于指示定时器发生更新事件的频率,500ms取反一次
(2)资源
LED0-PB5
LED1-PE5
定时器

4、程序设计

定时器中断配置步骤
1)定时器时钟使能
__HAL_RCC_TIMx_CLK_ENABLE()
2) 初始化定时器参数,设置自动重装值,分频系数,计数方式
使用HAL_TIM_Base_Init(),传入TIM_HandleTypeDef类型结构体
3)使能定时器更新中断,开启定时器计数,配置定时器中断优先级
通过HAL_TIM_Base_Start_IT函数使能定时器更新中断和开启定时器计数
在HAL_TIM_Base_Init()函数中的HAL_TIM_Base_MspInit()函数中通过HAL_NVIC_EnableIRQ函数使能定时器中断,通过HAL_NVIC_SetPriority函数设置中断优先级
4)编写终端服务函数
编写BTIM_TIMX_INT_IRQHandler函数,调用公共接口HAL_TIM_IRQHandler,再编写回调函数,实现LED1翻转功能。

TIM_HandleTypeDef g_timx_handle;  /* 定时器句柄 */
//初始化基本定时器
void btim_timx_int_init(uint16_t arr, uint16_t psc)
{
    g_timx_handle.Instance = BTIM_TIMX_INT;                      /* 通用定时器X */
    g_timx_handle.Init.Prescaler = psc;                          /* 设置预分频系数 */
    g_timx_handle.Init.CounterMode = TIM_COUNTERMODE_UP;         /* 递增计数模式 */
    g_timx_handle.Init.Period = arr;                             /* 自动装载值 */
    HAL_TIM_Base_Init(&g_timx_handle);         /*这个函数里会调用HAL_TIM_Base_MspInit*/

    HAL_TIM_Base_Start_IT(&g_timx_handle);    /* 使能定时器x及其更新中断 */
}
//初始化定时器底层驱动
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == BTIM_TIMX_INT)
    {
        BTIM_TIMX_INT_CLK_ENABLE();                     /* 使能TIM时钟 */
        HAL_NVIC_SetPriority(BTIM_TIMX_INT_IRQn, 1, 3); /* 抢占1,子优先级3,组2 */
        HAL_NVIC_EnableIRQ(BTIM_TIMX_INT_IRQn);         /* 开启ITM3中断 */
    }
}
//定时器中断服务函数
void BTIM_TIMX_INT_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&g_timx_handle); /* 定时器中断公共处理函数 */
}
//这个函数将会被定时器中断公共处理函数调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == BTIM_TIMX_INT)
    {
        LED1_TOGGLE(); /* LED1反转 */
    }
}

完成驱动文件后,main函数如下

int main(void)
{
    HAL_Init();                             /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    delay_init(72);                         /* 延时初始化 */
    usart_init(115200);                     /* 串口初始化为115200 */
    led_init();                             /* 初始化LED */
    btim_timx_int_init(5000 - 1, 7200 - 1); /* 10Khz的计数频率,计数5K次为500ms */

    while (1)
    {
        LED0_TOGGLE();            /*LED灯翻转*/
        delay_ms(200);
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面介绍 STM32F10x 实现基本定时器实验的步骤。 ### 1. 硬件连接 将 STM32F10x 系列单片机定时器外设与外部 LED 灯相连,例如将 PA0 引脚连接到 LED 正极,将 GND 引脚连接到 LED 负极。 ### 2. 创建工程 使用 Keil 或者其他开发工具创建一个 STM32F10x 工程,并选择对应的芯片型号。 ### 3. 配置时钟 在 `main()` 函数中调用 `SystemClock_Config()` 函数配置系统时钟。例如,如果你想将系统时钟配置为 72MHz,可以按照以下代码进行配置: ```c static void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; 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(); } 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(); } } ``` ### 4. 初始化定时器 在 `main()` 函数中,首先需要初始化定时器外设,例如: ```c TIM_HandleTypeDef htim; void TIM_Config(void) { TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; htim.Instance = TIM1; htim.Init.Prescaler = 7199; // 定时器时钟预分频值 htim.Init.CounterMode = TIM_COUNTERMODE_UP; htim.Init.Period = 999; // 定时器周期为 1 秒 htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&htim); sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; HAL_TIM_ConfigClockSource(&htim, &sClockSourceConfig); sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; HAL_TIMEx_MasterConfigSynchronization(&htim, &sMasterConfig); } ``` 在上面的代码中,我们使用了 TIM1 定时器,配置了时钟预分频值为 7199,定时器周期为 1 秒。 ### 5. 启动定时器 在 `main()` 函数中,调用 `TIM_Config()` 函数初始化定时器,并调用 `HAL_TIM_Base_Start_IT(&htim)` 函数启动定时器并开启定时器中断。 ```c int main(void) { HAL_Init(); SystemClock_Config(); TIM_Config(); // 配置定时器 HAL_TIM_Base_Start_IT(&htim); // 启动定时器并开启定时器中断 while (1) { // 循环执行其他代码 } } ``` ### 6. 中断处理函数 在 `stm32f10x_it.c` 文件中实现定时器中断处理函数,并在其中控制 LED 灯的亮灭。例如,以下代码实现了每隔 1 秒钟交替点亮和熄灭 LED 灯的功能: ```c #include "stm32f10x_it.h" void TIM1_UP_IRQHandler(void) { HAL_TIM_IRQHandler(&htim); // 调用 HAL 库中的定时器中断处理函数 } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM1) // 判断是哪个定时器中断 { static uint8_t state = 0; // LED 灯状态,0 表示熄灭,1 表示点亮 if (state) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // 熄灭 LED state = 0; } else { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // 点亮 LED state = 1; } } } ``` 在上面的代码中,我们在 `HAL_TIM_PeriodElapsedCallback()` 函数中判断定时器中断是哪个定时器,并在其中交替点亮和熄灭 LED 灯。 至此,STM32F10x 实现基本定时器实验的步骤就介绍完毕了。需要注意的是,如果你使用的是其他的定时器外设,具体的步骤和代码会有所不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值