搜索
bottom↓
回复: 38

请教如何用STM32控制步进电机脉冲个数

[复制链接]

出0入0汤圆

发表于 2019-5-25 23:27:00 | 显示全部楼层 |阅读模式
现在用了stm32的主从模式能控制脉冲的个数,但是有个问题,因为控制脉冲个数的寄存器最大值是个16位的数,也就是最大脉冲数只能是16位的值。

还有什么方法可以控制脉冲数,方式不限制,可以用其它芯片,外加芯片有32来控制芯片输出脉冲的个数。

最大频率能到几百K的那种。

谢谢。

出0入4汤圆

发表于 2019-5-25 23:42:05 来自手机 | 显示全部楼层
f4 的tim2 和tim5 是32位的。速度到4M都没问题。

出0入20汤圆

发表于 2019-5-25 23:50:52 | 显示全部楼层
老生常谈了,最简单的就是开从定时器的溢出中断,超过就是超过就是了,中断里面直接加上去,别说32位,64位都没问题。

出0入0汤圆

 楼主| 发表于 2019-5-25 23:53:33 | 显示全部楼层
xiaoergao 发表于 2019-5-25 23:42
f4 的tim2 和tim5 是32位的。速度到4M都没问题。

现在是F1,可以试试用F4

出0入0汤圆

 楼主| 发表于 2019-5-25 23:54:04 | 显示全部楼层
Error.Dan 发表于 2019-5-25 23:50
老生常谈了,最简单的就是开从定时器的溢出中断,超过就是超过就是了,中断里面直接加上去,别说32位,64位 ...

频率高,中断太频繁了

出0入20汤圆

发表于 2019-5-26 10:28:03 | 显示全部楼层
wongT 发表于 2019-5-25 23:54
频率高,中断太频繁了

真的吗?再想想。

出0入0汤圆

发表于 2019-5-26 13:57:35 | 显示全部楼层
脉冲个数为什么只能是16bits?哪个寄存器?

出0入10汤圆

发表于 2019-5-26 22:04:00 | 显示全部楼层
解决方案: 采用定时器A作为PWM输出 脉冲, 定时器A的溢出更新中断作为另一定时器的计数时钟。

出0入0汤圆

发表于 2019-5-26 22:35:33 来自手机 | 显示全部楼层
定时器可以串联使用,两个16拼成32。不差钱还是用f4

出0入0汤圆

 楼主| 发表于 2019-5-27 19:48:45 | 显示全部楼层
Error.Dan 发表于 2019-5-26 10:28
真的吗?再想想。

频率100K的话,PWM周期就是10us,10us中断一次,计数加一,你的意思是这样吗?

出0入0汤圆

 楼主| 发表于 2019-5-27 19:51:35 | 显示全部楼层
go2deathward 发表于 2019-5-26 13:57
脉冲个数为什么只能是16bits?哪个寄存器?

ARR 主从模式,主定时器工作在PWM,溢出触发从定时器计数
从定时器ARR只有16bit

出0入0汤圆

 楼主| 发表于 2019-5-27 19:52:28 | 显示全部楼层
widesoft2 发表于 2019-5-26 22:04
解决方案: 采用定时器A作为PWM输出 脉冲, 定时器A的溢出更新中断作为另一定时器的计数时钟。  ...

这不就是主从模式吗,从定时器ARR来设置脉冲数

出0入0汤圆

 楼主| 发表于 2019-5-27 19:53:39 | 显示全部楼层
ilawp 发表于 2019-5-26 22:35
定时器可以串联使用,两个16拼成32。不差钱还是用f4

F4用不了标准库,现在用的是标准库,HAL太绕了

出0入20汤圆

发表于 2019-5-27 22:48:50 | 显示全部楼层
wongT 发表于 2019-5-27 19:52
这不就是主从模式吗,从定时器ARR来设置脉冲数

你从定时器还有计数器溢出中断呢,然后再扩展一下,你从定时器还有最多4个比较器中断,,比较器还有硬件输出,你想想咋玩~
实际上要求非常严格的场合确实不太适合用主从模式,因为有0XFFFF+1个脉冲这种极端情况,可以写算法分类处理,但是程序很恶心。

顺便,调戏STM32的标准硬件来做脉冲个数控制,这已经是基础玩法了,还有更淫荡的办法,你再想想。

出0入0汤圆

 楼主| 发表于 2019-5-27 22:58:28 | 显示全部楼层
Error.Dan 发表于 2019-5-27 22:48
你从定时器还有计数器溢出中断呢,然后再扩展一下,你从定时器还有最多4个比较器中断,,比较器还有硬件 ...

