打印
[STM32F0]

2个定时器同时输出4路PWM,控制4相8拍电机

[复制链接]
3527|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tgwfcc|  楼主 | 2015-8-20 12:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
简介:
1、芯片是F0C8的,通过ULN2803驱动24BYJ48,5V减速步进电机,定时器是TIM1和TIM3,TIM1是高级的,TIM3是通用的,通道都是用的CH1、2、3、4。
2、要求是输出4路占空比一定37.5%,相位差90°的波形。
3、方法是定时器输出翻转,使能OC中断,在中断中不停的改变CCR的值,达到占空比一定的要求;4个通道的CCR初始值相差1/4的ARR值。
4、TIM1已经搞定,可以实现正转、反转,速度控制,开始、停止。
问题:
1、TIM3可以转动,不能停止,在定时器初始化TIM3->CR1 |=0x01;后加打印信息,不能打印;单步调试时执行到串口里边就死掉了。
  while (USART_GetFlagStatus(UART_USED, USART_FLAG_TXE) == RESET)
        {}

代码:
1、定时器初始化
void Motor_LR_TIM3_Init(uint8_t direct,uint16_t speed)
{                                                                                              
        TIM3->ARR=32*speed/10-1;                        //É趨¼ÆÊýÆ÷×Ô¶¯ÖØ×°Öµ  arr=48000000/(psc+1)/(1000000/(8*speed))
        TIM3->PSC=120-1;
       
        //MOTOR_LR TIM3 Configuration
        TIM3->CCMR1|=3<<4;          //CH1 Æ¥Åäʱ·­×ª
        TIM3->CCMR1|=3<<12;          //CH2 Æ¥Åäʱ·­×ª
        TIM3->CCMR2|=3<<4;          //CH3 Æ¥Åäʱ·­×ª
        TIM3->CCMR2|=3<<12;          //CH4 Æ¥Åäʱ·­×ª

        TIM3->CCER|=1<<0;           //OC1 Êä³öʹÄÜ          
        TIM3->CCER|=1<<4;           //OC2 Êä³öʹÄÜ          
        TIM3->CCER|=1<<8;           //OC3 Êä³öʹÄÜ          
        TIM3->CCER|=1<<12;           //OC4 Êä³öʹÄÜ          

        TIM3->CR1        |=1<<7;           //ARPEʹÄÜ
        TIM3->DIER |=0x1F;                //ʹÄÜTIM²¶»ñ/±È½Ï1 2 3 4ÖжÏ
        UART_send_byte(0xA);   //可以打印
        if(direct==MOTOR_DIR_LEFT)
        {
                        TIM3->CCR1=MOTOR_LEFT_BLUE_VALUE;
                        TIM3->CCR2=MOTOR_LEFT_BROWN_VALUE;
                        TIM3->CCR3=MOTOR_LEFT_YELLOW_VALUE;
                        TIM3->CCR4=MOTOR_LEFT_BLACK_VALUE;
                        UART_send_byte(0xB);  //可以打印
        }
        else if(direct==MOTOR_DIR_RIGHT)
        {
                        TIM3->CCR1=MOTOR_RIGHT_BLUE_VALUE;
                        TIM3->CCR2=MOTOR_RIGHT_BROWN_VALUE;
                        TIM3->CCR3=MOTOR_RIGHT_YELLOW_VALUE;
                        TIM3->CCR4=MOTOR_RIGHT_BLACK_VALUE;               
        }
        UART_send_byte(0xC);  //可以打印
        TIM3->CR1 |=0x01;            //使能定时器3
        UART_send_byte(0xC);    //不能打印
}
2、失能定时器,停止电机
void Motor_LR_Stop(void)
{
        TIM3->CR1 &=~(0x01);            //¹Ø±Õ¶¨Ê±Æ÷3
}
3、开始程序,方向改变时定时器重新初始化,改变方向全局变量motor_dir
void Motor_LR_Start(uint8_t direct,uint16_t speed)
{
        motor_dir=direct;    //全局变量,在中断里判断方向
        //TIM_DeInit(TIM3);       
        Motor_LR_TIM3_Init(direct,speed);
        UART_send_byte(0x0D);   //不能打印
}
4、中断程序
void TIM3_IRQHandler(void)
{
        uint16_t LR_capture1;
        uint16_t LR_capture2;
        uint16_t LR_capture3;
        uint16_t LR_capture4;
       
        if(TIM_GetITStatus(TIM3,TIM_IT_CC1)!=RESET)
        {
                LR_capture1=TIM_GetCapture1(TIM3);
                switch(motor_dir)
                {
                        case MOTOR_DIR_LEFT :
                        {
                                if(LR_capture1==MOTOR_LEFT_BLUE_VALUE)
                                        TIM_SetCompare1(TIM3,MOTOR_LEFT_BLUE_VALUE+HIGH_DUTY_CYCLE);
                                else if(LR_capture1==MOTOR_LEFT_BLUE_VALUE+HIGH_DUTY_CYCLE)        
                                        TIM_SetCompare1(TIM3,MOTOR_LEFT_BLUE_VALUE);
                        }break;       
                        case MOTOR_DIR_RIGHT :
                        {
                                if(LR_capture1==MOTOR_RIGHT_BLUE_VALUE)
                                        TIM_SetCompare1(TIM3,MOTOR_RIGHT_BLUE_VALUE+HIGH_DUTY_CYCLE);
                                else if(LR_capture1==MOTOR_RIGHT_BLUE_VALUE+HIGH_DUTY_CYCLE)       
                                        TIM_SetCompare1(TIM3,MOTOR_RIGHT_BLUE_VALUE);
                        }break;       
                }
               
                TIM_ClearITPendingBit(TIM3,TIM_IT_CC1);
        }
       
        else if(TIM_GetITStatus(TIM3,TIM_IT_CC2)!=RESET)
        {
                LR_capture2=TIM_GetCapture2(TIM3);
                switch(motor_dir)
                {
                        case MOTOR_DIR_LEFT :
                        {
                                if(LR_capture2==MOTOR_LEFT_BROWN_VALUE)
                                        TIM_SetCompare2(TIM3,MOTOR_LEFT_BROWN_VALUE+HIGH_DUTY_CYCLE);
                                else if (LR_capture2==MOTOR_LEFT_BROWN_VALUE+HIGH_DUTY_CYCLE)       
                                        TIM_SetCompare2(TIM3,MOTOR_LEFT_BROWN_VALUE);
                        }break;
                        case MOTOR_DIR_RIGHT :
                        {
                                if(LR_capture2==MOTOR_RIGHT_BROWN_VALUE)
                                        TIM_SetCompare2(TIM3,MOTOR_RIGHT_BROWN_VALUE+HIGH_DUTY_CYCLE);
                                else if(LR_capture2==MOTOR_RIGHT_BROWN_VALUE+HIGH_DUTY_CYCLE)
                                        TIM_SetCompare2(TIM3,MOTOR_RIGHT_BROWN_VALUE);
                        }break;       
                }
               
                TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);
        }
       
        else if(TIM_GetITStatus(TIM3,TIM_IT_CC3)!=RESET)
        {
                LR_capture3=TIM_GetCapture3(TIM3);
                switch(motor_dir)
                {
                        case MOTOR_DIR_LEFT :
                        {
                                if(LR_capture3==MOTOR_LEFT_YELLOW_VALUE)
                                        TIM_SetCompare3(TIM3,MOTOR_LEFT_YELLOW_VALUE+HIGH_DUTY_CYCLE);
                                else if(LR_capture3==MOTOR_LEFT_YELLOW_VALUE+HIGH_DUTY_CYCLE)
                                        TIM_SetCompare3(TIM3,MOTOR_LEFT_YELLOW_VALUE);               
                        }break;
                        case MOTOR_DIR_RIGHT :
                        {
                                if(LR_capture3==MOTOR_RIGHT_YELLOW_VALUE)
                                        TIM_SetCompare3(TIM3,MOTOR_RIGHT_YELLOW_VALUE+HIGH_DUTY_CYCLE);
                                else if(LR_capture3==MOTOR_RIGHT_YELLOW_VALUE+HIGH_DUTY_CYCLE)
                                        TIM_SetCompare3(TIM3,MOTOR_RIGHT_YELLOW_VALUE);
                        }break;
                }
               
                TIM_ClearITPendingBit(TIM3,TIM_IT_CC3); //¼Ó´òÓ¡ÓÐÎÊÌâ
        }
       
        else if(TIM_GetITStatus(TIM3,TIM_IT_CC4)!=RESET)
        {
                LR_capture4=TIM_GetCapture4(TIM3);
                switch(motor_dir)
                {
                        case MOTOR_DIR_LEFT :
                        {
                                if(LR_capture4==MOTOR_LEFT_BLACK_VALUE)
                                        TIM_SetCompare4(TIM3,MOTOR_LEFT_BLACK_VALUE+HIGH_DUTY_CYCLE-8*BEAT);
                                else if(LR_capture4==MOTOR_LEFT_BLACK_VALUE+HIGH_DUTY_CYCLE-8*BEAT)
                                        TIM_SetCompare4(TIM3,MOTOR_LEFT_BLACK_VALUE);
                        }break;
                        case MOTOR_DIR_RIGHT :
                        {
                                if(LR_capture4==MOTOR_RIGHT_BLACK_VALUE)
                                        TIM_SetCompare4(TIM3,MOTOR_RIGHT_BLACK_VALUE+2*BEAT);
                                else if(LR_capture4==MOTOR_RIGHT_BLACK_VALUE+2*BEAT)  
                                        TIM_SetCompare4(TIM3,MOTOR_RIGHT_BLACK_VALUE+7*BEAT);
                                else if(LR_capture4==MOTOR_RIGHT_BLACK_VALUE+7*BEAT)
                                        TIM_SetCompare4(TIM3,MOTOR_RIGHT_BLACK_VALUE+2*BEAT);
                        }break;
                }
               
                TIM_ClearITPendingBit(TIM3,TIM_IT_CC4);
        }
}

