stm32入门学习7-编码器接口

(一)编码器接口

编码器接口使用输入捕获的通道1和通道2接收两个正交信号(即一个信号比另一个信号领先90°),通过某个端口的触发判断另一端口的电平,来决定计数值的增加还是减少,可以用来实现之前在外部中断中提到的旋转编码器功能,如果我们在一定的时间内测量其产生的脉冲,就可以知道其频率了,假设t时间内产生了n+1个上升沿,那么信号的周期就是t/n,那么该信号的频率为f=n/t,我们也可以直接把CNT的值读出,用于了解信号的相对的速度的快慢

编码器接口使用的是输入捕获通道的通道1和通道2作为信号的输入端来接收两个正交信号

其通过两个正交信号的关系来执行计数器的增减

配置一个编码器接口模块,我们要实现这几步:(1)打开时钟;(2)打开编码器接口的输入端口;(3)初始化时基单元;(4)配置一部分的输入捕获电路;(5)配置编码器接口的工作模式;(7)打开定时器

这里除了配置编码器外其余和之前的输入捕获基本相同,这里由于计数器没有使用到内部时钟,而是受编码器的控制,所以相比前面少了时钟源选择这一步

配置编码器接口的工作模式仅用到一个代码

void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode, uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);
//配置定时器的编码器模式

(二)初始化配置

(1)打开时钟和要用的gpio口

这里我们使用TIM3定时器,其输入捕获通道1和通道2和PA6、PA7复用,我们需要打开对应的IO口

void encoder_rcc_init()
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
}
void encoder_gpio_init()
{
	GPIO_InitTypeDef gpio_init;
	gpio_init.GPIO_Mode = GPIO_Mode_IPU;
	gpio_init.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	gpio_init.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_Init(GPIOA, &gpio_init);
}

(2)初始化时基单元

时基单元的配置中,我们让自动重装值最大,以便多记一些数,我们使用不是内部时钟,因此我们不需要分频

void encoder_time_base_init()
{
	TIM_TimeBaseInitTypeDef time_base_init;
	time_base_init.TIM_ClockDivision = TIM_CKD_DIV1;
	time_base_init.TIM_CounterMode = TIM_CounterMode_Up;
	time_base_init.TIM_Period = 65536-1;
	time_base_init.TIM_Prescaler = 1-1;
	time_base_init.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &time_base_init);
}

(3)配置输入捕获部分

由于我们只用到输入捕获的通道和滤波部分,我们只需要对输入捕获的通道和滤波初始化即可(边沿检测部分会在配置编码器接口部分配置)

void encoder_ic_init()
{
	TIM_ICInitTypeDef ic_init;
	TIM_ICStructInit(&ic_init);
	
	ic_init.TIM_Channel = TIM_Channel_1;
	ic_init.TIM_ICFilter = 0xF;
	TIM_ICInit(TIM3, &ic_init);
	
	ic_init.TIM_Channel = TIM_Channel_2;
	TIM_ICInit(TIM3, &ic_init);
}

(4)配置编码器接口的工作模式

跳转到初始化函数的定义中,可以看到

这里第一个参数是定时器,我们选择的是定时器3;第二个参数是选择编码器模式,第一个选项是只有通道1触发,第二个选项是只有通道2触发,第三个选项是通道1和通道2都触发;最后两个方式分别选择通道1和通道2的触发方式,这里和之前输入捕获中配置的边沿检测是一样的,可以选择上升沿触发和下降沿触发。我们选择定时器3,只在通道1上升沿时触发

void encoder_interface_mode_init()
{
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI1, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
}

(5)打开定时器

void encoder_time_open()
{
	TIM_Cmd(TIM3, ENABLE);
}

(6)初始化部分封装为一个函数

void encoder_interface_init()
{
	encoder_rcc_init();
	encoder_gpio_init();
	encoder_time_base_init();
	encoder_ic_init();
	encoder_interface_mode_init();
	encoder_time_open();
}

(7)读取计数值

我们在读取计数值后将计数值清零,这样我们只要相隔固定的时间读取计数值,就可以实现测速功能了

uint16_t encoder_get_count()
{
	uint16_t count = 0;
	count = TIM_GetCounter(TIM3);
	TIM_SetCounter(TIM3, 0);
	return count;
}

(8)主函数调用

我们可以在主函数中每隔一秒调用一下,这里可以使用Delay函数,也可以使用其他定时器来实现一个定时中断功能

int16_t counter = 0;

int main()
{
	OLED_Init();
	encoder_interface_init();
	timer_interrupt_init();
	OLED_ShowString(1, 1, "speed:");
	while(1)
	{
		OLED_ShowSignedNum(1,7, counter, 5);
	}
	return 0;
}


void TIM2_IRQHandler()
{
	counter = encoder_get_count();
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}

这里值得注意的问题是,我们如果要测量一个有方向的物体,比如编码器,我们需要用有符号整数来显示计数值,有些时候我们使用的int类型数据是32为的,而编码器返回值却是16位的,这样计算机会自动在前面补0,导致我们出现+65535这样的情况,为了避免这种情况,我们使用16位整型来接收数据,也就是int16_t

(三)总结

通过定时器的编码器接口模式学习,我们了解了定时器的另一模式,定时器的学习已经结束,我们通过定时器部分的学习,了解了定时器的四个功能:(1)定时中断;(2)输出比较;(3)输入捕获;(4)编码器接口

  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值