一、编码器的介绍
编码器拆解视频
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();//设置为下降沿捕获,等待下一次下降沿的到来
}
}
}
}