前言
雨打灯难灭,风吹色更明。 若飞上天空,定制月边星——李白的《咏萤火虫》
一、介绍旋转编码器
旋转编码器是一种可以左右旋转,也可以按下,也可以按下旋转设备,通过左右旋转对应不同开关的内部,同时也可以旋转,旋转编码器可以实现非常复杂的功能,简单的左右旋转可以调整音量、亮、暗功能,按钮可以发挥普通按钮的作用,同时左右旋转可以区分普通旋转按钮,因此,旋转编码器可以同时调整音量和亮度(例如),不同的功能也可以通过不同的速度实现。综上所述,它的功能非常复杂和有用。
旋转编码器用于测量转速和配合
PWM
该技术可以实现快速调速装置。光电旋转编码器可以通过光电转换将输出轴的角位移、角速度等机械量转换为数字输出的相应电脉冲(REP)
。
- 电压输出、集电极开路输出、推拉互补输出和长期驱动输出。
有轴型
:轴型可分为夹紧法兰型、同步法兰型和伺服安装型。轴套型
:轴套型可分为半空型、全空型和大口径型。 光电、磁电和触点刷。 编码器可分为增量式和绝对式。
旋转编码器的原理和特点
-
原理:
- 旋转编码器是集光机电技术于一体的速度位移传感器。当旋转编码器轴驱动光栅盘旋转时,发光元件发出的光被光栅盘狭缝切割成间歇性光,接收元件接收产生初始信号。该信号输出脉冲或代码信号。
- 旋转编码器由一个中心有轴的光电码盘组成,由四组正弦波信号组合而成A、B、C、D,每个正弦波相差90度C、D反向信号,叠加A、B在两相上,可以增强稳定信号;另外,每转输出一个Z相脉冲,代表零参考位。因为A、B两个相差90度,可以通过比较A或B相来判断编码器的正反转,通过零位脉冲可以获得编码器的零位参考位。
-
特点:
体积小、重量轻、品种多、功能齐全、频响高、分辨率高、扭矩小、能耗低、性能稳定、使用寿命长。
1.增量编码器
它是将位移转换为周期性电信号,然后将电信号转换为计数脉冲,用脉冲数表示位移的大小。增量编码器,又称正交编码器,通过两条信号线的脉冲输出进行数据处理。输出脉冲对应于增量位移。每次编码器旋转一定位移,都会产生脉冲信号。,达到的效果
(v = s / t)
,通过 计算距离的效果的效果(s = n * d)
。
-
工作原理:
增量旋转编码器通过两个光敏接收管转换角度码盘的时间顺序和相位关系,以增加(正方向)或减少角度码盘的角位移(负方向)。 - 上图A、B两点之间的距离是S2,A、B表示两个相同的光敏接收管,下角码盘的光栅间距分别为S0(凹槽)和S1(凸起)。
- 当角度码盘匀速旋转时,输出波形图中可以知道S0:S1:S2比值和实际图S0:S1:S2比值相同,同理,当角度码盘变速转动时,输出波形图中的S0:S1:S2比值和实际图S0:S1:S2比值仍然相同。
顺时针运动 | 逆时针运动 |
---|---|
A B | A B |
1 1 | 1 1 |
0 1 | 1 0 |
0 0 | 0 0 |
1 0 | 0 1 |
-
我们把现在的A、B保存输出值和下一个到来A、B通过比较输出值,可以得码盘旋转的方向;
-
如果光栅格S0等于S1时,也就是S0和S弧度夹角相同,而且S2等于S0的1/2,这个角度码盘的运动位移角度可以得到S0弧度夹角的1/2,除以所需时间,得到角码盘运动位移的角速。
-
S0等于S1时,且S2等于S如果0的1/2,1/4的运动周期可以得到运动方向和位移角度S0不等于S1,S2不等于S0的1/2,需要一个运动周期才能得到运动方向和位移角度。
-
实际使用的增量编码器输出三组方波脉冲A、B和Z(有的叫C相)相。A、B两组脉冲相位差90o,可以判断旋转方向和速度。Z相脉冲也称为零位脉冲(有时也称为索引脉冲),每周输出一个脉冲,Z相脉冲代表零位参考位,编码器的零位参考位可通过零位脉冲获得,专门用于基准点定位,如下图所示:
-
当编码器转轴旋转时,有相应的脉冲输出,其计数起点可任意设置,可实现多圈无限累积和测量。编码器轴旋转一圈将输出固定的脉冲数。脉冲数由编码器代码盘上光栅的线数决定。编码器称为分辨率,也称为分析分度,或分析分度,通常在每转5~当需要提高分辨率时,可以使用90度相位差A、B两个信号倍频或更换高分辨率编码器。
-
增量编码器的精度取决于机电因素,包括光栅分度误差、光盘偏心、轴承偏心、电子读数装置引入的误差和光学部件的不准确性。
-
编码器的信号输出包括正弦波(电流或电压)和方波(TTL、HTL)等多种形式。而且可以用差分驱动,包含对称A /A-、B /B-、Z /Z-三相信号,由于对称负信号的连接,电流对电缆的电磁场为0,信号稳定衰减最小,抗干扰最好,传输距离较远,如:TTL对称负信号输出的编码器,信号传输距离可达150米。对于HTL对称负信号输出的编码器,信号传输距离可达300米。
-
当增量编码器轴旋转时,有相应的相位输出。在后判向电路和计数器的帮助下,需要确定其旋转方向和脉冲数量的增减。可任意设置计数起点,实现多圈无限累积和测量。每转发一个脉冲Z信号也可以作为参考机械零位。当脉冲固定,需要提高分辨率时,可以使用90度相位差A,B原脉冲数的两个信号倍频。
-
编码器时序:
二、引脚配置
我使用的旋转编码器有五个引脚,可能还有其他不同类型的引脚, 这五个引脚分别为GND, VCC( ), SW, DT, CLK
,具体的引脚已经在简介的图中标明了。
VCC
:接电源正极3.3~5V
;GND
:接地;SW
:PA7(TIM3_CH2)
DT
:PA6(TIM3_CH1)
CLK
:PA5
旋转编码器的接口 | STM32的IO口 | 设置的工作模式 |
---|---|---|
VCC | VCC(3.3V) | - |
GND | GND | - |
SW(Switch:开关) | PA7 | 定时器编码模式 |
DT(DT:数据) | PA6 | 定时器编码模式 |
CLK(CLK:时钟) | PA5 | GPIO_Mode_IPU(上拉输入模式) |
- | PA9 | TX(USART1 串口1通信) |
- | PA10 | RX(USART1 串口1通信) |
三、新建工程
1.打开STM32CubeMX软件,点击“新建工程”
2. 选择 MCU 和封装
3.配置时钟
博客网站-RCC学习
4.配置调试模式
5.串口(USART1)配置
6.定时器(TIM)配置
7.生成代码
输入项目名称和路径。 选择应用的IDE
,开发环境MDK-ARM V5
- 所有初始化代码都生成在
main.c
- 初始化代码生成在对应的外设文件。 如
GPIO
初始化代码生成在gpio.c
中。
8.构建工程
芯片进行选择:
四、编写代码
在main.c
文件中,添加一下代码:
- 重写
fget
和fput
函数:,添加头文件<stdio.h>
;
/* USER CODE BEGIN Includes */
#include<stdio.h>
/* USER CODE END Includes */
/**
* 函数功能: 重定向c库函数printf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/**
* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
#include "encoder.h"
在 encoder.c
中添加代码:
#include "encoder.h" uint8_t lock; //
旋钮锁死标志(1表示锁死) uint16_t count; //计数标志 uint8_t ENCODER_READ(void) { uint8_t key = 0; //存放按键的值 uint8_t level; //记录按钮另一端的电平值 if(HAL_GPIO_ReadPin(encoder_port_A, encoder_right) && HAL_GPIO_ReadPin(encoder_port_A, encoder_left)) //读取此时 { lock = 0; //判断旋钮是否锁死 } if(!HAL_GPIO_ReadPin(encoder_port_A, encoder_right) && lock == 0) //判断是否旋转按钮,同时判断是否有按钮锁死 { HAL_Delay(100); level = HAL_GPIO_ReadPin(encoder_port_A,encoder_left); //把旋钮另一端电平状态记录 HAL_Delay(13); //延时 if(!HAL_GPIO_ReadPin(encoder_port_A, encoder_right)) //去抖 { if(level == 0) { key = 1; //右转 } else { key = 2; //左转 } count = 0; //初始锁死判断计数器 while(!HAL_GPIO_ReadPin(encoder_port_A, encoder_right) && count < 60000) //等待放开旋钮,同时累加判断锁死 { count++; lock = 1; HAL_Delay(200); } } } if(!HAL_GPIO_ReadPin(encoder_port_A,encoder_down) && lock == 0) { HAL_Delay(20); if(!HAL_GPIO_ReadPin(encoder_port_A,encoder_down)) //消抖 { key=3; } } return key; }
在 encoder.h
中添加代码:
#ifndef _ENCODER_H_
#define _ENCODER_H_
#include "main.h"
#include "tim.h"
#define encoder_port_A GPIOA
#define encoder_left GPIO_PIN_6 //定义IO接口,DT, 旋钮左转
#define encoder_right GPIO_PIN_5 //定义IO接口,CLK,旋钮右转
#define encoder_down GPIO_PIN_7 //定义IO接口,SW, 旋钮按下
uint8_t ENCODER_READ(void); //接口读取值
#endif
在主函数 main.c
中添加代码:
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
int b;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("encoder is ready:\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
b = ENCODER_READ(); //读出旋转器编码器值
HAL_Delay(1000);
if(b==1)
{
printf("编码器右转\r\n");
}
if(b==2)
{
printf("编码器左转\r\n");
}
if(b==3)
{
printf("编码器按下\r\n");
}
}
/* USER CODE END 3 */
}