YFROBOT创客社区

标题: 编码器速度和方向检测,371电机方向与速度检测,stm32编码器接口模式 [打印本页]

作者: aosini    时间: 2014-3-4 20:39
标题: 编码器速度和方向检测,371电机方向与速度检测,stm32编码器接口模式

编码器是什么玩意呢,它可是一个好玩的东西,做小车测速必不可少的玩意,下面,我将从编码器的原理讲起,一直到用stm32的编码器接口模式,测出电机转速与方向。

1.编码器

[attach]832[/attach]
图1 编码器示意图
      图1为编码器的示意图,中间是一个带光栅的码盘,光通过光栅,接收管接收到高电平,没通过,接收到低电平。电机旋转一圈,码盘上有多少光栅,接受管就会接收多少个高电平。371电机中的码盘就是这样的,他是334线码盘,具有较高的测速精度,也就是电机转一圈输出334个脉冲,芯片上已集成了脉冲整形触发电路,输出的是矩形波,直接接单片机IO就OK。        
     增量式旋转编码器通过内部两个光敏接受管转化其角度码盘的时序和相位关系,得到其角度码盘角度位移量增加(正方向)或减少(负方向)。下图为编码器的原理图:

[attach]830[/attach]
图2 增量式旋转编码器

A,B两点对应两个光敏接受管,A,B两点间距为 S2 ,码盘的光栅间距分别为S0和S1。S0+S1的距离是S2的四倍。这样保证了A,B波形相位相差90度。旋转的反向不同,锯齿波A,B先到达高电平的顺序就会不同,如上图左侧所示,顺序的不同,就可以得到旋转的方向。

2.stm32编码器接口模式(寄存器)
        stm32的编码器接口模式在STM32中文参考手册中有详细的说明,在手册273页,14.3.12节。程序是完全按照 下图方式,设置寄存器的。
      请到本文尾下载
STM32中文参考手册
       [attach]831[/attach]
图3
         从图3中可以看出,TI1波形先于TI2波形90°时,每遇到一个边沿变化是,计数器加1(可以通过寄存器设置加减),可以看出一个光栅,被计数了4次。TI1波形后于TI2波形90°时 ,每遇到一次边沿变化,计数器减1。
  1. //TIM2_Encoder_Init,Tim2_CH1(PA0);Tim2_CH2(PA1)
  2. //arr:自动重装值 0XFFFF
  3. //psc:时钟预分频数        ,不分频
  4. void TIM2_Encoder_Init(u16 arr,u16 psc)
  5. {
  6.     RCC->APB1ENR|=1<<0;       //TIM2时钟使能
  7.         RCC->APB2ENR|=1<<2;       //使能PORTA时钟
  8.         
  9.     GPIOA->CRL&=0XFFFFFF00;   //PA0、PA1 清除之前设置
  10.     GPIOA->CRL|=0X00000044;   //PA0、PA1 浮空输入
  11.             
  12.     TIM2->ARR=arr;            //设定计数器自动重装值
  13.     TIM2->PSC=psc;            //预分频器

  14.         TIM2->CCMR1 |= 1<<0;          //输入模式,IC1FP1映射到TI1上
  15.         TIM2->CCMR1 |= 1<<8;          //输入模式,IC2FP2映射到TI2上
  16.         TIM2->CCER |= 0<<1;                  //IC1不反向
  17.         TIM2->CCER |= 0<<5;           //IC2不反向
  18.         TIM2->SMCR |= 3<<0;                  //所用输入均在上升沿或下降沿有效
  19.         TIM2->CR1 |= 1<<0;                  //使能计数器
  20. }
复制代码
3 硬件

用到的模块有STM32核心板、L298电机驱动、371带编码器电机(1:34)。这里主要介绍一下电机,1:34指的是电机轴转动34圈,电机输出1圈。1:X,X值越小,电机的输出转速也就越快,扭矩也就越小;反之,X值越大,电机的输出转速越慢,扭矩也越大。

[attach]834[/attach]

图4 电机实物图

左边两根黄线是电机两极。绿线和白线是脉冲输出线,分别接编码器的接收管A、B,用一根可以测得速度,两根同时用可测出电机速度与转向。红线和黑线是编码器电源接线,红正黑负,电压3.3V-5V,不不可接反

4 控制代码