5、测试程序
void test2(void)
{
        Motor_LR_Start(MOTOR_DIR_LEFT,SPEED);
        //以下不能执行
        UART_send_byte(0x0D);   
        delayms(800);
        printf("\r\r\n motor_dir=%d \r\r\n",motor_dir);
        Motor_LR_Stop();
        delayms(1000);
        printf("\r\r\n motor_dir=%d \r\r\n",motor_dir);
        Motor_LR_Start(MOTOR_DIR_RIGHT,SPEED);
        delayms(8000);
        printf("\r\r\n end \r\r\n");       
        Motor_LR_Stop();
        delayms(1000);
}


沙发
amanda_s| | 2015-8-20 15:16 | 只看该作者
走到串口的程序就死掉。那是串口有问题。
死掉是进到HARDFAULT里了吗?

使用特权

评论回复
板凳
airwill| | 2015-8-20 20:01 | 只看该作者
我决定这个控制方式有问题, 把定时器用得太复杂啦. 特别是实现相位差的 PWM 信号输出. 稳定性做不好. 其实步进电机不就是换相表嘛, 单一定时器溢出中断, 选换相表数据输出就是了. 这样可以轻松应付电机加减速的要求.

至于楼主的问题, 还有可能是中断嵌套里的优先级问题

使用特权

