打印
[AT32F403/403A]

AT32学习记录——通用定时器(一)

[复制链接]
1416|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zexin|  楼主 | 2024-8-9 18:02 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 zexin 于 2024-8-13 08:59 编辑

AT32F403A通用定时器(一)
一、简介
通用定时器(TMR2TMR5)包含一个支持向上向下中央双向对齐计数的16计数器、4个捕获比较寄存器和4组独立通道。
二、功能
1. 计数时钟
计数时钟可由内部时钟CK_INT)、外部时钟(外部时钟模式A/B)和内部触发输入ISx)提供。
1) 内部时钟
默认使用内部时钟CK_INT)经预分频器驱动计数器计数,如下图。
2) 外部时钟
l 外部时钟模式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_CTRL1TMREN = 1
l 外部时钟模式B

步骤如下
①设置外部信号极性分频滤波
.配置次定时器控制寄存器的外部信号极性,即TMRx_STCTRLESP
.配置次定时器控制寄存器的外部信号分频,即TMRx_STCTRLESDIV
.配置次定时器控制寄存器的外部信号滤波,即TMRx_STCTRLESF
②使能外部时钟模式B
配置‘次定时器控制寄存器的外部时钟模式B’,即TMRx_STCTRLECMBEN = 1
③设置计数器计数频率
配置‘定时器的预分频器’,即TMRx_DIV[15:0]
④设置计数器计数周期
配置‘定时器的周期寄存器’,即TMRx_PR[15:0]
⑤使能计数器:
配置‘定时器的控制寄存器1’,即TMRx_CTRL1TMREN = 1
注:外部时钟模式B等效于外部时钟模式A选择EXT信号作为外部时钟源(TRGIN)。
l 内部触发输入
内部触发是指一个定时器的计数时钟(TMR_CLK)可由另一个定时器的输出信号(TRGOUT)提供
步骤如下
①设置计数器计数频率
配置‘定时器的预分频器’,即TMRx_DIV[15:0]
②设置计数器计数周期
配置‘定时器的周期寄存器’,即TMRx_PR[15:0]
③设置计数器计数模式
配置‘定时器控制寄存器1的中央双向对齐计数模式选择,即TMRx_CTRL1TWCMSEL[1:0]
④选择内部触发:
配置‘次定时器控制寄存器的次定时器输入选择’,即TMRx_STCTRLSTIS[2:0]
.STIS[2:0] =3'b000时,选择输入源0IS0);
.STIS[2:0] =3'b001时,选择输入源1IS1);
.STIS[2:0] =3'b010时,选择输入源2IS2);
.STIS[2:0] =3'b011时,选择输入源3IS3)。
例如:当主定时器选TMR2次定时器选TMR3时,根据下图需配置STIS[2:0] = 3'b001(选择IS1)。
注:如果某款芯片没有相应的定时器(TMRx),则对应的触发信号(ISx)也不存在。
⑤使能外部时钟模式A
配置‘次定时器模式选择’,即SMSEL[1:0] = 3b'111
⑥使能计数器:
配置‘定时器的控制寄存器1’,即TMRx_CTRL1TMREN = 1。
2. 计数模式
计数模式包括向上向下中央双向对齐三种计数模式,可以由定时器控制器1中央双向对齐计数模式选择单向对齐计数方向配置,即TMRx_CTRL1TWCMSELTwo-way count mode selectionOWCDIRone-way countdirection
①若TWCMSEL[1:0] = 2b'00OWCDIR = 0开启向上计数模式;
②若TWCMSEL[1:0] = 2b'00OWCDIR = 1开启向下计数模式;
③若TWCMSEL[1:0] ≠ 2b'00开启中央双向对齐计数模式:
.TWCMSEL[1:0] =2b'01CxIF(捕获比较中断标志位)仅在向上计数时置起
.TWCMSEL[1:0] =2b'10CxIF(捕获比较中断标志位)仅在向下计数时置起
.TWCMSEL[1:0] =2b'11CxIF(捕获比较中断标志位)在向上和向下计数时都置起
注:中央双向对齐计数模式时,OWCDIR为只读位,用于查看计数器的计数方向
1) 向上计数模式
计数器向上计数:
当计数值达到TMR_PR时,计数器向上溢出并产生溢出事件,同时OVFIF(溢出中断标志)置1,之后从0开始向上计数
2) 向下计数模式
计数器向下计数:
当计数值达到0时,计数器向下溢出并产生溢出事件,同时OVFIF(溢出中断标志)置1,之后从TMR_PR开始向下计数。
3) 中央双向计数模式
计数器交替向上、向下计数
当计数值达到TMR_PR-1时,计数器向上溢出并产生溢出事件,同时OVFIF(溢出中断标志)置1,之后从TMR_PR开始向下计数;
当计数值达到1时,计数器向下溢出并产生溢出事件,同时OVFIF(溢出中断标志)置1,之后从0开始向上计数。
3. 编码模式
编码模式需要提供两组输入信号TMRx_CH1TMRx_CH2,根据一组信号的电平值,在另一组信号的边沿向上或者向下计数,计数方向OWCDIR指示。
1) 编码模式A
需配置“次定时器模式选择”,即SMSEL[1:0] = 3b'001,计数器在C1IFP1边沿(上升沿和下降沿)计数,计数方向由C1IFP1的边沿方向C2IFP2的电平高低共同决定。

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

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

C1IFP1为上升沿
C1IFP1为下降沿
C2IFP2为上升沿
C2IFP2为下降沿
相对信号为高电平
向下计数
向上计数
向上计数
向下计数
相对信号为低电平
向上计数
向下计数
向下计数
向上计数
注:
- 编码模式C时,计数边沿为 C1IFP1 和 C2IFP2
- C1IFP1的相对信号为C2IFP2;
- C2IFP2的相对信号为C1IFP1。
4. 编码模式实例
如上图,编码模式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的编码模式CPA2和PA3模拟编码信号,PA2输出方波到PA0(TMR2_CH1),PA3输出方波到PA1(TMR2_CH2),在调试窗口(DEBUG)中观察,每过一轮循环,计数值加4
2. 步骤
①打开WorkBench,选择对应的型号,以AT32F403A为例新建工程;
启用TMR2,选择编码器模式 ;
③选择编码器模式C
④选择任意端口作为输出,以PA2PA3为例;
⑤配置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. 现象
硬件操作:PA0PA2连接,PA1PA3连接。
实验结果:打开调试窗口(DEBUG),将变量“counter”添加到watch1中,单步运行,每过一个“while(1)”循环,计数值(变量counter)增加4
参考资料:
《RM_AT32F403A_407_CH_V2.06》的14.2通用定时器(TMR2到TMR5)​参考
由于作者水平有限,本文难免有错误之处,恳请读者批评指正!

使用特权

评论回复
沙发
可怜的小弗朗士| | 2024-8-12 09:27 | 只看该作者
这种文章希望可以一直更新,图文好舒适。时钟树部分的描述特别清晰

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

5

主题

8

帖子

0

粉丝