打印
[STM32F1]

stm32使用TIM3输出脉冲 TIM2控制脉冲个数 驱动伺服电机

[复制链接]
1877|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ljxh401|  楼主 | 2021-5-5 20:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#申请原创#先初始化 定时器3 和 定时器2  定时器3作为主定时器 通过溢出 驱动定时器2

#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的溢出 作为信号
//设置从定时器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
        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                */
}



使用特权

评论回复
沙发
豆杀包| | 2021-6-10 23:02 | 只看该作者
通过主从定时器控制,主定时器输出PWM,从定时器计数,从定时器溢出关闭主定时器,

使用特权

评论回复
板凳
王旺| | 2021-7-15 10:49 | 只看该作者
老哥您好,我也在做这个电机,能不能麻烦老哥发一下这个代码,老哥确实很麻烦您,非常感谢,万分感谢,感激不尽。拜托老哥了 790795176@qq.com

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

49

主题

220

帖子

3

粉丝