哈哈,懂了,从定时器的溢出后再计数。

我目前能想到的这个对我来说算淫荡了。

还请赐教啊。。

出0入10汤圆

发表于 2019-5-28 09:50:03 | 显示全部楼层
wongT 发表于 2019-5-27 22:58
哈哈,懂了,从定时器的溢出后再计数。

我目前能想到的这个对我来说算淫荡了。

   计数全部采用硬件模式。  包括更新 PWM频率,也要采用DMA的模式,  在某个上升沿或下降沿一起更新。  如果想精确控制发送脉冲的个数, 在最后阶段要做个减速。  TIM->CR1的这个单脉冲功能要用好。发完最后一个脉冲,定时器自动停止。

出0入10汤圆

发表于 2019-5-28 09:53:20 | 显示全部楼层
    /* Time4 base configuration */
    TIM_DeInit(TIM4);
    TIM_TimeBaseStructure.TIM_Period = 65535u;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure);
    TIM_ITRxExternalClockConfig(TIM4,TIM_TS_ITR2);
    TIM_Cmd(TIM4, ENABLE);
    /* Time3 base configuration */
    TIM_DeInit(TIM3);
    TIM_TimeBaseStructure.TIM_Period = 8000u - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
    /* TIM3 PWM1 Mode configuration: Channel1 */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 4000u;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_DMAConfig(TIM3,TIM_DMABase_PSC,TIM_DMABurstLength_4Bytes);
    TIM_OC1Init(TIM3, &TIM_OCInitStructure);
    TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Disable);   
    TIM_ARRPreloadConfig(TIM3, DISABLE);
    /*输出更新触发*/
    TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Update);
    TIM_SetCounter(TIM4,0);
   上一段代码吧。 TIM3发PWM波形, TIM4 接受发出脉冲个数。

出0入0汤圆

发表于 2019-5-28 17:39:14 | 显示全部楼层
wongT 发表于 2019-5-27 19:51
ARR 主从模式,主定时器工作在PWM,溢出触发从定时器计数
从定时器ARR只有16bit ...

这个ARR是pwm的周期吧,
并不是pwm脉冲的,想统计个数
在pwm溢出的时候,做个计数就可以了
方法1,定时器级联,pwm溢出作为下一级定时器的计数,
方法2,pwm开启中断,每次完成pwm,进中断统计脉冲数

出0入0汤圆

 楼主| 发表于 2019-5-28 19:20:57 | 显示全部楼层
widesoft2 发表于 2019-5-28 09:53
/* Time4 base configuration */
    TIM_DeInit(TIM4);
    TIM_TimeBaseStructure.TIM_Period = 6553 ...

对的,我就是这样

出0入0汤圆

 楼主| 发表于 2019-5-28 19:25:07 | 显示全部楼层
go2deathward 发表于 2019-5-28 17:39
这个ARR是pwm的周期吧,
并不是pwm脉冲的,想统计个数
在pwm溢出的时候,做个计数就可以了

我就是级联,方式1,一开始没想到我那个问题的答案。

溢出作为第二个定时器的计数,计数到了,第二个定时器又arr满了就会溢出,所以可以在第二个定时器溢出中断里处理(就是这里我一开始没想到)

出0入10汤圆

发表于 2019-5-29 10:46:49 | 显示全部楼层
wongT 发表于 2019-5-28 19:25
我就是级联,方式1,一开始没想到我那个问题的答案。

溢出作为第二个定时器的计数,计数到了,第二个定 ...

/*----------------------------------------------*/
static void ReadMotorDevPos(TMotorDevParameter *pmotordevparameter)
{
    INT16S value,k;
    value = (INT16S)TIM_GetCounter(pmotordevparameter->RcvPlusTimer);
    k = value - pmotordevparameter->iLastValue;
    pmotordevparameter->iLastValue = value;
    if (pmotordevparameter->bMotorDir == FALSE)
    {
        k = -k;
    }
    if ((k & (INT16U)0x8000u) != 0)
    {
        pmotordevparameter->lCurPos += ((INT32S)k | 0xffff0000ul);
    }
    else
    {
        pmotordevparameter->lCurPos += (INT32S)k;
    }
}               再上一段代码。  周期性读取 计数定时器的,每次将 两次的差值记下, 增量计数,  根据方向模拟做加脉冲加减。

出0入0汤圆

发表于 2019-5-30 14:51:36 | 显示全部楼层
wongT 发表于 2019-5-27 19:53
F4用不了标准库,现在用的是标准库,HAL太绕了


