OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 6784|回复: 9

通过级联TIM,产生变频率PWM控制电机,遇到问题求教

[复制链接]

2

主题

17

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2015-3-18
在线时间
1 小时
发表于 2015-3-19 10:46:57 | 显示全部楼层 |阅读模式
5金钱
下面是我根据网上的别人的方法修改后的用PWM控制电机的程序。
原始的方法链接如下:http://bbs.eeworld.com.cn/thread-252318-1-1.html
他的例子里PWM是固定频率的,只能改变脉冲数,这样就没法控制电机快慢了。
我工作中控制电机加减速,是用固定周期打不同频率的脉冲,实现电机的加减速、快慢控制,
下面是我的方法:
TIM3 TIM2级联,主计数器TIM3的周期定位2ms,TIM3的使能信号作为TIM2的触发信号,单发模式。
TIM2作为从计数器以gate模式受TIM3控制,在2ms周期内以不同频率不同个数发出PWM脉冲。

现在有两个问题我没法解决:
1 、程序在我把断点设到中断里时,工作很正常,能在指定周期内完美的输出脉冲波形,但是去掉断点连续跑,
TIM3直接就不进中断去了。
2 、中断里的TIM2->CR1&=(uint16_t)~TIM_CR1_CEN;TIM2->CR1|=1; 两个语句是我自己加的,
原来的例子里没有。如果没有手动清除TIM2 CEN,则中断断点后TIM2还在计数,TIM2->CNT = 0; 这句就无效,pwm乱套。

我奇怪GATE MODE下, TIM2不是要跟着TIM3一起启动和停止的吗?可是断点时发现TIM2的CEN位根本没清除
进入中断后观察过TIM2 ->SMCR值是0XA5 TIM3->SMCR是0X80 CR2 OPM是1 ,也就是说设置都没错。
这个模式在来源的例子中是能工作正常的,可是我一改变TIM2的设置,就不能正常工作了?why?
又,查手册说TRGI信号有delay,才促发,可是我找来找去找不着delay在哪里,怎么设置的!

第一次用STM32做设计,眼看似乎就好了,结果掉这坑里!求指点?
代码如下:
//---------------------------------------------------------------------------
[mw_shl_code=c,true] #define PWM_BASE 18000 void pwm_init(void) { GPIO_InitTypeDef GPIO_InitStructure; /* TIM2 clock enable */ RCC_PCLK1Config(RCC_HCLK_Div16); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //TIM2 CH1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度 GPIO_Init(GPIOA, &GPIO_InitStructure); //TIM_Cmd(TIM2,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PB0 TIM3 CH3 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度 GPIO_Init(GPIOB, &GPIO_InitStructure); /* TIM2 Main Output Enable */ //------------------------------------------------------------------- /* Setup timer2 channel 2, Timer2 is slave timer This timer is used to output waveforms */ { //TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //TIM_OCInitTypeDef TIM_OCInitStructure; TIM_DeInit(TIM2); TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_OCStructInit(&TIM_OCInitStructure); TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period = PWM_BASE;//PWM_Period; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); /* Timer2 Channel 2 Configuration in PWM2 mode, this is used for enable Recive clcok */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = PWM_BASE/2; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM2,&TIM_OCInitStructure); TIM_CtrlPWMOutputs(TIM2, ENABLE); } //----------------------------------------------------------------------- /* Setup Timer3 channel 3, Timer3 is master timer This timer is used to control the waveform count of timer1 */ { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_DeInit(TIM3); TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_OCStructInit(&TIM_OCInitStructure); TIM_TimeBaseStructure.TIM_Prescaler =0;//PWM_BASE/8 - 1;;//PWM_BASE/2 - 1; //PWM_Period/2 - 1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period =PWM_BASE ;//waveNumber*8 - 1;//waveNumber*2; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse =PWM_BASE/2;// waveNumber*8 - 2;//waveNumber*2 - 1; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC3Init(TIM3,&TIM_OCInitStructure); TIM_CtrlPWMOutputs(TIM3, ENABLE); TIM_SelectOnePulseMode(TIM3, TIM_OPMode_Single); { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn ; //选择定时器TIM3 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //选择抢先式优先级(与中断嵌套级别有关) NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //选择子优先级(同抢先式优先级的响应顺序) NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //选择使能中断源 NVIC_Init(&NVIC_InitStructure); TIM_ClearFlag(TIM3,TIM_FLAG_CC3); //中断标志位清零 TIM_ITConfig(TIM3,TIM_IT_CC3,ENABLE); //允许更新中断 } } //-------------------------------------------------------------------------- /* Create relationship between timer1 and timer3, timer3 is master, timer1 is slave timer2 is work under gate control mode, and controled by timer3 timer3's channel 3 is used as the control signal */ /* Enable timer's master/slave work mode */ TIM_SelectMasterSlaveMode(TIM3,TIM_MasterSlaveMode_Enable); TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable); /* timer3's channel 4 is used as the control signal */ //TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_OC3Ref ); TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Enable); /* Check the master/slave is valid or not */ compile_assert((u16)GetInternalTrigger(TIM2,TIM3) != (U16)-1); /* Config timer1's external clock */ TIM_ITRxExternalClockConfig(TIM2, GetInternalTrigger(TIM2,TIM3)); TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Gated); /* Enable the slave tiemr*/ TIM_Cmd(TIM2,ENABLE); //----------------------------------------------------------------------------- TIM3->CR1|=1; } void TIM3_IRQHandler(void) { static U32 ct; U16 capture; /* enter interrupt */ rt_interrupt_enter(); //set pluse here TIM_ClearITPendingBit(TIM3, TIM_IT_CC3); TIM2->CR1&=(uint16_t)~TIM_CR1_CEN; //add by myself TIM2->CNT = 0; /* update waveform number */ if(waveNumber == 4){ waveNumber = 2; }else{ waveNumber=4; } TIM2->ARR = PWM_BASE/waveNumber; TIM2->CCR2 = (PWM_BASE/waveNumber)/2; TIM3->CR1|=1; /* Re-enable the timer */ TIM2->CR1|=1; /* leave interrupt */ rt_interrupt_leave(); rt_hw_interrupt_thread_switch(); }[/mw_shl_code]


