stm32 使用 TIM3 输出脉冲 TIM2 进行脉冲计数

17 篇文章 0 订阅
8 篇文章 0 订阅

先上 定时器 和 io 的设置

#include "includes.h"
#define TMRNCLK	(SYSCLK)


/*---- S E T   T   I   M 3   P W M   O U T P U T ----
【功能】:设置 tim3 使用 pc6 pc7 pc8 pc9输出,低电平有效, 当 tim3->cnt>= pwm占空比 就输出低电平
【参数】:****
【返回】:****
【说明】:****
--------------作者:卢杰西   2021年5月2日17:27:38--------------------------------*/
void SetTIM3PwmOutput()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	//将tim3的ch 输出 重定位到  pc6 pc7 pc8 pc9
	GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);
	SetPinState(GPIOC, GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9, GPIO_Mode_AF_PP);
	//步进电机的方向控制
	SetPinState(GPIOD, GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15, GPIO_Mode_Out_PP);
}

/*
//TIM3 CH1 PWM 输出设置
//PWM 输出初始化
//arr:自动重装值
//psc:时钟预分频数
*/
/*---- T I M 3   T O   M O T O R   I N I T ----
【功能】:初始化 tim3作为主定时器 给 tim2 输出脉冲,tim2作为计数定时器,tim2定义各个ch中断,对应4个电机
【参数】:****
【返回】:****
【说明】:****
--------------作者:卢杰西   2021年5月2日23:58:21--------------------------------*/
void Tim3ToMotorInit(INT32U frequency,INT8U enIrq)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;  
//    TIM_OCInitTypeDef TIM_OCInitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 						//使能 TIMx 外设

	//设置住定时器TIM3
	TIM_DeInit(TIM3);
	TIM_TimeBaseStructure.TIM_Period = PWM_Period-1;								//设置自动重装载周期值
	TIM_TimeBaseStructure.TIM_Prescaler =TMRNCLK/frequency/PWM_Period-1; 		//设置预分频值 不分频
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 								//设置时钟分割:TDTS = Tck_tim			这里是 32M
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 				//向上计数
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);								//初始化 TIMx
	TIM_ClearFlag(TIM3, TIM_FLAG_Update);                 
	TIM_ARRPreloadConfig(TIM3, ENABLE); 										//使能 TIMx 在 ARR 上的预装载寄存器

	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; 					//CH1 PWM2 模式
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 		//比较输出使能
	TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
	TIM_OCInitStructure.TIM_Pulse = 0; 									//设置待装入捕获比较寄存器的脉冲值,系统没有启动前,默认低电平,让电机没有脉冲输入
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; 			//发生对比后输出高电平
	TIM_OC1Init(TIM3, &TIM_OCInitStructure); 							//根据指定的参数初始化外设 TIMx
	TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); 					//CH1 预装载使能	
	TIM_OC2Init(TIM3, &TIM_OCInitStructure); 							//根据指定的参数初始化外设 TIMx
	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); 					//CH2 预装载使能
	TIM_OC3Init(TIM3, &TIM_OCInitStructure); 							//根据指定的参数初始化外设 TIMx
	TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); 					//CH3 预装载使能
	TIM_OC4Init(TIM3, &TIM_OCInitStructure); 							//根据指定的参数初始化外设 TIMx
	TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); 					//CH4 预装载使能
	SetTIM3PwmOutput();
	TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Update);				//以TIM3的溢出 作为信号
#if 1
	//设置从定时器TIM2
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); 						//使能 TIMx 外设
	TIM_DeInit(TIM2);
	TIM_TimeBaseStructure.TIM_Period = 65535;									//设置自动重装载周期值
	TIM_TimeBaseStructure.TIM_Prescaler =0;								 		//设置预分频值 不分频
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 								//设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 				//向上计数
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);								//初始化 TIMx
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);                 
	TIM_ARRPreloadConfig(TIM2, ENABLE); 										//使能 TIMx 在 ARR 上的预装载寄存器
	TIM_SelectInputTrigger(TIM2, TIM_TS_ITR2);									//选择tim3的trgo输入
	TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_External1);							//选择trgi作为时钟输入
	if(enIrq)		
	{
		NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;       			/*溢出中断*/  
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&NVIC_InitStructure);  
		TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);                   				/* 使能中断 */	
	}
	TIM_Cmd(TIM2, ENABLE); 														//使能 TIM3
#else
	if(enIrq)
	{
		NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQChannel;       			/*溢出中断*/  
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&NVIC_InitStructure);  
		TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);                   				/* 使能中断 */	
	}
#endif
	TIM_Cmd(TIM3, ENABLE); 														//使能 TIM3
}

再将电机驱动封装为一个任务 用消息队列去发送操作命令

