野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 16140|回复: 5

STM32F407编码器模式测量电机转速时怎么测不出方向,无论...

[复制链接]

STM32F407编码器模式测量电机转速时怎么测不出方向,无论电机正反转,测出来的结果都是正方向的速度?怎么测速测方向??

发表于 2020-8-17 21:58:31 | 显示全部楼层 |阅读模式
STM32F407 TIM2配置成编码器模式测量电机的转速和方向,
TIM3配置成定时器模式,用来定时,比如每隔10ms中断一次,
进入其中断函数处理TIM2中的与相关数据

用单片机的的PA5、PB3分别接编码器的A、B相,编码器是65536线的增量式编码器

配置TIM2的计数器的初始值为0x00FFFFFF(16777215)

我设想的是
当电机带动编码器沿一个方向转动时,计数器的值在初始值0x00FFFFFF的基础,往上
当电机带动编码器沿另一个相反的方向转动时,计数器的值在初始值0x00FFFFFF的基础,往下
Encoder.zip (13.21 MB, 下载次数: 14)


而电机的转速和方向就用间隔10ms进入中断时,
读出来的计数器值减去计数器的初始值0x00FFFFFF,
当相减的结果为时,可认为转动方向是方向,
当相减的结果为时,可认为转动方向是方向。

实际测试中,无论电机带动编码器往哪个方向转动,
读出来的计数器值都比初始值0x00FFFFFF要大?

现在有个疑问就是,是不是计数器的值只能增不会减?

大家还有其他的方法测量电机的转动方向吗?

请大佬们不吝赐教!!

谢谢!




代码如下:

#define  Encoder_TIM_PSC            0
#define  Encoder_TIM_PERIOD         0xFFFFFFFF
#define  CNT_MAX                    4294967296
#define  Encoder_InitCNT            0x00FFFFFF



#define Encoder_TIM                             TIM2
#define Encoder_TIM_CLK                         RCC_APB1Periph_TIM2

#define Encoder_CH1_PIN             GPIO_Pin_5            
#define Encoder_CH1_GPIO_PORT       GPIOA                     
#define Encoder_CH1_GPIO_CLK        RCC_AHB1Periph_GPIOA
#define Encoder_CH1_PINSOURCE                                GPIO_PinSource5
#define Encoder_CH1_AF                                                        GPIO_AF_TIM2

#define Encoder_CH2_PIN             GPIO_Pin_3            
#define Encoder_CH2_GPIO_PORT       GPIOB                     
#define Encoder_CH2_GPIO_CLK        RCC_AHB1Periph_GPIOB
#define Encoder_CH2_PINSOURCE                                GPIO_PinSource3
#define Encoder_CH2_AF                                                        GPIO_AF_TIM2


/** @brief        linear encoder init
  *                        phaseA        PA5                T2_CH1
  *                        phaseB        PB3                T2_CH2
  * @param        void
  * @retval        void
  */
void Encoder_Init(void)
{
        GPIO_InitTypeDef                       GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;
        TIM_ICInitTypeDef                       TIM_ICInitStructure;
      
//        Encoder_IndexConfig();

        /* Encoder GPIO Initialization */
        RCC_AHB1PeriphClockCmd(Encoder_CH1_GPIO_CLK|Encoder_CH2_GPIO_CLK, ENABLE);
        GPIO_PinAFConfig(Encoder_CH1_GPIO_PORT, Encoder_CH1_PINSOURCE, Encoder_CH1_AF);
        GPIO_PinAFConfig(Encoder_CH2_GPIO_PORT, Encoder_CH2_PINSOURCE, Encoder_CH2_AF);      
        GPIO_InitStructure.GPIO_Pin = Encoder_CH1_PIN  ;                /* Encoder A */
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(Encoder_CH1_GPIO_PORT , &GPIO_InitStructure);
      
        GPIO_InitStructure.GPIO_Pin =  Encoder_CH2_PIN;   /* Encoder B */
        GPIO_Init(Encoder_CH2_GPIO_PORT , &GPIO_InitStructure);
               
        /* TIM Initialization */
        RCC_APB1PeriphClockCmd(Encoder_TIM_CLK , ENABLE);
        TIM_DeInit( Encoder_TIM );                /* TIMER reset */      
        TIM_TimeBaseStructure.TIM_Prescaler = Encoder_TIM_PSC;
        TIM_TimeBaseStructure.TIM_Period = Encoder_TIM_PERIOD ;
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
        TIM_TimeBaseInit(Encoder_TIM, &TIM_TimeBaseStructure);
      
        TIM_EncoderInterfaceConfig(Encoder_TIM, TIM_EncoderMode_TI12,TIM_ICPolarity_BothEdge,TIM_ICPolarity_BothEdge);
      
        TIM_ICStructInit(&TIM_ICInitStructure);
        TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
        TIM_ICInitStructure.TIM_ICFilter = 3;
        TIM_ICInit(Encoder_TIM, &TIM_ICInitStructure);
      
        TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
        TIM_ICInit(Encoder_TIM, &TIM_ICInitStructure);
      
        /* Set counter to default value */
        TIM_SetCounter(Encoder_TIM, Encoder_InitCNT);
//        Encoder_TIM->CNT=Encoder_InitCNT;
               
        /* Start TIM */
        TIM_Cmd(Encoder_TIM, ENABLE);
}
      


