外设模块学习(2)——旋转编码器
简单介绍了旋转编码器的基本原理和控制方式。
一、核心概念
旋转编码器是一种将机械旋转运动转化为电信号的传感器,可输出两路相位差 90° 的脉冲(A 相、B 相),通过判断脉冲顺序实现正反转识别,配合计数可获取旋转角度 / 圈数,部分型号带按键(Z 相)实现按下功能。
其核心作用是将机械旋转量(角度、圈数、方向)转化为可被微控制器识别的电信号,广泛应用于调速旋钮、角度测量、位置控制等场景。

二、工作原理
简单来说,旋转编码器就是通过判断AB相输出的脉冲信号中出现上升沿或下降沿的先后关系来获取编码器正反转情况;然后通过检测编码器输出到端口的边沿数,来计算其旋转的圈数以及角度,从而得到旋转的转速等量。
那首先,我们思考一下既然它是通过输出脉冲来获取一系列参数,那么编码器什么时候开始输出的AB脉冲信号呢?
0 编码器脉信号的产生
实际上,编码器输出 AB 脉冲的时机完全由其机械运动状态决定,即:从编码器的轴开始旋转的瞬间起,就会输出 AB 相脉冲信号;旋转停止时,脉冲输出也会立即停止。
当然,对于不同编码器,其脉冲的产生方式还与其内部构造决定。这里简单介绍光电式与磁电式两类编码器产生脉冲信号的方式:
-
光电式编码器:内部有固定光栅和旋转光栅,当轴旋转时,旋转光栅会遮挡 / 透过光线,使光敏元件接收到的光信号产生明暗变化,从而转化为 AB 相脉冲(旋转即有脉冲,停转即无脉冲)。
-
磁电式编码器:内部有旋转磁极和固定磁敏元件(如霍尔传感器),旋转时磁场变化会使磁敏元件输出电信号的高低变化,形成 AB 相脉冲(同样是 “旋转即输出,停转即停止”)。
也就是说,编码器的 AB 脉冲输出与机械旋转是实时同步的 —— 轴动则脉冲生,轴停则脉冲止,没有 “预热”“延迟启动” 等额外条件,这也是它能精准检测瞬时运动的核心原因。
1 信号特征
编码器会输出 A、B 两路方波,具有以下特征:
-
正转时,A 相超前 B 相 90°(A 相先出现边沿)
-
反转时,B 相超前 A 相 90°(B 相先出现边沿)
-
"超前" 指在时间轴上先出现上升沿或下降沿