#include "includes.h"
#define TIM3CEN	PerpheralBit(TIM3->CR1,0)
OS_EVENT *OSQMotor;
S_MOTOR motor[4]={
	{eMtStateStop,0,0,0,TIM_IT_CC1,&TIM3->CCR1,Bit2Addr32X(GPIOD->ODR,12),&TIM2->CCR1},
	{eMtStateStop,0,0,0,TIM_IT_CC2,&TIM3->CCR2,Bit2Addr32X(GPIOD->ODR,13),&TIM2->CCR2},
	{eMtStateStop,0,0,0,TIM_IT_CC3,&TIM3->CCR3,Bit2Addr32X(GPIOD->ODR,14),&TIM2->CCR3},
	{eMtStateStop,0,0,0,TIM_IT_CC4,&TIM3->CCR4,Bit2Addr32X(GPIOD->ODR,15),&TIM2->CCR4},
};

/*---- S E N D   M T   M S G ----
【功能】:****
【参数】:index 电机编号 0-3   event :eMtCmdStop ...  cnt 移动的距离 只有28位有效数字
【返回】:****
【说明】:****
--------------作者:卢杰西   2021年5月4日13:21:38--------------------------------*/
void SendMtMsg(INT8U index,INT8U event,INT32S cnt)
{
	INT32U msg=(cnt<<4)|(event<<2)|index;
	OSQPost(OSQMotor,(void*)msg);
}


/*---- G E T   M O T O R   P O S ----
【功能】:获取电机的 当前位置
【参数】:****
【返回】:****
【说明】:****
--------------作者:卢杰西   2021年5月4日1:16:20--------------------------------*/
INT32S GetMotorPos(INT8U i)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
	OS_CPU_SR  cpu_sr = 0;
#endif
	INT32S ret;
	OS_ENTER_CRITICAL();
	if(motor[i].state==eMtStateAdd)
		ret=motor[i].pos_base+TIM2->CNT;
	else if(motor[i].state==eMtStateDec)
		ret=motor[i].pos_base-TIM2->CNT;
	else ret=motor[i].pos;
	OS_EXIT_CRITICAL();
	return ret;
}

/*---- S T O P   M O T O R ----
【功能】:停止电机转动
【参数】:****
【返回】:****
【说明】:停止电机转动
--------------作者:卢杰西   2021年5月4日0:42:19--------------------------------*/
void StopMotor(INT8U i)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
	OS_CPU_SR  cpu_sr = 0;
#endif
	if(motor[i].state==eMtStateAdd)
	{
		TIM3CEN=0;									//pwm占空比设置为0,不输出脉冲,保持低电平
		OS_ENTER_CRITICAL();
		*motor[i].pwm=0;							//关闭脉冲输出
		motor[i].pos=motor[i].pos_base+TIM2->CNT;
		TIM_ITConfig(TIM2,motor[i].irq,DISABLE);	/* 关闭中断 */	
		motor[i].state=eMtStateStop;
		OS_EXIT_CRITICAL();
		TIM3CEN=1;
	}
	else if(motor[i].state==eMtStateDec)
	{
		TIM3CEN=0;									//pwm占空比设置为0,不输出脉冲,保持低电平
		OS_ENTER_CRITICAL();
		*motor[i].pwm=0;							//关闭脉冲输出
		motor[i].pos=motor[i].pos_base-TIM2->CNT;
		TIM_ITConfig(TIM2,motor[i].irq,DISABLE);	/* 关闭中断 */	
		motor[i].state=eMtStateStop;
		OS_EXIT_CRITICAL();
		TIM3CEN=1;
	}
	TIM_ClearITPendingBit(TIM2, motor[i].irq);
}

/*---- M O T O R R   R U N ----
【功能】:
【参数】:****
【返回】:****
【说明】:电机移动到指定位置
--------------作者:卢杰西   2021年5月4日0:47:06--------------------------------*/
void MotorrRunTo(INT8U i,INT32S dst)
{
#if OS_CRITICAL_METHOD == 3                     /* Allocate storage for CPU status register           */
	OS_CPU_SR  cpu_sr = 0;
#endif
	INT32S cur;
	TIM3CEN=0;									//pwm占空比设置为0,不输出脉冲,保持低电平
	OS_ENTER_CRITICAL();
	if(motor[i].state==eMtStateAdd)
		cur=motor[i].pos_base+TIM2->CNT;
	else if(motor[i].state==eMtStateDec)
		cur=motor[i].pos_base-TIM2->CNT;
	else cur=motor[i].pos;
	if(cur==dst)
	{
		*motor[i].pwm=0;							//关闭脉冲输出
		motor[i].pos=cur;
		TIM_ITConfig(TIM2,motor[i].irq,DISABLE);	/* 关闭中断 */	
		motor[i].state=eMtStateStop;
	}
	else if(cur<dst)
	{
		*motor[i].pwm=PWM_Period/2;
		*motor[i].dir=eMtStateAdd;						//正转
		motor[i].state=eMtStateAdd;
		motor[i].dst=dst;
		motor[i].pos_base=cur-TIM2->CNT;				//base 位置
		if(dst-motor[i].pos_base<=65536)
		{
			TIM_ClearITPendingBit(TIM2, motor[i].irq);
			*motor[i].tmr=dst-motor[i].pos_base;
			TIM_ITConfig(TIM2,motor[i].irq,ENABLE);		/* 启动中断 */
		}
		else
			TIM_ITConfig(TIM2,motor[i].irq,DISABLE);	/* 关闭中断 */	
	}
	else if(cur>dst)
	{
		*motor[i].pwm=PWM_Period/2;
		*motor[i].dir=eMtStateDec;						//正转
		motor[i].state=eMtStateDec;
		motor[i].dst=dst;
		motor[i].pos_base=cur+TIM2->CNT;				//base 位置
		if(motor[i].pos_base-dst<=65536)
		{
			TIM_ClearITPendingBit(TIM2, motor[i].irq);
			*motor[i].tmr=motor[i].pos_base-dst;
			TIM_ITConfig(TIM2,motor[i].irq,ENABLE);		/*启动中断*/
		}
		else
			TIM_ITConfig(TIM2,motor[i].irq,DISABLE);	/*关闭中断*/	
	}
	OS_EXIT_CRITICAL();
	TIM3CEN=1;									//pwm占空比设置为0,不输出脉冲,保持低电平
}


