打印
[AT32F403/403A]

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

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

#申请原创#
AT32F403A通用定时器02
一、输入部分

通道1输入部分
1.输入捕获
触发信号被检测到时,通道x的数据寄存器(TMRx_CxDT)会记录当前计数器的计数值,并将捕获中断标志(CxIF)置1。如果有使能中断或者DMA请求,则还会进入到相应的中断或DMA。
注:如果在发生捕获后又立即检测到触发信号,此时计数器的计数值会覆盖之前的计数值,同时通道再捕获标志(CxRF)置1。
2.多输入异或


多输入异或
通道1的输入端可以通过TMRx_CH1TMRx_CH2TMRx_CH3经过异或逻辑后输入,可用于连接霍尔传感器,进而计算出电机的转速。
3.PWM输入

PWM输入
使用PWM输入模式时需要将C1INC2IN同时映射到同一个TMRx_CHx,同时通道1(或通道2)配置成次定时器的复位模式
PWM输入时序图
如图,通道1(CH1)输入信号的上升沿会触发捕获,并将捕获值(0xA)储存到通道1的数据寄存器(C1DT),同时复位定时器,使之从0开始计数
接着,通道1(CH1)输入信号的下降沿会触发捕获,并将捕获值(0x4)储存到通道2的数据寄存器(C2DT);
则输入信号的周期:T = C1DT ÷ TMR_CLK;
输入信号的占空比:D = C2DT ÷ C1DT。
二、案例
1.多输入异或
(1)功能
对三路霍尔输入信号进行异或输出。
(2)配置
介绍
使用PA3PA6PA7产生三路霍尔信号,将其输入到PA0、PA1、PA2进行异或,PA8根据异或结果输出方波。
步骤
①启用定时器(以TMR2为例),选择“异或/HALL模式”;

②选择触发极性(以上升沿为例);
③开启中断;
④设置PA3、PA6、PA7、PA8为输出模式;
⑤生成代码。
(3)代码
main.c
#include "at32f403a_407_wk_config.h"
#include "wk_system.h"

int main(void)
{
  wk_system_clock_config();
  wk_periph_clock_config();
  wk_nvic_config();
  wk_timebase_init();
  wk_tmr2_init();
  wk_gpio_config();
  tmr_counter_enable(TRM2, TRUE);

  while(1)
  {
    /* 产生三路霍尔信号 */
    gpio_bits_set(GPIOA, GPIO_PINS_3);
    delay_us(10)
    gpio_bits_set(GPIOA, GPIO_PINS_6);
    delay_us(10)
    gpio_bits_set(GPIOA, GPIO_PINS_7);
    delay_us(10)
    gpio_bits_reset(GPIOA, GPIO_PINS_3);
    delay_us(10)
    gpio_bits_reset(GPIOA, GPIO_PINS_6);
    delay_us(10)
    gpio_bits_reset(GPIOA, GPIO_PINS_7);
    delay_us(10)
  }
}
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);

  NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
  nvic_irq_enable(TMR2_GLOBAL_IRQn, 0, 0);
}

