概述
先上 定时器 和 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); //停止运动
最后
以上就是幸福草莓为你收集整理的stm32 使用 TIM3 输出脉冲 TIM2 进行脉冲计数的全部内容,希望文章能够帮你解决stm32 使用 TIM3 输出脉冲 TIM2 进行脉冲计数所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复