编码器接口测速

编码器接口测速接线部分

接线图:

这里PA6和PA7两个引脚可以交换一下,A相接PA6,B相接PA7,或者A相接PA7,B相接PA6,都是可以的,就是正转和反转的极性不一样而已,但是PA6和PA7这两个引脚不能随便更换

PA6和PA7是TIM3的通道1和通道2,我们计划用TIM3接编码器,所以需要接在PA6和PA7这两个引脚

代码部分

第一步,RCC开启时钟,开启GPIO和定时器的时钟

c 复制代码
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

第二步, 配置GPIO,这里需要把PA6和PA7配置成输入模式

c 复制代码
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//可以选择上拉、下拉或者浮空,上拉和下拉如何选择呢?我们一般可以看一下接在这个引脚的,外部模块输出的默认电平,如果外部模块空闲默认输出高电平,我们就选择上拉输入,默认输入高电平,如果外部模块默认输出低电平,我们配置下拉输入, 默认输入低电平,和外部模块保持默认状态一致,防止默认电平打架,这是上拉和下拉的选择原则,不过一般来说, 默认高电平,这是一个习惯的状态,所以一般上拉输入用的比较多,然后如果你不确定外部模块输出的默认状态,或者外部信号输出功率非常小,这时就尽量选择浮空输入,浮空输入,没有上拉电阻和下拉电阻去影响外部信号,但是缺点就是当引脚悬空时,没有默认的电平了,输入就会受噪声干扰,来回不断地跳变,这就是三种输入模式的选择原则
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

第三步,配置时基单元,这里预分频器我们一般选择不分频,自动重装,一般给最大65535, 只需要个CNT执行计数就行了

c 复制代码
//TIM_InternalClockConfig(TIM3);这一行就不需要了,因为编码器接口会托管时钟,编码器接口就是一个带方向控制的外部时钟,所以这个内部时钟就没有用了
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//计数器模式 这个参数目前也是没有作用的,因为计数方向也是被编码器接口托管的
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARR,自动重装值, 自前还是给65536-1,也就是满量程计数,这样计数的范围是最大的,而且方便换算为负数
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;		//PSC,预分频器,这里改成1-1,预分频给0, 就是不分频,编码器的时钟,直接驱动计数器
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //最后初始化TIM3

第四步, 配置输入捕获单元,不过这里输入捕获单元只有滤波器和极性这两个参数有用,后面的参数没有用到,与编码器无关

c 复制代码
//看流程图发现,输入捕获单元并没有全部使用到,编码器接口只使用了通道1和通道2的滤波器和极性选择,所以我们只需要配置这两部分的参数即可,那在代码这里,就是后面这两个参数(上节代码部分),与编码器无关,删掉,或者你留看也行,只是它们目前没有作用,那删掉之后,目前结构体的配置是不完整的,为了防止结构体中出现不确定值可能会造成的问题,我们最好用structinit给结构体赋一个初始值,加个Structlnit也是提醒一下我们,结构体并没有配置完整
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICStructInit(&TIM_ICInitStructure); 
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //通道为1
TIM_ICInitStructure.TIM_ICFilter = 0xF; //滤波器为0xF
//TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //电平极性在默认赋值里面就是上升沿,上一小节我们说过,这里的上升沿并不代表上升沿有效,因为编码器接口始终都是上升沿、下降沿都有效的,这里的上升沿参数代表的是高低电平极性不反转,也就是我们PPT这里演示的TI1,TI2是否反相,对应通道,给上升沿,就是不反相,给下降沿 就是反相,其实这里的这个极性参数,等会儿我们配置编码器接口的时候也有,属于重复配置了,这里这个其实也可以删掉
TIM_ICInit(TIM3, &TIM_ICInitStructure); //最后传给ICInit,这些参数写到通道1,调用ICInit函数之后,就写入到硬件的寄存器了,所以Init之后,这个结构体我们可以换个值继续使用,不需要重新定义新的结构体了
//下面通道2
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInit(TIM3, &TIM_ICInitStructure);

第五步,配置编码器接口模式,这个直接调用一个库函数就可以了

c 复制代码
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); //这后两个参数和上面代码极性选择部分是一样的,实际效果确实一样,这两个地方的参数,其实都配置的是同一个寄存器,属于重复配置了,后配置的参数,会覆盖前面的参数,所以我们可以把这前面那个极性的参数也删掉,只使用这个函数来配置极性,不过要注意,这时一定要保证,这个Encoder函数位于ICInit函数的下面,否则的话,就是ICInit覆盖Encoder函数的配置了
c 复制代码
/**
  * @brief  Configures the TIMx Encoder Interface.
  * @param  TIMx: where x can be  1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
  * @param  TIM_EncoderMode: specifies the TIMx Encoder Mode. 选择编码器模式
  *   This parameter can be one of the following values:
  *     @arg TIM_EncoderMode_TI1: Counter counts on TI1FP1 edge depending on TI2FP2 level.仅在TI1计数
  *     @arg TIM_EncoderMode_TI2: Counter counts on TI2FP2 edge depending on TI1FP1 level.仅在TI2计数
  *     @arg TIM_EncoderMode_TI12: Counter counts on both TI1FP1 and TI2FP2 edges depending 在TI1和TI2都计数
  *                                on the level of the other input.
  * @param  TIM_IC1Polarity: specifies the IC1 Polarity 选择IC1的极性
  *   This parameter can be one of the following values:
  *     @arg TIM_ICPolarity_Falling: IC Falling edge. 选择Falling就是这个通道反相
  *     @arg TIM_ICPolarity_Rising: IC Rising edge. 选择Rising就是这个通道不反相
  * @param  TIM_IC2Polarity: specifies the IC2 Polarity 选择IC2的极性
  *   This parameter can be one of the following values:
  *     @arg TIM_ICPolarity_Falling: IC Falling edge.
  *     @arg TIM_ICPolarity_Rising: IC Rising edge.
  * @retval None
  */