你可以用cube生成初始化代码,把里面的内容复制出来,按标准库的方式操作。
HAL不饶的,很有规律,前提是理解了它的规律。不过可能有bug倒是真的

出0入0汤圆

发表于 2019-5-30 15:52:38 | 显示全部楼层
wongT 发表于 2019-5-27 19:53
F4用不了标准库,现在用的是标准库,HAL太绕了

F4用不了标准库==可以用啊,我现在也是用标准库,上去下一个就可以了

出0入0汤圆

发表于 2019-6-1 07:29:18 | 显示全部楼层
widesoft2 发表于 2019-5-28 09:50
计数全部采用硬件模式。  包括更新 PWM频率,也要采用DMA的模式,  在某个上升沿或下降沿一起更新。   ...

使用定时器+DMA的方法能很好的控制脉冲个数,且不用频繁中断,我已经实现了,但是使用这个方式要如何实现加减速却没什么思路,因为要实现加减速需要PSC,ARR,CCR1同时变化才能实现,您说的“某个上升沿或下降沿一起更新”是怎么实现的?

出0入0汤圆

发表于 2019-6-1 16:50:08 | 显示全部楼层
W872529868 发表于 2019-6-1 07:29
使用定时器+DMA的方法能很好的控制脉冲个数,且不用频繁中断,我已经实现了,但是使用这个方式要如何实现 ...

你的意思是将pwm的值放在DMA数据区吗?如果步数少,细分少,减速比低,确实是可行的
如果步数很大怎么办?
RAM可能不够用,而且DMA的大小不能超过64K吧
比如我的一个应用里
一圈的脉冲数是(200*8*20,一圈200,细分8,减速比20),就是32000,你要用这么大的缓冲区做DMA吗?

出0入0汤圆

发表于 2019-6-1 17:25:44 | 显示全部楼层
W872529868 发表于 2019-6-1 07:29
使用定时器+DMA的方法能很好的控制脉冲个数,且不用频繁中断,我已经实现了,但是使用这个方式要如何实现 ...

其实最好的办法还是用定时器级联,第一级做pwm发生,第二级做计数,但是F1只能计65535个,有些应用里可能不够,需要额外再自己做个处理
这样,在一定步数以后调整pwm的period值,就可以做加减速的过程了

出0入22汤圆

发表于 2019-6-1 18:14:20 来自手机 | 显示全部楼层
go2deathward 发表于 2019-6-1 17:25
其实最好的办法还是用定时器级联,第一级做pwm发生,第二级做计数,但是F1只能计65535个,有些应用里可能 ...

对的,我就是这么做的。如果要用超过65536,可以在计数器里面中断累加。

出0入0汤圆

发表于 2019-6-2 18:00:34 | 显示全部楼层
go2deathward 发表于 2019-6-1 16:50
你的意思是将pwm的值放在DMA数据区吗?如果步数少,细分少,减速比低,确实是可行的
如果步数很大怎么办 ...

DMA方式是“内存地址不递增”这样只需一个U16就行了,但是也面临一个问题,如何实现加减速,试了一下,超级复杂。

出0入0汤圆

发表于 2019-6-2 18:02:38 | 显示全部楼层
zxq6 发表于 2019-6-1 18:14
对的,我就是这么做的。如果要用超过65536,可以在计数器里面中断累加。

现在需要加减速,用DMA要怎么实现?占空比,频率,需要同时改变,而改变频率需要改变PSC和ARR2个寄存器。

出0入4汤圆

发表于 2019-6-2 18:20:30 | 显示全部楼层
W872529868 发表于 2019-6-2 18:02
现在需要加减速,用DMA要怎么实现?占空比,频率,需要同时改变,而改变频率需要改变PSC和ARR2个寄存器。 ...

加减速就需要查表了

出0入4汤圆

发表于 2019-6-2 18:43:01 | 显示全部楼层
用个CPLD就可以解决了,16位也是可以的,进入中断计数器--

出0入22汤圆

发表于 2019-6-2 21:05:41 来自手机 | 显示全部楼层
W872529868 发表于 2019-6-2 18:02
现在需要加减速,用DMA要怎么实现?占空比,频率,需要同时改变,而改变频率需要改变PSC和ARR2个寄存器。 ...

没用dma,用的是pwm模式,然后用另外一个定时器的etr,计数的。

出0入10汤圆

