用户工具

站点工具


通用定时器实验_定时点亮led
银杏科技有限公司旗下技术文档发布平台
技术支持电话0379-69926675-801
技术支持邮件Gingko@vip.163.com
版本 日期 作者 修改内容
V1.0 2020-07-04 gingko 初次建立

实验十二:通用定时器实验——定时点亮LED

一、 实验目的与意义

  1. 了解STM32 TIMER结构。
  2. 了解STM32 TIMER特征。
  3. 掌握通用定时器的使用方法。
  4. 掌握STM32 HAL库中TIMER属性的配置方法。
  5. 掌握KEIL MDK 集成开发环境使用方法。

二、 实验设备及平台

  1. iCore4 双核心板点击购买
  2. JLINK(或相同功能)仿真器点击购买
  3. Micro USB线缆。
  4. Keil MDK 开发平台。
  5. STM32CubeMX开发平台。
  6. 装有WIN XP(及更高版本)系统的计算机。

三、 实验原理

1、用定时器简介

  • STM32F767的通用定时器包含一个16位或32位自动重载计数器(CNT),该计数器由可编程预分频器(PSC)驱动。STM32F767的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)等。使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32F767的每个通用定时器都是完全独立的,没有互相共享的任何资源。
  • STM32的通用TIMx(TIM2~TIM5和TIM9~TIM14)定时器功能包括:
    • (1)16位/32位(仅TIM2和TIM5)向上、向下、向上/向下自动装载计数(TIMx_CNT),注意:TIM9~TIM14只支持向上(递增)计数方式。
    • (2)16位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为1~65535之间的任意数值。
    • (3)4个独立通道(TIMx_CH1~4,TIM9~TIM14最多2个通道),这些通道可以用来作为:
      • A.输入捕获
      • B.输出比较
      • C.PWM生成(边缘或中间对齐模式),注意:TIM9~TIM14不支持中间对齐模式
      • D.单脉冲模式输出
    • (4)可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用1个定时器控制另外一个定时器)的同步电路。
    • (5)如下事件发生时产生中断/DMA(TIM9~TIM14不支持DMA):
      • A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
      • B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
      • C.输入捕获
      • D.输出比较
      • E.支持针对定位的增量(正交)编码器和霍尔传感器电路(TIM9~TIM14不支持)
      • F.触发输入作为外部时钟或者按周期的电流管理(TIM9~TIM14不支持)

2、时基单元

  • 可编程定时器的主要模块由一个16位/32位计数器及其相关的自动重装寄存器组成。计数器可递增计数、递减计数或同时递增和递减计数。计数器的时钟可通过预分频器进行分频。计数器、自动重载寄存器和预分频器寄存器可通过软件进行读写。即使在计数器运行时也可执行读写操作。
  • 时基单元包括:
    •  计数器寄存器(TIMx_CNT)
    •  预分频器寄存器(TIMx_PSC)
    •  自动重载寄存器(TIMx_ARR)
  • 自动重载寄存器是预装载的。对自动重载寄存器执行写入或读取操作时会访问预装载寄存器。预装载寄存器的内容既可以直接传送到影子寄存器,也可以在每次发生更新事件(UEV)时传送到影子寄存器,这取决于TIMx_CR1寄存器中的自动重载预装载使能位(ARPE)。当计数器达到上溢值(或者在递减计数时达到下溢值)并且TIMx_CR1寄存器中的UDIS位为0时,将发送更新事件。该更新事件也可由软件产生。计数器由预分频器输出CK_CNT提供时钟,仅当TIMx_CR1寄存器中的计数器启动位(CEN)置1时,才会启动计数器。注意,实际的计数器使能信号CNT_EN在CEN置1的一个时钟周期后被置1。

