搜索
bottom↓
回复: 32

STM32控制步进电机驱动程序---战舰MINI开发板库函数MDK版

  [复制链接]

出0入0汤圆

发表于 2014-7-21 10:12:41 | 显示全部楼层 |阅读模式
本帖最后由 磊磊映画 于 2014-7-21 10:14 编辑

学习过程中参考了ID:lxyppc的程序及思路
帖子http://www.amobbs.com/thread-3607403-1-1.html
stm32发送控制信号给驱动器,驱动器控制步进电机。
驱动器:控制一个步进电机转动,使用一路PWM信号,和一路方向信号,根据pwm信号的频率控制步进电机的转速,方向信号控制步进转动的方向。
之前看到很多寄存器版,我已成功移植到战舰的开发板上,对LXYPPC的程序进行了修改,使用了mdk,lxyppc的程序中调用了很多ARM标准的API,可见功底深厚。
对于程序有几点理解。
1.使用了定时器的主从门控模式,定时器3做主定时器,定时器1做从定时器,综合程序,我不禁要问主从门控模式发生的条件是什么,结果是什么?
根据程序中配置定时器的程序
TIM_SelectSlaveMode(TIM1,TIM_SlaveMode_Gated);      goto   definition后发现#define TIM_SlaveMode_Gated                ((uint16_t)0x0005)
查询参考手册发现符合3.15定时器同步中,使用一个定时器使能另一个定时器的类型
门控模式可以对内部计数,当定时器溢出的更新条件发生后,可以使能另一个定时器工作,也就是说,更新发生后,另一个定时器会使能工作,所以就会出现while(1)中,if(!(TIM3->CR1 & 1))这句话,判断定时器3的使能与否。
2.见原帖中的六楼,比如TIM1输出PWM, 频率为F,可以用TIM2通过Gate来控制TIM1的输出,将TIM2预频设为1/(F*2),则TIM2的Period 就是 脉冲个数*2 - 1
对这句话不是很理解,为什么主定时器的频率要跟从定时器的频率发生关系,为什么是两倍,而不是三倍?
TIM1在配置好pwm输出后,就一直输出pwm波,TIM2的预分频跟TIM1设置PWM_Period/2 - 1,周期是waveNumber*2,当TIM1发生了F次PWM波之后,会使能TIM2,TIM2开始工作,这时将定时器TIM1计数器清零,将TIM2的周期修改,以便下次达到pwm发生预设的次数后,触发发生条件。
3.以上程序只是控制一路步进电机的,实际应用中要控制多路步进电机工作,在多路步进电机控制中使用该方法控制时要怎么做呢?
比如程序中使用的是定时器1的通道2和定时器3的通道4的主从门控工作模式,再多一路步进电机控制时,仍使用定时器1和定时器3的其他通道吗?还是使用另外两个定时器?
4.以上是我个人的理解,可能不对,欢迎指教。
  1. #include "led.h"
  2. #include "delay.h"
  3. #include "sys.h"
  4. #include "key.h"
  5. #include "usart.h"
  6. #include "exti.h"
  7. #include "wdg.h"
  8. #include "timer.h"
  9. #include "pwm.h"

  10. //Mini STM32开发板范例代码8
  11. //PWM输出 实验
  12. //正点原子@ALIENTEK
  13. //技术论坛:www.openedv.com       


  14. #define   PWM_Period      120



  15. void  RCC_Configuration(void);
  16. void  NVIC_Configuration(void);
  17. void  TIMER_Configuration(void);

  18. u16       waveNumber = 10;

  19. /*---------------------------------------------------------------------------------------------------------------------------------------*/
  20. /* Just make parameter name shorter */
  21. #define     _GetInternalTrigger(S,M) \
  22.   (S == TIM1 ? (M == TIM5 ? TIM_TS_ITR0 : (M == TIM2 ? TIM_TS_ITR1 : (M == TIM3 ? TIM_TS_ITR2 :(M == TIM4 ? TIM_TS_ITR3 : (u16)-1)))): \
  23.   (S == TIM8 ? (M == TIM1 ? TIM_TS_ITR0 : (M == TIM2 ? TIM_TS_ITR1 : (M == TIM4 ? TIM_TS_ITR2 :(M == TIM5 ? TIM_TS_ITR3 : (u16)-1)))): \
  24.   (S == TIM2 ? (M == TIM1 ? TIM_TS_ITR0 : (M == TIM8 ? TIM_TS_ITR1 : (M == TIM3 ? TIM_TS_ITR2 :(M == TIM4 ? TIM_TS_ITR3 : (u16)-1)))): \
  25.   (S == TIM3 ? (M == TIM1 ? TIM_TS_ITR0 : (M == TIM2 ? TIM_TS_ITR1 : (M == TIM5 ? TIM_TS_ITR2 :(M == TIM4 ? TIM_TS_ITR3 : (u16)-1)))): \
  26.   (S == TIM4 ? (M == TIM1 ? TIM_TS_ITR0 : (M == TIM2 ? TIM_TS_ITR1 : (M == TIM3 ? TIM_TS_ITR2 :(M == TIM8 ? TIM_TS_ITR3 : (u16)-1)))): \
  27.   (S == TIM5 ? (M == TIM2 ? TIM_TS_ITR0 : (M == TIM3 ? TIM_TS_ITR1 : (M == TIM4 ? TIM_TS_ITR2 :(M == TIM8 ? TIM_TS_ITR3 : (u16)-1)))): \
  28.   (u16)-1))))))
  29. #define     GetInternalTrigger(SlaveTimer,MasterTimer)      _GetInternalTrigger(SlaveTimer,MasterTimer)
  30. #define compile_assert(exp)   {extern char lxyppc_at_163_dot_com[(exp) ? 1:-1];}

  31. int main(void)
  32. {

  33.         /* System Clocks Configuration */
  34.         SystemInit();
  35.         delay_init(72);             //延时初始化
  36.         NVIC_Configuration();
  37.         //uart_init(9600);
  38.         /* Enable related peripheral clocks */
  39.         RCC_APB2PeriphClockCmd(  RCC_APB2Periph_GPIOA,ENABLE);
  40.     RCC_APB2PeriphClockCmd(  RCC_APB2Periph_GPIOB,ENABLE);
  41.     RCC_APB2PeriphClockCmd(  RCC_APB2Periph_TIM1,ENABLE);
  42.     RCC_APB1PeriphClockCmd(  RCC_APB1Periph_TIM3,ENABLE);
  43.         TIMER_Configuration();
  44.         /* Create relationship between timer1 and timer3, timer3 is master, timer1 is slave
  45.         timer1 is work under gate control mode, and controled by timer3
  46.         timer3's channel 4 is used as the control signal */
  47.         /* Enable timer's master/slave work mode */
  48.         TIM_SelectMasterSlaveMode(TIM3,TIM_MasterSlaveMode_Enable);
  49.     TIM_SelectMasterSlaveMode(TIM1,TIM_MasterSlaveMode_Enable);
  50.         /* timer3's channel 4 is used as the control signal */
  51.     TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_OC4Ref );
  52.         /* Check the master/slave is valid or not */
  53.         compile_assert((u16)GetInternalTrigger(TIM1,TIM3) != (u16)-1);
  54.         /* Config timer1's external clock */
  55.     TIM_ITRxExternalClockConfig(TIM1, GetInternalTrigger(TIM1,TIM3));
  56.     TIM_SelectSlaveMode(TIM1,TIM_SlaveMode_Gated);
  57.     /* Enable the slave timer*/
  58.         TIM_Cmd(TIM1,ENABLE);
  59.          while(1){
  60.       /* Check whether the previous action is done or not */
  61.       if(!(TIM3->CR1 & 1)){
  62.         TIM1->CNT = 0; /* It would be very perfect if gate mode can
  63.                           reset the slave timer automatically */
  64.         TIM3->ARR = waveNumber*2;  /* Reload wave number*/
  65.         TIM3->CCR4 = waveNumber*2 - 1;
  66.         TIM3->CR1|=1; /* Re-enable the timer */
  67.         /* update waveform number */
  68.         waveNumber++;
  69.         if(waveNumber == 13){
  70.           waveNumber = 10;
  71.         }
  72.       }
  73.     }






  74. }



  75. /* Config IO for related timers */
  76. void  TIMER_Configuration(void)
  77. {
  78.          GPIO_InitTypeDef GPIO_InitStructure;
  79.      /* Timer1 Channel 2, PA9 */
  80.      GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_9;
  81.      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  82.      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  83.      GPIO_Init(GPIOA, &GPIO_InitStructure);
  84.      /* Timer3 Channel 4, PB1*/
  85.      GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_1;
  86.      GPIO_Init(GPIOB, &GPIO_InitStructure);
  87.          /* Setup Timer3 channel 4, Timer3 is master timer
  88.          This timer is used to control the waveform count of timer1 */
  89.          do
  90. {
  91.          TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  92.      TIM_OCInitTypeDef  TIM_OCInitStructure;
  93.      TIM_DeInit(TIM3);
  94.          TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  95.      TIM_OCStructInit(&TIM_OCInitStructure);
  96.      TIM_TimeBaseStructure.TIM_Prescaler = PWM_Period/2 - 1;
  97.      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  98.      TIM_TimeBaseStructure.TIM_Period = waveNumber*2;
  99.      TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  100.      TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
  101.      
  102.       /* Timer2 Channel 3 Configuration in PWM2 mode, this is used for enable Recive clcok */
  103.      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  104.      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  105.      TIM_OCInitStructure.TIM_Pulse = waveNumber*2 - 1;
  106.      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  107.      TIM_OC4Init(TIM3,&TIM_OCInitStructure);
  108.      TIM_CtrlPWMOutputs(TIM3, ENABLE);
  109.      TIM_SelectOnePulseMode(TIM3, TIM_OPMode_Single);

  110.          
  111.          do
  112.          {
  113.                  /* Setup timer1 channel 2, Timer1 is slave timer
  114.              This timer is used to output waveforms */
  115.                  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  116.              TIM_OCInitTypeDef  TIM_OCInitStructure;
  117.              TIM_DeInit(TIM1);
  118.              TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  119.              TIM_OCStructInit(&TIM_OCInitStructure);
  120.              TIM_TimeBaseStructure.TIM_Prescaler = 0;
  121.              TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  122.              TIM_TimeBaseStructure.TIM_Period = PWM_Period;
  123.              TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  124.              TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);
  125.              
  126.               /* Timer2 Channel 3 Configuration in PWM2 mode, this is used for enable Recive clcok */
  127.              TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  128.              TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  129.              TIM_OCInitStructure.TIM_Pulse = PWM_Period/2;
  130.              TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  131.              TIM_OC2Init(TIM1,&TIM_OCInitStructure);
  132.              TIM_CtrlPWMOutputs(TIM1, ENABLE);
  133.          }
  134.          while(0);

  135. }
  136.      while(0);

  137. }
