目录
概述
本文主要是使用AT32F403A开发板,基于V2库使用tmr的同步功能来实现定时器输出移相pwm的功能。
串口工具使用的Atlink-ez自带的串口功能。
工程建立、调试工具配置在前面章节有详细介绍。
硬件
硬件方面使用的是参考官方AT32F437 SURF板子而设计的一个AT32F403A开发板,板子上的芯片是AT32F403AVGT7的型号,开发板上面还板载了一个atlink-ez的仿真器,atlink-ez除了可以在线仿真和下载之外还有一个串口的功能,硬件上是通过跳线帽接到了MCU的串口1,pa9/10上面。
如下图是开发板pcb图,以及硬件资源。(左边上角的就是atlink-ez,用usb线接到pc即可):
如下是实物图:
本章是移相pwm输出的功能,TMR2-CH1(PA0), TMR3-CH1(PA6),示波器直接接到对应的排针上即可。
TMR互联同步
定时器之间支持互联同步,因此一个定时器的 TMR_CLK 可由另一个定时器输出信号 TRGOUT 提供。配 置 STIS[2:0]选择内部触发信号驱动计数器计数。
上图是主次定时器的内部触发连接图,可以根据需求使用对应的主次定时器,比如TMR2作为主定时器,TMR3作为次定时器,那么就需要选择IS1。
下图是主定时器可以输出到次定时器的信号:
其中CxORAM是通道x的中间信号。
下图是次定时器的工作模式:
所以在使用同步模式的时候可以根据需求去使用不同的搭配。
软件
初始化
本功能的主要思路就是使用主定时器输出两路pwm,并且pwm为PWM B模式、低极性输出,其中一路用来作为次定时器的触发源,用来触发的pwm对输出极性和输出不太注重,因为使用的是这个通道的中间信号作为触发,输不输出不影响;次定时器输出一路pwm,频率、占空比、PWM模式、输出极性都设置和主定时器的一样,次定时器的工作模式为触发模式,当有上升沿的时候,就开始工作,所以用来作为触发的pwm的占空比就是移相的大小。
软件上使用TMR2为主定时器,TMR2-CH1/CH2作为pwm输出,并且把CH2做为次定时器的输入信号;TMR3作为次定时器,TMR3-CH1作为输出pwm,这样TMR2-CH1和TMR3-CH1就是移相的两个pwm波。
TMR2-CH1(PA0), TMR3-CH1(PA6),先初始化这两个IO为复用推挽输出,然后设置TMR2/3的pwm输出,设置主定时器的输出信号,设置次定时器的输入关联,最后使能TMR2即可。
初始化代码
/**
*TMR pwm 移相
*主定时器:TMR2
*从定时器:TMR3
*phase:移相值
*div:定时器预分频系数
*pre:定时器重载值
*duty:通道数据寄存器值
*pwm周期:(pre/(240/div))us
*频率:1/(pre/(240/div))hz
*pwm占空比:duty/pre
*移相幅度:phase/pre
*/
void pwm_phase_shift(u16 phase,u16 div,u32 pre,u32 duty)
{
gpio_init_type gpio_init_struct = {0};
tmr_output_config_type tmr_output_struct;
tmr_reset(TMR2);
tmr_reset(TMR3);
/* enable gpioa/tmr2/tmr3 clock */
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE); //开启gpioa时钟
crm_periph_clock_enable(CRM_TMR2_PERIPH_CLOCK, TRUE); //开启tmr2时钟
crm_periph_clock_enable(CRM_TMR3_PERIPH_CLOCK, TRUE); //开启tmr3时钟
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_pins = GPIO_PINS_0|GPIO_PINS_6 ; //PA0/6
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; //推挽输出
gpio_init_struct.gpio_pull = GPIO_PULL_NONE; //无上下拉
gpio_init_struct.gpio_mode = GPIO_MODE_MUX; //复用
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(GPIOA, &gpio_init_struct);
tmr_base_init(TMR2, pre, div); // 240M/(0+1)/(23999+1)=10khz
tmr_cnt_dir_set(TMR2, TMR_COUNT_UP); //向上计数方式
tmr_base_init(TMR3, pre, div); // 240M/(0+1)/(23999+1)=10khz
tmr_cnt_dir_set(TMR3, TMR_COUNT_UP); //向上计数方式
/* channelx Configuration in output mode */
tmr_output_default_para_init(&tmr_output_struct);
tmr_output_struct.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_B; //PWM B模式
tmr_output_struct.oc_output_state = TRUE; //使能输出
tmr_output_struct.oc_polarity = TMR_OUTPUT_ACTIVE_LOW; //极性低
/* timer2 channel 1 */
tmr_output_channel_config(TMR2, TMR_SELECT_CHANNEL_1, &tmr_output_struct); //TMR2-CH1 (PA0)
tmr_channel_value_set(TMR2, TMR_SELECT_CHANNEL_1, duty); //设置TMR2的通道1的数据寄存器的值(占空比)
/* timer3 channel 1 */
tmr_output_channel_config(TMR3, TMR_SELECT_CHANNEL_1, &tmr_output_struct); //TMR3-CH1 (PA6)
tmr_channel_value_set(TMR3, TMR_SELECT_CHANNEL_1, duty); //设置TMR3的通道1的数据寄存器的值(占空比)
/* timer2 channel 2 */
tmr_output_struct.oc_output_state = FALSE; //可输出也可不输出,因为是使用的中间信号.
tmr_output_channel_config(TMR2, TMR_SELECT_CHANNEL_2, &tmr_output_struct); //TMR2-CH2
tmr_channel_value_set(TMR2, TMR_SELECT_CHANNEL_2, phase); //设置TMR2的通道2的数据寄存器的值(占空比)
/* timer2 select enable signal to sub timer */
tmr_primary_mode_select(TMR2, TMR_PRIMARY_SEL_C2ORAW); //设置TMR2为主模式,通道2中间信号作为次定时器的输入
tmr_sub_sync_mode_set(TMR2, TRUE); //主次定时器高度同步
/* sub mode selection: tmr3 */
tmr_sub_mode_select(TMR3, TMR_SUB_TRIGGER_MODE); //设置TMR3为次定时器,设定为触发模式
tmr_trigger_input_select(TMR3, TMR_SUB_INPUT_SEL_IS1); //设置主次定时器内部关联
/* enable tmr2*/
tmr_counter_enable(TMR2, TRUE); //使能主定时器
}
测试
测试代码
设定输出10k hz,占空比 25%的pwm波形,移相幅度为周期的1/4,也就是和占空比一样。
测试结果:
捉到的波形和预期的一致。蓝色是PA0的输出,黄色是PA6的输出,频率和占空比一样,相差1/4周期的幅度。
最后
有问题的可以加QQ群技术交流,同时相关代码上传到QQ群中。