void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode, uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity)

最后,调用TIM_Cmd,启动定时器, 就完事了

c 复制代码
TIM_Cmd(TIM3, ENABLE);

电路初始化完成之后,CNT就会随着编码器旋转而自增自减,如果想要测量编码器的位置,直接读出CNT的值就行了,如果想测量编码器的速度和方向,那就需要每隔一段固定的闸门时间,取出一次CNT, 然后再把CNT清零,这样就是测频法测量速度了

流程看完, 我们来看一下库函数

c 复制代码
void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode, uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity); //定时器编码器接口配置,第二个参数选择编码器模式,然后后面两个参数 分别选择通道1和通道2的电平极性

调用一下这个Encoder_Init函数,编码器旋转就能控制CNT自增自减了

再写一个Get函数

c 复制代码
int16_t Encoder_Get(void)
{
	int16_t Temp; //为了显示负数,就直接把uint16_t类型强制转换成int16_t就行了
	Temp = TIM_GetCounter(TIM3); //得到CNT的值
	TIM_SetCounter(TIM3, 0); //为了测速度,读完后清零CNT
	return Temp;
}

编码器每转一格(段落感)

A相提前还是滞后90度,取决于正转还是反转

那可以看出,现在编码器转动一格,A、B相各出现了一个下降沿和上升沿,所以计次总共加了4次,当然如果你是电机的编码器,那就不会有这个段落感了

main.c

c 复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "Encoder.h"

int16_t Speed;

int main(void)
{
	OLED_Init();
	Timer_Init();
	Encoder_Init();
	
	OLED_ShowString(1, 1, "Speed:");
	
	while (1)
	{
		OLED_ShowSignedNum(1, 7, Speed, 5); //这个函数可以显示负数
		//Delay_ms(1000);
		//可以这个地方加delay函数,测这个delay时间段内计次的个数,如果你是编码电机飞速旋转的话,闸门时间就可以给短点,这样可以提高速度刷新的频率,而且防止计数器溢出,最好不要在主循环加入过长的Delay,这样会阻塞主循环的执行,那比较好的方法,就是用定时中断
	}
}

void TIM2_IRQHandler(void) //这里定时中断自前是每隔1s执行一次,你可以修改定时中断的时间 来调整闸门时间
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		Speed = Encoder_Get(); //每隔1s读取一下速度,存在Speed变量里,然后主循环,就可以快速刷新显示speed了
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

研究一下极性问题

自前向右转是增,向左转是减,如果这个方向和你想要的不一致的话,可以修改一下极性

在硬件层面,我们可以这样,把A、B相两根线换一下

在硬件层面,我们可以修改这里的(TIM_EncoderInterfaceConfig), 两个输入通道的极性,把任意一个极性反转一下, 方向就会反过来,如果两个极性都反转,那极性还是保持不变

相关推荐
超能力MAX6 分钟前
IIC驱动EEPROM
单片机·嵌入式硬件·fpga开发
QQ5471760529 分钟前
stm32实现回调功能
stm32·单片机·嵌入式硬件
wenchm2 小时前
细说STM32F407单片机轮询方式读写SPI FLASH W25Q16BV
stm32·单片机·嵌入式硬件
委员2 小时前
基于NodeMCU的物联网电灯控制系统设计
单片机·物联网·嵌入式·nodemcu··lu_asr01·gy-302
北国无红豆2 小时前
【CAN总线】STM32的CAN外设
c语言·stm32·嵌入式硬件
单片机学习之路2 小时前
【C语言】结构
c语言·开发语言·stm32·单片机·51单片机
m0_748254094 小时前
STM32--超声波模块(HC—SR04)(标准库+HAL库)
stm32·单片机·嵌入式硬件
南城花随雪。4 小时前
单片机:实现FFT快速傅里叶变换算法(附带源码)
单片机·嵌入式硬件·算法
逝灮4 小时前
【蓝桥杯——物联网设计与开发】基础模块8 - RTC
stm32·单片机·嵌入式硬件·mcu·物联网·蓝桥杯·rtc
LXL_245 小时前
模拟——郑益慧_笔记1_绪论
嵌入式硬件