你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32的TIMx实现编码器四倍频

[复制链接]
攻城狮Melo 发布时间:2023-3-18 12:18
一.储备知识
通过STM32的定时器编码器接口模式对编码器进行四倍频,并使用M法测速得到小车电机的速度信息。
编码器的相关知识之前介绍过:编码器s
M法测速:读取每10ms的脉冲数,以脉冲数的多少代表速度的快慢。

二.TIMx的编码器模式介绍
TIMx的编码器模式,每个定时器只能测量一组AB相的值(编码器的AB相),分别使用CH1和CH2接AB相,通过判断CH1和CH2的输入信号,来实现编码器的测速。需要配置TI1和TI2的极性、计数边沿、自动装载值等信息来驱动编码器模式。在实现编码器后,电机的转速会以计数器的值来表示,然后在另一个TIMx的10ms中断程序中读取编码器计数器的值(读取完要置零)。
下面大概总结一下配置编码器模式的信息:

1.计数边沿设置

我是使用编码器四倍频技术测速,所以要对AB相的上下沿都要计数,也就是说TI1和TI2的上下沿都要触发计数器计时。
关于编码器计数模式,通过配置TIMx_SMCR寄存器中的SMS[2:0]位可以设置,参考手册中的原图如下:

20200222110643214.png 20200222110619523.png

所以,要配置编码器模式3才可以对TI1和TI2的上下沿都计数,即SMS=011。


2.选择极性和使能

设置TIMx_CCER寄存器中的CC1P和CC2P位,可以选择TI1和TI2极性,如图:

20200222121758415.png
2020022212182348.png

3.使能

TIMx_CR1寄存器中的CEN=’1’用来使能计数器:

20200222122058845.png
20200222122048369.png

4.计数方向
在工作时,计数器只在0到TIMx_ARR寄存器的自动重装值之间进行连续计数,所以计数开始前要配置TIMx_ARR。
通过对AB相的输入捕获,可以得到电机的转动方向和转速,是通过计数器的计数方向和计数值来表示的,计数方向和编码器信号的对应关系如图:

20200222122445815.png

四倍频配置如下:

2020022212252355.png

得到的计数器计数过程就如图:

20200222122557930.png


三.代码部分
在STM32中,可以用TIM2、TIM4的CH1、CH2来连接俩个电机的AB相,进行编码器测速,然后在TIM3进行10ms的中断读取计数器的值,这样就实现了编码器的四倍频测速,代码如下:

TIM2、TIM4初始化代码
  1. /* 测量编码器输出的TIM初始化,TIMx编码器模式
  2. TIM2、TIM4编码器模式测速
  3. A电机:PA0、PA1(TIM2的CH1、CH2)
  4. B电机:PB6、PB7(TIM2的CH1、CH2)
  5. */
  6. void Encoder_TIM2_TIM4_Init( void )
  7. {
  8.         GPIO_InitTypeDef GPIO_InitStruct;
  9.         TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
  10.         TIM_ICInitTypeDef TIM_ICInitStruct;
  11.        
  12.         RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE );
  13.         RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM4, ENABLE );
  14.        
  15.         /* GPIO初始化 */
  16.         GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  17.         GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  18.         GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
  19.         GPIO_Init( GPIOA, &GPIO_InitStruct );
  20.         GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
  21.         GPIO_Init( GPIOB, &GPIO_InitStruct );
  22.        
  23.         /* 配置时基结构体 */
  24.         TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
  25.         TIM_TimeBaseInitStruct.TIM_Period = 65535;//定时器自动重装值
  26.         TIM_TimeBaseInitStruct.TIM_Prescaler = 0;
  27.         TIM_TimeBaseInit( TIM2, &TIM_TimeBaseInitStruct );
  28.         TIM_TimeBaseInit( TIM4, &TIM_TimeBaseInitStruct );
  29.        
  30.         /* 编码器模式3,极性上升沿 */
  31.         TIM_EncoderInterfaceConfig( TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising );
  32.         TIM_EncoderInterfaceConfig( TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising );

  33.         /* 配置输入捕获结构体 */
  34.         TIM_ICStructInit( &TIM_ICInitStruct );
  35.         /*CCMR1寄存器位7:4是IC1F[3:0]:这几位定义了TI1输入的采样频率及数字滤波器长度。数字滤波器由一个事件计数器组成,它记
  36. 录到N个事件后会产生一个输出的跳变:*/
  37.         TIM_ICInitStruct.TIM_ICFilter = 10;//1010:采样频率fSAMPLING=fDTS/16, N=5
  38.         TIM_ICInit( TIM2, &TIM_ICInitStruct );
  39.         TIM_ICInit( TIM4, &TIM_ICInitStruct );
  40.        
  41.         /* 中断配置 */
  42.         TIM_ClearFlag( TIM2, TIM_IT_Update );
  43.         TIM_ITConfig( TIM2, TIM_IT_Update, ENABLE );
  44.         TIM_ClearFlag( TIM4, TIM_IT_Update );
  45.         TIM_ITConfig( TIM4, TIM_IT_Update, ENABLE );
  46.        
  47.         /* 配置计数器的值 */
  48.         TIM_SetCounter( TIM2, 0 );
  49.         TIM_SetCounter( TIM2, 0 );
  50.        
  51.         /* 使能TIM */
  52.         TIM_Cmd( TIM2, ENABLE );
  53.         TIM_Cmd( TIM4, ENABLE );
  54.        
  55. }