2 AB 相的边沿特性
AB 相的边沿特性和输入电平状态,是硬件规定与软件配置共同作用的结果,具体可从 “硬件固有特性” 和 “软件可控范围” 两个层面深入理解:
AB 相的边沿(上升沿 / 下降沿)是编码器硬件本身的输出特性,由其内部机械结构(如光电式的光栅、磁电式的磁极)决定,软件无法直接控制边沿的产生,只能通过配置硬件接口来 “检测” 这些边沿。
2.1 硬件规定了本质
编码器旋转时,A、B 相的脉冲边沿(何时产生上升沿 / 下降沿)是由机械运动直接决定的:
-
例如光电编码器中,光栅盘转动时遮挡 / 透过光线,导致光敏元件输出的电平跳变(产生边沿),这个过程完全由物理运动决定,与软件无关;
-
正转时 A 相超前 B 相 90°、反转时 B 相超前 A 相 90° 的相位关系,也是编码器出厂时就设计好的硬件特性( datasheet 中会明确标注),软件无法改变这个相位差。
2.2 软件的作用——选择
软件虽然不能控制边沿产生,但可以通过配置外部中断(如 STM32 的 EXTI)来选择 “需要检测哪些边沿”:
-
例如配置为 “仅检测 A 相上升沿”(1 倍频)、“检测 A 相的上升沿 + 下降沿”(2 倍频)、“检测 A 相和 B 相的所有 4 个边沿”(4 倍频);
-
这些配置只是告诉 MCU “哪些边沿会触发中断”,而非 “控制编码器产生哪些边沿”。
3 输入到端口的电平
硬件决定基准,软件可配置 “解读方式”
编码器输出的电平高低(高电平是 3.3V 还是 5V,低电平是 0V 还是接近 0V)由硬件决定,但软件可以通过配置 GPIO 的输入模式(上拉 / 下拉)来适应硬件特性,避免信号误判。
3.1 硬件规定的电平范围
编码器的输出电平是其硬件电路决定的:
-
例如 5V 供电的编码器,高电平通常为 4~5V,低电平为 0~0.5V;3.3V 供电的编码器,高电平通常为 2.5~3.3V,低电平为 0~0.5V,具体看 datasheet ;
-
正常工作时,旋转编码器的 A、B 相电平会在高 / 低之间跳变(形成方波),这个跳变的 “高低电平阈值” 是硬件固定的,软件无法修改。
3.2 软件的作用:适应硬件
软件通过配置 GPIO 的上拉 / 下拉电阻,确保在编码器信号 “无跳变” 或 “微弱抖动” 时,MCU 能稳定识别电平:
-
例如编码器输出默认是 “悬空”(未旋转时电平不确定),软件可配置 GPIO 为 “下拉输入”(未触发时默认读低电平)或 “上拉输入”(默认读高电平),避免因信号浮空导致的误判;
-
但软件无法改变 “编码器输出高电平时 MCU 读到高电平、输出低电平时读到低电平” 这个基本对应关系(这是硬件电路的通断逻辑决定的)。
4 正反转判断原理
可通过检测对应端口捕获的 A、B 相的电平变化(上升沿 / 下降沿)及相位关系判断转向:
-
当 A 相出现边沿时,检测 B 相当前电平
-
当 B 相出现边沿时,检测 A 相当前电平
-
根据两相电平的 "相同 / 相反" 关系确定正反转方向
5 相关量计算原理
5.1 关键参数
-
PPR(Pulse Per Revolution):编码器每转一圈,单路输出的脉冲数
-
单圈总计数:PPR × 倍频系数(如 20PPR×4 倍频 = 80)
5.2 旋转量计算
依赖 “脉冲计数” 与 “编码器参数” 的换算:
-
脉冲计数:每检测到一个有效边沿(根据倍频系数,1/2/4 倍频对应不同的边沿数量),计数变量
Encoder_Cnt就 ±1,累计的脉冲数直接反映 “旋转的精细程度”; -
圈数计算:已知编码器每转一圈的总脉冲数(
PPR×倍频系数),用累计计数除以这个值,即可得到旋转圈数(例如 20PPR+4 倍频,每 80 个脉冲对应 1 圈); -
角度计算:将圈数乘以 360°,即可得到旋转的绝对角度(例如 0.5 圈对应 180°)。
5.3 转速计算
基于 “脉冲变化率” 与 “时间” 的关系:转速是 “单位时间内的旋转量”,需结合时间维度计算。
-
记录两个时间点的脉冲数差值
Δcnt和时间差Δt; -
转速(圈 / 秒)=
(Δcnt / 单圈总脉冲数) / Δt; -
也可换算为 “度 / 秒”“转 / 分钟(RPM)” 等单位(如乘以 360 得度 / 秒,乘以 60 得 RPM)。
5.4 公式总结
-
旋转圈数 = 累计计数 ÷ 单圈总计数
-
旋转角度 = (累计计数 ÷ 单圈总计数)× 360°
-
绝对角度 = 旋转角度 % 360°(限制在 0°~360° 范围)
6 倍频原理与精度提升
6.1 编码器的倍频
倍频是通过更精细地检测脉冲边沿来提高计数精度的方法。简单来说,倍频的核心思想是:通过更精细地 “观察” 编码器输出的 AB 相方波信号,在不改变编码器硬件的情况下,将每转一圈能识别到的 “有效位置变化” 次数(即计数脉冲数)增加一倍或四倍。 次数越多,能分辨的最小角度就越小,精度自然就越高。常见模式有:
| 倍频模式 | 检测对象 | 每圈计数值 (200PPR) | 最小分辨率 | 特点 |
|---|---|---|---|---|
| 1 倍频 | A 相或 B 相的一个边沿 | 20 | 18° | 实现简单,精度最低 |
| 2 倍频 | A 相或 B 相的两个边沿 (上升 + 下降) | 40 | 9° | 精度提升 1 倍,实现较简单 |
| 4 倍频 | A 相和 B 相的四个边沿 | 80 | 4.5° | 精度最高,充分利用信号 |
倍频核心原理:通过增加单位旋转角度内的计数次数,减小最小可分辨角度,从而提高精度。例如 4 倍频时,能将 200PPR 编码器的有效分辨率提升至 800 脉冲 / 圈。
下面我们通过一个具体的例子来拆解这个过程。假设我们使用一个 20 线(PPR=20) 的编码器,即它每旋转一圈,A 相和 B 相各自会产生 20 个完整的方波周期。
6.2 三种常见的倍频模式
6.2.1 1 倍频 (仅检测 A 相或 B 相的一个边沿)
这是最基础的计数方式。我们只关注 A 相(或 B 相)的上升沿(或下降沿)。
-
原理:编码器每转一圈,A 相只会产生 20 个上升沿。
-
计数:MCU 每检测到一个 A 相上升沿,计数值 + 1。
-
结果:旋转一圈,总计数值增加 20。
-
最小分辨率:能分辨的最小角度为
360° / 20 = 18°。
6.2.2 2 倍频 (检测 A 相或 B 相的两个边沿)
为了提高精度,我们可以同时检测 A 相(或 B 相)的上升沿和下降沿。
-
原理:一个完整的方波周期包含一个上升沿和一个下降沿。编码器每转一圈,A 相会产生 20 个上升沿和 20 个下降沿,共 40 个边沿。
-
计数:MCU 每检测到 A 相的上升沿或下降沿,计数值 + 1。
-
结果:旋转一圈,总计数值增加 40 (20 × 2)。
-
最小分辨率:能分辨的最小角度为
360° / 40 = 9°。
此时可以发现,我们最小可观察到的角度变化由原来1.8°变成了现在的9°,精度提升了一倍!
6.2.3 4 倍频 (同时检测 A 相和 B 相的所有四个边沿)
这是最高效、精度最高的模式,它同时利用了 A 相和 B 相的信息。
-
原理:由于 A 相和 B 相相差 90°,在一个完整的 A 相方波周期内(或 B 相),A 相和 B 相总共会产生 4 个不同的边沿(A 相上升沿、B 相上升沿、A 相下降沿、B 相下降沿)。
-
计数:我们配置 MCU,让 A 相和 B 相的任何一个边沿(上升沿或下降沿)都能触发中断。每触发一次中断,计数值 + 1。
-
结果:旋转一圈,总计数值增加 80 (20 × 4)。
-
最小分辨率:能分辨的最小角度为
360° / 80 = 4.5°。
此时精度又在 2 倍频的基础上提升了一倍!
6.3 对比总结
| 倍频模式 | 检测对象 | 每圈计数值 (基于 200PPR) | 最小分辨率 (角度) | 优点 | 缺点 |
|---|---|---|---|---|---|
| 1 倍频 | A 相(或 B 相)的一个边沿 | 20 | 18° | 实现最简单,CPU 开销最小 | 精度最低 |
| 2 倍频 | A 相(或 B 相)的两个边沿 | 40 | 9° | 精度比 1 倍频高,实现相对简单 | 精度仍有提升空间 |
| 4 倍频 | A 相和 B 相的所有四个边沿 | 80 | 4.5° | 精度最高,充分利用了编码器信号 | CPU 开销最大,对中断响应速度要求高 |
7 案例实践——旋转编码器控制与计数显示
基于STM32F103C8T6微控制器,实现使用OLED屏幕显示旋转编码器计数值。