发表于 2019-6-3 00:05:07 | 显示全部楼层
go2deathward 发表于 2019-6-1 16:50
你的意思是将pwm的值放在DMA数据区吗?如果步数少,细分少,减速比低,确实是可行的
如果步数很大怎么办 ...

    用DMA的目的是为保证更改定时器的参数值的“原子操作",   比如为了更改频率,同时又要保证50%的占空比。 这涉及到更改 ARR及OCR 两个寄存器的, 用软件就有时序先后了,而定时器的运行计数又是不可控制。  利用定时器的溢出中断(定时器归到初始值0) 触发DMA呢,就是保证几乎同时更改两个值。

出0入0汤圆

发表于 2019-6-3 12:54:21 | 显示全部楼层
widesoft2 发表于 2019-6-3 00:05
用DMA的目的是为保证更改定时器的参数值的“原子操作",   比如为了更改频率,同时又要保证50%的占空 ...

使用“更新事件”的DMA只能改一个值吧?如何实现一个事件触发2个不同的DMA传输?

出0入10汤圆

发表于 2019-6-3 13:15:29 | 显示全部楼层
W872529868 发表于 2019-6-3 12:54
使用“更新事件”的DMA只能改一个值吧?如何实现一个事件触发2个不同的DMA传输? ...

TIM_DMAConfig(TIM3,TIM_DMABase_PSC,TIM_DMABurstLength_4Bytes);    上一行代码。 可以同时改几个寄存器值。

出0入0汤圆

发表于 2019-6-3 22:22:29 | 显示全部楼层
widesoft2 发表于 2019-6-3 13:15
TIM_DMAConfig(TIM3,TIM_DMABase_PSC,TIM_DMABurstLength_4Bytes);    上一行代码。 可以同时改几个寄存 ...

想到一个新方法,不知道行不行,明天试下。因为ARR和CCR的值是联动的,CRR=ARR/2,那么能不能不改ARR的值,比如ARR=19 CCR=9,只修改PSC的值,35999=100HZ,35=100Khz 理论上应该是行的。
但是现在最麻烦的是要控制步进电机S曲线加减速,100加速到10KHZ,按照论坛里面的软件计数得出200ms的加速总共需要1400+个点,那么要怎么配合才能更好低实现,就没什么好思路,望各位大牛指点一下,谢谢。

出0入10汤圆

发表于 2019-6-4 22:29:28 | 显示全部楼层
W872529868 发表于 2019-6-3 22:22
想到一个新方法,不知道行不行,明天试下。因为ARR和CCR的值是联动的,CRR=ARR/2,那么能不能不改ARR的值 ...

因为ARR和CCR的值是联动的, 用DMA的目的, 就是为了 在极短的时间内 几乎同时  联动更改ARR,CRR,PSC 三个寄存的值。

出0入20汤圆

发表于 2019-6-5 00:17:34 | 显示全部楼层
wongT 发表于 2019-5-27 22:58
哈哈,懂了,从定时器的溢出后再计数。

我目前能想到的这个对我来说算淫荡了。

欧姆龙的CP1H系列PLC有4组内置的定位控制功能,其手册上对于加减速的这么描述的:根据定义好的加减速模式,每4ms更新一次当前的脉冲输出速度。多解释一下,PLC里面可以设置基底速度和最高速,然后PLC指令里面会指定目标速度。

你已经知道怎么用DMA了,所以谁来更新数值或者说怎么更新已经知道了,那么剩下的就是什么时候更新了。
这个办法就多了去了,欧姆龙PLC用的是最简单的办法,起一个4ms的定时器去触发DMA就行了。这个在实际使用的时候就够啦~
具体的点数据位置固定以后用DMA去搬就可以了,实际上就是解决一个DMA触发源的问题。
然后这里有个目标速度到达的判定的硬件操作方法:用DMA传输结束标志位,或者干脆开中断。

如果要更复杂一些,比如说要做位置前瞻,也很简单的,把从定时器的比较器用起来就行了~
其实卡住脉冲个数以后针对脉冲发送过程中的加减速处理没必要要求非常精确的实时性的,因为脉冲定位的时候只要你数量不错,加速度多一点少一点在us级别的中断响应周期下几乎可以忽略,所以放心开中断进中断处理,冲突也没事,反正位置不会错。
这个里面的工程经验或者说调试的意义实际上更多在于放裕量的问题,这个和机械结构是强耦合的,你电子系统发的脉冲再精确,机械跟不上也没用的。

出0入0汤圆

发表于 2019-6-23 23:24:33 | 显示全部楼层
步进电机不用计数吧,因为要计算加减速,所以脉冲已经可以算出来了。如果要紧急停止电机,会丢步,也没有计数的意义。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-4-20 18:11

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

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