void wk_gpio_config(void)
{

  gpio_init_type gpio_init_struct;
  gpio_default_para_init(&gpio_init_struct);


  gpio_bits_set(GPIOA, GPIO_PINS_3 | GPIO_PINS_6 | GPIO_PINS_7 | GPIO_PINS_8);

  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_3 | GPIO_PINS_6 | GPIO_PINS_7 | GPIO_PINS_8;
  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;
  tmr_output_config_type tmr_output_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);

  gpio_init_struct.gpio_pins = GPIO_PINS_2;
  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_STI;
  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_channel1_input_select(TMR2, TMR_CHANEL1_2_3_CONNECTED_C1IRAW_XOR);

  tmr_trigger_input_select(TMR2, TMR_SUB_INPUT_SEL_C1INC);

  tmr_sub_mode_select(TMR2, TMR_SUB_RESET_MODE);

  tmr_output_struct.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_B;
  tmr_output_struct.oc_output_state = TRUE;
  tmr_output_struct.occ_output_state = FALSE;
  tmr_output_struct.oc_polarity = TMR_OUTPUT_ACTIVE_HIGH;
  tmr_output_struct.occ_polarity = TMR_OUTPUT_ACTIVE_HIGH;
  tmr_output_struct.oc_idle_state = FALSE;
  tmr_output_struct.occ_idle_state = FALSE;
  tmr_output_channel_config(TMR2, TMR_SELECT_CHANNEL_2, &tmr_output_struct);

  tmr_output_channel_immediately_set(TMR2, TMR_SELECT_CHANNEL_4, FALSE);
  tmr_channel_value_set(TMR2, TMR_SELECT_CHANNEL_2, 0);
  tmr_output_channel_buffer_enable(TMR2, TMR_SELECT_CHANNEL_2, FALSE);

  tmr_primary_mode_select(TMR2, TMR_PRIMARY_SEL_RESET);

//tmr_counter_enable(TMR2, TRUE);

  /* 使能定时器中断 */
  tmr_interrupt_enable(TMR2, TMR_TRIGGER_INT, TRUE);
}
at32f403a_407_int.c
#include "at32f403a_407_int.h"
#include "wk_system.h"

void SysTick_Handler(void)
{
  wk_timebase_handler();
}

void TMR2_GLOBAL_IRQHandler(void)
{
  if(tmr_interrupt_flag_get(TMR2, TMR_TRIGGER_FLAG) != RESET)
  {
     tmr_flag_clear(TMR2, TMR_TRIGGER_FLAG);
     GPIOA->odt ^= GPIO_PINS_8;       //PA8根据异或结果翻转电平
  }
}
(4)现象
连接PA0和PA3、PA1和P6、PA2和PA7,逻辑分析仪测量PA0(霍尔1)、PA1(霍尔2)、PA2(霍尔3)和PA8(异或结果)的波形。
当霍尔信号 = “001”时,异或结果为“1”;
当霍尔信号 = “011”时,异或结果为“0”;
当霍尔信号 = “111”时,异或结果为“1”;
……
即只有当霍尔信号中“1”的个数为奇数时,异或结果才为“1”,其余情况都为“0”。
2.PWM输入
(1)功能
使用32位计数器测量输入PWM的频率和占空比。(以测量频率20Hz以上的信号为例)
(2)配置
介绍
PA6产生PWM方波(有条件的可以使用信号发生器),输入到PA0进行测量,在Debug模式下查看所测频率与占空比与逻辑分析所测结果是否一致。
步骤
①TMR2选择“通道1PWM输入”模式,开启“增强模式”(32bit);

② 可通过所测信号的频率范围来设置周期值(以最小20Hz为例),配置通道1极性为上升沿,并且次定时器模式为复位模式,配置通道2极性为下降沿
③开启中断;
④配置PA6为输出模式用于产生PWM;
⑤ 生成代码。
(3)代码
main.c
#include "at32f403a_407_wk_config.h"
#include "wk_system.h"

uint16_t duty_cycle = 0;  //占空比
uint32_t frequency = 0;   //频率

int main(void)
{
  wk_system_clock_config();
  wk_periph_clock_config();
  wk_nvic_config();
  wk_timebase_init();
  wk_tmr2_init();
  wk_gpio_config();

  while(1)
  {
    /* 产生PWM波 */
    gpio_bits_set(GPIOA, GPIO_PINS_6);
    delay_us(30);
    gpio_bits_reset(GPIOA, GPIO_PINS_6);
    delay_us(10);
  }
}
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);
  NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
  nvic_irq_enable(TMR2_GLOBAL_IRQn, 0, 0);
}

