找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9368|回复: 10
打印 上一主题 下一主题
收起左侧

STM32步进伺服电机梯形加速源程序 单轴简易运动控制器

  [复制链接]
跳转到指定楼层
楼主
ID:82014 发表于 2018-4-26 12:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
步进电机梯形加速程序

单片机源程序如下:
  1. /*基于STM32的单轴简易运动控制器/脉冲发生器*/
  2. /*脉冲+方向控制步进伺服电机*/
  3. /*
  4. 优化记录:
  5. 增加急停GPIOC.0、正向极限GPIOC.1、负向极限GPIOC.2等输入IO接点

  6. 中断修改TIMx_PSC一个寄存器的值,而不是修改TIMx_ARR预加载寄存器+TIMx_CCRx比较值寄存器两个值,缩短中断处理时间

  7. 定位指令DRVI/DRVA中,目标频率设定过高、而实际输出脉冲数过少时,则不必加速到目标频率即进入减速区
  8. */

  9. /*
  10. DRVI(A);相对定位,输出A(A取绝对值)个脉冲
  11. A不能为0
  12. 若A为正数,则方向为正、GPIOB.0为高电平
  13. 若A为负数,则方向为负、GPIOB.0为低电平

  14. DRVA(A)  绝对定位,输出脉冲,运行至A个脉冲的位置
  15. 若目标位置A等于当前位置D,则不执行脉冲输出
  16. 若A大于D 则方向为正GPIOB.5为高电平
  17. 若A小于D 则方向为负GPIOB.5为低电平

  18. GPIOB.1为脉冲输出
  19. GPIOB.0为方向输出
  20. 占空比为50%
  21. GPIOC.0急停
  22. GPIOC.1正向极限
  23. GPIOC.2反向极限
  24. GPIOC.3
  25. GPIOC.4
  26. GPIOC.5
  27. GPIOC.6
  28. GPIOC.7启动
  29. 阶梯曲线形式加减速
  30. 加减速时间以10毫秒为基本单位
  31. 加减速以每10毫秒为一级
  32. 例如
  33. 加减速时间为50毫秒,则加减速级数为50/10=5
  34. 加减速时间为100毫秒,则加减速级数为100/10=10
  35. 加减速时间为150毫秒,则加减速级数为150/10=15
  36. */

  37. #include "sys.h"  
  38. #include "delay.h"

  39. #define  MasterFrequency  0x100000//最高频率限制100K

  40. long Current;                        //当前位置脉冲数
  41. long Target;                        //目标位置脉冲数
  42. long StartSave;                        //定位指令刚开始启动时的当前值
  43. long DownStartSave;                //开始进入减速时的当前值


  44. typedef enum
  45. {
  46.         OFF = 0,
  47.         ON = 1,
  48. }STATUS_Type;


  49. typedef enum
  50. {
  51.         us=1,
  52.         ms=1000,
  53.         sce=1000000,
  54. }DELAY_Type;


  55. STATUS_Type RunFlag;        //定位指令脉冲输出执行标志
  56. STATUS_Type StopCommand;//定位指令脉冲输出停止命令标志
  57. STATUS_Type PlusMinus;        //正负方向标志


  58. u32 StartFreq;                        //启动频率
  59. u32 TargetFreq;                        //目标频率
  60. u32 UDTimer=1000;                        //加减速时间

  61. u32 LadderFreq[102];
  62. u16 LadderPSC[202];                //加减速0至9级速度/频率预分频值
  63. u16 LadderNum;                        //加减速速度级数
  64. u16 LadderOrderNum;                //加减速速度编号
  65. long LadderTarget[202];        //各速度等级目标值
  66. int m;

  67. void MyTimer3_Init()//定时器3初始化
  68. {
  69.                 RCC->APB2ENR|=(1<<3)|(1<<0);   //使能AFIO、GPIOB时钟
  70.                 GPIOB->CRL&=0xffffff00;  //PB5
  71.                 GPIOB->CRL|=0x000000a2;        //配置PORTB.1为复用推挽输出、配置PORTB.0为推挽输出,输出最大频率2MHz   00B000a2
  72.                 GPIOB->BRR=1<<0;
  73.                
  74.                 RCC->APB1ENR|=1<<1;           //使能定时器TIMER3时钟
  75.                 TIM3->CR1|=1<<2;                                   //设置只有计数溢出作为T3更新中断
  76.                 TIM3->DIER|=1<<0;                           //允许定时器3计数溢出中断

  77.                 MY_NVIC_Init(1,3,TIM3_IRQn,2);
  78.                 TIM3->CCMR2&=~(3<<8);               //T3_CH4通道配置为输出模式
  79.                 TIM3->CCMR2|=7<<12;                 //T3_CH4为PWM模式2
  80.                 TIM3->CCER|=1<<12;                  //T3_CH4通道输出使能               
  81.                 TIM3->PSC=71;                  
  82. }


  83. void Pluse_start()
  84. {
  85.           
  86.                 RunFlag=ON;                             //脉冲输出定位指令执行标志置ON
  87.                 StartSave=Current;
  88.                 LadderOrderNum=0;//加减速级数序号为0       
  89.                 TIM3->ARR=LadderPSC[0];
  90.     TIM3->CCR4=TIM3->ARR>>1;   //匹配值1等于重装值一半,是以占空比为50%
  91.            //delay_ms(2);                       //脉冲信号比方向信号滞后,以提高可靠性
  92.        
  93.                 TIM3->CR1|=1<<0;              //启动定时器TIMER2计数
  94. }

  95. /*********************************************************************************
  96. 函数名称:DRVI
  97. 函数功能:相对定位
  98. 入口参数:long offset相对偏移脉冲,u32 frequency最高频率
  99. 返回值:无
  100. *********************************************************************************/
  101. void DRVI(long offset,u32 frequency)
  102. {
  103.         u16 h;
  104.         u16 i;
  105.         u32 j;
  106.         if((offset!=0)&&(RunFlag==OFF)&&((GPIOC->IDR&0x01)==0))//相对偏移值为0则不接受命令,脉冲输出已执行,不接受命令
  107.         {       
  108.                 Target=Current+offset;     //目标值等于当前值加上相对偏移值
  109.                
  110.                 if(frequency<StartFreq)    //如果设定目标频率小于启动频率
  111.                 {
  112.                         frequency=StartFreq;
  113.                 }
  114.                 else if(frequency>MasterFrequency)//否则如果设定目标频率高于最高限制频率
  115.                 {
  116.                         frequency=MasterFrequency;
  117.                 }
  118.                
  119.                 LadderNum=UDTimer/10;//加减速级数
  120.                 j=(frequency-StartFreq)/LadderNum;//等差
  121.                 for(i=0;i<LadderNum;i++)
  122.                 {
  123.                         LadderFreq[i]=i*j+StartFreq;//加减速各阶梯频率
  124.                         LadderPSC[i]=(6000000/LadderFreq[i])-1;//加减速各阶梯频率对应定时器预分频值
  125.                 }
  126.                 LadderFreq[LadderNum]=frequency;//目标频率,最高频率
  127.                 LadderPSC[LadderNum]=6000000/frequency-1;//目标频率(最高频率)对应定时器预分频值
  128.                                
  129.                 if(offset>0)//相对偏移值为正数
  130.                 {
  131.                         GPIOB->BSRR=1<<0;//相对偏移值为正数,方向为正,方向信号高电平
  132.                         PlusMinus=ON;//正负方向标志置ON
  133.                        
  134.                         LadderTarget[0]=Current+StartFreq/100;//加速第一段目标脉冲值
  135.                         for(i=1;i<LadderNum;i++)
  136.                         {
  137.                                 LadderTarget[i]=LadderTarget[i-1]+LadderFreq[i]/100;//加速各段目标脉冲值
  138.                         }       
  139.                        
  140.                         while(offset<=((LadderTarget[LadderNum-1]-Current)<<1))//如果偏移量小于二倍加速增量
  141.                         {
  142.                                 LadderNum--;//加速等级数减一  频率设定过高、实际输出脉冲数过少的情况下不必加速至设定频率,避免过冲
  143.                         }
  144.                        
  145.                         for(i=0,h=LadderNum<<1;  i<LadderNum;  i++,h--)
  146.                         {
  147.                                 LadderPSC[h]=LadderPSC[i];//减速各段定时器重装值
  148.                         }
  149.                        
  150.                         LadderTarget[LadderNum<<1]=Target;//减速最后一段目标脉冲值
  151.                         for(i=(LadderNum<<1)-1,h=0;i>LadderNum;i--,h++)
  152.                         {
  153.                                 LadderTarget[i]=LadderTarget[i+1]-LadderFreq[h]/100;//减速各段目标脉冲值
  154.                         }
  155.                 }
  156.                 else//否则相对偏移值为负数                                             
  157.                 {
  158.                         GPIOB->BRR=1<<0;//相对偏移值为负数,方向为负,方向信号低电平
  159.                         PlusMinus=OFF;//正负方向标志OFF
  160.                        
  161.                         LadderTarget[0]=Current-StartFreq/100;//加速第一段目标脉冲值
  162.                         for(i=1;i<LadderNum;i++)
  163.                         {
  164.                                 LadderTarget[i]=LadderTarget[i-1]-LadderFreq[i]/100;//加速各段目标脉冲值
  165.                         }
  166.                        
  167.                         while(offset>=((LadderTarget[LadderNum-1]-Current)<<1))//如果偏移量小于二倍加速增量
  168.                         {
  169.                                 LadderNum--;//加速等级数减一  频率设定过高、实际输出脉冲数过少的情况下不必加速至设定频率,避免过冲
  170.                         }
  171.                        
  172.                         for(i=0,h=LadderNum<<1;  i<LadderNum;  i++,h--)
  173.                         {
  174.                                 LadderPSC[h]=LadderPSC[i];
  175.                         }
  176.                        
  177.                         LadderTarget[LadderNum<<1]=Target;//减速最后一段目标脉冲值
  178.                         for(i=(LadderNum<<1)-1,h=0;i>LadderNum;i--,h++)
  179.                         {
  180.                                 LadderTarget[i]=LadderTarget[i+1]+LadderFreq[h]/100;//减速各段目标脉冲值
  181.                         }
  182.                 }
  183.                 LadderTarget[LadderNum]=Target + Current - LadderTarget[LadderNum-1];
  184.                 Pluse_start();//脉冲输出正式启动
  185.         }
  186. }

  187. /*********************************************************************************
  188. 函数名称:DRVA
  189. 函数功能:绝对定位
  190. 入口参数:long target目标位置脉冲,u32 frequency最高频率
  191. 返回值:无
  192. *********************************************************************************/
  193. void DRVA(long target,u32 frequency)//3200  2khz
  194. {
  195.         u16 h;
  196.         u16 i;
  197.         u32 j;
  198.         long offset=target-Current;//
  199.         if((offset!=0)&&(RunFlag==OFF)&&((GPIOC->IDR&0x01)==0))    //目标位置等于当前位置,则不接受命令  
  200.         {                       
  201. ///////////////////////////////////////////////////////////////////////////////////////////////////////               
  202.                 Target=target;                 //目标位置设定(等于参数)
  203.                
  204.                 if(frequency<StartFreq)        //如果设定目标频率小于启动频率
  205.                 {
  206.                         frequency=StartFreq;
  207.                 }
  208.                 else if(frequency>MasterFrequency)//否则如果设定目标频率高于最高限制频率
  209.                 {
  210.                         frequency=MasterFrequency;
  211.                 }
  212.                 LadderNum=UDTimer/10;//加减速级数 分成100级
  213.                 j=(frequency-StartFreq)/LadderNum;//等差 每个阶段所加的频率数
  214.        
  215.                 for(i=0;i<LadderNum;i++)         //获取每个阶段的速度值
  216.                 {
  217.                         LadderFreq[i]=i*j+StartFreq;//加减速各阶梯频率 每个阶段的速度 等级到J
  218.                         LadderPSC[i]=(1000000/LadderFreq[i])-1;//加减速各阶梯频率对应定时器初值
  219.                 }
  220.                
  221.                 LadderFreq[LadderNum]=frequency;
  222.                 LadderPSC[LadderNum]=1000000/frequency-1;//  
  223. /////////////////////////////////////////////////////////////////////////////////////////////////////       
  224.            if(offset>0)//目标位置值大于当前位置值  
  225.                  {
  226.                         GPIOB->BSRR=1<<0;//则方向为正,方向信号高电平
  227.                         PlusMinus=ON;//正负方向标志置ON
  228.                        
  229.                         LadderTarget[0]=Current+StartFreq/100;
  230.                         for(i=1;i<LadderNum;i++)
  231.                         {
  232.                                 LadderTarget[i]=LadderTarget[i-1]+LadderFreq[i]/100;
  233.                         }       
  234.                        
  235.                         while(offset<=((LadderTarget[LadderNum-1]-Current)<<1))//如果偏移量小于二倍加速增量
  236.                         {
  237.                                 LadderNum--;//加速等级数减一  频率设定过高、实际输出脉冲数过少的情况下不必加速至设定频率,避免过冲
  238.                         }
  239.                        
  240.                         for(i=0,h=LadderNum<<1;  i<LadderNum;  i++,h--)
  241.                         {
  242.                                 LadderPSC[h]=LadderPSC[i];
  243.                         }
  244.                        
  245.                         LadderTarget[LadderNum<<1]=Target;//减速最后一段目标脉冲值
  246.                         for(i=(LadderNum<<1)-1,h=0;i>LadderNum;i--,h++)
  247.                         {
  248.                                 LadderTarget[i]=LadderTarget[i+1]-LadderFreq[h]/100;//减速各段目标脉冲值
  249.                         }
  250.      }
  251.                 else//否则目标位置值小于当前位置值,                                                          
  252.                 {
  253.                         GPIOB->BRR=1<<0;//则方向为负,方向信号低电平       
  254.                         PlusMinus=OFF;//正负方向标志OFF
  255.                        
  256.                         LadderTarget[0]=Current-StartFreq/100;
  257.                         for(i=1;i<LadderNum;i++)
  258.                         {
  259.                                 LadderTarget[i]=LadderTarget[i-1]-LadderFreq[i]/100;
  260.                         }
  261.                        
  262.                         while(offset>=((LadderTarget[LadderNum-1]-Current)<<1))//如果偏移量小于二倍加速增量
  263.                         {
  264.                                 LadderNum--;//加速等级数减一  频率设定过高、实际输出脉冲数过少的情况下不必加速至设定频率,避免过冲
  265.                         }               
  266.                         for(i=0,h=LadderNum<<1;  i<LadderNum;  i++,h--)
  267.                         {
  268.                                 LadderPSC[h]=LadderPSC[i];
  269.                         }               
  270.                         LadderTarget[LadderNum<<1]=Target;//减速最后一段目标脉冲值
  271.                         for(i=(LadderNum<<1)-1,h=0;          i>LadderNum;   i--,h++)
  272.                         {
  273.                                 LadderTarget[i]=LadderTarget[i+1]+LadderFreq[h]/100;//减速各段目标脉冲值
  274.                         }
  275.                 }
  276.                 LadderTarget[LadderNum]=Target + Current - LadderTarget[LadderNum-1];//匀速段目标位置/进入减速时位置        数组元素60
  277.                 Pluse_start();//脉冲输出正式启动
  278.         }
  279. }

  280. /*********************************************************************************
  281. 函数名称:SLOPE
  282. 函数功能:斜坡设置(坡度斜率设置)  限定启动频率在100---1000之间 限制时间在50---1000
  283. 入口参数:u32 frequency启动频率,u32 timer加减速时间
  284. 返回值:无
  285. *********************************************************************************/
  286. void SLOPE(u32 frequency,u32 timer)//200hz 600
  287. {
  288.         if(frequency<100)               
  289.         {
  290.                 StartFreq=100;
  291.         }
  292.         else if(frequency>1000)
  293.                                 {
  294.                                         StartFreq=1000;
  295.                                 }
  296.                                 else                                       
  297.                                 {
  298.                                         StartFreq=frequency;
  299.                                 }//启动频率设置大于等于100小于等于1000
  300.        
  301.         if(timer<50)               
  302.         {
  303.                 UDTimer=50;
  304.         }
  305.         else if(timer>1000)       
  306.                         {
  307.                                 UDTimer=1000;
  308.                         }
  309.                         else                               
  310.                         {               
  311.                                 UDTimer=(timer/10)*10; //取整数
  312.                         }//加减速时间设置 大于等于50小于等于1000,且为整十数
  313. }

  314. void TIM3_IRQHandler()      //定时器3全局中断函数
  315. {
  316.         long temp;
  317.         if(TIM3->SR&0x0001)
  318.         {
  319.                 if(PlusMinus==ON)  
  320.                 {
  321.                         temp=Current;
  322.                //如果方向为正,当前值加一  
  323.                         temp++;
  324.                         Current=temp;
  325.                 }
  326.                 else   
  327.                 {
  328.                         temp=Current;
  329.                         temp--;       //否则方向为负,当前值减一
  330.                         Current=temp;
  331.                 }
  332.                

  333.                 if(Current==LadderTarget[LadderOrderNum])
  334.                 {
  335.                         if(LadderOrderNum< (LadderNum<<1))
  336.                         {
  337.                                 LadderOrderNum++;
  338.                                 TIM3->PSC=LadderPSC[LadderOrderNum];
  339.                         }
  340.                         else
  341.                         {
  342.                                 TIM3->CR1&=~(1<<0);          
  343.                                 TIM3->CNT=0x0000;
  344.                                
  345.                                 RunFlag=OFF;         
  346.                         }
  347.                 }                               
  348.                
  349.                 TIM3->SR=0x0000;
  350.         }
  351. }
  352. void Variable_Init()
  353. {
  354.         Target=0;//目标位置脉冲值
  355.         Current=0;//当前位置脉冲值
  356.         RunFlag=OFF;//脉冲定位指令执行标志
  357.         StopCommand=OFF;//定位指令脉冲输出停止命令标志
  358. }
  359. void PAUSE()
  360. {
  361.         while(RunFlag==ON);       
  362. }


  363. int main(void)
  364. {
  365. //        Stm32_Clock_Init(9);
  366.         //delay_init(72);
  367.         MyTimer3_Init();        //定时器2初始化
  368.         Variable_Init();        //变量初始化
  369.         SLOPE(200,600);                //启动频率200Hz,加减速时间600毫秒 斜率设置
  370.         DRVA(1200,4000);       
  371.         while(1)
  372.         {
  373.                             //以2KHz频率前进3200脉冲当量距离
  374. //                                //PAUSE();                                //等待脉冲输出执行完毕
  375. //                                delay_ms(500);                                                                       
  376. //                          DRVA(0,20000);                //以2KHz频率前进3200脉冲当量距离
  377. //                          PAUSE();                                //等待脉冲输出执行完毕
  378. //                          delay_ms(500);       
  379.   }
  380. }