7.1 接线方式
| 外设模块 | 引脚连接 (STM32F103C8T6) | 接线细节 |
|---|---|---|
| 旋转编码器 | A相 → PA6 B相 → PA7 GND/VCC → GND/VCC |
A、B相分别连接到PA6和PA7,编码器VCC和GND引脚接GND或VCC。按键(C)未使用。 |
| SSD1306 OLED | SCL → PA0 SDA → PA1 VCC → 3.3V GND → GND |
OLED的I2C时钟和数据线连接到PA0和PA1。务必确保VCC和GND与单片机正确连接。 |
| ST-Link V2 | SWDIO, SWCLK, GND, 3.3V | 严格对应引脚连接,为单片机提供调试和烧录接口。 |
⚠️ 特别注意:
- 所有外设的GND必须与STM32的GND连接在一起(共地)
- OLED屏幕如果使用5V供电,可能会损坏,请确认其工作电压
7.2 部分代码
/*
* @Descripttion: 旋转编码器控制与计数显示
* @Author: JaRyon
* @version:
* @Date: 2025-09-21 11:45:26
*/
// FileName: main.c
#include "includes.h"
// 定义当前值、上一次计数值、变化值
int16_t LastCnt = 0, CurrentCnt = 0, deltaCnt = 0;
// 编码器计数
int16_t Encoder_value = 0; // 计数
double Encoder_angle = 0.0; // 旋转角度
int16_t Encoder_round = 0; // 圈数
int main(void)
{
OLED_Init();
ENCODER_Init();
while (1)
{
CurrentCnt = ENCODER_GetCnt(); // 获取当前计数值
deltaCnt = CurrentCnt - LastCnt; // 计算计数变化值
Encoder_value += deltaCnt; // 更新编码器值
LastCnt = ENCODER_GetCnt();
Encoder_angle = (int16_t)(Encoder_value / 80.0 * 360) % 360;
Encoder_round = Encoder_value / 80;
OLED_ShowString(3, 5, "cnt: ", 8);
OLED_ShowDecNum(40, 5, Encoder_value, 5, 8);
OLED_ShowString(3, 25, "angle: ", 8);
OLED_ShowDecNum(55, 25, Encoder_angle, 3, 8);
OLED_ShowString(3, 45, "round: ", 8);
OLED_ShowDecNum(55, 45, Encoder_round, 2, 8);
OLED_Update();
}
}
7.3 完整代码获取
点击下面链接即可查看完整工程:
8、Keil MDK 特别配置注意事项
使用 OLED 相关代码时,需在 Keil MDK 中进行如下配置,否则可能编译报错:在 Keil MDK 的 Options for Target 窗口中,进入 C/C++ 选项卡,在 Misc Controls 中添加字符 --no-multibyte-chars。
笔者小白,能力有限,以上内容难免存在不足和纰漏,仅供参考,各位阅读时请带着批判性思维学习,遇到问题多查查。同时欢迎各位评论区批评指正。谢谢。
更多推荐



所有评论(0)