AT32F403A通用定时器详解与使用方法(第零一讲)

目录

一、简介

二、功能

1.基本结构

2.计数时钟

(1)内部时钟(CK_INT)

(2)外部时钟

外部时钟模式A

外部时钟模式B

内部触发输入

3.计数模式

(1)向上计数模式

(2)向下计数模式

(3)中央双向对齐计数模式

三、编码模式

1.编码模式A

2.编码模式B

3.编码模式C

4.编码模式实例

四、案例 

1.描述

2.步骤

3.代码

4.现象


一、简介

通用定时器(TMR2TMR5)包含一个支持向上向下中央双向对齐计数的16位计数器、4个捕获比较寄存器和4组独立通道。

二、功能

1.基本结构

计数器基本结构 

2.计数时钟

计数时钟可由内部时钟(CK_INT)、外部时钟(外部时钟模式A/B)和内部触发输入(ISx)提供。

(1)内部时钟(CK_INT)

默认使用内部时钟(CK_INT)经预分频器驱动计数器计数,如下图。

选择内部时钟 

使用内部时钟(CK_INT)计数 

(2)外部时钟

外部时钟可分为外部时钟模式A外部时钟模式B内部触发输入

  • 外部时钟模式A
  • 外部时钟模式A框图 

    步骤如下

    ①配置外部时钟源的参数:

    Ⅰ.若选择来源为TMRx_CH1,需配置通道1的输入滤波极性

    Ⅱ.若选择来源为TMRx_CH2,需配置通道2的输入滤波极性

    Ⅲ.若选择来源为TMRx_EXT,需配置外部信号极性分频滤波

    ②设置外部信号的来源:

    Ⅰ.当STIS[2:0] = 3'b100时,选择通道1的上升沿和下降沿信号;

    Ⅱ.当STIS[2:0] = 3'b101时,选择通道1经滤波且极性选择后的信号;

    Ⅲ.当STIS[2:0] = 3'b110时,选择通道2经滤波且极性选择后的信号;

    Ⅳ.当STIS[2:0] = 3'b111时,选择外部输入经极性选择、分频和滤波后的信号。

    注:

     – STIS[2:0]表示‘次定时器输入来源’的第0位到第2位;

     – 3‘b100表示三位二进制100。

    ③使能外部时钟模式A:

    配置‘次定时器模式选择’,即SMSEL[1:0] = 3b'111

    ④设置计数器计数频率:

    配置‘定时器的预分频器’,即TMRx_DIV[15:0]。

    ⑤设置计数器计数周期:

    配置‘定时器的周期寄存器’,即TMRx_PR[15:0]。

    ⑥使能计数器:

    配置‘定时器的控制寄存器1’,即TMRx_CTRL1的TMREN = 1

    使用外部时钟A计数 

  • 外部时钟模式B
  • 外部时钟模式B框图 

    步骤如下

    ①设置外部信号极性、分频和滤波:

    Ⅰ.配置‘次定时器控制寄存器的外部信号极性’,即TMRx_STCTRL的ESP

    Ⅱ.配置‘次定时器控制寄存器的外部信号分频’,即TMRx_STCTRL的ESDIV

    Ⅲ.配置‘次定时器控制寄存器的外部信号滤波’,即TMRx_STCTRL的ESF

    ②使能外部时钟模式B:

    配置‘次定时器控制寄存器的外部时钟模式B’,即TMRx_STCTRL的ECMBEN = 1

    ③设置计数器计数频率:

    配置‘定时器的预分频器’,即TMRx_DIV[15:0]。

    ④设置计数器计数周期:

    配置‘定时器的周期寄存器’,即TMRx_PR[15:0]。

    ⑤使能计数器:

    配置‘定时器的控制寄存器1’,即TMRx_CTRL1的TMREN = 1

    注:外部时钟模式B等效于外部时钟模式A选择EXT信号作为外部时钟源(TRGIN)。

    使用外部时钟模式B计数 

  • 内部触发输入
  • 内部触发是指一个定时器的计数时钟(TMR_CLK)可由另一个定时器输出信号(TRGOUT)提供。

    内部触发输入框图 

    步骤如下

    ①设置计数器计数频率:

    配置‘定时器的预分频器’,即TMRx_DIV[15:0]。

    ②设置计数器计数周期:

    配置‘定时器的周期寄存器’,即TMRx_PR[15:0]。

    ③设置计数器计数模式:

    配置‘定时器控制寄存器1的中央双向对齐计数模式选择’,即TMRx_CTRL1的TWCMSEL[1:0]。

    ④选择内部触发:

    配置‘次定时器控制寄存器的次定时器输入选择’,即TMRx_STCTRL的STIS[2:0]:

    Ⅰ.当STIS[2:0] = 3'b000时,选择输入源0(IS0);

    Ⅱ.当STIS[2:0] = 3'b001时,选择输入源1(IS1);

    Ⅲ.当STIS[2:0] = 3'b010时,选择输入源2(IS2);

    Ⅳ.当STIS[2:0] = 3'b011时,选择输入源3(IS3)。

    例如:当主定时器选TMR2、次定时器选TMR3时,根据下图需配置STIS[2:0] = 3'b001(选择IS1)。

    各定时器的内部触发输入 

    注:如果某款芯片没有相应的定时器(TMRx),则对应的触发信号(ISx)也不存在。 

    ⑤使能外部时钟模式A:

    配置‘次定时器模式选择’,即SMSEL[1:0] = 3b'111。

    ⑥使能计数器:

    配置‘定时器的控制寄存器1’,即TMRx_CTRL1的TMREN = 1

    3.计数模式

    计数模式包括向上、向下和中央双向对齐三种计数模式,可以由定时器控制器1的“中央双向对齐计数模式选择”和“单向对齐计数方向”配置,即TMRx_CTRL1的“TWCMSEL(Two-way count mode selection)”和“OWCDIR(one-way count direction)”。

    ①若TWCMSEL[1:0] = 2b'00且OWCDIR = 0,开启向上计数模式;

    ②若TWCMSEL[1:0] = 2b'00且OWCDIR = 1,开启向下计数模式;

    ③若TWCMSEL[1:0] ≠ 2b'00,开启中央双向对齐计数模式:

    Ⅰ.当TWCMSEL[1:0] = 2b'01,CxIF(捕获比较中断标志位)仅在向上计数时置起;

    Ⅱ.当TWCMSEL[1:0] = 2b'10,CxIF(捕获比较中断标志位)仅在向下计数时置起;

    Ⅲ.当TWCMSEL[1:0] = 2b'11,CxIF(捕获比较中断标志位)在向上和向下计数时都置起;

    注:中央双向对齐计数模式时,OWCDIR为只读位,用于查看计数器的计数方向

    (1)向上计数模式

    向上计数模式(TMR_PR = 0x32) 

    计数器向上计数:

    当计数值达到TMR_PR时,计数器向上溢出并产生溢出事件,同时OVFIF(溢出中断标志)置1,之后从0开始向上计数 。

    (2)向下计数模式

    向下计数模式(TMR_PR = 0x32)

    计数器向下计数:

    当计数值达到0时,计数器向下溢出并产生溢出事件,同时OVFIF(溢出中断标志)置1,之后从TMR_PR开始向下计数。

    (3)中央双向对齐计数模式

    中央双向对齐计数模式(TMR_PR = 0x32)

    计数器交替向上、向下计数 :

    当计数值达到TMR_PR-1时,计数器向上溢出并产生溢出事件,同时OVFIF(溢出中断标志)置1,之后从TMR_PR开始向下计数;

    当计数值达到1时,计数器向下溢出并产生溢出事件,同时OVFIF(溢出中断标志)置1,之后从0开始向上计数。

    三、编码模式

    编码模式需要提供两组输入信号TMRx_CH1和TMRx_CH2,根据一组信号的电平值,在另一组信号的边沿向上或者向下计数,计数方向由OWCDIR指示。 

    编码模式结构图 

    1.编码模式A

    需配置“次定时器模式选择”,即SMSEL[1:0] = 3b'001,计数器在C1IFP1边沿(上升沿和下降沿)计数,计数方向由C1IFP1的边沿方向和C2IFP2的电平高低共同决定。

    编码模式A的计数方向(计数边沿为
    C1IFP1
    C1IFP1为上升沿 C1IFP1为下降沿
    C2IFP2为高电平 向下计数 向上计数
    C2IFP2为低电平 向上计数 向下计数

    2.编码模式B

    需配置“次定时器模式选择”,即SMSEL[1:0] = 3b'010,计数器在C2IFP2边沿(上升沿和下降沿)计数,计数方向由C2IFP2的边沿方向和C1IFP1的电平高低共同决定。

    编码模式B的计数方向(计数边沿为
    C2IFP2
    C2IFP2为上升沿 C2IFP2为下降沿
    C1IFP1为高电平 向上计数 向下计数
    C1IFP1为低电平 向下计数 向上计数

    3.编码模式C

    需配置“次定时器模式选择”,即SMSEL[1:0] = 3b'011,计数器在C1IFP1和C2IFP2边沿(上升沿和下降沿)计数,计数方向由C1IFP1和C2IFP2的边沿方向、C1IFP1和C2IFP2的电平高低共同决定。

    编码模式C的计数方向(计数边沿为
    C1IFP1

    C2IFP2
    C1IFP1为上升沿 C1IFP1为下降沿 C2IFP2为上升沿 C2IFP2为下降沿
    相对信号为高电平 向下计数 向上计数 向上计数 向下计数
    相对信号为低电平 向上计数 向下计数 向下计数 向上计数

    注:

     – C1IFP1的相对信号为C2IFP2;

     – C2IFP2的相对信号为C1IFP1。

    4.编码模式实例

    编码模式C 

    如上图,编码模式C下:

    ①当C1IRAW为上升沿且C2IRAW为低电平时,计数器向上计一个数(COUNTER = 0x20);

    ②当C2IRAW为上升沿且C1IRAW为高电平时,计数器向上计一个数(COUNTER = 0x21);

    ③当C1IRAW为下降沿且C2IRAW为高电平时,计数器向上计一个数(COUNTER = 0x22);

    ④当C2IRAW为下降沿且C1IRAW为低电平时,计数器向上计一个数(COUNTER = 0x23);

    ……

    即COUNTER每过一个周期会计4个数。

    注:

    C1IRAW为通道1预处理的信号;

    C2IRAW为通道2预处理的信号;

    四、案例 

    1.描述

    使用TMR2的编码模式C,PA2和PA3模拟编码信号,PA2输出方波到PA0(TMR2_CH1),PA3输出方波到PA1(TMR2_CH2),在调试窗口(DEBUG)中观察,每过一轮循环,计数值加4

    2.步骤

    ①打开WorkBench,选择对应的型号,以AT32F403A为例新建工程;

    ②启用TMR2,选择编码器模式

    ③选择编码器模式C

    ④选择任意端口作为输出,以PA2和PA3为例;

    ⑤配置PA2和PA3;

    ⑥代码预览;

     ⑦生成代码并编译,打开main.c,右击“wk_tmr2_init()”跳转,将定时器使能的语句“ tmr_counter_enable(TMR2, TRUE);”剪切到main.c的“while(1)”之前;

    ⑧在main.c中右击“wk_gpio_config()”跳转,将端口设置的语句“gpio_bits_set(GPIOA, GPIO_PINS_2 | GPIO_PINS_3);”剪切到main.c的“while(1)”之中;

    ⑨定义一个变量,以counter为例,并添加delay函数,将main.c的主函数修改为下图;

    3.代码

    main.c

    #include "at32f403a_407_wk_config.h"
    void delay(uint32_t time)
    uint32_t counter;
    
    void delay(uint32_t time)
    {
      uint32_t i;
      for(i = 0; i < time; i++);
    }
    
    int main(void)
    {
      wk_system_clock_config();
      wk_periph_clock_config();
      wk_nvic_config();
      wk_tmr2_init();
      wk_gpio_config();
      tmr_counter_enable(TMR2, TRUE);
      while(1)
      {
        /**  产生编码信号  **/
        gpio_bits_set(GPIOA, GPIO_PIINS_2);
        delay(150);
        gpio_bits_set(GPIOA, GPIO_PIINS_3);
        delay(150);
        gpio_bits_reset(GPIOA, GPIO_PIINS_2);
        delay(150);
        gpio_bits_reset(GPIOA, GPIO_PIINS_3);
        delay(150);
        /**  获取计数值  **/
        counter = tmr_counter_value_get(TMR2);
      }
    }

     at32f403a_407_wk_config.c

    #include "at32f403a_407_wk_config.h"
    
    void wk_system_clock_config(void)
    {
      crm_reset();
      crm_clock_source_enable(CRM_CLOCK_SOURCE_LICK, TRUE);
      while(crm_flag_get(CRM_LICK_STABLE_FLAG) != SET)
      {
      }
      crm_clock_source_enable(CRM_CLOCK_SOURCE_HICK, TRUE);
    
      while(crm_flag_get(CRM_HICK_STABLE_FLAG) != SET)
      {
      }
    
      crm_pll_config(CRM_PLL_SOURCE_HICK, CRM_PLL_MULT_60, CRM_PLL_OUTPUT_RANGE_GT72MHZ);
      crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE);
      while(crm_flag_get(CRM_PLL_STABLE_FLAG) != SET)
      {
      }
      crm_ahb_div_set(CRM_AHB_DIV_1);
      crm_apb2_div_set(CRM_APB2_DIV_2);
      crm_apb1_div_set(CRM_APB1_DIV_2);
      crm_auto_step_mode_enable(TRUE);
      crm_sysclk_switch(CRM_SCLK_PLL);
      while(crm_sysclk_switch_status_get() != CRM_SCLK_PLL)
      {
      }
      crm_auto_step_mode_enable(FALSE);
      system_core_clock_update();
    }
    
    void wk_periph_clock_config(void)
    {
      crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
      crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
      crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
      crm_periph_clock_enable(CRM_TMR2_PERIPH_CLOCK, TRUE);
    }
    
    void wk_nvic_config(void)
    {
      nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
    }
    
    void wk_gpio_config(void)
    {
      gpio_init_type gpio_init_struct;
      gpio_default_para_init(&gpio_init_struct);
    
      //gpio_bits_set(GPIOA, GPIO_PINS_2 | GPIO_PINS_3);这里需要注释掉或者删除
    
      gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
      gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
      gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
      gpio_init_struct.gpio_pins = GPIO_PINS_2 | GPIO_PINS_3;
      gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
      gpio_init(GPIOA, &gpio_init_struct);
    }
    
    void wk_tmr2_init(void)
    {
      gpio_init_type gpio_init_struct;
      tmr_input_config_type  tmr_input_struct;
      gpio_default_para_init(&gpio_init_struct);
    
      gpio_init_struct.gpio_pins = GPIO_PINS_0;
      gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
      gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
      gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
      gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
      gpio_init(GPIOA, &gpio_init_struct);
    
      gpio_init_struct.gpio_pins = GPIO_PINS_1;
      gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
      gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
      gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
      gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
      gpio_init(GPIOA, &gpio_init_struct);
    
      tmr_base_init(TMR2, 65535, 0);
      tmr_cnt_dir_set(TMR2, TMR_COUNT_UP);
      tmr_clock_source_div_set(TMR2, TMR_CLOCK_DIV1);
      tmr_period_buffer_enable(TMR2, FALSE);
    
      tmr_sub_sync_mode_set(TMR2, FALSE);
      tmr_primary_mode_select(TMR2, TMR_PRIMARY_SEL_RESET);
    
      tmr_input_struct.input_channel_select = TMR_SELECT_CHANNEL_1;
      tmr_input_struct.input_mapped_select = TMR_CC_CHANNEL_MAPPED_DIRECT;
      tmr_input_struct.input_polarity_select = TMR_INPUT_RISING_EDGE;
      tmr_input_struct.input_filter_value = 0;
      tmr_input_channel_init(TMR2, &tmr_input_struct, TMR_CHANNEL_INPUT_DIV_1);
    
      tmr_input_struct.input_channel_select = TMR_SELECT_CHANNEL_2;
      tmr_input_struct.input_mapped_select = TMR_CC_CHANNEL_MAPPED_DIRECT;
      tmr_input_struct.input_polarity_select = TMR_INPUT_RISING_EDGE;
      tmr_input_struct.input_filter_value = 0;
      tmr_input_channel_init(TMR2, &tmr_input_struct, TMR_CHANNEL_INPUT_DIV_1);
    
      tmr_encoder_mode_config(TMR2, TMR_ENCODER_MODE_A, TMR_INPUT_RISING_EDGE, TMR_INPUT_RISING_EDGE);
    
      //tmr_counter_enable(TMR2, TRUE);这里需要剪切到mian.c中
    }
    

    4.现象

    硬件操作:PA0与PA2连接,PA1与PA3连接。

    实验结果:打开调试窗口(DEBUG),将变量“counter”添加到watch1中,单步运行,每过一个“while(1)”循环,计数值(变量counter)增加4


    参考资料:
    《RM_AT32F403A_407_CH_V2.06》的14.2通用定时器(TMR2到TMR5)​编辑 网页链接

    作者:張良嗣

    物联沃分享整理
    物联沃-IOTWORD物联网 » AT32F403A通用定时器详解与使用方法(第零一讲)

    发表回复