[AT32F403/403A] AT32学习记录——通用定时器(二)

[复制链接]
 楼主| zexin 发表于 2024-9-1 18:09 | 显示全部楼层 |阅读模式
本帖最后由 zexin 于 2024-9-2 10:51 编辑

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

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

8989566d4376816683.png

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

106466d437ef6cd0a.png
PWM输入
使用PWM输入模式时需要将C1INC2IN同时映射到同一个TMRx_CHx,同时通道1(或通道2)配置成次定时器的复位模式
1637566d4388f9127a.png
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模式”;

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

  3. int main(void)
  4. {
  5.   wk_system_clock_config();
  6.   wk_periph_clock_config();
  7.   wk_nvic_config();
  8.   wk_timebase_init();
  9.   wk_tmr2_init();
  10.   wk_gpio_config();
  11.   tmr_counter_enable(TRM2, TRUE);

  12.   while(1)
  13.   {
  14.     /* 产生三路霍尔信号 */
  15.     gpio_bits_set(GPIOA, GPIO_PINS_3);
  16.     delay_us(10)
  17.     gpio_bits_set(GPIOA, GPIO_PINS_6);
  18.     delay_us(10)
  19.     gpio_bits_set(GPIOA, GPIO_PINS_7);
  20.     delay_us(10)
  21.     gpio_bits_reset(GPIOA, GPIO_PINS_3);
  22.     delay_us(10)
  23.     gpio_bits_reset(GPIOA, GPIO_PINS_6);
  24.     delay_us(10)
  25.     gpio_bits_reset(GPIOA, GPIO_PINS_7);
  26.     delay_us(10)
  27.   }
  28. }