复制代码

读取编码器计数值
  1. /* 读取编码器计数 */
  2. int Read_Encoder( uint8_t TIMx )
  3. {
  4.         int Encoder;
  5.         /* 读取相应TIM的计数器值CNT,然后清零 */
  6.         switch(TIMx)
  7.         {
  8.                 case 2:Encoder = (short)TIM2->CNT;TIM2->CNT=0;break;
  9.                 case 4:Encoder = (short)TIM4->CNT;TIM4->CNT=0;break;
  10.                 default:Encoder = 0;break;
  11.         }
  12.        
  13.         return Encoder;
  14. }
复制代码

TIM2、TIM4中断程序
  1. void TIM2_IRQHandler(void)
  2. {
  3.         /* SR位:当捕获事件发生时该位由硬件置’1’,它由软件清’0’或通过读TIMx_CCR1清’0’。
  4. 0:无输入捕获产生;
  5. 1:计数器值已被捕获(拷贝)至TIMx_CCR1(在IC1上检测到与所选极性相同的边沿)。 */
  6.         if( TIM2->SR&0x0001 )
  7.                 ;
  8.         /* 清除中断标志位 */
  9.         TIM2->SR&=~(1<<0);
  10. }



  11. void TIM4_IRQHandler(void)
  12. {
  13.         /* SR位:当捕获事件发生时该位由硬件置’1’,它由软件清’0’或通过读TIMx_CCR1清’0’。
  14. 0:无输入捕获产生;
  15. 1:计数器值已被捕获(拷贝)至TIMx_CCR1(在IC1上检测到与所选极性相同的边沿)。 */
  16.         if( TIM4->SR&0x0001 )
  17.                 ;
  18.         /* 清除中断标志位 */
  19.         TIM4->SR&=~(1<<0);
  20. }

复制代码

TIM3配置、中断读取计数器值
  1. void TIM3_Int_Init(u16 arr,u16 psc)
  2. {
  3.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  4.         NVIC_InitTypeDef NVIC_InitStructure;

  5.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能

  6.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值         计数到5000为500ms
  7.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  
  8.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
  9.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
  10.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

  11.         TIM_ITConfig(  //使能或者失能指定的TIM中断
  12.                 TIM3, //TIM2
  13.                 TIM_IT_Update ,
  14.                 ENABLE  //使能
  15.                 );
  16.         NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
  17.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
  18.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
  19.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
  20.         NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

  21.         TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设
  22.                                                          
  23. }
  24. void TIM3_IRQHandler(void)   //TIM3中断
  25. {
  26.         if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源
  27.                 {
  28.                 TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源
  29.                 Encoder_Left=(short)TIM2->CNT;
  30.                 TIM2->CNT=0;       
  31.                 }
  32. }
复制代码

————————————————
版权声明:Aspirant-GQ
如有侵权请联系删除



收藏 评论0 发布时间:2023-3-18 12:18

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版