差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
rotary_encoder [2022/02/05 13:13] gongyusu |
rotary_encoder [2022/04/26 13:05] (当前版本) gongyusu [5. 用Verilog控制] |
||
---|---|---|---|
行 1: | 行 1: | ||
- | [[verilog_rotary_encoder|基于FPGA的旋转编码器控制]] | + | ## Rotary Encoder - 旋转编码器 |
+ | 旋转编码器是一种位置传感器,它可以根据旋转运动生成的模拟或数字电信号来确定旋转轴的角位置。我们常用的旋转编码器是增量式编码器,是用来测量旋转的最简单的位置传感器。 | ||
- | ## 基于STEP FPGA的旋转编码器电路驱动 | + | {{ :rotarty-encoder-v2.jpg |}} |
- | 本节将和大家一起使用FPGA驱动底板上的EC11的旋转编码器的原理及驱动方法。 | ||
- | --- | + | ### 1. 工作原理 |
- | ### 硬件说明 | + | {{ :incremental_directional_encoder.gif |}}<WRAP centeralign>增量旋转编码器的工作示意</WRAP> |
- | 旋转编码器是用来测量转速的装置,因其人性化的操作被用于越来越多的电子设备中,旋转编码器有多种分类: | + | |
- | * 以编码器工作原理可分为:光电式、磁电式和触点电刷式。 | + | {{ :rotary-encoder-waveform-v2.jpg |}}<WRAP centeralign>旋转编码器的输出信号波形</WRAP> |
- | * 以码盘刻孔方式不同分为:增量式和绝对式两类。 | + | |
- | 关于以上各类编码器的区别,大家自行查阅资料,这里就不多做介绍了。 | + | {{ :contact-noise-v2.jpg |}}<WRAP centeralign>旋转编码器由于抖动导致的电信号噪声</WRAP> |
- | \\ | + | |
- | 我们[[STEP-BaseBoard]]底板上集成的EC11的旋转编码器就属于增量式触电电刷编码器,其工作原理如下: | + | |
- | \\ | + | |
- | {{ :增量式触电点刷编码器.jpg?400 |}} | + | |
- | \\ | + | |
- | 如上图所示,当顺时针旋转时A信号提前B信号90度相位,当逆时针旋转时B信号提前A信号90度相位,FPGA接收到旋转编码器的A、B信号时,可以根据A、B的状态组合判定编码器的旋转方向。 | + | |
- | \\ | + | |
- | 程序设计中我们可以对A、B信号检测,检测A信号的边沿及B信号的状态, | + | |
- | * 当A信号上升沿时B信号为低电平,或当A信号下降沿时B信号为高电平,证明当前编码器为顺时针转动 | + | |
- | * 当A信号上升沿时B信号为高电平,或当A信号下降沿时B信号为低电平,证明当前编码器为逆时针转动 | + | |
- | 本设计实际电路连接如下: | + | ### 2. 电路连接 |
- | \\ | + | |
- | {{ :旋转编码器硬件连接.jpg?800 |}} | + | |
- | \\ | + | |
- | --- | + | {{ ::rotary_encoder_symbol.png |}}<WRAP centeralign>KiCad中旋转编码器的原理图符号</WRAP> |
- | ### Verilog代码 | + | {{ ::rotary_encoder_fp.png |}}<WRAP centeralign>KiCad中旋转编码器的PCB封装</WRAP> |
+ | {{ ::rotary_encoder_3d.png |}}<WRAP centeralign>KiCad中旋转编码器的PCB 3D效果图</WRAP> | ||
- | <code verilog> | + | {{ :rotary_encoder_schematic.png |}}<WRAP centeralign>用一个旋转编码器和2个按键构成的输入控制系统原理图</WRAP> |
- | // -------------------------------------------------------------------- | + | |
- | // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< | + | |
- | // -------------------------------------------------------------------- | + | |
- | // Module: Encoder | + | |
- | // | + | |
- | // Author: Step | + | |
- | // | + | |
- | // Description: Driver for rotary encoder | + | |
- | // | + | |
- | // Web: www.stepfapga.com | + | |
- | // | + | |
- | // -------------------------------------------------------------------- | + | |
- | // Code Revision History : | + | |
- | // -------------------------------------------------------------------- | + | |
- | // Version: |Mod. Date: |Changes Made: | + | |
- | // V1.0 |2016/04/20 |Initial ver | + | |
- | // -------------------------------------------------------------------- | + | |
- | module Encoder | + | |
- | ( | + | |
- | input clk_in, //系统时钟 | + | |
- | input rst_n_in, //系统复位,低有效 | + | |
- | input key_a, //旋转编码器A管脚 | + | |
- | input key_b, //旋转编码器B管脚 | + | |
- | input key_ok, //旋转编码器D管脚 | + | |
- | output reg Left_pulse, //左旋转脉冲输出 | + | |
- | output reg Right_pulse, //右旋转脉冲输出 | + | |
- | output OK_pulse //按动脉冲输出 | + | |
- | ); | + | |
- | + | ||
- | localparam NUM_500US = 6_000; | + | |
- | reg [12:0] cnt; | + | ### 3. 用MicroPython控制 |
- | //计数器周期为500us,控制键值采样频率 | + | * [[mp_rotary_encoder|用MicroPython驱动旋转编码器]] |
- | always@(posedge clk_in or negedge rst_n_in) begin | + | |
- | if(!rst_n_in) cnt <= 0; | + | |
- | else if(cnt >= NUM_500US-1) cnt <= 1'b0; | + | |
- | else cnt <= cnt + 1'b1; | + | |
- | end | + | |
- | + | ||
- | reg [5:0] cnt_20ms; | + | |
- | reg key_a_r,key_a_r1; | + | |
- | reg key_b_r,key_b_r1; | + | |
- | reg key_ok_r; | + | |
- | //针对A、B、D管脚分别做简单去抖操作, | + | ### 4. 用Arduino控制 |
- | //如果对旋转编码器的要求比较高,建议现对旋转编码器的输出做严格的消抖处理后再来做旋转编码器的驱动 | + | * [[arduino_rotary_encoder|用Arduino控制旋转编码器]] |
- | //对旋转编码器的输入缓存,消除亚稳态同时延时锁存 | + | |
- | always@(posedge clk_in or negedge rst_n_in) begin | + | |
- | if(!rst_n_in) begin | + | |
- | key_a_r <= 1'b1; | + | |
- | key_a_r1 <= 1'b1; | + | |
- | key_b_r <= 1'b1; | + | |
- | key_b_r1 <= 1'b1; | + | |
- | cnt_20ms <= 1'b1; | + | |
- | key_ok_r <= 1'b1; | + | |
- | end else if(cnt == NUM_500US-1) begin | + | |
- | key_a_r <= key_a; | + | |
- | key_a_r1 <= key_a_r; | + | |
- | key_b_r <= key_b; | + | |
- | key_b_r1 <= key_b_r; | + | |
- | if(cnt_20ms >= 6'd40) begin //对于按键D信号还是采用20ms周期采样的方法,40*500us = 20ms | + | |
- | cnt_20ms <= 6'd0; | + | |
- | key_ok_r <= key_ok; | + | |
- | end else begin | + | |
- | cnt_20ms <= cnt_20ms + 1'b1; | + | |
- | key_ok_r <= key_ok_r; | + | |
- | end | + | |
- | end | + | |
- | end | + | |
- | reg key_ok_r1; | + | ### 5. 用Verilog控制 |
- | //对按键D信号进行延时锁存 | + | 参见[[fpga_quad_decoder|用FPGA做正交解码]] |
- | always@(posedge clk_in or negedge rst_n_in) begin | + | - [[verilog_rotary_encoder|基于STEP FPGA的旋转编码器电路驱动]] |
- | if(!rst_n_in) key_ok_r1 <= 1'b1; | + | - [[旋转调节系统设计|基于旋转编码器的调节系统设计]] |
- | else key_ok_r1 <= key_ok_r; | + | |
- | end | + | |
- | wire A_state = key_a_r1 && key_a_r && key_a; //旋转编码器A信号高电平状态检测 | + | ### 6. 参考技术文章 |
- | wire B_state = key_b_r1 && key_b_r && key_b; //旋转编码器B信号高电平状态检测 | + | * [[https://www.allaboutcircuits.com/projects/how-to-use-a-rotary-encoder-in-a-mcu-based-project/|How to Use a Rotary Encoder in an MCU-Based Project]] |
- | assign OK_pulse = key_ok_r1 && (!key_ok_r); //旋转编码器D信号下降沿检测 | + | * [[https://microcontrollerslab.com/rotary-encoder-module-interfacing-pic/|Rotary Encoder Module interfacing with pic16f877a microcontroller]] |
- | + | * [[https://www.electronicshub.org/position-sensors/|Position Sensors - Types, LVDT, Rotary Encoder]] | |
- | reg A_state_reg; | + | |
- | //延时锁存 | + | |
- | always@(posedge clk_in or negedge rst_n_in) begin | + | |
- | if(!rst_n_in) A_state_reg <= 1'b1; | + | |
- | else A_state_reg <= A_state; | + | |
- | end | + | |
- | + | ||
- | //旋转编码器A信号的上升沿和下降沿检测 | + | |
- | wire A_pos = (!A_state_reg) && A_state; | + | |
- | wire A_neg = A_state_reg && (!A_state); | + | |
- | + | ||
- | //通过旋转编码器A信号的边沿和B信号的电平状态的组合判断旋转编码器的操作,并输出对应的脉冲信号 | + | |
- | always@(posedge clk_in or negedge rst_n_in)begin | + | |
- | if(!rst_n_in)begin | + | |
- | Right_pulse <= 1'b0; | + | |
- | Left_pulse <= 1'b0; | + | |
- | end else begin | + | |
- | if(A_pos && B_state) Left_pulse <= 1'b1; | + | |
- | else if(A_neg && B_state) Right_pulse <= 1'b1; | + | |
- | else begin | + | |
- | Right_pulse <= 1'b0; | + | |
- | Left_pulse <= 1'b0; | + | |
- | end | + | |
- | end | + | |
- | end | + | |
- | + | ||
- | endmodule | + | |
- | + | ||
- | </code> | + | |
- | \\ | + | |
- | + | ||
- | --- | + | |
- | ### 小结 | + | |
- | 本节主要为大家讲解了旋转编码器的工作原理及软件设计,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。 | + | |
- | \\ | + | |
- | 如果你对Diamond软件的使用不了解,请参考这里:[[lattice_diamond的使用|Diamond的使用]]。 | + | |
- | + | ||
- | --- | + | |
- | ### 相关资料 | + | |
- | \\ | + | |
- | 使用[[STEP-MXO2第二代]]的旋转编码器应用程序: 后续会有下载连接 待更新 | + | |
- | \\ | + | |
- | 使用[[STEP-MAX10]]的旋转编码器应用程序: 后续会有下载连接 待更新 | + | |
- | \\ | + |