at32f403a_407_wk_config.c

  1. #include "at32f403a_407_wk_config.h"

  2. void wk_system_clock_config(void)
  3. {
  4.   crm_reset();
  5.   crm_clock_source_enable(CRM_CLOCK_SOURCE_LICK, TRUE);
  6.   while(crm_flag_get(CRM_LICK_STABLE_FLAG) != SET)
  7.   {
  8.   }

  9.   crm_clock_source_enable(CRM_CLOCK_SOURCE_HICK, TRUE);

  10.   while(crm_flag_get(CRM_HICK_STABLE_FLAG) != SET)
  11.   {
  12.   }

  13.   crm_pll_config(CRM_PLL_SOURCE_HICK, CRM_PLL_MULT_60, CRM_PLL_OUTPUT_RANGE_GT72MHZ);

  14.   crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE);

  15.   while(crm_flag_get(CRM_PLL_STABLE_FLAG) != SET)
  16.   {
  17.   }

  18.   crm_ahb_div_set(CRM_AHB_DIV_1);

  19.   crm_apb2_div_set(CRM_APB2_DIV_2);

  20.   crm_apb1_div_set(CRM_APB1_DIV_2);

  21.   crm_auto_step_mode_enable(TRUE);

  22.   crm_sysclk_switch(CRM_SCLK_PLL);

  23.   while(crm_sysclk_switch_status_get() != CRM_SCLK_PLL)
  24.   {
  25.   }

  26.   crm_auto_step_mode_enable(FALSE);

  27.   system_core_clock_update();
  28. }

  29. void wk_periph_clock_config(void)
  30. {
  31.   crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);

  32.   crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

  33.   crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);

  34.   crm_periph_clock_enable(CRM_TMR2_PERIPH_CLOCK, TRUE);
  35. }

  36. void wk_nvic_config(void)
  37. {
  38.   nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);

  39.   NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
  40.   nvic_irq_enable(TMR2_GLOBAL_IRQn, 0, 0);
  41. }

  42. void wk_gpio_config(void)
  43. {

  44.   gpio_init_type gpio_init_struct;
  45.   gpio_default_para_init(&gpio_init_struct);


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

  47.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  48.   gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  49.   gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
  50.   gpio_init_struct.gpio_pins = GPIO_PINS_3 | GPIO_PINS_6 | GPIO_PINS_7 | GPIO_PINS_8;
  51.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  52.   gpio_init(GPIOA, &gpio_init_struct);

  53. }


  54. void wk_tmr2_init(void)
  55. {
  56.   gpio_init_type gpio_init_struct;
  57.   tmr_input_config_type  tmr_input_struct;
  58.   tmr_output_config_type tmr_output_struct;

  59.   gpio_default_para_init(&gpio_init_struct);

  60.   gpio_init_struct.gpio_pins = GPIO_PINS_0;
  61.   gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  62.   gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  63.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  64.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  65.   gpio_init(GPIOA, &gpio_init_struct);

  66.   gpio_init_struct.gpio_pins = GPIO_PINS_1;
  67.   gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  68.   gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  69.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  70.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  71.   gpio_init(GPIOA, &gpio_init_struct);

  72.   gpio_init_struct.gpio_pins = GPIO_PINS_2;
  73.   gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  74.   gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  75.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  76.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  77.   gpio_init(GPIOA, &gpio_init_struct);

  78.   tmr_base_init(TMR2, 65535, 0);
  79.   tmr_cnt_dir_set(TMR2, TMR_COUNT_UP);
  80.   tmr_clock_source_div_set(TMR2, TMR_CLOCK_DIV1);
  81.   tmr_period_buffer_enable(TMR2, FALSE);

  82.   tmr_sub_sync_mode_set(TMR2, FALSE);
  83.   tmr_primary_mode_select(TMR2, TMR_PRIMARY_SEL_RESET);

  84.   tmr_input_struct.input_channel_select = TMR_SELECT_CHANNEL_1;
  85.   tmr_input_struct.input_mapped_select = TMR_CC_CHANNEL_MAPPED_STI;
  86.   tmr_input_struct.input_polarity_select  = TMR_INPUT_RISING_EDGE;
  87.   tmr_input_struct.input_filter_value = 0;
  88.   tmr_input_channel_init(TMR2, &tmr_input_struct, TMR_CHANNEL_INPUT_DIV_1);

  89.   tmr_channel1_input_select(TMR2, TMR_CHANEL1_2_3_CONNECTED_C1IRAW_XOR);

  90.   tmr_trigger_input_select(TMR2, TMR_SUB_INPUT_SEL_C1INC);

  91.   tmr_sub_mode_select(TMR2, TMR_SUB_RESET_MODE);

  92.   tmr_output_struct.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_B;
  93.   tmr_output_struct.oc_output_state = TRUE;
  94.   tmr_output_struct.occ_output_state = FALSE;
  95.   tmr_output_struct.oc_polarity = TMR_OUTPUT_ACTIVE_HIGH;
  96.   tmr_output_struct.occ_polarity = TMR_OUTPUT_ACTIVE_HIGH;
  97.   tmr_output_struct.oc_idle_state = FALSE;
  98.   tmr_output_struct.occ_idle_state = FALSE;
  99.   tmr_output_channel_config(TMR2, TMR_SELECT_CHANNEL_2, &tmr_output_struct);

  100.   tmr_output_channel_immediately_set(TMR2, TMR_SELECT_CHANNEL_4, FALSE);
  101.   tmr_channel_value_set(TMR2, TMR_SELECT_CHANNEL_2, 0);
  102.   tmr_output_channel_buffer_enable(TMR2, TMR_SELECT_CHANNEL_2, FALSE);

  103.   tmr_primary_mode_select(TMR2, TMR_PRIMARY_SEL_RESET);

  104. //tmr_counter_enable(TMR2, TRUE);

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

  3. void SysTick_Handler(void)
  4. {
  5.   wk_timebase_handler();
  6. }

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

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

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

  5. int main(void)
  6. {
  7.   wk_system_clock_config();
  8.   wk_periph_clock_config();
  9.   wk_nvic_config();
  10.   wk_timebase_init();
  11.   wk_tmr2_init();
  12.   wk_gpio_config();

  13.   while(1)
  14.   {
  15.     /* 产生PWM波 */
  16.     gpio_bits_set(GPIOA, GPIO_PINS_6);
  17.     delay_us(30);
  18.     gpio_bits_reset(GPIOA, GPIO_PINS_6);
  19.     delay_us(10);
  20.   }
  21. }
at32f403a_407_wk_config.c
  1. #include "at32f403a_407_wk_config.h"

  2. void wk_system_clock_config(void)
  3. {
  4.   crm_reset();
  5.   crm_clock_source_enable(CRM_CLOCK_SOURCE_LICK, TRUE);
  6.   while(crm_flag_get(CRM_LICK_STABLE_FLAG) != SET)
  7.   {
  8.   }

  9.   crm_clock_source_enable(CRM_CLOCK_SOURCE_HICK, TRUE);

  10.   while(crm_flag_get(CRM_HICK_STABLE_FLAG) != SET)
  11.   {
  12.   }
  13.   crm_pll_config(CRM_PLL_SOURCE_HICK, CRM_PLL_MULT_60, CRM_PLL_OUTPUT_RANGE_GT72MHZ);
  14.   crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE);
  15.   while(crm_flag_get(CRM_PLL_STABLE_FLAG) != SET)
  16.   {
  17.   }

  18.   crm_ahb_div_set(CRM_AHB_DIV_1);
  19.   crm_apb2_div_set(CRM_APB2_DIV_2);
  20.   crm_apb1_div_set(CRM_APB1_DIV_2);
  21.   crm_auto_step_mode_enable(TRUE);
  22.   crm_sysclk_switch(CRM_SCLK_PLL);
  23.   while(crm_sysclk_switch_status_get() != CRM_SCLK_PLL)
  24.   {
  25.   }
  26.   crm_auto_step_mode_enable(FALSE);
  27.   system_core_clock_update();
  28. }

  29. void wk_periph_clock_config(void)
  30. {
  31.   crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
  32.   crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
  33.   crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
  34.   crm_periph_clock_enable(CRM_TMR2_PERIPH_CLOCK, TRUE);
  35. }

  36. void wk_nvic_config(void)
  37. {
  38.   nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  39.   NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
  40.   nvic_irq_enable(TMR2_GLOBAL_IRQn, 0, 0);
  41. }

  42. void wk_gpio_config(void)
  43. {
  44.   gpio_init_type gpio_init_struct;
  45.   gpio_default_para_init(&gpio_init_struct);
  46.   gpio_bits_set(GPIOA, GPIO_PINS_6);

  47.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  48.   gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  49.   gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
  50.   gpio_init_struct.gpio_pins = GPIO_PINS_6;
  51.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  52.   gpio_init(GPIOA, &gpio_init_struct);
  53. }

  54. void wk_tmr2_init(void)
  55. {
  56.   gpio_init_type gpio_init_struct;
  57.   tmr_input_config_type tmr_ic_init_struct;

  58.   gpio_default_para_init(&gpio_init_struct);

  59.   gpio_init_struct.gpio_pins = GPIO_PINS_0;
  60.   gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  61.   gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  62.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  63.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  64.   gpio_init(GPIOA, &gpio_init_struct);

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

  67.   tmr_base_init(TMR2, 11999999, 0);
  68.   tmr_cnt_dir_set(TMR2, TMR_COUNT_UP);
  69.   tmr_clock_source_div_set(TMR2, TMR_CLOCK_DIV1);
  70.   tmr_period_buffer_enable(TMR2, FALSE);

  71.   tmr_sub_sync_mode_set(TMR2, FALSE);
  72.   tmr_primary_mode_select(TMR2, TMR_PRIMARY_SEL_RESET);

  73.   tmr_ic_init_struct.input_filter_value = 0;
  74.   tmr_ic_init_struct.input_channel_select = TMR_SELECT_CHANNEL_1;
  75.   tmr_ic_init_struct.input_mapped_select = TMR_CC_CHANNEL_MAPPED_DIRECT;
  76.   tmr_ic_init_struct.input_polarity_select = TMR_INPUT_RISING_EDGE;
  77.   tmr_pwm_input_config(TMR2, &tmr_ic_init_struct, TMR_CHANNEL_INPUT_DIV_1);

  78.   tmr_trigger_input_select(TMR2, TMR_SUB_INPUT_SEL_C1DF1);
  79.   tmr_sub_mode_select(TMR2, TMR_SUB_RESET_MODE);

  80.   tmr_counter_enable(TMR2, TRUE);

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

  3. extern uint16_t duty_cycle;
  4. extern uint32_t frequency;
  5. uint32_t ic1value = 0;

  6. void SysTick_Handler(void)
  7. {
  8.   wk_timebase_handler();
  9. }

  10. void TMR2_GLOBAL_IRQHandler(void)
  11. {
  12.   if(tmr_interrupt_flag_get(TMR2, TMR_C1_FLAG) != RESET)
  13.   {
  14.      tmr_flag_clear(TMR2, TMR_C1_FLAG);
  15.      ic1value = tmr_channel_value_get(TMR2, TMR_SELECT_CHANNEL_1);//获取上升沿时的计数值
  16.      if(ic1value != 0)
  17.      {
  18.         /* 计算占空比(上升沿时的计数值/下降沿时的计数值) */
  19.         duty_cycle = (tmr_channel_value_get(TMR2, TMR_SELECT_CHANNEL_2) * 100) / ic1value;
  20.         /* 计算频率(定时器时钟/上升沿时的计数值) */
  21.         frequency = system_cor_clock / ic1value;
  22.      }
  23.      else
  24.      {
  25.         duty_cycle = 0;
  26.         frequency = 0;
  27.      }
  28.   }
  29. }
(4)现象
先用逻辑分析仪测量PA6所产生的PWM的频率和占空比;
5296966d43cd7813f1.png
再连接PA6与PA0,进入Debug(调试模式),对比Watch 1中变量duty_cycle和frequency的值与逻辑分析仪的结果基本一致。

5100766d43cf3f03e1.png

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

评论

感谢大佬分享!二姨家的原创奖励文章需首发于21ic论坛哦~由于您在其他平台发布早于21ic,由此本篇文章不审核原创~希望大佬下次可以先发布在21ic~ ps:大佬的文章排版用心啦!  发表于 2024-9-12 14:17
caigang13 发表于 2024-9-2 07:42 来自手机 | 显示全部楼层
看来二姨家的网页设计应该优化一下了。
trucyw 发表于 2024-9-2 08:07 | 显示全部楼层
晚点来认真学习下
xionghaoyun 发表于 2024-9-2 13:58 | 显示全部楼层
不知道为啥看着觉得很乱(排版?)
呐咯密密 发表于 2024-9-2 16:28 | 显示全部楼层
我觉得这个排版挺不错的啊,重点信息的配色挺好的,图片很清晰,
alz 发表于 2025-7-4 17:48 | 显示全部楼层
霍尔的pa8的波形,为什么会在xor每次变化的时候都触发中断呢?不是上升沿才触发中断吗?
寂静之回响 发表于 2025-7-8 11:39 | 显示全部楼层
alz 发表于 2025-7-4 17:48
霍尔的pa8的波形,为什么会在xor每次变化的时候都触发中断呢?不是上升沿才触发中断吗? ...

是的我也由此疑问,可能配置的时候触发方式不对
您需要登录后才可以回帖 登录 | 注册

本版积分规则

9

主题

17

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部