OpenEdv-开源电子网

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

请教关于主从定时器是否能分别同时控制三个通道输出不同频率PWM信号

[复制链接]

2

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
108
金钱
108
注册时间
2018-11-12
在线时间
26 小时
发表于 2021-9-7 23:38:12 | 显示全部楼层 |阅读模式
10金钱
最近在使用STM32F4系列单片机来控制三轴步进电机运动。想用定时器3和定时器4做主从模式控制定时器3的三个通道分别输出不同频率的PWM及精准脉冲数的控制信号。但是对主从控制模式还不太了解,想请教下各位有用过主从模式控
制步进电机的大佬们,这样的方式能实现吗,谢谢!针对各个通道的独立开启和关闭PWM输出是使用TIM_ITConfig(TIMx,TIM_IT_CCx,DISABLE);这个函数来执行吗?
另外,帮忙看下void Pulse_output(u32 Cycle, u32 PulseNum)这个函数要怎么调整才能实现各个通道独立设置频率和脉
冲数的值,谢谢!



// 定时器3 主定时器
void TIM3_Mode_Config(u32 cycle)
{
        TIM_TimeBaseInitTypeDef          TIM_TimeBaseStructure;        
        TIM_OCInitTypeDef                          TIM_OCInitStructure;   
        NVIC_InitTypeDef                         NVIC_InitStructure;       
       
        SET_GPIO_AF_OUTPUT(GPIOC, GPIO_Pin_6);   
        SET_GPIO_AF_OUTPUT(GPIOC, GPIO_Pin_7);
        SET_GPIO_AF_OUTPUT(GPIOC, GPIO_Pin_8);       
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM3);
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_TIM3);
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_TIM3);
       
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

        TIM_TimeBaseStructure.TIM_Period = cycle - 1;                               // 当定时器从0计数到999,即为1000次,为一个定时周期  10KHz
        TIM_TimeBaseStructure.TIM_Prescaler = 83;            
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;               // 设置时钟分频系数:不分频           
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;          // 向上计数模式  
        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);                


        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                    // 配置为输出比较反转模式  
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   
        TIM_OCInitStructure.TIM_Pulse = (cycle + 1)/2;                                        // 设置比较值(跳变值),即频率调整值,压盖电机
       
        TIM_OC1Init(TIM3, &TIM_OCInitStructure);                                                  // 根据T指定的参数初始化外设TIM8 OC1
        TIM_OC2Init(TIM3, &TIM_OCInitStructure);                                          // 使能通道2
        TIM_OC3Init(TIM3, &TIM_OCInitStructure);                                                // 初始化输出比较寄存器
       
        TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);        // 设置定时器3为主定时器模式
        TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);                        // 选择触发模式
       
        TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);                                 // 通道1使能
        TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);                                 // 通道2使能
        TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);                                 // 通道3使能
       
        TIM_ARRPreloadConfig(TIM3, ENABLE);                                 // 使能TIM2重载寄存器ARR   

}

//TIM4 从定时器
void TIM4_config(u32 PulseNum)
{
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

        TIM_TimeBaseStructure.TIM_Period = PulseNum-1;   
        TIM_TimeBaseStructure.TIM_Prescaler =0;   
        TIM_TimeBaseStructure.TIM_ClockDivision = 0;     
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
        TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);  

        TIM_SelectInputTrigger(TIM4, TIM_TS_ITR2);
        TIM4->SMCR|=0x27;                                  //设置从模式寄存器  ITR2(TS=010)

        TIM_ITConfig(TIM4,TIM_IT_Update,DISABLE);

        NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;        
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;     
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
}
void Pulse_output(u32 Cycle, u32 PulseNum)
{
    TIM4_config(PulseNum);
    TIM_Cmd(TIM4, ENABLE);
    TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
    TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
    TIM3_Mode_Config(Cycle);
    TIM_Cmd(TIM3, ENABLE);
}



最佳答案

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

