距离上次更新本文已经过去了 694 天,文章部分内容可能已经过时,请注意甄别

本次实验还是需要用到 PCF8591 模数转换器,莫非它要取代双色 LED 成为新的常驻嘉宾吗?

QQ图片20220424132543

本次实验是摇杆实验。这个玩意可以用于操控机器人或者是树莓派的遥控小车。当然,生活中最常见的用途还是在游戏手柄上。不知道你打不打游戏,有没有用过手柄玩游戏呢?

本人有一个游戏手柄,玩 3a 还是挺爽的,哈哈


1. 实验器材

  • 树莓派开发板
  • 40p 软排线 + T 型转接板 + 面包板
  • PS2 手柄模块
  • PCF8591 模数转换器模块(实验 12)
  • 一些跳线
  • 一个一字螺丝刀

IMG_20220513_153730

2. 实验原理

手柄模块通过以 90 度角安装两个电位计来判断当前的 X 值和 Y 值,从而计算出手柄的方向。再加上一个按钮,来判断手柄被按下(也就是游戏手柄上的 L3 和 R3 键的原理)

处于静止位置时,此模块从 X 和 Y 产生约 2.5V 的输出。移动操纵杆将导致输出在 0v 到 5V 之间变化,具体取决于其方向。如果将此模块连接到微控制器,则可能会在其静止位置读取大约 512 的值 (由于弹簧和机构的微小误差而引起的细微变化)。移动操纵杆时,应该看到该值从 0 变为到 1023,具体取决于其位置。

该模块有两个模拟输出 (对应 X 和 Y 坐标) 和一个数字输出,表示是否在 Z 轴上按下。

在本实验中,我们将引脚 X 和 Y 连接到 PCF8591A/D 转换器的模拟输入端口,以便将模拟量转换为数字量。然后在树莓派上编程以检测操纵杆的移动方向

2.1 电路图

14.PS2操纵杆模块原理图

2.2 接线图

树莓派 T 型转接板 PCF8591
SDASDASDA
SCLSCLSCL
5V5VVCC
GNDGNDGND
PS2 手柄模块 T 型转接板 PCF8591
VRY*AIN 0
VRX*AIN 1
SW*ANI 2
5V5V5V
GNDGNDGND

14_JoyStick_PS2_bb

这个是我的接线图,其实可以直接用双母头跳线直接连接 PCF8591 和手柄模块,不过还是借助了 T 型转接板来连接二者。

IMG_20220513_153300

3. 效果演示

3.1 代码示例

c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//PS2操作杆实验
#include <stdio.h>
#include <wiringPi.h>
#include <pcf8591.h>

#define makerobo_PCF 120 // 基础管脚120
#define uchar unsigned char

int pcf_AIN0 = makerobo_PCF + 0; // AIN0 端口
int pcf_AIN1 = makerobo_PCF + 1; // AIN1 端口
int pcf_AIN2 = makerobo_PCF + 2; // AIN2 端口

// 方向状态信息
char *state[7] = {"home", "up", "down", "left", "right", "pressed"};

// 方向判断函数
int makerobo_direction(){
int ain_x, ain_y, ain_b; // X方向,Y方向,B 是否按下
int makerobo_tmp=0; // 状态值
ain_x = analogRead(pcf_AIN1); // X为AIN1端口
ain_y = analogRead(pcf_AIN0); // Y为AIN0端口
ain_b = analogRead(pcf_AIN2); // B按下为AIN2端口

if (ain_y <= 30)
makerobo_tmp = 1; // up
if (ain_y >= 225)
makerobo_tmp = 2; // down

if (ain_x >= 225)
makerobo_tmp = 4; // left
if (ain_x <= 30)
makerobo_tmp = 3; // right

if (ain_b == 0)
makerobo_tmp = 5; // button 按下
if (ain_x-125<15 && ain_x-125>-15 && ain_y-125<15 && ain_y-125>-15 && ain_b >= 60)
makerobo_tmp = 0; // home 位置

return makerobo_tmp;
}

// 主函数
int main (void)
{
int makerobo_tmp=0; // 当前值
int makerobo_status = 0; // 状态值
wiringPiSetup ();
// 在基本引脚120上设置pcf8591,地址0x48
pcf8591Setup (makerobo_PCF, 0x48);
// 无线循环
while(1)
{
makerobo_tmp = makerobo_direction(); // 调用方向判断函数
if (makerobo_tmp != makerobo_status) // 判断状态是否发生改变
{
printf("%s\n", state[makerobo_tmp]); // 打印出方向位
makerobo_status = makerobo_tmp;
// 把当前状态赋给状态值,以防止同一状态多次打印
}
}
return 0 ;
}

这部分比较好理解,代码也很直观。只有 home 位置需要我们单独进行计算(即手柄处于正中心区域且没有按下的情况,才是 home 的情况)

3.2 效果翻车

不过轮到实际测试的时候,翻大车了。在我还没有动摇杆的时候,它就会显示出左和按钮被按下的提示。我尝试修改代码来修复这个错误,发现并不可行

GIF1

于是我直接把代码给注释掉,加了一个打印 X\Y\B 当前值的代码

image-20220513155734051

结果呢,在我没动摇杆的时候,打印出来的 X 和 Y 都是乱七八糟的。只有按下摇杆的 B=0 可以被正常检测到,其他的方位啥的都是毫无反应。

image-20220513155907608

直接给这个模块下达了死亡通知书,拜拜了您嘞!

结语

通过学习这个模块的代码,可以看到实际上一些零部件的基本原理并不是非常难掌握。不过你想把一个摇杆变成一个完整的游戏手柄,那就需要更复杂的控制代码和手柄的内部芯片来转义这些数字值了。

有什么问题的话,可以在评论区提出呢

还是有所收获的,要是摇杆没坏就好了