评论回复
地板
天灵灵地灵灵| | 2015-8-21 11:25 | 只看该作者
控制电机多的话最好用DSP吧

使用特权

评论回复
5
StevenLau2008| | 2015-8-21 14:52 | 只看该作者
电机控制 MICROCHIP 是应用比较广泛的。

Steven Lau(刘玉胜)  Microchip &  IR 授权代理商
*****************************************
深圳市高健实业股份有限公司
Topsee Interational Co.,Ltd
股票代码:832042
Tel:0755-26993393/26617466(转IC部)
Mobile:13148736025
Fax:0755-26993880
E-mail:steven.liu@topsee.com

地址:深圳市**区南区科技南一路W1-A5达实智能大厦二楼

******************************************

使用特权

评论回复
6
tgwfcc|  楼主 | 2015-8-21 15:36 | 只看该作者
amanda_s 发表于 2015-8-20 15:16
走到串口的程序就死掉。那是串口有问题。
死掉是进到HARDFAULT里了吗?

串口在使能定时器前边是可以的,后边就不行了,而且用TIM1是没有问题的。
死掉是在while的等待中

使用特权

评论回复
7
tgwfcc|  楼主 | 2015-8-21 15:46 | 只看该作者
本帖最后由 tgwfcc 于 2015-8-21 15:47 编辑
airwill 发表于 2015-8-20 20:01
我决定这个控制方式有问题, 把定时器用得太复杂啦. 特别是实现相位差的 PWM 信号输出. 稳定性做不好. 其实 ...