工作指示灯、电机方向与速度控制代码。

  1. //LED IO 初始化 端口PD.2  运行指示灯
  2. void LED_Init(void)
  3. {                    
  4.         RCC->APB2ENR|=1<<5;      //使能PORTD时钟         
  5.         GPIOD->CRL&=0XFFFFF0FF;
  6.         GPIOD->CRL|=0X00000300;  //PD.2推挽输出
  7.         GPIOD->ODR|=1<<2;        //PD.2输出高
  8. }
  9. //电机旋转方向控制信号端口初始化
  10. //PC1~0推挽输出,输出高
  11. void M_Init(void)
  12. {
  13.         RCC->APB2ENR|=1<<4;      //使能PORTC时钟
  14.         GPIOC->CRL&=0XFFFFFF00;
  15.         GPIOC->CRL|=0X00000033;  //PC1~0推挽输出
  16.         GPIOC->ODR|=0XF<<0;             //PC1~0输出高电平
  17. }

  18. //定时器TIM3,PWM输出初始化,CH1(PA6)
  19. //arr:自动重装值
  20. //psc:时钟预分频数
  21. //设置自动重装值为900,那么PWM频率=72000/900=8Khz
  22. ////见STM32参考手册,14.3.9PWM模式。
  23. void TIM3_PWM_Init(u16 arr,u16 psc) //arr设定计数器自动重装值   
  24.                                     //psc预分频器不分频,psc=0
  25. {
  26.         RCC->APB1ENR|=1<<1;       //TIM3时钟使能   
  27.                   
  28.         GPIOA->CRL&=0XF0FFFFFF;//PA6输出
  29.         GPIOA->CRL|=0X0B000000;//复用功能输出           
  30.         GPIOA->ODR|=1<<6;//PA6上拉        

  31.         TIM3->ARR=arr;//设定计数器自动重装值
  32.         TIM3->PSC=psc;//预分频器不分频
  33.         
  34.         TIM3->CCMR1|=6<<4;  //CH1 PWM1模式        高电平有效         
  35.         TIM3->CCMR1|=1<<3; //CH1预装载使能

  36.         TIM3->CCER|=1<<0;   //OC1 输出使能   

  37.         TIM3->CR1=0x0080;   //ARPE使能
  38.         TIM3->CR1|=0x01;    //使能定时器3
  39. }

  40. //电机方向与速度控制,速度调节范围为-100~+100
  41. //大于0时,正转,小于0时,反转
  42. // 占空比低于0.4时电机不转
  43. //(占空比是指高电平在一个周期之内所占的时间比率)
  44. //TIM3->CCR1的设定范围为0~900(因为arr=900)
  45. //见STM32参考手册,14.3.9PWM模式。
  46. void Motor_Speed_Control(s16 motorSpeed)         
  47. {
  48.     s16 speed = 0 ;        
  49.         
  50.     if(motorSpeed>100)  speed = 100;
  51.             else if (motorSpeed<-100)  speed = -100;
  52.                         else  speed = motorSpeed;
  53.         if(speed == 0)
  54.         {
  55.                 M_1 = 0;
  56.                 M_2 = 0;
  57.         }
  58.             else if(speed > 0)
  59.                 {
  60.                         M_1 = 0;
  61.                         M_2 = 1;
  62.                         TIM3->CCR1 = speed * 9;
  63.                 }
  64.                         else
  65.                         {
  66.                                 M_1 = 1;
  67.                                 M_2 = 0;
  68.                                 TIM3->CCR1 = -speed * 9;
  69.                         }
  70. }
复制代码

