1. 项目概述
在嵌入式系统开发中,编码器作为重要的位置和速度检测传感器,广泛应用于电机控制、机器人导航等领域。本文将详细介绍如何在龙芯2K0300开发板上实现正交编码器的驱动移植,包括硬件连接、寄存器配置、驱动开发以及应用层测试的全过程。
2. 硬件选型与工作原理
2.1 编码器选型
我们选用龙邱科技的LQ_1024线方向mini编码器,这款编码器具有以下特点:
- 分辨率:A/B相正交输出1024线
- 最高转速:10000rpm
- 工作温度范围:-40℃ ~ +125℃
- 霍尔检测技术,无接触式测量
- 紧凑尺寸:直径14mm,高度18mm,轴径3mm
2.2 编码器工作原理
2.2.1 基本工作原理
编码器的"线数"指编码器旋转一圈输出的脉冲数量。1024线编码器意味着旋转一圈会在A/B相各输出1024个脉冲,两相信号存在90°相位差。
与传统编码器不同,我们选用的型号额外提供了方向(Dir)输出引脚,这带来两个优势:
- 转速测量:通过统计A相脉冲数量,结合时间间隔可计算转速
- 方向判断:直接读取Dir引脚电平状态即可确定旋转方向,无需通过A/B相信号的相位关系判断
2.2.2 转速计算公式
转速计算公式如下:
n = (S × 60) / (N × T)
其中:
- n:转速(rpm)
- S:时间T内统计到的有效脉冲数
- N:编码器每转脉冲数(本例为1024)
- T:采样时间(s)
3. 硬件连接设计
3.1 引脚定义与连接
编码器引出6个引脚,实际使用中我们主要连接以下引脚:
- GND:必须可靠接地
- 3.3~5V:供电引脚
- A相:脉冲输出
- Dir:方向输出
- B相:本方案未使用
- NC:悬空
3.2 开发板接口分配
3.2.1 左电机编码器连接
| 编码器引脚 | 功能 | 连接的龙芯GPIO |
|---|---|---|
| PIN1 | GND | GND |
| PIN2 | 3.3V供电 | 3.3V |
| PIN3 | A相输出 | GPIO67(SPI2_CS) |
| PIN4 | Dir输出 | GPIO72(CAN2_RX) |
| PIN5 | B相输出 | 未连接 |
| PIN6 | NC | 未连接 |
3.2.2 右电机编码器连接
| 编码器引脚 | 功能 | 连接的龙芯GPIO |
|---|---|---|
| PIN1 | GND | GND |
| PIN2 | 3.3V供电 | 3.3V |
| PIN3 | A相输出 | GPIO64(SPI2_CLK) |
| PIN4 | Dir输出 | GPIO73(CAN2_TX) |
| PIN5 | B相输出 | 未连接 |
| PIN6 | NC | 未连接 |
注意:GPIO64和GPIO67可复用为PWM功能,这是实现编码器测量的关键。
4. PWM控制器配置
4.1 PWM寄存器映射
龙芯2K0300的PWM控制器寄存器地址空间如下:
- 0x1611b000: PWM0
- 0x1611b010: PWM1
- 0x1611b020: PWM2
- 0x1611b030: PWM3
每路PWM控制器占用16B配置空间,包含5个关键寄存器:
- low_buffer: 低脉冲缓冲寄存器(Base+0x4)
- full_buffer: 脉冲周期缓冲寄存器(Base+0x8)
- CTRL: 控制寄存器(Base+0xC)
- Low_level: 低电平时间计数器(硬件内部)
- full_pulse: 完整周期计数器(硬件内部)
4.2 脉冲测量原理
PWM控制器的脉冲测量过程完全由硬件自动完成:
- 初始化:配置控制寄存器后,计数器开始工作
- 下降沿触发:
- 将full_pulse值存入full_buffer
- 重置Low_level和full_pulse计数器
- 低电平期间:两个计数器同步递增
- 上升沿触发:
- 将Low_level值存入low_buffer
- 重置Low_level计数器
- 下一个下降沿:重复上述过程
测量结果:
- low_buffer: 低电平持续时间(时钟周期数)
- full_buffer: 完整脉冲周期(时钟周期数)
- 高电平时间 = full_buffer - low_buffer
4.3 时钟配置
龙芯2K0300的PWM控制器时钟来自dev_pllclk,默认频率200MHz。可通过以下命令查看时钟树:
bash复制cat /sys/kernel/debug/clk/clk_summary
关键时钟路径:
- ref_clk(120MHz) → ddr_pll_clk → dev_pllclk(200MHz) → apb_clk → PWM控制器
5. 驱动开发实现
5.1 驱动框架设计
编码器驱动采用标准的Linux字符设备框架,主要功能包括:
- 设备树解析:获取寄存器地址、GPIO、PPR等参数
- 寄存器映射:将PWM控制器寄存器映射到内核空间
- 方向GPIO配置:设置为输入模式
- PWM控制器初始化:配置为编码器模式
- 提供用户接口:通过ioctl获取转速和方向信息
5.2 关键数据结构
c复制struct encoder_counts {
long long count; // 转速(RPM)
int direction; // 方向(1:正转, -1:反转)
unsigned int raw_count; // 原始计数值
};
struct encoder_info {
int ppr; // 每转脉冲数
unsigned long clk_freq; // 时钟频率
unsigned int max_count; // 最大计数值
};
struct encoder_device {
void __iomem *base; // 寄存器基地址
int dir_gpio; // 方向GPIO
int ppr; // 每转脉冲数
unsigned long clk_freq; // 时钟频率
struct miscdevice miscdev;
struct device *dev;
};
5.3 转速计算实现
c复制static long long encoder_calc_rpm(struct encoder_device *enc, u32 raw_count)
{
unsigned long long temp;
if (unlikely(raw_count == 0 || raw_count > OVERFLOW_THRESHOLD)) {
dev_warn_ratelimited(enc->dev, "Invalid raw_count: %u\n", raw_count);
return 0;
}
temp = 60ULL * enc->clk_freq;
do_div(temp, raw_count);
do_div(temp, enc->ppr);
return (long long)temp;
}
5.4 IOCTL接口设计
驱动提供以下ioctl命令:
- ENCODER_GET_COUNT:获取当前转速和方向
- ENCODER_GET_INFO:获取编码器参数信息
- ENCODER_RESET_COUNT:重置计数器
6. 设备树配置
6.1 左编码器节点
dts复制encoder_left {
compatible = "pulse-dir-encoder";
label = "left";
pinctrl-names = "default";
pinctrl-0 = <&pwm3_mux_m0>;
dir-gpios = <&gpio 72 GPIO_ACTIVE_HIGH>;
reg = <0 0x1611b030 0 0x10>;
rotary-encoder,steps-per-period = <1024>;
};
6.2 右编码器节点
dts复制encoder_right {
compatible = "pulse-dir-encoder";
label = "right";
pinctrl-names = "default";
pinctrl-0 = <&pwm0_mux_m0>;
dir-gpios = <&gpio 73 GPIO_ACTIVE_HIGH>;
reg = <0 0x1611b000 0 0x10>;
rotary-encoder,steps-per-period = <1024>;
};
7. 应用层测试程序
7.1 程序功能
测试程序提供以下功能:
- 实时显示转速和方向
- 查看编码器信息
- 重置计数器
- 可配置采样间隔和采样次数
7.2 关键代码片段
c复制while (max_samples < 0 || sample_count < max_samples) {
if (ioctl(fd, ENCODER_GET_COUNT, &cnt) < 0) {
perror("ioctl GET_COUNT");
break;
}
long long delta = cnt.count - last_count;
last_count = cnt.count;
printf("%-10d %-10lld %-10d %-10u %-10lld\n",
sample_count++, cnt.count, cnt.direction,
cnt.raw_count, delta);
usleep(sample_ms * 1000);
}
8. 实际测试与问题排查
8.1 常见问题
-
无信号输出:
- 检查供电是否正常
- 确认编码器与开发板接地良好
- 验证编码器是否正常旋转
-
方向检测错误:
- 检查Dir引脚连接是否正确
- 确认GPIO输入配置正确
- 可能需要调整GPIO_ACTIVE_HIGH/LOW设置
-
转速计算异常:
- 确认PPR参数设置正确
- 检查时钟频率配置
- 验证寄存器读取是否正确
8.2 性能优化建议
-
对于高速应用,可以:
- 减小采样间隔
- 使用中断代替轮询
- 优化转速计算算法
-
提高测量精度:
- 使用更高分辨率的编码器
- 提高系统时钟频率
- 采用滤波算法消除抖动
9. 扩展应用
本驱动框架可轻松扩展到其他类型的编码器,只需调整以下参数:
- PPR值:适配不同分辨率的编码器
- 时钟频率:支持不同速度范围的测量
- 方向检测方式:可改为通过A/B相信号相位差判断方向
此外,该驱动可与电机控制驱动结合,实现闭环控制系统,提高运动控制精度。