复制代码



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2014-7-21 10:15:04 | 显示全部楼层
mark        

出0入0汤圆

 楼主| 发表于 2014-7-21 10:17:46 | 显示全部楼层

别MARK  求指导

出0入0汤圆

发表于 2014-7-21 11:03:07 | 显示全部楼层
这种做法误差无法避免。定位精度必须+-一个脉冲!

出0入0汤圆

 楼主| 发表于 2014-7-21 11:25:13 | 显示全部楼层
hmd420304805 发表于 2014-7-21 11:03
这种做法误差无法避免。定位精度必须+-一个脉冲!

哦 好的 谢谢,控制两个步进电机还要再开两个定时器吗

出0入0汤圆

发表于 2014-7-21 12:16:09 | 显示全部楼层
磊磊映画 发表于 2014-7-21 11:25
哦 好的 谢谢,控制两个步进电机还要再开两个定时器吗

看我帖子

出0入0汤圆

 楼主| 发表于 2014-7-21 12:20:44 | 显示全部楼层

好的 明白  O(∩_∩)O谢谢

出0入0汤圆

 楼主| 发表于 2014-7-21 18:04:03 | 显示全部楼层
磊磊映画 发表于 2014-7-21 12:20
好的 明白  O(∩_∩)O谢谢

也就是说需要额外两组定时器做,文中说普通stm32只能生成3路,需要更多信号的话需要更高级的芯片了