//通用定时器中断初始化
//这里时钟选择为APB1的2倍,而APB1为42M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
         
void Encoder_TIM_Init(uint16_t arr,uint16_t psc)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

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

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

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

        TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设  计数器使能                                                         
}

//定时器3中断服务函数
void TIM3_IRQHandler(void)
{
        if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET)
                {
                        uint32_t  Encoder_SUMCNT ;
                        uint32_t  Encoder_CNT ;
                        float     speed;
                       
                  TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
                //        Encoder_SUMCNT = Encoder_TIM->CNT ;
                       
                        Encoder_SUMCNT = TIM_GetCounter(Encoder_TIM);
                        printf("计数器总值:%d ",Encoder_SUMCNT);
                       
                        Encoder_CNT= Encoder_SUMCNT- Encoder_InitCNT ;
                //  Encoder_TIM->CNT=Encoder_InitCNT;
                       
                        TIM_SetCounter(Encoder_TIM, Encoder_InitCNT);
                       
                        printf("计数器初始值:%d ",Encoder_TIM->CNT);
                       
                        printf("计数器变化值:%d ",Encoder_CNT);
                       
                //        TIM_SetCounter(Encoder_TIM, Encoder_InitCNT);      
                        speed=(float)Encoder_CNT/(65536*4*0.01);      
                        printf("电机速度:%.3f \r\n",speed);
                       
                }      
}
回复

使用道具 举报

发表于 2020-8-18 09:26:10 | 显示全部楼层
本帖最后由 H781997429 于 2020-8-18 09:32 编辑

检测A相和B相那个先触发,就能得到方向

回复 支持 反对

使用道具 举报

发表于 2020-8-18 09:39:32 | 显示全部楼层
编码器模式可以通过TIMx_CR1->DIR位,读取计数方向来判断正反转,1递增计数正转,0递减计数反转。直接读计数器的值永远都是正数。
关于速度计算可以用M法,就是一个固定时间间隔读出计数值,和上一时刻的计数值做差,然后再乘上每秒读了多少次,就得到每秒的速度了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-8-18 10:27:12 | 显示全部楼层
ZZZ_XXJ 发表于 2020-8-18 09:39
编码器模式可以通过TIMx_CR1->DIR位,读取计数方向来判断正反转,1递增计数正转,0递减计数反转。直接读计 ...

好的 谢谢
回复 支持 反对

使用道具 举报

发表于 2020-8-18 14:50:06 | 显示全部楼层
幸运飞艇而电机的转速和方向就用间隔10ms进入中断时,
读出来的计数器值减去计数器的初始值0x00FFFFFF,
当相减的结果为时,安徽快3可认为转动方向是方向,
当相减的结果为时,台湾今彩539  可认为转动方向是方向
回复 支持 反对

使用道具 举报

发表于 2022-8-6 13:13:07 | 显示全部楼层
解决了吗   我用TIN3没问题 改成TIM2就不行了  是不是PA0  PA1开发板复用的原因
回复 支持 反对

使用道具 举报

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

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-5-19 00:34 , Processed in 0.077451 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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