大家好,欢迎来到IT知识分享网。
STM32编码器模式
- 看前说明:这里重点介绍的时STM32的定时器编码器模式,是根据STMF10x参考手册,如果有使用过编码器或编码器不一样的可以直接跳过前面的编码器介绍,直接看理论分析与程序部分。
1、编码器介绍
- 这里需要注意的参数
- 输出脉冲线数:1024线:编码器每旋转一周输出的脉冲的个数,这个数据就是你在编写的定时器的重装载值。
- 两种编码器的区别
- 从图中看就会来的更加直接:
- 带方向的编码器只有一路的脉冲输出,另外一路就是编码器的正反转的信号,零位信号就是编码器的机械零位。
- 带方向的编码器只有一路的脉冲输出,另外一路就是编码器的正反转的信号,零位信号就是编码器的机械零位。
- 从图中看就会来的更加直接:
- 正交编码器两路的脉冲输出,在判断电机的正反转时,是更加A、B两相的波形来的,其实就是看哪路波形超前,这里用32的定时器编码器功能就只需要去查计数器的方向位来判断电机的正反转。
- 引脚说明
2、脉冲计数对应电机速度的数据两种处理方式
(1) 定时器中断法,计算电机的圈数(过程小题大做,不推荐)
- 前面提到了编码器的线数为1024线(编码器每转一周就会输出1024个脉冲),那么你的重装载值为(1024-1),当计数值达到1024就会发生溢出中断,也就是说识别到了脉冲数为1024个(编码器转了一圈)。每发生一次中断,就说明电机转了一圈
(1)脉冲计数法,直接根据单位时间内所采集到的脉冲数作为电机的转速(更加精准,推荐)
- 编码器在实际的测数使用时确实是根据,电机转一圈:编码器转多少圈的方式来实际测量电机的转速的,但是在其本质就还是编码器的输出的脉冲数,所以直接计算编码器的单位时间的脉冲数推算电机的速度是一样的,数据来的更加直接、精准。
3、STM32定时器编码器模式理论分析
(1)定时器编码器模式选择
- 首先是定时器编码器模式的选择,其实就是选择在那一个通道计数,还是两个通道都要计数也就是这三种模式。
- 对于带方向的就只有一路脉冲,所以选择其中一路通道就ok了。
- 对于正交编码器而言有两路脉冲,所以就选择第三中方式,两路通道都计数。
(2)定时器编码器输入极性的选择
- 看懂这张图才是,确定输入极性的关键所在:所谓极性就是选择在输入脉冲信号的上升沿计数还是下降沿计数。
(3)定时器编码器输入极性的寄存器配置
CC1S=’01’ (TIMx_CCMR1寄存器,IC1FP1映射到TI1) CC2S=’01’ (TIMx_CCMR1寄存器,IC2FP2映射到TI2) CC1P=’0’ (TIMx_CCER寄存器,IC1FP1不反相,IC1FP1=TI1) CC2P=’0’ (TIMx_CCER寄存器,IC2FP2不反相,IC2FP2=TI2) SMS=’011’ (TIMx_SMCR寄存器,所有的输入均在上升沿和下降沿有效). CEN=’1’ (TIMx_CR1寄存器,计数器使能)
- 这里解释一下
- TIx 就相当于输入信号的 TIM4->CH1 TIM4->CH2;
- TIxF 滤波后信号;
- TIxFPx经过带极性选择的边缘检测器过后的产生的信号;
4、结合手册函数刨析库函数
(1)STM32定时器编码器模式的库函数配置代码
/*TIM2初始化为编码器接口*/ void Encoder_Init_TIM2(void) {
//结构体变量的创建 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; GPIO_InitTypeDef GPIO_InitStructure; //RCC时钟使能 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定时器4的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PA端口时钟 //编码器引脚的配置,对于定时器的通道管脚在用户手册上的==8.3.7定时器复用功能重映射== 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 = 0xffff; //设定计数器自动重装值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上计数 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //编码器模式选择与配置 //参数一TIMx:定时器的选择 //参数二TIM_EncoderMode:编码器模式的选择 //参数三TIM_IC1Polarity:通道一的极性选择 //参数四TIM_IC2Polarity:通道二的极性选择 //具体配置->正交编码器:配置如下 TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); //带方向的编码器配置如下->区别只在于带方向的编码器只有一个脉冲输入,而正交编码器有两个脉冲输入 TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI1, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); 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); TIM_Cmd(TIM2, ENABLE); }
(2)刨析
- 转到
void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode, uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity)
函数下可以看到如下代码:
/* Get the TIMx SMCR register value */ tmpsmcr = TIMx->SMCR; /* Get the TIMx CCMR1 register value */ tmpccmr1 = TIMx->CCMR1; /* Get the TIMx CCER register value */ tmpccer = TIMx->CCER;
- 再看下面来自用户手册中的截图,就不用我再继续挖下去了。
5、编码器速度的读取
- 前面已经说过了编码器的脉冲计数对应电机速度的数据处理方法,这里就继续说明了。
- 速度是单位时间为前提的,我这里采用的是直接计算单位时间对应的脉冲数来推算电机的速度的。这里的单位时间也就是采样率的意思,就是我们间隔多少时间去采集然后清零脉冲计数值一次。这里的采样率不能太高,也不能太低。对电机的控制,一般采样率=5毫秒越小就越接近瞬时速度,为什么不能过小想必不用说大家也知道。所以这里就需要一个定时器来计算采样周期
//配置定时器1每5毫秒中断一次,在中断函数中读取编码器数值 void Time1_Init(void) {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStrure; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); //定时器的基本配置 TIM_TimeBaseStrure.TIM_Period = 1000-1;//计数的次数 TIM_TimeBaseStrure.TIM_Prescaler = 7200-1;//控制频率/7200=10000;频率=10000HZ TIM_TimeBaseStrure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStrure.TIM_ClockDivision = 0; TIM_TimeBaseStrure.TIM_RepetitionCounter = 0;//重复计数次数 TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStrure); TIM_ClearITPendingBit(TIM1,TIM_IT_Update);//清空中断标志位 TIM_ITConfig(TIM1,TIM_IT_Update|TIM_IT_Trigger,ENABLE);//开启中断更新和触发中断源 NVIC_InitStruct.NVIC_IRQChannel = TIM1_UP_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); TIM_Cmd(TIM1,ENABLE); } int Read_Encoder(void) {
int value_1; value_1=(int)TIM_GetCounter(TIM2); TIM_SetCounter(TIM2,0); return value_1; } void TIM1_UP_IRQHandler() {
int circle_count ; if(TIM_GetITStatus(TIM1,TIM_IT_Update) != RESET) {
circle_count = Read_Encoder(); TIM_ClearITPendingBit(TIM1,TIM_IT_Update);//清空中断标志位 } }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/151391.html