基于AT32简易相位差计设计

目录


原理实现

代码

总结


设计方案:

利用AT32定时器主从模式输出两路相位差的方波,后通过定时器输入捕获上升沿的时间差,最后通过Phase_difference(相位差)=360*(tmr5freq*tmr6cut)/1000000;进行转换。

注:tmr5freq是同频方波的频率,tmr6cut是两方波的时间差。


代码:

定时器主从模式输出方波代码:

/**
*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);
	/* 初始化时钟 */
	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);	 //向上计数方式
 
 
	/* 通道输出模式配置 */
	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;			//极性低
 
	/* TMR2通道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的数据寄存器的值(占空比)
	
	/* TMR3通道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的数据寄存器的值(占空比)
	
	/* TMR2通道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);		//设置主次定时器内部关联
 
	/* 使能TMR2*/
	tmr_counter_enable(TMR2, TRUE);		//使能主定时器
 
}

定时器输入捕获代码:

/**
*TMR5 输入捕获初始化函数
*预分频1,重载值0xffff
*定时器计数时钟240M,
*周期:(65536/240)us=273us,
*引脚:PA1   PA2  
*
*/
 
void input_tmr3_init(void)
{
		gpio_init_type gpio_init_struct;
		tmr_input_config_type  tmr_input_config_struct;
	
		crm_periph_clock_enable(CRM_TMR5_PERIPH_CLOCK, TRUE);	//开启tmr3时钟
		crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);	//开启gpioa时钟
	
		gpio_default_para_init(&gpio_init_struct);
 
    gpio_init_struct.gpio_pins = GPIO_PINS_1|GPIO_PINS_2;					//PA1   PA2
    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_INPUT;				//输入模式
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init(GPIOA, &gpio_init_struct);
	
	
		tmr_base_init(TMR5, 0xffff, 0);				//设置TMR3的预分频为1=0+1;重载值480=479+1;(参数要减去1)
		tmr_cnt_dir_set(TMR5, TMR_COUNT_UP);		//设置为向上计数方式
 
	
		/* configure tmr3 channel1 to get clock signal */
		tmr_input_config_struct.input_channel_select = TMR_SELECT_CHANNEL_2;			//通道2,
		tmr_input_config_struct.input_mapped_select = TMR_CC_CHANNEL_MAPPED_DIRECT;		//直接映射
		tmr_input_config_struct.input_polarity_select = TMR_INPUT_RISING_EDGE;			//上升沿
		tmr_input_config_struct.input_filter_value=0;									//不滤波
		tmr_input_channel_init(TMR5, &tmr_input_config_struct, TMR_CHANNEL_INPUT_DIV_1);	//输入1分频
		
				/* configure tmr3 channel1 to get clock signal */
		tmr_input_config_struct.input_channel_select = TMR_SELECT_CHANNEL_3;			//通道3
		tmr_input_config_struct.input_mapped_select = TMR_CC_CHANNEL_MAPPED_DIRECT;		//直接映射
		tmr_input_config_struct.input_polarity_select = TMR_INPUT_RISING_EDGE;			//上升沿
		tmr_input_config_struct.input_filter_value=0;									//不滤波
		tmr_input_channel_init(TMR5, &tmr_input_config_struct, TMR_CHANNEL_INPUT_DIV_1);	//输入1分频
 
		tmr_interrupt_enable(TMR5, TMR_C2_INT, TRUE);		//使能TMR3通道2中断
		tmr_interrupt_enable(TMR5, TMR_C3_INT, TRUE);		//使能TMR3通道3中断
 
		nvic_irq_enable(TMR5_GLOBAL_IRQn, 0, 0);			//使能tmr3中断
 
		/*使能TMR3 */
		tmr_counter_enable(TMR5, TRUE);		//使能定时器
}



/**
  * TMR3中断服务函数
  * 
  * 
*/

uint32_t tmr5freq = 0;//输入信号的频率

uint16_t capturenumber = 0;//捕获到高电平标志位
uint16_t ic3readvalue1 = 0, ic3readvalue2 = 0;
uint32_t capture = 0;

uint32_t Phase_difference;//相位差

void TMR5_GLOBAL_IRQHandler(void)
{
  if(tmr_flag_get(TMR5, TMR_C2_FLAG) != RESET) //通道2中断
  {
			tmr6cut=0;
			tmr_flag_clear(TMR5, TMR_C2_FLAG);		//清除通道2中断
			if(capturenumber == 0)		//第一次捕获到高电平
			{
					/* get the Input Capture value */
					ic3readvalue1 = tmr_channel_value_get(TMR5, TMR_SELECT_CHANNEL_2);	//把通道2的数值保存起来
					capturenumber = 1;
			}
			else if(capturenumber == 1)		//第二次捕获到高电平
			{
					/* get the Input Capture value */
					ic3readvalue2 = tmr_channel_value_get(TMR5, TMR_SELECT_CHANNEL_2);	//把通道2的数值保存起来
 
					/* capture computation */
		  if(ic3readvalue2 > ic3readvalue1)			//判定是否有超过0xffff,这里就是限制了输入的最低频率。	
      {
					capture = (ic3readvalue2 - ic3readvalue1);		//两个高电平之间的计数差,也就是1个周期的时间
      }
      else
      {
        capture = ((0xFFFF - ic3readvalue1) + ic3readvalue2);	//两个高电平之间的计数差,也就是1个周期的时间
      }
 
					/* frequency computation */
					tmr5freq = (uint32_t) system_core_clock / capture;	//计算出输入的频率。
					capturenumber = 0;
		}
	}
	if(tmr_flag_get(TMR5, TMR_C3_FLAG) != RESET) //通道1中断
  {
		 tmr_flag_clear(TMR5, TMR_C3_FLAG);		//清除通道1中断
		
		 Phase_difference=360*(tmr5freq*tmr6cut*5)/1000000;
		
		 display_dec_int(Phase_difference);
		 display_scan();//刷新函数
  }
}

定时器读取两方波上升沿时间差:

/***
*TMR6 溢出中断初始化
*预分频 480 ,重载值
*定时器计数时钟为240M
*溢出时间=240M/240*5=5US;
*/

void m_tmr_init(void)
{
	crm_periph_clock_enable(CRM_TMR6_PERIPH_CLOCK,TRUE);//开启TMR6时钟
	tmr_base_init(TMR6,5-1,239);  //设置TMR6的预分频480=479+1;重载值2=1+1;参数要减去1;
	tmr_cnt_dir_set(TMR6,TMR_COUNT_UP);//设置为向上计数方式
	
	nvic_irq_enable(TMR6_GLOBAL_IRQn,0,1);//使能TMR6中断
	tmr_interrupt_enable(TMR6,TMR_OVF_INT,TRUE);//使能TMR6溢出中断
	
	 /* enable tmr1 */  
  tmr_counter_enable(TMR6, TRUE);

}


/*
*TMR中断服务函数
*溢出中断
*/
uint16_t tmr6cut;

void TMR6_GLOBAL_IRQHandler(void)
{
	if(tmr_flag_get(TMR6,TMR_OVF_FLAG)!=RESET)//溢出中断
	{
		  tmr6cut++;
			if(tmr6cut>=65536)
				tmr6cut=0;
	}
	tmr_flag_clear(TMR6,TMR_OVF_FLAG);//清除标志位   
}

总结: 

以上代码存在一些问题,比如1khz以下的方波采集不准确,后续找出问题会进行改正,同时欢迎各位批评指正。

  • 12
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值