用定时器溢出中断控制是可以的,之前想用PWM控制这个电机,发现控制不了,就用定时器翻转模式来控制。
中断嵌套,如果只用一个TIM3控制一个电机的话,就一个定时器中断吧?

使用特权

评论回复
8
tgwfcc|  楼主 | 2015-8-21 15:46 | 只看该作者
天灵灵地灵灵 发表于 2015-8-21 11:25
控制电机多的话最好用DSP吧

就两个电机,DSP就不用了

使用特权

评论回复
9
mintspring| | 2015-8-21 17:12 | 只看该作者
两个电机绰绰有余的。楼主慢慢调试。

使用特权

评论回复
10
tgwfcc|  楼主 | 2015-8-21 17:14 | 只看该作者
mintspring 发表于 2015-8-21 17:12
两个电机绰绰有余的。楼主慢慢调试。

就是找不到原因了,才来求助啊,

使用特权

评论回复
11
tgwfcc|  楼主 | 2015-8-21 17:16 | 只看该作者
TIM3的使能和串口冲突,TIM3使能屏蔽掉,可以正常打印,不屏蔽掉,使能后的都打印不了

使用特权

评论回复
12
airwill| | 2015-8-21 21:50 | 只看该作者
对于整步走的步进电机, 一般驱动的转换速度不会超过 10Khz, 用一个定时器控制一个电机. 两个定时器控制两个电机, 中断冲突引起的延迟也不会影响到电机的运行.

使用特权

评论回复
13
豆腐块| | 2015-8-23 16:21 | 只看该作者
会不会是是中断嵌套优先级问题

使用特权

评论回复
14
冰河w| | 2015-8-23 17:09 | 只看该作者
个人感觉楼主的方法是可以实现的, 中断冲突引起的延迟也不会影响到电机的运行

使用特权

评论回复
15
tgwfcc|  楼主 | 2015-8-24 09:17 | 只看该作者
豆腐块 发表于 2015-8-23 16:21
会不会是是中断嵌套优先级问题

现在就用到一个TIM3中断,没有其他的啊,串口只发,也没用到中断

使用特权

评论回复
16
tgwfcc|  楼主 | 2015-8-24 14:31 | 只看该作者
谢谢大家的帮助,现在问题已解决,不过还是ST代理解决的。
现在说一下问题,TIM3的更新中断标志没有清零,导致程序在中断里一直出不来,那么TIM3使能完,后边的程序是不会执行的。所以在中断中,要把TIM_IT_Update清零,TIM_ClearITPendingBit(TIM3,TIM_IT_Update)。
虽然问题解决,但是还有个疑问,TIM1用的TIM1_CC_IRQHandler,TIM3用的TIM3_IRQHandler,那么TIM1只要清空TIM_IT_CCx中断即可,TIM3还要清空TIM_IT_Update。如果有TIM3_CC_IRQHandler的话,还是只要清空TIM_IT_CCx中断就行。不知道是不是这样的?
等等在了解下更新中断和捕获/比较中断的区别。

使用特权

评论回复
17
lefeng| | 2015-8-24 15:34 | 只看该作者
死掉是在while的等待中,是什么情况,程序逻辑没问题吧

使用特权

评论回复
18
豆腐块| | 2015-8-24 15:50 | 只看该作者
TIM3的更新中断标志没有清零,导致程序在中断里一直出不来,解决就好,学习了

使用特权

评论回复
19
FireRiver9| | 2015-8-24 16:21 | 只看该作者
在中断中,要把TIM_IT_Update清零,TIM_ClearITPendingBit(TIM3,TIM_IT_Update)。解决就好,赞

使用特权

评论回复
20
尤彼卡| | 2015-8-24 16:57 | 只看该作者
控制电机最好用DSP

使用特权

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

本版积分规则

34

主题

260

帖子

4

粉丝