电机速度与方向检测代码

  1. //TIM2_Encoder_Init,Tim2_CH1(PA0);Tim2_CH2(PA1)
  2. //arr:自动重装值 0XFFFF
  3. //psc:时钟预分频数        ,不分频
  4. //见STM32中文手册 14.3.12编码器接口模式
  5. void TIM2_Encoder_Init(u16 arr,u16 psc)
  6. {
  7.     RCC->APB1ENR|=1<<0;       //TIM2时钟使能
  8.         RCC->APB2ENR|=1<<2;       //使能PORTA时钟
  9.         
  10.     GPIOA->CRL&=0XFFFFFF00;   //PA0、PA1 清除之前设置
  11.     GPIOA->CRL|=0X00000044;   //PA0、PA1 浮空输入
  12.             
  13.     TIM2->ARR=arr;            //设定计数器自动重装值
  14.     TIM2->PSC=psc;            //预分频器

  15.         TIM2->CCMR1 |= 1<<0;          //输入模式,IC1FP1映射到TI1上
  16.         TIM2->CCMR1 |= 1<<8;          //输入模式,IC2FP2映射到TI2上
  17.         TIM2->CCER |= 0<<1;                  //IC1不反向
  18.         TIM2->CCER |= 0<<5;           //IC2不反向
  19.     TIM2->SMCR |= 3<<0;                  //所用输入均在上升沿或下降沿有效
  20.         TIM2->CR1 |= 1<<0;                  //使能计数器
  21. }
  22. //计数寄存器赋值
  23. void TIM2_Encoder_Write(int data)
  24. {
  25.     TIM2->CNT = data;
  26. }
  27. //读计数个数
  28. int TIM2_Encoder_Read(void)
  29. {
  30.     TIM2_Encoder_Write(0);        //计数器清0
  31.         delay_ms(10);          //检测时间,可调节
  32.     return (int)((s16)(TIM2->CNT));           //数据类型转换
  33.                              //记录边沿变化次数(一个栅格被记录4次)
  34. }
复制代码

这里我们只显示边沿变化次数,没有具体的算出速度。
主函数

  1. int main(void)
  2. {
  3. //        motorSpeed的范围为-100 ~ +100;
  4.         s16 motorSpeed = 100;
  5.         Stm32_Clock_Init(9); //系统时钟设置
  6.         delay_init(72);             //延时初始化
  7.         uart_init(72,9600);  //串口1初始化
  8.         LED_Init();                         //初始化与LED连接的硬件接口
  9.         M_Init();                           ////初始化电机运行方向控制端口
  10.         TIM3_PWM_Init(900,0);          //不分频。PWM频率=72000/900=8Khz
  11.         TIM2_Encoder_Init(0xffff, 0); //计数器自动重装值为最大

  12.         while(1)
  13.     {
  14.                 LED =! LED;
  15.             Motor_Speed_Control(motorSpeed);
  16.                 printf("编码器值:%d\n ",TIM2_Encoder_Read());
  17.     }               
  18. }
复制代码
5 估算验证
         这里我们只是大概的估算验证测量值是否正确,不具有完全正确性。
        我们设置motorSpeed = 100 ,得到测量值如下图:

[attach]838[/attach]
图5 motorSpeed = 100

因为误差是不可避免的,所以看到每次检测的值都是不一样的。我们取462,因为一个光栅被记录了4次,所以在10ms内一共检测到了462/4=115.5,那么得到11.55个/ms,每ms内检测到11.55个光栅。

     通过手动计时,记录电机输出50圈,用时50.2s,那么这时应该检测到的光栅个数为50*34(电机转34圈,输出1圈)*334(每圈有334个光栅)=567800,除以时间,得到估算值11.31个/ms。可以看出估算值与测量值是相近的,认为测量是准确的。
      设置motorSpeed = -50 ,得到测量值如下图 :

[attach]837[/attach]
图6 motorSpeed=-50

可以看到测量值是负值,说明电机是反转,与实际设置相符。

附件下载:(点击下载)

STM32中文参考手册

STM32编码器测速工程  

      我们读的是计数器TIM2->CNT中的值,此值为什么会是负的,这里为什么这样用?      编码器模式中使用上下计数,假设我们初始化TIM2_Encoder_Init_1(0xff, 0);自动装载值为0xFF,这时,计数器中的值,就会在0x00与0xFF之间循环变化,由0x01减为0x00,再减1时,计数器中的值为0xFF,我们将此数做为有符型整数处理,当然,计数的前提是每个周期的计数个数不能超过0x7F,超过,计数将不准确。
      符号强制转换,return (int)((s16)(TIM2->CNT));里面有个类型转换,强制转换返回有符型数据。数值都是以补码表示的,正整数补码是源码,负整数补码是绝对值取反加1。向下计数时减1,为0时,就需要向高位借位减“1”,可以这样理解,一个8位数00000000B-00000001B,但0不够减1的,就向不存在的第9位借1,100000000B-00000001B=11111111B,数是以补码形式表示的,这样11111111B就为-1了。
      在例程中,初始化自动重装值为0xFFFF可以做个实验,直接输出TIM2->CNT的值看一下:      printf("编码器值1:%x \r\n",TIM2->CNT)。