3、相关寄存器

  • (1)控制寄存器1(TIMx_CR1),该寄存器的各位描述如图所示:

  • 在本实验中,我们只用到了TIMx_CR1的最低位,也就是计数器使能位,该位必须置 1,才能让定时器开始计数。
  • (2)DMA/中断使能寄存器(TIMx_DIER),该寄存器是一个16位的寄存器,其各位描述如图所示:

  • 这里我们同样仅关心它的第0位,该位是更新中断允许位,实验中用到的是定时器的更新中断,所以该位要设置为1,来允许由于更新事件所产生的中断。
  • (3)预分频寄存器(TIMx_PSC)。该寄存器用来设置对时钟进行分频,然后提供给计数器,作为计数器的时钟。该寄存器的各位描述如图所示:

  • 这里,定时器的时钟来源有4个:
    •  内部时钟(CK_INT)
    •  外部时钟模式1:外部输入脚(TIx)
    •  外部时钟模式2:外部触发输入(ETR),仅适用于TIM2、TIM3、TIM4
    •  内部触发输入(ITRx):使用A定时器作为B定时器的预分频器(A为B提供时钟)。
  • 这些时钟,具体选择哪个可以通过TIMx_SMCR寄存器的相关位来设置。这里的CK_INT时钟是从APB1倍频的来的,除非APB1的时钟分频数设置为1(一般都不会是1),否则通用定时器TIMx的时钟是APB1时钟的2倍,当APB1的时钟不分频的时候,通用定时器TIMx的时钟就等于APB1的时钟。这里还要注意的就是高级定时器以及TIM9~TIM11的时钟不是来自APB1,而是来自APB2的。
  • (4)自动重装载寄存器(TIMx_ARR),该寄存器在物理上实际对应着2个寄存器。一个是程序员可以直接操作的,另外一个是程序员看不到的,这个看不到的寄存器在《STM32F7中文参考手册》里面被叫做影子寄存器。事实上真正起作用的是影子寄存器。根据TIMx_CR1寄存器中APRE位的设置:APRE=0时,预装载寄存器的内容可以随时传送到影子寄存器,此时2者是连通的;而APRE=1时,在每一次更新事件(UEV)时,才把预装载寄存器(ARR)的内容传送到影子寄存器。自动重装载寄存器的各位描述如图所示:

  • (5)状态寄存器(TIMx_SR),该寄存器用来标记当前与定时器相关的各种事件/中断是否发生。该寄存器的各位描述如图所示:

  • 只要对以上几个寄存器进行简单的设置,我们就可以使用通用定时器了,并且可以产生中断。
  • 本实验中,通过STM32的三个GPIO口来驱动LED灯的三个通道,设定GPIO为推挽输出模式,采用灌电流的方式与LED连接,输出高电平LED灭,输出低电平LED亮,通过通用定时器TIM3实现500ms定时,每500ms变换一次LED颜色。

四、 实验程序

1、主函数

int main(void)
{
    system_clock.initialize();//初始化系统时钟
    led.initialize();         //LED初始化
    timer3.initialize();      //timer3初始化 
 
    while(1);
}
 

2、定时器初始化

static int initialize(void)
{
  //定时1s
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 21599; //预分频系数
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP; //向上计数模式
  htim3.Init.Period = 4999;   //自动装载值
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //时钟分频因子
  htim3.Init.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE;//自动装载使能
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK) //初始化定时器参数
  {
    while(1);
  }
  //使能定时器更新中断和使能定时器
  HAL_TIM_Base_Start_IT(&htim3);
  return 0;
}
 
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
{
  /* 检查参数 */
  assert_param(IS_TIM_INSTANCE(htim->Instance));
  /* 使能定时器更新中断 */
  __HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);
  /* 使能外围设备 */
  __HAL_TIM_ENABLE(htim);
  /* 返回函数状态*/
  return HAL_OK;
}
 

3、TIM3中断优先级设置

  • HAL中定时器使能是通过宏定义标识符来实现对相关寄存器操作的。在定时器中断使能之后,因为要产生中断,必不可少的要设置 NVIC 相关寄存器,设置中断优先级。和串口等其他外设一样, HAL库为定时器初始化定义了回调函数 HAL_TIM_Base_MspInit。一般情况下,与MCU有关的时钟使能,以及中断优先级配置我们都会放在该回调函数内部。
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
  if(tim_baseHandle->Instance==TIM3)
  {
    /* TIM3时钟使能 */
    __HAL_RCC_TIM3_CLK_ENABLE();
 
    /* 初始化中断 */
    HAL_NVIC_SetPriority(TIM3_IRQn, 1, 3);//设置中断优先级
    HAL_NVIC_EnableIRQ(TIM3_IRQn);//开启中断
  }
}

4、中断服务函数

  • 我们通过重写中断回调函数,来处理定时器产生的相关中断。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    static int counter = 0;
 
    if(counter % 3 == 0){
        LED_RED_ON;
        LED_BLUE_OFF;
        LED_GREEN_OFF;
    }else if(counter % 3 == 1){
        LED_RED_OFF;
        LED_BLUE_ON;
        LED_GREEN_OFF;
    }else if(counter % 3 == 2){
        LED_RED_OFF;
        LED_BLUE_OFF;
        LED_GREEN_ON;
    }
    counter ++;
}

五、 实验步骤

  1. 把仿真器与iCore4的SWD调试口相连(直接相连或者通过转接器相连);
  2. 把iCore4通过Micro USB线与计算机相连,为iCore4供电;
  3. 打开Keil MDK 开发环境,并打开本实验工程;
  4. 烧写程序到iCore4上;
  5. 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。

六、 实验现象

  • 三色LED每隔1s循环点亮。
通用定时器实验_定时点亮led.txt · 最后更改: 2022/03/22 10:19 由 sean