正交编码器学习(二)

来源:互联网 发布:中文地址模糊匹配算法 编辑:程序博客网 时间:2024/05/29 19:58

编码器的设计思想有多种思路,主要分为两种(1)定时器中断计数(2)外部中断触发计数。
STM32中包含了TIM_EncoderInterfaceConfig()函数[1]。其配置的定时器有编码器接口等功能,一般是定时器的通道1和通道2才能作为编码器的输入口,对应编码器输出的两项。
TIMx参数就是使用哪个定时器作为编码器接口的捕捉定时器。
个人理解为:一个编码器占用一个定时器。
TIM_EncoderMode参数是模式,是单相计数(只能反映速度)还是两相计数(速度和方向)。
TIM_IC1Polarity和TIM_IC2Polarity参数就是通道1、2的捕捉极性。
但是一般来说,STM32对应的都是两相计数,一项计数容易误判,也就是说,你可以按一路计数,但是接线时好像两相的编码线A,B都是需要接上的,否则容易误判。(可能理解有误,后续有更改可以给我底下写评论)。
这里写图片描述
分析也是从速度和方向上来分析,通过上升下降沿来判断。
一:Counting on TI1 only(通过TI1来计数,一个周期内只能有两个跳边沿):
若TI2为高时(第一行):TI1上升沿则向下计数,下降沿则向上计数。
1时刻:TI2为低电平,TI1上升沿跳变,计数器向上计数;
3时刻:TI2为高电平,TI1下降沿跳变,计数器仍然向上计数。
二. Countingon TI1 and TI2:一个周期完成4次跳变。精度提高
1时刻:TI2为低电平,TI1上升沿跳变,计数器向上计数;
2时刻:TI1为高电平,TI2上升沿跳变,计数器仍然向上计数;
3时刻:TI2为高电平,TI1下降沿跳变,计数器仍然向上计数;
4时刻:TI1为低电平,TI2下降沿跳变,计数器仍然向上计数。
这里写图片描述
这里写图片描述
一个大家不是很懂的图,分析一下
这里写图片描述
1.有效边沿 其实就是对应上面设置的编码器的三种模式
2.相对信号的电平,这里没有理解手册意思,我把它理解为于它的高低电平意味着将PB6和PB7接口对换,PB7接A PB6接B 这样一来就意味着原来的正转变成反转 计数上升变为下降[2]由此完成了编码器的配置,至于读取编码器角度的时间,要根据实际需要来设置编码器线数为 w线/圈 转速为 V 圈/min 读取间隔时间 t(线间隔时间) t <= 60/WV 单位为秒

1.编码器有个转速上限,超过这个上限是不能正常工作的,这个是硬件的限制,原则上线数越多转速就越低,这点在选型时要注意,编码器的输出一般是开漏的,所以单片机的io一定要上拉输入状态.
2.定时器初始化好以后,任何时候CNT寄存器的值就是编码器的位置信息,正转他会加反转他会减这部分是不需要软件干预的,初始化时给的TIM_Period 值应该是码盘整圈的刻度值,在减溢出会自动修正为这个数.加超过此数值就回0.
3.如果要扩展成多圈计数需要溢出中断像楼主说的,程序上圈计数加减方向位就行了.
4.每个定时器的输入脚可以通过软件设定滤波
5.应用中如果没有绝对位置信号或者初始化完成后还没有收到绝对位置信号前的计数只能是相对计数.收到绝对位置信号后重新修改一次CNT的值就行了.码盘一般都有零位置信号,结合到定时器捕获输入就行.上电以后要往返运动一下找到这个位置.
6.即便有滤波计数值偶尔也会有出错误的情况,一圈多计一个或少计一个数都是很正常的特别是转速比较高的时候尤其明显,有个绝对位置信号做修正是很有必要的.绝对位置信号不需要一定在零位置点,收到这个信号就将CNT修正为一个固定的数值即可.
7.开启定时器的输入中断可以达到每个步计数都作处理的效果,但是高速运转的时候你可能处理不过来.
正转向上计数,反转向下计数,方向在CR1的DIR位里
读取只要不在捕获中断里就行,但最好放到定时器中断里,应该拿过来就能用。但我想知道怎么测速呢,这就得看平衡车的使用了。

encoder.c文件

/**************************************************************************函数功能:把TIM2初始化为编码器接口模式入口参数:无返回  值:无**************************************************************************/void Encoder_Init_TIM2(void){    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;    TIM_ICInitTypeDef TIM_ICInitStructure;    GPIO_InitTypeDef GPIO_InitStructure;  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定时器4的时钟  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PB端口时钟  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;  //端口配置  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入  GPIO_Init(GPIOA, &GPIO_InitStructure);                          //根据设定参数初始化GPIOA  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);  TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器   TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //设定计数器自动重装值  //65535   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;////TIM向上计数    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);  TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3  TIM_ICStructInit(&TIM_ICInitStructure); //将结构体中的内容缺省输入  TIM_ICInitStructure.TIM_ICFilter = 10;  TIM_ICInit(TIM2, &TIM_ICInitStructure);  TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新标志位  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//运行更新中断  //Reset counter  TIM_SetCounter(TIM2,0); //TIM4->CNT=0  TIM_Cmd(TIM2, ENABLE); }
/**************************************************************************函数功能:单位时间读取编码器计数入口参数:定时器返回  值:速度值**************************************************************************/int Read_Encoder(u8 TIMX){    int Encoder_TIM;       switch(TIMX)     {       case 2:  Encoder_TIM= (int)TIM2 -> CNT;  TIM2 -> CNT=0;break;         default:  Encoder_TIM=0;     }        return (int)Encoder_TIM;}/**************************************************************************函数功能:TIM2中断服务函数入口参数:无返回  值:无**************************************************************************/void TIM2_IRQHandler(void){                                       if(TIM2->SR&0X0001)//溢出中断    {                       //一般都是不加代码,我也不知道是为啥    }                      TIM2->SR&=~(1<<0);//清除中断标志位        }

参考网址:
[1]https://zhidao.baidu.com/question/540091949.html
[2]http://blog.csdn.net/wang328452854/article/details/50579832

原创粉丝点击