/*---- M O T O R   T A S K ----
【功能】:电机驱动任务,
【参数】:****
【返回】:****
【说明】:所有电机动作前,先关闭TIM3的cen,电机操作后 再重新打开cen
--------------作者:卢杰西   2021年5月3日23:18:48--------------------------------*/
void MotorTask(void *pdata)
{
	INT8U i,event;
	INT32U msg;
	INT32S cnt,bak;
	msg=(INT32U)pdata;
	CREATE_SMSG(OSQMotor, 12);
	Tim3ToMotorInit(10000, 1);
	do{
		msg=(INT32U)OSQPend(OSQMotor,0,&i);
		i=msg&0x03;
		event=(msg>>2)&0x03;
		cnt=msg>>4;
		if(msg&0x80000000) cnt|=0xF0000000;
		switch(event)
		{
			case eMtCmdStop:
				StopMotor(i);
				break;
			case eMtCmdStopSet:
				StopMotor(i);
				motor[i].pos=cnt;
				break;
			case eMtCmdRun:
				bak=GetMotorPos(i);
				if((bak>0 && cnt>0) && (cnt+bak)<0)	
					cnt=0x7FFFFFFF;
				else if((bak<0 && cnt<0) && (cnt+bak)>0) 
					cnt=0-0x7FFFFFFF;
				else cnt+=bak;
			case eMtCmdRunTo:
				MotorrRunTo(i,cnt);
				break;
		}
	}while(1);
}

/*---- T   I   M 2 _   I   R   Q   H A N D L E R ----
【功能】:计算脉冲数的定时器中断处理
【参数】:****
【返回】:****
【说明】:溢出中断 电机更新 base计数  当base计数 和 dst 的差距<=65536 就可以开 ccx 中断,精确停止
--------------作者:卢杰西   2021年5月4日13:23:44--------------------------------*/
void TIM2_IRQHandler (void)
{
	INT8U i;
	OSIntEnter();
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
	{
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
		for(i=0;i<GetItemSum(motor);i++)
		{
			if(motor[i].state==eMtStateAdd)
			{
				motor[i].pos_base+=65536;
				if(motor[i].dst-motor[i].pos_base<=65536 && motor[i].dst!=motor[i].pos_base)
				{
					TIM_ClearITPendingBit(TIM2, motor[i].irq);
					*motor[i].tmr=motor[i].dst-motor[i].pos_base;
					TIM_ITConfig(TIM2,motor[i].irq,ENABLE); 	/* 启动中断 */
				}
			}
			else if(motor[i].state==eMtStateDec)
			{
				motor[i].pos_base-=65536;
				if(motor[i].pos_base-motor[i].dst<=65536 && motor[i].dst!=motor[i].pos_base)
				{
					TIM_ClearITPendingBit(TIM2, motor[i].irq);
					*motor[i].tmr=motor[i].pos_base-motor[i].dst;
					TIM_ITConfig(TIM2,motor[i].irq,ENABLE); 	/* 启动中断 */
				}
			}
		}
	}
	for(i=0;i<GetItemSum(motor);i++)
	{
		if (TIM_GetITStatus(TIM2, motor[i].irq) != RESET && TIM_GetITStatus(TIM2, motor[i].irq))
		{
			SendMtMsg(i,eMtCmdStop,0);
			TIM_ClearITPendingBit(TIM2, motor[i].irq);
		}
	}
    OSIntExit();                                                /* Tell uC/OS-II that we are leaving the ISR                */
}

通过命令    

SendMtMsg(0, eMtCmdRun, 3600);                 //相对移动

SendMtMsg(0, eMtCmdRunTo, 3600);             //绝对运动

SendMtMsg(0, eMtCmdStop, 3600);                //停止运动

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值