没仔细研究过你的主从定时器模式,不过要给步进电机脉冲计数必须进中断,普通的步进电机不细分的话最高就是1000pps,16细分并且考虑到一个脉冲进两次中断也才32k的频率,如果定时中断内的语句不乱写的话stm32F4的最大定时器频率大概是200K,大概可以同时控制最多6个步进电机,但是一个定时器一般只有四路比较器,所以一般可以独立控制4个步进电机。如果需要独立控制的电机数量多于4个,那就要用到2个或更多的定时器了。另外,上面 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

13

主题

91

帖子

0

精华

高级会员

Rank: 4

积分
749
金钱
749
注册时间
2020-6-24
在线时间
311 小时
发表于 2021-9-7 23:38:13 | 显示全部楼层
本帖最后由 ColeSofCJ 于 2021-9-9 09:05 编辑
kenchen 发表于 2021-9-8 14:42
谢谢你的回复,你提到的这种控制方式是采用三个独立的定时器输出脉冲频率吗?因为采用独立定时器控制输出 ...

没仔细研究过你的主从定时器模式,不过要给步进电机脉冲计数必须进中断,普通的步进电机不细分的话最高就是1000pps,16细分并且考虑到一个脉冲进两次中断也才32k的频率,如果定时中断内的语句不乱写的话stm32F4的最大定时器频率大概是200K,大概可以同时控制最多6个步进电机,但是一个定时器一般只有四路比较器,所以一般可以独立控制4个步进电机。如果需要独立控制的电机数量多于4个,那就要用到2个或更多的定时器了。另外,上面的估算是按步进电机最大速度估算的,如果电机实际运行速度较慢的话,单片机可以同时控制的电机数量也会更多。   解释一下:定时中断内的语句乱写是指有些定时中断明明只有1毫秒的时间,有些人却偏偏要在里面执行10毫秒左右的代码!(我说的步进电机独立控制是指位移、速度各电机之间相互独立,效果等同于用不同的单片机分别控制每一个电机)
     另外你提到内存消耗,我的印象是做加减速S曲线控制比较耗内存,因为要精确控制速度和位移,所有的脉冲都要经过计算并在必要时实时存储脉冲数据,所以非常耗内存,只是脉冲计数我印象是不怎么费内存的!
    还有,要是想不明白一个定时器怎么通过输出比较器实现4个频率独立的脉冲信号输出的话,一路脉冲占用一个定时器也是可以的,现在的单片机定时器资源都很丰富,应该足够用的。
回复

使用道具 举报

6

主题

890

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1477
金钱
1477
注册时间
2020-8-19
在线时间
335 小时
发表于 2021-9-8 09:59:22 | 显示全部楼层
帮顶  
回复

使用道具 举报

109

主题

5564

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
10561
金钱
10561
注册时间
2017-2-18
在线时间
1912 小时
发表于 2021-9-8 10:11:32 | 显示全部楼层
只做过主从定时器控制一个通道的,帮顶
回复

使用道具 举报

13

主题

91

帖子

0

精华

高级会员

Rank: 4

积分
749
金钱
749
注册时间
2020-6-24
在线时间
311 小时
发表于 2021-9-8 13:15:36 | 显示全部楼层
  Msp430、mega128、stm32F0等单片机都能做三路步进电机独立控制的,使用一个定时器资源就可以,不过频率会受限制,stm32F4单片机大概能输出最大100K-200K左右的脉冲频率,再高就要换单片机或换方案了。
回复

使用道具 举报

2

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
108
金钱
108
注册时间
2018-11-12
在线时间
26 小时
 楼主| 发表于 2021-9-8 14:42:59 | 显示全部楼层
ColeSofCJ 发表于 2021-9-8 13:15
Msp430、mega128、stm32F0等单片机都能做三路步进电机独立控制的,使用一个定时器资源就可以,不过频率会 ...