作者: jndxwx    时间: 2014-9-9 11:24
STM32-编码器模式
作者: aosini    时间: 2014-9-12 09:05
jndxwx 发表于 2014-9-9 11:24
STM32-编码器模式

是的,还是挺好用的
作者: aihuailei    时间: 2015-4-2 12:15
arr,设的是正值的话,反转的话,cnt到达-arr进中断吗,还是就不会进中断?
作者: aosini    时间: 2015-4-6 08:16
aihuailei 发表于 2015-4-2 12:15
arr,设的是正值的话,反转的话,cnt到达-arr进中断吗,还是就不会进中断?

原答案:
会的
修改后答案:
原先的回答不对,在此谢谢xueshawu,我现在也想不起,为什么会给出这样的答案。在此程序中也没有使用到溢出中断。





作者: LqRob    时间: 2015-5-9 17:56
楼主,你好。现在TIM2的CH1和CH2用作编码器模式后,CH3和CH4是否还能用作PWM输出?  我用了编码器后,CH3和Ch4通道不能输出PWM了。
作者: aosini    时间: 2015-5-13 08:26
LqRob 发表于 2015-5-9 17:56
楼主,你好。现在TIM2的CH1和CH2用作编码器模式后,CH3和CH4是否还能用作PWM输出?  我用了编码器后,CH3和 ...

不可以的,他们使用了同一个计数器。不可以同时PWM输出,又编码器捕获。
作者: 孤旅人    时间: 2015-5-30 17:02
楼主,我读回来的数据是1,0,-1.这些数据诶  怎么办
作者: aosini    时间: 2015-6-1 08:03
孤旅人 发表于 2015-5-30 17:02
楼主,我读回来的数据是1,0,-1.这些数据诶  怎么办