出0入0汤圆

发表于 2014-7-21 22:24:48 | 显示全部楼层
磊磊映画 发表于 2014-7-21 18:04
也就是说需要额外两组定时器做,文中说普通stm32只能生成3路,需要更多信号的话需要更高级的芯片了  ...

是这样说。

出0入0汤圆

 楼主| 发表于 2014-7-22 16:34:26 | 显示全部楼层
本帖最后由 磊磊映画 于 2014-7-22 16:36 编辑


stm32f103rct6 3路可控PWM波已经调试出了,现在要根据需求写应用了。
按您所说,假设定时器1与定时器3工作在主从模式的一个定时器作为另一个定时器的预分频器类型
定时器3对定时器1的脉冲个数计数,当达到定时器3溢出后,定时器3的会有什么变化呢(包括状态和标志位)?
条件出发后,定时器3会失能是吗?
对于这段程序
  1. /* Check whether the previous action is done or not */
  2.       if(!(TIM3->CR1 & 1)){
  3.         TIM1->CNT = 0; /* It would be very perfect if gate mode can
  4.                           reset the slave timer automatically */
  5.         TIM3->ARR = waveNumber*2;  /* Reload wave number*/
  6.         TIM3->CCR4 = waveNumber*2 - 1;
  7.         TIM3->CR1|=1; /* Re-enable the timer */
  8.         /* update waveform number */
  9.         waveNumber++;
  10.         if(waveNumber == 13){
  11.           waveNumber = 10;
复制代码

if(!(TIM3->CR1 & 1))程序中是这么判断的,赋完初值后又重启定时器3了。

出0入0汤圆

发表于 2014-7-23 12:39:23 | 显示全部楼层
磊磊映画 发表于 2014-7-22 16:34
stm32f103rct6 3路可控PWM波已经调试出了,现在要根据需求写应用了。
按您所说,假设定时器1与定时器3工 ...

看你怎么配置,可以让主定时器马上停止,也可以让他不停止然后在外部处理。

出0入0汤圆

 楼主| 发表于 2014-7-23 12:45:18 | 显示全部楼层
hmd420304805 发表于 2014-7-23 12:39
看你怎么配置,可以让主定时器马上停止,也可以让他不停止然后在外部处理。 ...

程序中,显然在判断定时器3被失能了,然后对定时器1清零,对定时器3赋初值了  

出0入0汤圆

发表于 2014-7-23 14:01:24 | 显示全部楼层
磊磊映画 发表于 2014-7-23 12:45
程序中,显然在判断定时器3被失能了,然后对定时器1清零,对定时器3赋初值了   ...

有两点非常必要:1、不要用软件判断发送完成;2、不要用中断来停止输出脉冲。我的配置方法不同,你说这种的我没测试过。

出0入0汤圆

 楼主| 发表于 2014-7-23 18:43:24 | 显示全部楼层
今天看书的时候发现,在单脉冲模式下,当发生更新事件后,CEN位会被自动清除,完美解释问题,也就是说定时器3的使能位会被清零

出0入0汤圆

发表于 2014-7-23 19:28:34 | 显示全部楼层
不錯的資料,正在學習,用51搞定了,但噪音很大.

出0入0汤圆

 楼主| 发表于 2014-7-23 19:36:58 | 显示全部楼层
lryxr2507 发表于 2014-7-23 19:28
不錯的資料,正在學習,用51搞定了,但噪音很大.

1.谢谢
2.换个大点的晶振试试
你挺厉害的

出0入0汤圆

发表于 2014-8-8 15:04:25 | 显示全部楼层
学习中~~~~~~~~~~~~ 感谢楼主的分享

出0入0汤圆

发表于 2014-8-8 16:15:52 | 显示全部楼层
太好了,学习学习。

出0入0汤圆

发表于 2015-3-11 00:16:42 | 显示全部楼层
谢谢分享!!

出0入0汤圆

 楼主| 发表于 2015-3-11 11:35:16 | 显示全部楼层

我当时开发时就缺少资料,所以把自己找到吸收的资料写了心得分享出来

出0入0汤圆

发表于 2015-3-18 15:22:21 | 显示全部楼层
磊磊映画 发表于 2015-3-11 11:35
我当时开发时就缺少资料,所以把自己找到吸收的资料写了心得分享出来

感谢楼主分享,请教是不是可以在下面的代码中控制步进电机的加速算法呢?
/* Check whether the previous action is done or not */
      if(!(TIM3->CR1 & 1)){
        TIM1->CNT = 0; /* It would be very perfect if gate mode can
                          reset the slave timer automatically */
        TIM3->ARR = waveNumber*2;  /* Reload wave number*/
        TIM3->CCR4 = waveNumber*2 - 1;
        TIM3->CR1|=1; /* Re-enable the timer */
        /* update waveform number */
        waveNumber++;
        if(waveNumber == 13){
          waveNumber = 10;

出0入0汤圆

发表于 2015-3-18 15:22:59 | 显示全部楼层
磊磊映画 发表于 2015-3-11 11:35
我当时开发时就缺少资料,所以把自己找到吸收的资料写了心得分享出来

if(waveNumber == 13){
          waveNumber = 10; 这两句是啥意思呢?

出0入0汤圆

 楼主| 发表于 2015-3-20 17:56:06 | 显示全部楼层
spy2008 发表于 2015-3-18 15:22
if(waveNumber == 13){
          waveNumber = 10; 这两句是啥意思呢?

对脉冲进行计数,计到预设频率后,恢复初值

出0入0汤圆

发表于 2015-4-9 21:51:22 | 显示全部楼层
也想学电机控制,保存了。想做个基础变频器

出0入0汤圆

 楼主| 发表于 2015-4-10 08:15:47 | 显示全部楼层
93434387@qq.com 发表于 2015-4-9 21:51
也想学电机控制,保存了。想做个基础变频器

看来你已经把帖子看明白了

出0入0汤圆

发表于 2015-8-5 20:52:23 | 显示全部楼层
mark

出0入0汤圆

发表于 2015-11-25 17:21:37 | 显示全部楼层
同样的疑问,我实际下载跑了这个程序 发现输出PWM的定时器管脚始终有脉冲输出 如何关闭?

出0入0汤圆

 楼主| 发表于 2015-11-25 18:42:57 | 显示全部楼层
f_14@163.com 发表于 2015-11-25 17:21
同样的疑问,我实际下载跑了这个程序 发现输出PWM的定时器管脚始终有脉冲输出 如何关闭? ...

已经很久远了,忘了都,关闭定时器使能吧?
我后来换了 换成AVR446算法的了

出0入0汤圆

发表于 2016-5-30 17:20:37 | 显示全部楼层
学习中。

出0入0汤圆

发表于 2017-9-8 17:34:33 | 显示全部楼层
磊磊映画 发表于 2015-11-25 18:42
已经很久远了,忘了都,关闭定时器使能吧?
我后来换了 换成AVR446算法的了 ...

也学习一下avr446。谢谢分享。

出0入0汤圆

 楼主| 发表于 2017-9-11 08:34:49 | 显示全部楼层
sddzycnq 发表于 2017-9-8 17:34
也学习一下avr446。谢谢分享。

AVR446  在步进电机控制已经是经典了  强烈推荐

出0入0汤圆

发表于 2017-11-29 21:14:41 | 显示全部楼层
好东西,谢谢楼主的分享

出100入101汤圆

发表于 2017-12-4 23:28:21 | 显示全部楼层
资料不错!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-23 18:55

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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