void wk_gpio_config(void)
{
  gpio_init_type gpio_init_struct;
  gpio_default_para_init(&gpio_init_struct);
  gpio_bits_set(GPIOA, GPIO_PINS_6);

  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_6;
  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_ic_init_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);

  /* 使能32位计数器 */
  tmr_32_bit_function_enable(TMR2, TRUE);

  tmr_base_init(TMR2, 11999999, 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_ic_init_struct.input_filter_value = 0;
  tmr_ic_init_struct.input_channel_select = TMR_SELECT_CHANNEL_1;
  tmr_ic_init_struct.input_mapped_select = TMR_CC_CHANNEL_MAPPED_DIRECT;
  tmr_ic_init_struct.input_polarity_select = TMR_INPUT_RISING_EDGE;
  tmr_pwm_input_config(TMR2, &tmr_ic_init_struct, TMR_CHANNEL_INPUT_DIV_1);

  tmr_trigger_input_select(TMR2, TMR_SUB_INPUT_SEL_C1DF1);
  tmr_sub_mode_select(TMR2, TMR_SUB_RESET_MODE);

  tmr_counter_enable(TMR2, TRUE);

  /* 开启中断 */
  tmr_counter_enable(TRM2, TMR_C1_INT, TRUE)
}
at32f403a_407_int.c
#include "at32f403a_407_int.h"
#include "wk_system.h"

extern uint16_t duty_cycle;
extern uint32_t frequency;
uint32_t ic1value = 0;

void SysTick_Handler(void)
{
  wk_timebase_handler();
}

void TMR2_GLOBAL_IRQHandler(void)
{
  if(tmr_interrupt_flag_get(TMR2, TMR_C1_FLAG) != RESET)
  {
     tmr_flag_clear(TMR2, TMR_C1_FLAG);
     ic1value = tmr_channel_value_get(TMR2, TMR_SELECT_CHANNEL_1);//获取上升沿时的计数值
     if(ic1value != 0)
     {
        /* 计算占空比(上升沿时的计数值/下降沿时的计数值) */
        duty_cycle = (tmr_channel_value_get(TMR2, TMR_SELECT_CHANNEL_2) * 100) / ic1value;
        /* 计算频率(定时器时钟/上升沿时的计数值) */
        frequency = system_cor_clock / ic1value;
     }
     else
     {
        duty_cycle = 0;
        frequency = 0;
     }
  }
}
(4)现象
先用逻辑分析仪测量PA6所产生的PWM的频率和占空比;
再连接PA6与PA0,进入Debug(调试模式),对比Watch 1中变量duty_cycle和frequency的值与逻辑分析仪的结果基本一致。


由于作者水平有限,文中如有错误之处,恳请读者批评指正。
参考资料:
《RM_AT32F403A_407_CH_V2.06》的14.2通用定时器(TMR2到TMR5)https://www.arterytek.com/file/download/1995

使用特权

评论回复
评论
21小跑堂 2024-9-12 14:17 回复TA
感谢大佬分享!二姨家的原创奖励文章需首发于21ic论坛哦~由于您在其他平台发布早于21ic,由此本篇文章不审核原创~希望大佬下次可以先发布在21ic~ ps:大佬的文章排版用心啦! 
来自 2楼
zexin|  楼主 | 2024-9-1 18:22 | 只看该作者
本帖最后由 muyichuan2012 于 2024-9-2 11:20 编辑

因图片过多发帖后容易造成排版混乱,若想追求更舒适的观感可自行移步至CSDN观看:https://blog.csdn.net/weixin_64557865/article/details/140933118?spm=1001.2014.3001.5501

使用特权

评论回复
板凳
caigang13| | 2024-9-2 07:42 | 只看该作者
看来二姨家的网页设计应该优化一下了。

使用特权

评论回复
地板
trucyw| | 2024-9-2 08:07 | 只看该作者
晚点来认真学习下

使用特权

评论回复
5
xionghaoyun| | 2024-9-2 13:58 | 只看该作者
不知道为啥看着觉得很乱(排版?)

使用特权

评论回复
6
呐咯密密| | 2024-9-2 16:28 | 只看该作者
我觉得这个排版挺不错的啊,重点信息的配色挺好的,图片很清晰,

使用特权

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

本版积分规则

5

主题

8

帖子

0

粉丝