您看一下是否初始化
作者: henidaguaishou    时间: 2015-7-17 10:21
楼主你好,请教你一个问题,STM32系列的芯片2个高级控制寄存器和4个通用定时器都具有支持针对定位的增量(正交)编码器电路,是不是就是说STM32芯片有6路增量编码器电路或者能接6个增量编码器?谢谢!
作者: aosini    时间: 2015-7-17 16:07
henidaguaishou 发表于 2015-7-17 10:21
楼主你好,请教你一个问题,STM32系列的芯片2个高级控制寄存器和4个通用定时器都具有支持针对定位的增量( ...

理论上是的
作者: 笨笨牛    时间: 2015-8-2 16:50
aosini 发表于 2015-6-1 08:03
您看一下是否初始化

我也是0,-1,1,2,9,之类的   。该怎么办  ?我用的是STM32F103。TIM3寄存器是由变化的,比如DIR CEN都是有的,但是接不接编码器都是收到随机数。
作者: chd121487941    时间: 2015-8-2 19:16
LZ 为什么你脉冲值可以直接就读出正负值,我的是如果正转的话就就向上计数,反转的话就向下计数。反正都是正值,还是你有在软件上做过处理 转化成有符号的?
作者: aosini    时间: 2015-8-3 08:16
笨笨牛 发表于 2015-8-2 16:50
我也是0,-1,1,2,9,之类的   。该怎么办  ?我用的是STM32F103。TIM3寄存器是由变化的,比如DIR CEN都是 ...

首先看一下时钟初始化是否正确,初始化时,涉及寄存器较多,一不小心,就会设置错误,还有就是注意对应的检测端口。
作者: aosini    时间: 2015-8-3 08:26
chd121487941 发表于 2015-8-2 19:16
LZ 为什么你脉冲值可以直接就读出正负值,我的是如果正转的话就就向上计数,反转的话就向下计数。反正都是 ...

在函数//读计数个数int TIM2_Encoder_Read(void)中有这么一句,return (int)((s16)(TIM2->CNT));  //数据类型转换,强制数据类型转化,您用0000-0001=1111,它就是-1的补码,数值都是以补码的形式标识的。
作者: chd121487941    时间: 2015-8-3 15:31
aosini 发表于 2015-8-3 08:26
在函数//读计数个数int TIM2_Encoder_Read(void)中有这么一句,return (int)((s16)(TIM2->CNT));  //数据 ...

原来是这样 ,不过这样的话如果正转超过32768就会变成反转吧
作者: 时文胜    时间: 2015-8-3 21:12
孤旅人 发表于 2015-5-30 17:02
楼主,我读回来的数据是1,0,-1.这些数据诶  怎么办

请问您的问题是如何解决的,我也出现了相同的问题,能分享经验吗

作者: 时文胜    时间: 2015-8-3 21:47
楼主,有两个问题,一,您的程序里有用到中断吗,没有发现;二,下面是我用库函数配置的定时器

        TIM_ICInitTypeDef  TIM_ICInitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

       
       
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
       

        TIM_DeInit(TIM2);
        TIM_TimeBaseStructure.TIM_Period = 65535;      
  TIM_TimeBaseStructure.TIM_Prescaler = 0;            //不分频
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ;        //0
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //Ï向上计数
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

        TIM_EncoderInterfaceConfig(TIM2,     TIM_EncoderMode_TI12,TIM_ICPolarity_BothEdge,TIM_ICPolarity_BothEdge);
        TIM_ICStructInit(&TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;     //不分频
  TIM_ICInitStructure.TIM_ICFilter = 0x0;                  //不滤波
  TIM_ICInit(TIM2, &TIM_ICInitStructure);
  TIM2->CNT = 0;

   TIM_Cmd(TIM2, ENABLE);
哪里有问题,,还请诸位指点。  读出来的数据就只是0,1
作者: aosini    时间: 2015-8-4 08:08
chd121487941 发表于 2015-8-3 15:31
原来是这样 ,不过这样的话如果正转超过32768就会变成反转吧

是的,但这个可以通过设置检测周期来控制的,这就不再是问题了。
作者: aosini    时间: 2015-8-4 08:20
时文胜 发表于 2015-8-3 21:47
楼主,有两个问题,一,您的程序里有用到中断吗,没有发现;二,下面是我用库函数配置的定时器

        ...

在例程中我没有使用中断,您可以看一下文件speed_cap.c最后2个函数,我是通过延时来计数的。
我不太明白,您程序中,倒数第二个语句“TIM->CNT=0”是在哪个函数中,只有在将计数寄存器(TIM2->CNT)中的读出后,才可以将它写“0”。
作者: thebest    时间: 2015-8-8 16:36
时文胜 发表于 2015-8-3 21:47
楼主,有两个问题,一,您的程序里有用到中断吗,没有发现;二,下面是我用库函数配置的定时器

        ...

编码器的AB相都接入了吗?只接一项好像是只有0 1,因为计数方向是有硬件决定的
作者: aosini    时间: 2015-8-31 08:12
wodezpy 发表于 2015-8-30 11:27
void Motor_Speed_Control(s16 motorSpeed)         
{
    s16 speed = 0 ;        

您好,是的 ,谢谢您我修改一下
作者: aosini    时间: 2015-9-3 19:06
wodezpy 发表于 2015-9-2 11:48
你好我想请问一下:
这里最后一句return (int)((s16)(TIM2->CNT));该如何理解,因为当计数器清零后,在10m ...

return (int)((s16)(TIM2->CNT));里面有个类型转换,强制转换返回有符型数据。数值都是以补码表示的,正整数补码是源码,负整数补码是绝对值取反加1。向下计数时减1,为0时,就需要向高位借位减“1”,可以这样理解,一个8位数00000000B-00000001B,但0不够减1的,就向不存在的第9位借1,100000000B-00000001B=11111111B,数是以补码形式表示的,这样11111111B就为-1了
作者: aosini    时间: 2015-9-7 08:36
wodezpy 发表于 2015-9-4 17:59
还有个问题,当计数器为0时,如果减1后CNT内的值就为减1后的补码形式存在?
但是手册里不是说CNT只能在0 ...

是的。具体可以看STM32中文参考手册,第273页,14.3.12编码器接口模式。里面有较详细的说明,如果没有这个手册,请到http://www.yfrobot.com/forum.php ... 360&highlight=stm32下载,或留个邮箱我给您发一下。在主函数中,初始化,TIM2_Encoder_Init(0xffff, 0); //计数器自动重装值为最大

作者: aosini    时间: 2015-9-16 13:52
wodezpy 发表于 2015-9-16 10:14
手册有,不过还有个问题就是CNT重装值设置为0XFFFF,那它表示的数值是0-65535,还是32768~32767,因为-1的 ...

请仔细看25楼哟
作者: aosini    时间: 2015-9-25 07:55
wodezpy 发表于 2015-9-24 11:19
还是不太懂,我就是搞不懂如何判断补码为1111到底表示的为-1还是15?既然是补码我可以认为1111为正数的补 ...

((s16)(TIM2->CNT))强制类型转换,转换成有符型的,那么最高位就是符号位。
作者: aosini    时间: 2015-10-7 13:47
wodezpy 发表于 2015-10-7 11:29
请问如果是普通的码盘测速,就是只有一个输出信号的不带方向检测的可以使用编码器接口模式吗?配置上和这个 ...

不可以使用的。那个只要用外部中断计数就可以了
作者: aosini    时间: 2015-10-9 08:21
wodezpy 发表于 2015-10-8 10:29
我有个疑问:我能不能通过人为的给某个通道用导线接个高或低电平(因为下图有个相对电平为高或者低),然 ...
14.3.12 编码器接口模式(P273)
选择编码器接口模式的方法是:如果计数器只在TI2的边沿计数,则置TIMx_SMCR寄存器中的SMS=001;如果只在TI1边沿计数,则置SMS=010;如果计数器同时在TI1和TI2边沿计数,则置SMS=011。
按照手册来说,是可以的 您可以试一下
作者: aosini    时间: 2015-10-9 10:32
wodezpy 发表于 2015-10-9 10:07
结果失败了,不知道什么问题!

[AppleScript] 纯文本查看 复制代码
//TIM2_Encoder_Init,Tim2_CH1(PA0);Tim2_CH2(PA1)
//arr:自动重装值 0XFFFF
//psc:时钟预分频数        ,不分频
void TIM2_Encoder_Init(u16 arr,u16 psc)
{
    RCC->APB1ENR|=1<<0;       //TIM2时钟使能
        RCC->APB2ENR|=1<<2;       //使能PORTA时钟
        
    GPIOA->CRL&=0XFFFFFF00;   //PA0、PA1 清除之前设置
    GPIOA->CRL|=0X00000044;   //PA0、PA1 浮空输入
            
    TIM2->ARR=arr;            //设定计数器自动重装值
    TIM2->PSC=psc;            //预分频器

        TIM2->CCMR1 |= 1<<0;          //输入模式,IC1FP1映射到TI1上
        TIM2->CCMR1 |= 1<<8;          //输入模式,IC2FP2映射到TI2上
        TIM2->CCER |= 0<<1;                  //IC1不反向
        TIM2->CCER |= 0<<5;           //IC2不反向
        TIM2->SMCR |= 3<<0;                  //所用输入均在上升沿或下降沿有效
        TIM2->CR1 |= 1<<0;                  //使能计数器
}

只把3改为1或2试一下,看上一次给您的回复

作者: 活在瞬间    时间: 2015-10-12 15:17
楼主 您好,请问您能不能告诉下我,要是加上中断该怎么加呢????

现在计数只能-65535/2~65535/2,可是加了中断后变成0~65535,只要反转就从0马上进入中断,好奇怪
作者: aosini    时间: 2015-10-13 08:35
活在瞬间 发表于 2015-10-12 15:17
楼主 您好,请问您能不能告诉下我,要是加上中断该怎么加呢????

现在计数只能-65535/2~65535/2,可 ...

编码器模式是不需要中断的
作者: wcb198866    时间: 2015-10-13 20:57
楼主,我这边编译出现了很多错误,请教是什么问题呢。请问你那边原来编译出现过错误吗??

作者: aosini    时间: 2015-10-14 10:01
wcb198866 发表于 2015-10-13 20:57
楼主,我这边编译出现了很多错误,请教是什么问题呢。请问你那边原来编译出现过错误吗??

软件的版本不同,使用会有所区别,您要先用这个版本的软件创建一个简单的工程,之后您就会知道如何用这个软件了。
作者: cbcy    时间: 2015-10-14 20:09
刚学这个,楼主高手,您是如何调用库文件呀!麻烦您指导一下!谢谢
作者: aosini    时间: 2015-10-15 08:11
cbcy 发表于 2015-10-14 20:09
刚学这个,楼主高手,您是如何调用库文件呀!麻烦您指导一下!谢谢

这几句话还真的说不清楚,你先学会建立一个简单的跑马灯,估计这个你就就自然而然的会调用了
作者: wcb198866    时间: 2015-10-23 11:25
aosini 发表于 2015-10-14 10:01
软件的版本不同,使用会有所区别,您要先用这个版本的软件创建一个简单的工程,之后您就会知道如何用这个 ...

请问你有没有在stm32f4上做过编码器解码??求助
作者: aosini    时间: 2015-10-23 14:47
wcb198866 发表于 2015-10-23 11:25
请问你有没有在stm32f4上做过编码器解码??求助

不好意思 没有哦 ?但是我想应该是一样的,您可以看一下stm32f4编码器部分的手册,对比一下看看。

作者: aosini    时间: 2015-12-15 09:20
Damon93 发表于 2015-12-14 00:30
我用的是stm32f103

您好,PWM调节的是电机转速,直接加固定电压也是可以的。是STM32F103系列,直接移植应该是没有问题的。
//读计数个数
int TIM2_Encoder_Read(void)
{
    TIM2_Encoder_Write(0);        //计数器清0
        delay_ms(10);          //检测时间,可调节
    return (int)((s16)(TIM2->CNT));           //数据类型转换
                             //记录边沿变化次数(一个栅格被记录4次)
}
我是使用的延时来读取计数值的。
作者: aosini    时间: 2015-12-17 08:04
Damon93 发表于 2015-12-17 00:42
还有我要实现指定角度旋转,这方面实在没有经验,大致的想法是这样的   在TIM2_Encoder_Init函数里加入计数 ...

公式应该是对的。
您可以通过定时中断来读计算寄存器TIM2->CNT的值。当TIM2->CNT的值达到您想要的值时,就执行关闭PWM使能。
作者: aosini    时间: 2015-12-19 14:18
Damon93 发表于 2015-12-17 09:04
谢谢您的回复,定时中断按一定时间去刷新读取cnt的值,我想过,但是这个略有误差,即如果刷新读取的间隔 ...
您好,是可以的,在编码器时,使用计数器溢出中断。给个参考程序,您试一下。
[AppleScript] 纯文本查看 复制代码
//TIM2_Encoder_Init,Tim2_CH1(PA0);Tim2_CH2(PA1)
//arr:自动重装值 0XFFFF
//psc:时钟预分频数        ,不分频
void TIM2_Encoder_Init_1(u16 arr,u16 psc)
{
    RCC->APB1ENR|=1<<0;       //TIM2时钟使能
        RCC->APB2ENR|=1<<2;       //使能PORTA时钟
        
    GPIOA->CRL&=0XFFFFFF00;   //PA0、PA1 清除之前设置
    GPIOA->CRL|=0X00000044;   //PA0、PA1 浮空输入
            
    TIM2->ARR=arr;            //设定计数器自动重装值
    TIM2->PSC=psc;            //预分频器

        TIM2->CCMR1 |= 1<<0;          //输入模式,IC1FP1映射到TI1上
        TIM2->CCMR1 |= 1<<8;          //输入模式,IC2FP2映射到TI2上
        TIM2->CCER |= 0<<1;                  //IC1不反向
        TIM2->CCER |= 0<<5;           //IC2不反向
    TIM2->SMCR |= 3<<0;                  //所用输入均在上升沿或下降沿有效
        TIM2->DIER|=1<<0;   //允许更新中断                                
        TIM2->DIER|=1<<6;   //允许触发中断
        TIM2->CR1 |= 1<<0;                  //使能计数器
         MY_NVIC_Init(1,3,TIM2_IRQChannel,2);//抢占1,子优先级3,组2        
}
//定时器2中断服务程序         
void TIM2_IRQHandler(void)
{                                                         
        if(TIM2->SR&0X0001)//溢出中断
        {               
                Motor_Speed_Control( 0);//刹车                                                                                                                        
        }                                   
        TIM2->SR&=~(1<<0);//清除中断标志位            
}

初始化void TIM2_Encoder_Init_1(u16 arr,u16 psc);这条语句。
例:初始化TIM2_Encoder_Init_1(1360, 0);340线,一圈检测到*4=1360个脉冲,也就是电机转一圈,然后刹车停止。
但是,这直流电机定位不准确,除非电机转动很慢的状况下才能实现,不然由于惯性,电机还是不能停在设定位置,建议直接使用步进电机,定位更加准确。

作者: hero_sun    时间: 2016-1-24 18:04
请问这是虾米电机?
作者: aosini    时间: 2016-1-24 21:44
hero_sun 发表于 2016-1-24 18:04
请问这是虾米电机?

371电机。只要是编码器,都是一样的
作者: hero_sun    时间: 2016-1-25 09:46
谢谢楼主!
作者: li786215784    时间: 2016-5-3 20:25
楼主您好 能不能将这段程序移植到HT32中,我正常写这部分的程序,现在不知道怎么弄?还有 资料怎么下载不了啊 786215784@qq.com望楼主可以发一份过来。十分感谢
作者: aosini    时间: 2016-5-4 08:06
li786215784 发表于 2016-5-3 20:25
楼主您好 能不能将这段程序移植到HT32中,我正常写这部分的程序,现在不知道怎么弄?还有 资料怎么下载不了 ...

已经发送到您的邮箱了哦!是可以的哦,您再试试看呢
作者: li786215784    时间: 2016-5-4 09:06
aosini 发表于 2016-5-4 08:06
已经发送到您的邮箱了哦!是可以的哦,您再试试看呢

我是第一次用单片机哈,您是对寄存器的调用嘛?
作者: aosini    时间: 2016-5-4 09:08
li786215784 发表于 2016-5-4 09:06
我是第一次用单片机哈,您是对寄存器的调用嘛?

是的哦,您看一下1楼哦
作者: li786215784    时间: 2016-5-4 09:09
能不能叫个QQ呢 大神 还是有好多不懂呢 786215784
作者: silentk    时间: 2016-9-28 13:52
大神!  现在我在做个编码器左旋&右旋的实验。判断左旋然后执行。。。右旋执行。。。。现在我在写前面的部分,能不能加个QQ讨论一下~~~~1554951564
作者: aosini    时间: 2016-9-29 08:11
silentk 发表于 2016-9-28 13:52
大神!  现在我在做个编码器左旋&右旋的实验。判断左旋然后执行。。。右旋执行。。。。现在我在写前面的部 ...

有问题直接跟帖,这样方便有同样问题的朋友看到!谢谢啦
作者: liawei    时间: 2016-11-20 21:12
楼主你好,我购买了老版本没显示器的平衡小车套件,在试验电机编码器时,通过串口助手发现返回的都是零。
作者: xueshawu    时间: 2017-1-15 23:17
aosini 发表于 2015-4-6 08:16
会的

arr 还能是负值? 别搞笑啊

In upcounting mode, the counter counts from 0 to the auto-reload value (content of the
TIMx_ARR register), then restarts from 0 and generates a counter overflow event.

In downcounting mode, the counter counts from the auto-reload value (content of the
TIMx_ARR register) down to 0, then restarts from the auto-reload value and generates a
counter underflow event.

还是不要误导别人比较好,
作者: aosini    时间: 2017-1-19 16:38
xueshawu 发表于 2017-1-15 23:17
arr 还能是负值? 别搞笑啊

In upcounting mode, the counter counts from 0 to the auto-reload valu ...

谢谢您的提示,确实错了。不好意思,给大家带来麻烦了。
作者: annirojess    时间: 2017-5-27 11:21
您好,能否分享下接线图?电机的两根电源线是接在l298的两路output上吗?pwm如何控制的转速?方向是通过一根引脚控制的吗?
作者: gcy1997    时间: 2018-4-7 20:11
您好,请问如果ARR装载值不是0XFFFF呢?再从0下溢出的时候,还能用这个算法吗
return (int)((s16)(TIM2->CNT));   比如ARR是0x1234,这样的话从零下溢出就是0x1234,是不是就不能当做-1了
作者: 肚肚佳    时间: 2018-7-12 12:02
好资料
作者: tiantianyouyou    时间: 2019-5-15 08:19
好好,学习




欢迎光临 YFROBOT创客社区 (http://yfrobot.com.cn/) Powered by Discuz! X3.1