最佳答案

查看完整内容[请看2#楼]

调试好的完整的代码在此,希望对同道有用,如果有可改进之处,请提出指教。 这个代码能用,但设置的级联似乎不怎么起作用,中断里还是要自己关闭TIM2和使能TIM2,这是遗留的疑惑,但应该不影响使用。 [mw_shl_code=c,true] #define PWM_BASE 18000 U16 waveNumber = 0; /*-------------------------------------------------------------------------------------------------------------------------------- ...
做一只高尚的猿,一只纯粹的猿,一只有益于世界的猿!
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

17

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2015-3-18
在线时间
1 小时
 楼主| 发表于 2015-3-19 10:46:58 | 显示全部楼层
调试好的完整的代码在此,希望对同道有用,如果有可改进之处,请提出指教。
这个代码能用,但设置的级联似乎不怎么起作用,中断里还是要自己关闭TIM2和使能TIM2,这是遗留的疑惑,但应该不影响使用。
[mw_shl_code=c,true] #define PWM_BASE 18000 U16 waveNumber = 0; /*---------------------------------------------------------------------------------------------------------------------------------------*/ /* Just make parameter name shorter */ #define _GetInternalTrigger(S,M) \ (S == TIM1 ? (M == TIM5 ? TIM_TS_ITR0 : (M == TIM2 ? TIM_TS_ITR1 : (M == TIM3 ? TIM_TS_ITR2 M == TIM4 ? TIM_TS_ITR3 : (u16)-1)))): \ (S == TIM8 ? (M == TIM1 ? TIM_TS_ITR0 : (M == TIM2 ? TIM_TS_ITR1 : (M == TIM4 ? TIM_TS_ITR2 M == TIM5 ? TIM_TS_ITR3 : (u16)-1)))): \ (S == TIM2 ? (M == TIM1 ? TIM_TS_ITR0 : (M == TIM8 ? TIM_TS_ITR1 : (M == TIM3 ? TIM_TS_ITR2 M == TIM4 ? TIM_TS_ITR3 : (u16)-1)))): \ (S == TIM3 ? (M == TIM1 ? TIM_TS_ITR0 : (M == TIM2 ? TIM_TS_ITR1 : (M == TIM5 ? TIM_TS_ITR2 M == TIM4 ? TIM_TS_ITR3 : (u16)-1)))): \ (S == TIM4 ? (M == TIM1 ? TIM_TS_ITR0 : (M == TIM2 ? TIM_TS_ITR1 : (M == TIM3 ? TIM_TS_ITR2 M == TIM8 ? TIM_TS_ITR3 : (u16)-1)))): \ (S == TIM5 ? (M == TIM2 ? TIM_TS_ITR0 : (M == TIM3 ? TIM_TS_ITR1 : (M == TIM4 ? TIM_TS_ITR2 M == TIM8 ? TIM_TS_ITR3 : (u16)-1)))): \ (u16)-1)))))) #define GetInternalTrigger(SlaveTimer,MasterTimer) _GetInternalTrigger(SlaveTimer,MasterTimer) #define compile_assert(exp) {extern char lxyppc_at_163_dot_com[(exp) ? 1:-1];} void pwm_init(void) { GPIO_InitTypeDef GPIO_InitStructure; /* TIM2 clock enable */ RCC_PCLK1Config(RCC_HCLK_Div16); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //TIM2 CH1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度 GPIO_Init(GPIOA, &GPIO_InitStructure); //TIM_Cmd(TIM2,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PB0 TIM3 CH3 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度 GPIO_Init(GPIOB, &GPIO_InitStructure); /* TIM2 Main Output Enable */ //------------------------------------------------------------------- /* Setup timer2 channel 2, Timer2 is slave timer This timer is used to output waveforms */ { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_DeInit(TIM2); TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_OCStructInit(&TIM_OCInitStructure); TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period = PWM_BASE*2;//PWM_Period; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); /* Timer2 Channel 3 Configuration in PWM2 mode, this is used for enable Recive clcok */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = PWM_BASE*2; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; TIM_OC2Init(TIM2,&TIM_OCInitStructure); TIM_CtrlPWMOutputs(TIM2, ENABLE); } //----------------------------------------------------------------------- /* Setup Timer3 channel 3, Timer3 is master timer This timer is used to control the waveform count of timer1 */ { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_DeInit(TIM3); TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_OCStructInit(&TIM_OCInitStructure); TIM_TimeBaseStructure.TIM_Prescaler =0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period =PWM_BASE ; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse =PWM_BASE-2; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; TIM_OC3Init(TIM3,&TIM_OCInitStructure); TIM_CtrlPWMOutputs(TIM3, ENABLE); TIM_SelectOnePulseMode(TIM3, TIM_OPMode_Single); { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn ; //选择定时器TIM3 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //选择抢先式优先级(与中断嵌套级别有关) NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //选择子优先级(同抢先式优先级的响应顺序) NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //选择使能中断源 NVIC_Init(&NVIC_InitStructure); TIM_ClearFlag(TIM3,TIM_FLAG_CC3); //中断标志位清零 TIM_ITConfig(TIM3,TIM_IT_CC3,ENABLE); //允许更新中断 } } //-------------------------------------------------------------------------- /* Create relationship between timer1 and timer3, timer3 is master, timer1 is slave timer1 is work under gate control mode, and controled by timer3 timer3's channel 4 is used as the control signal */ /* Enable timer's master/slave work mode */ TIM_SelectMasterSlaveMode(TIM3,TIM_MasterSlaveMode_Enable); TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable); /* timer3's channel 4 is used as the control signal */ //TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_OC3Ref ); TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Enable); /* Check the master/slave is valid or not */ compile_assert((u16)GetInternalTrigger(TIM2,TIM3) != (U16)-1); /* Config timer1's external clock */ TIM_ITRxExternalClockConfig(TIM2, GetInternalTrigger(TIM2,TIM3)); TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Gated); /* Enable the slave tiemr*/ //TIM_Cmd(TIM2,ENABLE); //----------------------------------------------------------------------------- TIM2->CR1|=1; TIM3->CR1|=1; //--------------------------------------------------------------------------- //set ios set speed select and } void TIM3_IRQHandler(void) { static U32 ct; U16 capture; /* enter interrupt */ rt_interrupt_enter(); //set pluse here TIM_ClearITPendingBit(TIM3, TIM_IT_CC3); TIM2->CR1&=(uint16_t)~TIM_CR1_CEN; //add by myself TIM2->CNT = 0; /* It would be very perfect if gate mode can reset the slave timer automatically */ if(waveNumber == 4){ waveNumber = 2; }else if(waveNumber==2){ waveNumber=0; }else if(waveNumber==0){ waveNumber=4; } /* update waveform number */ if(waveNumber==0) { TIM2->ARR = PWM_BASE*2; //holw cycle low TIM2->CCR2 = PWM_BASE*2; }else{ TIM2->ARR = PWM_BASE/waveNumber; //set freq by pluse number TIM2->CCR2 = (PWM_BASE/waveNumber)/2; } TIM2->CR1|=1; TIM3->CR1|=1; /* Re-enable the timer */ /* leave interrupt */ rt_interrupt_leave(); rt_hw_interrupt_thread_switch(); }[/mw_shl_code]


做一只高尚的猿,一只纯粹的猿,一只有益于世界的猿!
回复

使用道具 举报

2

主题

17

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2015-3-18
在线时间
1 小时
 楼主| 发表于 2015-3-19 15:34:18 | 显示全部楼层
发现问题在那里了,原来TIM3的ONE ULSE 模式,说CEN会在下一个event时被清0,我原以为是period到后清零,细读手册原来CCR3计数到了就产生event了。
还是看书不认真啊。
待我修正测试好了再更新代码。
做一只高尚的猿,一只纯粹的猿,一只有益于世界的猿!
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165516
金钱
165516
注册时间
2010-12-1
在线时间
2116 小时
发表于 2015-3-19 22:43:34 | 显示全部楼层
回复【2楼】vinge:
---------------------------------
谢谢分享
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

2

主题

17

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2015-3-18
在线时间
1 小时
 楼主| 发表于 2015-3-19 22:43:54 | 显示全部楼层
另外这段代码在KEIL里仿真的结果是错误的,只有第一次的波形正确,后面的都错了,似乎是仿真程序的bug;在实际电路板上测试是能正常工作的。
做一只高尚的猿,一只纯粹的猿,一只有益于世界的猿!
回复

使用道具 举报

7

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2015-7-17
在线时间
5 小时
发表于 2015-7-17 14:02:59 | 显示全部楼层
回复【3楼】vinge:
---------------------------------楼主,非常感谢,但是有点问题想问一下,你的程序为什么在KEIL中却有很多错误,尽管我不是很明白,比如 (S == TIM5 ? (M == TIM2 ? TIM_TS_ITR0: (M == TIM3 ? TIM_TS_ITR1: (M == TIM4 ? TIM_TS_ITR2 M == TIM8 ? TIM_TS_ITR3: (u16)-1)))): \
(u16)-1))))))这里为什么是错误的,还有你提示U16大小写错误的问题
回复

使用道具 举报

7

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2015-7-17
在线时间
5 小时
发表于 2015-7-17 14:26:00 | 显示全部楼层
回复【5楼】vinge:
---------------------------------
楼主,请分享下,谢谢
回复

使用道具 举报

2

主题

17

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2015-3-18
在线时间
1 小时
 楼主| 发表于 2015-11-16 15:33:30 | 显示全部楼层
回复【7楼】1132642671:
---------------------------------
好久没上来了!U16是我从ucos里借用过来的数据类型定义,就是unsigned short.
这个宏我是照搬人家写好的东西。我2个工程里都用过没有编译错误啊。
做一只高尚的猿,一只纯粹的猿,一只有益于世界的猿!
回复

使用道具 举报

44

主题

298

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
209
金钱
209
注册时间
2016-9-9
在线时间
84 小时
发表于 2016-11-17 09:15:46 | 显示全部楼层
能把你代码打个包,我下载过来一起调试吗?
回复

使用道具 举报

6

主题

17

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2018-9-1
在线时间
8 小时
发表于 2018-9-3 18:35:57 | 显示全部楼层
您好,能把代码打包一下发给我吗,谢谢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-24 19:11

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表