复制代码

所有资料51hei提供下载:
步进电机寄存器版本.zip (698.35 KB, 下载次数: 186)


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏12 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:445569 发表于 2019-2-2 11:08 | 只看该作者
学术型
回复

使用道具 举报

板凳
ID:138247 发表于 2019-9-9 11:34 | 只看该作者

感谢分享,非常有帮助。。
回复

使用道具 举报

地板
ID:245179 发表于 2019-10-21 16:56 | 只看该作者
写的不错,已分享使用
回复

使用道具 举报

5#
ID:334838 发表于 2019-10-24 15:11 | 只看该作者
学习下,正好需要做电机控制
回复

使用道具 举报

6#
ID:626923 发表于 2019-10-28 22:31 | 只看该作者
学习下
回复

使用道具 举报

7#
ID:579837 发表于 2019-12-18 00:01 | 只看该作者
最近正在学习电机控制,谢谢分享
回复

使用道具 举报

8#
ID:236035 发表于 2019-12-20 10:51 | 只看该作者
谢谢楼主分享,这是个弱项,还没搞过项目。
回复

使用道具 举报

9#
ID:353855 发表于 2020-2-9 18:19 | 只看该作者
感谢分享,非常有帮助。。
回复

使用道具 举报

10#
ID:353855 发表于 2020-2-18 16:21 | 只看该作者
写的不错,已分享使用
回复

使用道具 举报

11#
ID:25103 发表于 2020-7-16 12:12 | 只看该作者
仿真好像不能用,请教楼主,谢谢!
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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