【元器件使用】旋转编码器(STM32PWM输入实验)

一、编码器的介绍

编码器拆解视频
ECC11旋转编码器介绍
51的编程以及消抖(没完全消)

二、简单玩一玩

1.简单理解一下:

在这里插入图片描述
VCC和GND基本上都知道了
然后SW就是按钮,详细的看拆解视频,按下接通GND,为低电平。
CLK和DT说明:

//CLK和DT实际上并没有明确定义什么意思,别一拿到就想是IIC的sck个sda,这不是那个!!!

SCK和DT更像是通道A和通道B。
你旋转的话,涉及到了谁先转向低电平的问题。

比如我通道A(图中ch1,蓝色的那个)接CLK,通道2(CH2,黄色的那个)接DT,图拍的不好,看视频好一点,左右转时的电平变化情况:
左转:
在这里插入图片描述
在这里插入图片描述

右转:在这里插入图片描述

在这里插入图片描述

2.结论:

触发方式为下拉触发,也就是没事时为高电平,旋转时为低电平。
左转时CLK先下降,DT才下降。
右转时DT先下降,CLK才下降。

根据这个特性,我们就可以判断左右方向了,并且可以根据脉冲计数了。

3.arduino的米思齐编程:

在这里插入图片描述

#include <Encoder.h>
Encoder encoder_1(4,3);
void setup(){Serial.begin(9600);}
void loop(){Serial.println(encoder_1.read());}

可以在串口看到脉冲数据的加减。

三、STM32PWM输入实验

1.资料

正交解码类型编码器的原理和使用
在这里插入图片描述
Hal库驱动教程
野火编码器使用(大概看看就好,想控制电机可以深入)

2.外部中断解码

STM32检测编码器正方转(外部中断)
代码及其思路来源
在这里插入图片描述
主要代码:

#include "stdio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

int fputc(int ch, FILE *f){
HAL_UART_Transmit (&huart1,(uint8_t *)&ch,1,0xffff);
	return ch;
}

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
int FangXiang=0;
long  BMQ_num=0;


*/
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)  //外部中断 回调函数
{
/*
	if(GPIO_Pin == CLK_Pin) //检测到有变化就进来处理
	{
		if(HAL_GPIO_ReadPin(CLK_GPIO_Port,CLK_Pin) == HAL_GPIO_ReadPin(DT_GPIO_Port,DT_Pin))  //clk pb0 == dt pb1
		{FangXiang=1;		//	表示 正转
		  printf("\n\r***正转***\n\r");}
		else
	{	FangXiang=0;		//	表示 反转
		printf("\n\r***反转***\n\r");}
	}
	*/
	if(GPIO_Pin == CLK_Pin) //检测到CLK有变化就进来处理
	{	
		//判断DT的高低电平
		if(HAL_GPIO_ReadPin(GPIOC,DT_Pin)==GPIO_PIN_SET){
		BMQ_num++;
		FangXiang=1;
		}		
		if(HAL_GPIO_ReadPin(GPIOC,DT_Pin)==GPIO_PIN_RESET){
		BMQ_num--;
		FangXiang=0;
		}
		printf("num=%ld  FangXiang=%d \r\n",BMQ_num,FangXiang);
	}
}

其代码思路很简单,先不管DT,先看CLK,如果CLK为低电平,再去判断DT,DT为高,证明DT还没触发,所以是正转,CLK和DT都为低,证明DT已经触发过了,为反转!

实验效果:
在这里插入图片描述
总结:

使用外部中断这样子实现很简单,有是有效果,但是始终会有抖动,得想想办法消抖。

消抖

方法一

ENCODER.c

#include "ENCODER.h"

/*TIM2初始化为编码器接口*/
void Encoder_Init_TIM4(u16 arr,u16 psc)
{
	GPIO_InitTypeDef GPIO_InitStructure; //定义一个引脚初始化的结构体  
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定义一个定时器初始化的结构体
  TIM_ICInitTypeDef TIM_ICInitStructure; //定义一个定时器编码器模式初始化的结构体
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //使能TIM4时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能CPIOB时钟
 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;	//PB6、PB7
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);	//根据GPIO_InitStructure的参数初始化GPIOB0

	TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值
	TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频器 
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //选择时钟分频:不分频
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct的参数初始化定时器TIM4
	
	
	/*开起编码器模式*/
	TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3:CH1、CH2同时计数,四分频
	TIM_ICStructInit(&TIM_ICInitStructure); //把TIM_ICInitStruct 中的每一个参数按缺省值填入
	TIM_ICInitStructure.TIM_ICFilter = 10;  //设置滤波器长度
	TIM_ICInit(TIM4, &TIM_ICInitStructure); //根TIM_ICInitStructure参数初始化定时器TIM4编码器模式

	TIM_Cmd(TIM4, ENABLE); //使能定时器4
}

//读取编码器计数
int Read_Encoder_TIM4(void)
{
	int Encoder_TIM;
	Encoder_TIM=TIM4->CNT; //读取计数
	if(Encoder_TIM>0xefff)Encoder_TIM=Encoder_TIM-0xffff; //转化计数值为有方向的值,大于0正转,小于0反转。
	                                                      //TIM4->CNT范围为0-0xffff,初值为0。
	//TIM4->CNT=0; //读取完后计数清零
	return Encoder_TIM/4; //返回值
}

ENCODER.h

#ifndef __TIMER_H
#define __TIMER_H	
#include "sys.h"
#include "stm32f10x_tim.h"

void Encoder_Init_TIM4(u16 arr,u16 psc);
int Read_Encoder_TIM4(void);

#endif

main.c

#include "ENCODER.h"
#include "usart.h"   				
#include "delay.h"

int main(void)
{
	delay_init();
	uart_init(9600);
	Encoder_Init_TIM4(0xffff,0);
  while(1)
	{		 
		delay_ms(200); //每隔200ms读取一次编码器计数,即速度。
		               //可以使用定时中断实现更精准的速度计算,用户可自定义
    printf("Encoder=%d\r\n", Read_Encoder_TIM4());
	}
}

方法二:

(外部中断)

/*
__    __    __
  |__|  |__|    DT
 __    __    __
_  |__|  |__|   SLK
 
 


*/
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)  //外部中断 回调函数
{
	if(GPIO_Pin ==CLK_Pin)
	{
		if(R_CLK ==0){
			DT_jilu=HAL_GPIO_ReadPin(GPIOC,DT_Pin);
			HAL_Delay(1);
			if(R_CLK ==0)
			{
				if(DT_jilu==1)
				{
					BMQ=1;

				}
				else{
					BMQ=0;

				}
			MX_GPIO_Init_RISING();//设置为上升沿捕获,等待下一次上升沿的到来
			}
		}
		
		if(R_CLK ==1){
			DT_jilu=HAL_GPIO_ReadPin(GPIOC,DT_Pin);
			HAL_Delay(1);
			if(R_CLK ==1){
				if(DT_jilu==0	&&	BMQ==1)
				{
					BMQ_num++;
						BBQ=1;
				}
				if(DT_jilu==1	&&	BMQ==0)
				{
					BMQ_num--;
						BBQ=0;

				}
			MX_GPIO_Init_FALLING();//设置为下降沿捕获,等待下一次下降沿的到来
			}
		}
	}
}

  • 5
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

创客阿蛋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值