谢谢你的回复,你提到的这种控制方式是采用三个独立的定时器输出脉冲频率吗?因为采用独立定时器控制输出脉冲频率会频繁进入中断,在中断中进行脉冲数计数,这样比较占内存,所以想用主从模式来减少对内存的占用率。主从模式控制单通道输出PWM波是没问题的,但就是不知道能不能分别控制多通道输出不同的频率及脉冲数。
回复

使用道具 举报

2

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
108
金钱
108
注册时间
2018-11-12
在线时间
26 小时
 楼主| 发表于 2021-9-9 14:35:45 | 显示全部楼层
ColeSofCJ 发表于 2021-9-8 15:08
没仔细研究过你的主从定时器模式,不过要给步进电机脉冲计数必须进中断,普通的步进电机不细分的话最高就 ...

昨天调试了一天主从模式,可以确定主从模式不能同时给各个通道不同的频率,但可以调整他们的占空比,所以用主从模式控制多个电机实现频率控制是不可能的。看来还是老老实实用单定时器来控制比较稳妥。
回复

使用道具 举报

13

主题

91

帖子

0

精华

高级会员

Rank: 4

积分
749
金钱
749
注册时间
2020-6-24
在线时间
311 小时
发表于 2021-9-9 15:27:02 | 显示全部楼层
本帖最后由 ColeSofCJ 于 2021-9-9 15:51 编辑
kenchen 发表于 2021-9-9 14:35
昨天调试了一天主从模式,可以确定主从模式不能同时给各个通道不同的频率,但可以调整他们的占空比,所以 ... 不知道你用主从模式是啥原因,如果是因为16位计数器不够用,是可以自己扩展的。
还是贴一段代码,可用于16位计数器转32位:typedef  struct
  {
     uint32_t ARRFrom;    //与ARR同步的值
     uint32_t ShdFrom;    //32位计数值影子
     uint8_t  ToTrig;     //待触发
     uint8_t  Triged;     //已触发
     uint16_t CntTim;     //16位触发次数
  }  ExdTim16_32;

   if(((TIM3->SR &TIM_FLAG_Update)!=0)&&((TIM3->DIER &TIM_FLAG_Update)!=0))   //TIM3 update 使能且触发中断
   {
     TIM3->SR &= (uint16_t)~TIM_FLAG_Update;                                  //清除中断标志
     if((T3ext.ShdFrom>>16)>0)
      {
        if(T3ext.CntTim==0)       //首次初始化Tim3ARR
         {
           T3ext.ARRFrom=T3ext.ShdFrom;
           TIM3->ARR =0xffff;
           T3ext.ARRFrom-=0x10000;
           if(T3ext.ToTrig) { T3ext.Triged=1; T3ext.ToTrig=0; }
           if(T3ext.ARRFrom==0) {T3ext.CntTim=0; T3ext.ToTrig=1; } else T3ext.CntTim++;
         }
        else
        {
          if((T3ext.ARRFrom>>16)>0)   //非首次无需初始化 Tim3ARR
           {  
             TIM3->ARR =0xffff;
             T3ext.ARRFrom-=0x10000;
             if(T3ext.ARRFrom==0) {T3ext.CntTim=0; T3ext.ToTrig=1; } else T3ext.CntTim++;
           }
          else if(T3ext.ARRFrom>0)   //最后一次ARR值无需最大值
          {
             TIM3->ARR =T3ext.ARRFrom;
             T3ext.ARRFrom=0;
             T3ext.CntTim=0;
             T3ext.ToTrig=1;
          }
        }
      }
     else
     {
      if(T3ext.CntTim==0)       //首次初始化Tim3ARR
       {
        T3ext.ARRFrom=T3ext.ShdFrom;
        TIM3->ARR =T3ext.ARRFrom-1;
        T3ext.CntTim++;
       }
      else
      {
        T3ext.ARRFrom=T3ext.ShdFrom;
        TIM3->ARR =T3ext.ARRFrom-1;
        T3ext.Triged=1;
      }
     }
   }



回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-2-26 23:23

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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