第3章树莓派的GPIO 通俗地说,GPIO(generalpurposeI/Oports,通用输入输出端口)就是一些引脚,可以通过它们输 出高低电平或者读入引脚的状态(高电平或低电平)。树莓派的GPIO 如图3. 1所示。 图3.树莓派的GPIO 1 GPIO 是一个比较重要的概念。用户可以通过GPIO 与硬件进行数据交互(如UART )、控制硬件 工作(如LED 、蜂鸣器等)、读取硬件的工作状态信号(如中断信号)等。利用它们可以与外界交互,对树 莓派进行各种各样的扩展,作为可编程开关控制其他事务,以及接收外界的信息。 GPIO 的使用非常广泛。掌握了GPIO,就具备了操作硬件的能力。数字艺术家可以使用它们创建 交互式显示,机器人建造者可使用它们提升自己的作品。 在开始构建电路之前,首先需要知道如何连接树莓派的GPIO 。 1. 内转外接头 使用内转外接头是最简单的选择。作为转接头,内接头可以连接GPIO 引脚,外接头可以插入面包 板,这是访问GPIO 的最简便方法。 2.GPIO 扩展板(T型转接板) 2所示。注意, 可以使用40P 排线将树莓派的GPIO 引脚通过GPIO 扩展板连接起来,如图3.连接 的时候,必须将40P 排线上有“小三角”符号的一端(1号脚)对准树莓派的引脚1( 2中被排线遮住 的下方引脚)。如果插反,则会导致树莓派被烧坏。 图3. 一旦在GPIO 上连接了其他硬件,就有可能直接给CPU 供电,也就有可能将其损坏。绝对不能将 3.需要特别注意。 3V 电压连接到GPIO 上。这一点非常重要, 57 图3. 2 GPIO 扩展板与树莓派通过40P排线连接 与使用内转外接头相比,GPIO虽然没有提供任何新特性,但是看起来更整洁,也不容易混淆引脚。 3.无焊面包板 无论选择上述哪种方式,都需要使用面包板。通过它可以快速地将各个组件的电路连接在一起,完 成之后可以轻松拆除。 面包板有不同的尺寸,但基本排列十分类似。在典型面包板的长边上,有两条平行接口,用来连接 电源的正负极。它们中间是两排插孔,插孔中间留有间隙。与长边垂直的每5个孔板常用一条金属条 连接。面包板中央的一条凹槽,是为需要集成电路、芯片的试验而设计的。 可以将元器件直接插入孔中,使用公对公连接线或者小段单芯线缆将各个元件连接起来。 通过树莓派的I/O口可以外接很多外设,如伺服电动机、红外发送接收模块、继电器、步进电动机、 各类兼容传感器、屏幕等,通过这些外设可以进行很多有趣的设计。 4.RPiGPIO . 对于Pyn用户,可以使用RPiGPIO提供的API对GPIO进行编程,GPIO是一个控制树莓 派GPIO通道的模块,它提供了一个类来控制树莓派上的GPIO 。通常在文件开头使用importRPi . tho.RPi. GPIOasGPIO导入。 大多数树莓派的镜像默认安装了RPi.GPIO,可以直接使用它。如果没有,则可以通过执行命令 sudoapt-getinstalpython-dev进行安装。 3. 1 LED 树莓派GPIO控制输出的入门案例都是从控制LED(e,发光二极管)开始。 lightemitingdiod 3.1 七彩LED 1. 图3.会自动闪烁内置的颜色, 原理如 3所示的七彩LED上电后, 常用于制作迷人的灯光效果 , 4所示 。 图3. 树莓派的功能名、BCM编码、1所示 , 物理引脚与七彩LED引脚之间的关系如表3.T型转接板与 RGBLED之间的连线如图3.6所示, 中间引脚连 接GND 。 5所示。实物如图3.七彩LED的S引脚连接VCC, 58 图3.七彩LED 图3.七彩LED 的原理 34 表3.树莓派与七彩LED 引脚之间的关 系 1 功能名BCM 编码(T型转接板) 物理引脚(BOARD 编码) 七彩LED 模块的引脚 5V 5V 2、4 VCC GND GND GND GND 图3.七彩LED 的连线图3.七彩LED 的实物 56 3.2 双色LED 1. 双色LED 能够发出两种不同的颜色,经常用作电视机、数字照相机和遥控器的指示灯,实验用的双 色LED 如图3.7所示(“-”引脚对应GND,中间引脚对应R,S引脚对应G)。 本实验将引脚R和G连接到树莓派的GPIO,对树莓派进行编程,将LED 的颜色从红色变为绿色, 然后使用PWM(pulsewidthmodulation, 混合成其他颜色。原理如图3. 脉宽调制)8所示。 图3.双色LED 图3.双色LED 的原理 78 1. 电路连接 树莓派的功能名、BCM 编码、2所示, 物理引脚与双色LED 引脚之间的关系如表3.T型转接板与 5 9 双色LED之间的连线如图3.9所示,实物如图3.10所示。注意,不同的实物引脚顺序有所不同,图3.7 所示的实物,其“-”引脚对应GND,中间引脚对应R,S引脚对应G。 表3.2 树莓派与双色LED 引脚之间的关系 功 能 名BCM 编码(T型转接板) 物理引脚(BOARD 编码) 双色LED 模块的引脚 GPIO.0 17 11 R GPIO.1 18 12 G GND GND GND GND 图3.9 双色LED 的连线 图3.10 双色LED 的实物 2.软件编写 在pi目录下新建文件夹book,在book目录下新建文件ch3.1.2.py,代码如下: #!/usr/bin/env python import RPi.GPIO as GPIO import time colors=[0xFF0000, 0x00FF00, 0x0FF000, 0xF00F00] pins={'pin_R':11, 'pin_G':12} GPIO.setmode(GPIO.BOARD) for i in pins: GPIO.setup(pins[i], GPIO.OUT) GPIO.output(pins[i], GPIO.HIGH) p_R=GPIO.PWM(pins['pin_R'], 2000) p_G=GPIO.PWM(pins['pin_G'], 2000) p_R.start(0) p_G.start(0) 60 def map(x, in_min, in_max, out_min, out_max): return (x-in_min)*(out_max-out_min) / (in_max-in_min)+out_min def setColor(col): R_val=(col&0xFF0000)>>16 G_val=(col&0x00FF00)>>8 R_val=map(R_val, 0, 255, 0, 100) G_val=map(G_val, 0, 255, 0, 100) p_R.ChangeDutyCycle(R_val) p_G.ChangeDutyCycle(G_val) def loop(): while True: for col in colors: setColor(col) time.sleep(0.5) def destroy(): p_R.stop() p_G.stop() for i in pins: GPIO.output(pins[i], GPIO.HIGH) GPIO.cleanup() if __name__=="__main__": try: loop() except KeyboardInterrupt: destroy() (1)语句if__name__=="__main__":的含义。对于很多编程语言来说,程序都必须要有一个入 口,例如C、C++,以及完全面向对象的编程语言Java、C#等。 C和C++都需要有一个main()函数来作为程序的入口,也就是程序的运行会从main()函数开始。 同样,Java和C#必须要有一个包含main()方法的主类作为程序入口。而Python则不同,它属于脚本 语言,不像编译型语言那样,先将程序编译成二进制再运行,而是动态地逐行解释运行。也就是从脚本 第一行开始运行,没有统一的入口。 一个Python源码文件除了可以被直接运行外,还可以作为模块(也就是库)被导入。不管是导入还 是直接运行,最高层的代码都会被运行(Python用缩进来区分代码层次),而在实际导入时,有一部分代 码是不希望被运行的。例如,有一个const.py文件,代码及运行结果如图3.11所示。在这个文件里定 义了PI为3.14,然后又写了一个main()函数来输出定义的PI,最后运行main()函数就相当于对定义 做一遍人工检查,看看值设置得对不对。 6 1 又如,有一个area.py 文件用于计算圆的面积。该文件需要用到const.py 文件中的PI,那么从 const.py中把PI导入area.py中,代码及运行结果如图3.12所示。 图3.11 const.py程序及运行结果 图3.12 area.py程序及运行结果 图3.13 if__name__ == '__main__'的作用 可以看到,const中的main()函数也被运行了,实际上是不希望它被运行,提供main()也只是为了 对常量定义进行测试。这时,if__name__ == '__main__' 就派上了用场。修改const.py代码,再运行 area.py,修改的代码以及输出结果如图3.13所示,这才是想要 的效果。 if__name__ == '__main__'就相当于Python 模拟的程 序入口。Python本身并没有规定这么写,这只是一种编码习 惯。由于模块之间相互引用,不同模块可能都有这样的定义, 而入口程序只能有一个。到底哪个入口程序被选中,取决于 __name__ 的值。 结论:if__name__ == '__main__' 的意思就是,当模块 被直接运行时,以下代码块将被运行,当模块是被导入时,代码 块不被运行。 (2)异常处理。异常即是一个事件,该事件会在程序执行 过程中发生,影响程序的正常执行。一般情况下,在Python无 法正常处理程序时就会发生一个异常。当Python发生异常时 需要捕获处理它,否则程序将会终止执行。 捕捉异常可以使用try…except语句,try…except语句用 来检测try语句块中的错误,从而让except语句捕获异常信息 并处理。 以下为简单的try…except…else的语法。 62 try: <语句> #运行别的代码 except <名字>: <语句> #如果在try 部分引发了'name'异常 except <名字>,<数据>: <语句> #如果引发了'name'异常,获得附加的数据 else: <语句> #如果没有异常发生 在如图3.14 所示的程序中,发生异常时执行函数destroy(),关闭所有的LED。其中, KeyboardInterrupt表示用户中断执行(通常是按Ctrl+C键)。 图3.14 异常处理 GPIO.cleanup()的作用是释放脚本中使用的GPIO 引脚。一般来说,程序到达最后都需要释放资 源,这个好习惯可以避免损坏树莓派。 正常情况下执行loop()函数,循环执行setColor(col)函数和time.sleep(0.5)方法(休息0.5s)。 (3)#!/usr/bin/envpython的作用。这条语句的作用是防止操作系统用户没有将Python安装在 默认的/usr/bin路径里。当系统运行到这行时,首先会到env设置里查找Python的安装路径,再调用 对应路径下的解释器程序完成操作。 (4)设置模式GPIO.setmode。GPIO.setmode(mode)的mode参数有两个值:GPIO.BOARD 和 GPIO.BCM(注意,字母全是大写)。前者告诉程序按物理位置找GPIO(或者称channel),后者按GPIO 端口编号。两种模式各有各的好处,前者方便查找,后者方便程序在不同的树莓派版本上运行。 对照图3.1和表3.2,树莓派GPIO 的0 端口(GPIO.0),对应BCM 编码为17,对应物理引脚 (BOARD编码)为11;树莓派GPIO 的1端口(GPIO.1),对应BCM 编码为18,对应物理引脚(BOARD 编码)为12。 由于程序中使用了GPIO.BOARD,所以GPIO.setmode(GPIO.BOARD)上面一行的代码,pins= {'pin_R':11,'pin_G':12},代表的是物理引脚11和12,即GPIO.0和GPIO.1。 (5)设置GPIO 的输入和输出GPIO.setup。GPIO.setup(channel,mode)的参数channel就是要用 的GPIO,参数mode分为输入GPIO.IN 和输出GPIO.OUT。 6 3 GPIO.output(channel,GPIO.HIGH)表示输出高电平,就是输出信号1;GPIO.output(channel, GPIO.LOW)表示输出低电平,就是输出信号0。 (6)设置调制脉宽,输出模拟信号GPIO.PWM。树莓派本身既不能接收模拟信号,也不能输出模 拟信号,要么输出1,要么输出0。不过可以通过改变数字信号的输出占空比(DutyCycle,就是一个周 期内GPIO 的打开时间占总时间的比例),使输出效果近似模拟信号。 占空比是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比,如图3.15所示。 图3.15 占空比示意图 对于LED的光度调节,有一个传统办法,就是串联一个可调电阻,改变电阻值,灯的亮度就会改变。 另一个办法是脉宽调制。该方法不用串联电阻,而是串联一个开关。假设在1s内,有0.5s的时间 开关是打开的,0.5s关闭,那么灯就亮0.5s,灭0.5s。这样持续下去,灯就会闪烁。如果把频率调高一 点,例如1ms(即0.5ms开,0.5ms灭),那么灯的闪烁频率就很高。当闪烁频率超过一定值时,人眼就会 感觉不到,所以这时看不到灯的闪烁,只看到灯的亮度只有原来的一半。同理,如果1ms内(即0.1ms 开,0.9ms灭),那么灯的亮度就只有原来的1/10。这就是PWM 的基本原理。 在GPIO.PWM(channel,frequency)中,参数channel是GPIO,参数frequency 是频率。代码 GPIO.PWM(pins['pin_R'],2000)和GPIO.PWM(pins['pin_G'],2000),就是给GPIO.0和GPIO.1(物 理引脚11和12)设置2kHz的频率。 在函数setColor(col)中,ChangeDutyCycle(dc)的作用就是改变占空比(0.0< =dc< =100.0),确定 “开启”时间与常规时间的比例。 (7)setColor(col)函数。在loop()中,执行循环forcolincolors。对于程序开始时的代码colors= [0xFF0000,0x00FF00,0x0FF000,0xF00F00]中的每个颜色,在setColor(col)函数中执行(col& 0xFF0000)> >16和(col&0x00FF00)> >8。 RGB颜色是由红(Red)、绿(Green)、蓝(Blue)三原色组成的,所以可以使用这3个颜色的组合来代 表一种具体的颜色,其中R、G、B的每个数值都为0~255的整数。 在表达颜色的时候,既可以使用3个十进制数字来表达,也可以使用0x00RRGGBB格式的十六进 制来表达。下面是常见颜色的表达形式:红色(255,0,0)或0x00FF0000、绿色(0,255,0)或 64 0x0000FF00、蓝色(255,255,255)或0x00FFFFFF。 语句(col&0x00ff0000)> >16的含义是,首先将颜色值与十六进制表示的00ff0000进行“与”运 算,运算结果除了表示红色的数字值之外,GGBB部分颜色都为0。再将结果向右移位16位,得到的就 是红色的值。所以这句代码主要用来从一个颜色中抽取其组成色(红色)的值。 同样也可以通过代码(color&0x0000ff00)> >8得到绿色的值,代码(col&0x000000ff)> >0得到 蓝色的值。 由于双色LED只有两种颜色(红和绿),所以程序在得到R_val和G_val的值后,通过map()函数 得到0~100的占空比。最后执行ChangeDutyCycle,实现LED从红色到绿色,再到混合色的效果。 3.1.3 RGBLED RGBLED可以发出各种颜色的光,红色、绿色和蓝色的3个LED被封装在透明或半透明的塑料外 壳中,并带有4个引脚,如图3.16所示。 红色、绿色和蓝色三原色可以按照亮度混合并组合各种颜色,可以通过控制电路使RGBLED发出 彩色光。原理如图3.17所示。 图3.16 RGBLED 图3.17 RGBLED 的原理 1.电路连接 树莓派的功能名、BCM 编码、物理引脚与RGBLED模块的引脚之间的关系如表3.3所示,T 型转 接板与RGBLED模块之间的连线如图3.18所示,实物如图3.19所示。 表3.3 树莓派与RGBLED 引脚之间的关系 功 能 名BCM 编码(T型转接板) 物理引脚(BOARD 编码) RGBLED 模块的引脚 GPIO.0 17 11 R GPIO.1 18 12 G GPIO.2 27 13 B GND GND GND GND 2.软件编写 在book目录下新建文件ch3.1.3.py,代码如下: #!/usr/bin/env python import RPi.GPIO as GPIO import time colors=[0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF] 6 5 图3.18 RGBLED 的连线 图3.19 RGBLED 的实物 R=11 G=12 B=13 def setup(Rpin, Gpin, Bpin): global pins global p_R, p_G, p_B pins={'pin_R': Rpin, 'pin_G': Gpin, 'pin_B': Bpin} GPIO.setmode(GPIO.BOARD) for i in pins: GPIO.setup(pins[i], GPIO.OUT) GPIO.output(pins[i], GPIO.HIGH) p_R=GPIO.PWM(pins['pin_R'], 2000) p_G=GPIO.PWM(pins['pin_G'], 1999) p_B=GPIO.PWM(pins['pin_B'], 5000) p_R.start(100) p_G.start(100) p_B.start(100) def map(x, in_min, in_max, out_min, out_max): return (x-in_min)*(out_max-out_min)/(in_max-in_min)+out_min def off(): for i in pins: GPIO.output(pins[i], GPIO.HIGH) def setColor(col): R_val=(col & 0xff0000)>>16 G_val=(col & 0x00ff00 >>8 66 B_val=(col & 0x0000ff)>>0 R_val=map(R_val, 0, 255, 0, 100) G_val=map(G_val, 0, 255, 0, 100) B_val=map(B_val, 0, 255, 0, 100) p_R.ChangeDutyCycle(100-R_val) p_G.ChangeDutyCycle(100-G_val) p_B.ChangeDutyCycle(100-B_val) def loop(): while True: for col in colors: setColor(col) time.sleep(1) def destroy(): p_R.stop() p_G.stop() p_B.stop() off() GPIO.cleanup() if __name__=="__main__": try: setup(R, G, B) loop() except KeyboardInterrupt: destroy() 此代码与上一节大同小异。运行程序,可以看到RGBLED灯点亮,并依次显示不同的颜色。 3.2 继电器 继电器是一种电控制器件,在输入量的变化达到规定要求时,可使电气输出电路的被控量发生预定 的阶跃变化,通常应用于自动化控制电路中控制器与受控设备之间的隔离,如图3.20所示。 图3.20 继电器 继电器的基本原理是利用电磁效应控制机械触点实现通或断。当继电器通电时,电流开始流经控 制线圈,电磁铁开始通电,衔铁被吸到线圈上,将动触点拉动,从而 与常开触点连接,使带负载的电路通电;当继电器断电时,在弹簧的 作用下,动触点被拉到常闭触点,使带负载的电路断电。这样,继电 器的接通和断开就可以控制负载电路的状态。当需要用小信号控 制大电流或电压时,继电器非常有用,在电路中起着自动调节、安全 保护、转换电路的作用。 继电器的原理如图3.21所示。 67 图3.继电器的原理 21 1. 电路连接 树莓派的功能名、BCM 编码、 5所示。 4所示, 物理引脚与继电器模块的引脚之间的关系如表3.继电器模块 与双色LED 模块的引脚之间的关系如表3. 表3.树莓派与继电器引脚之间的关系 4 功能名BCM 编码(T型转接板) 物理引脚(BOARD 编码) 继电器模块的引脚 GPIO.0 17 11 SIG 5V 5V 2 VCC 5V 5V 4 COM GND GND GND GND 表3.继电器与双色LED 引脚之间的关系 5 继电器模块的触点BCM 编码(T型转接板) 双色LED 模块的引脚 常开R GND GND 常闭G T型转接板、继电器、22 所示, 23 所示。 双色LED 的连线如图3.实物如图3. 2. 软件编写 在book目录下新建文件c2.代码如下: h3.py, 68 图3.22 T型转接板、继电器、 双色LED 的连线 图3.23 T型转接板、继电器、 双色LED 的实物 #!/usr/bin/env python import RPi.GPIO as GPIO import time RelayPin=11 def setup(): GPIO.setmode(GPIO.BOARD) GPIO.setup(RelayPin, GPIO.OUT) GPIO.output(RelayPin, GPIO.HIGH) def loop(): while True: print('...relayd on') GPIO.output(RelayPin, GPIO.LOW) time.sleep(0.5) print('relay off...') GPIO.output(RelayPin, GPIO.HIGH) time.sleep(0.5) def destroy(): GPIO.output(RelayPin, GPIO.HIGH) GPIO.cleanup() if __name__=='__main__': setup() try: loop() except KeyboardInterrupt: destroy() 69 运行程序,可以听到常闭触点打开、常开触点闭合时发出的嘀嗒声,同时看到LED双色灯的变化, 以及如图3.el 输出内容( trl+C键结束运行)。 24所示的Sh直到按C 图3. l 显示效果 24 She 3.激光发射模块 3 激光是20世纪60年代的新光源,具有方向性好、亮度高、单色性好和高能量密度等特点。以激光 器为基础的激光工业在全球发展迅猛,现在已广泛应用于工业生产、通信、信息处理、医疗卫生、军事、文 化教育以及科研等方面。 激光发射模块如图3.25所示。它是一种可以发射激光的模块,原理如图3. 26所示。 图3.激光发射模块图3.激光发射模块的原理 25 26 1.电路连接 树莓派的功能名、BCM编码、6所示。 物理引脚与激光发射模块的引脚之间的关系如表3. 表3.树莓派与激光发射模块引脚之间的关系 6 功能名BCM 编码(T型转接板) 物理引脚(BOARD 编码) 激光发射模块的引脚 GPIO.0 17 11 SIG 5V 5V VCC 激光发射模块的连线如图3.实物如图3.中间引脚不用连接。 27所示, 28所示, 70 图3.27 激光发射模块的连线图3.28 激光发射模块的实物 2.软件编写 在book目录下新建文件ch3.3.py,代码如下: #!/usr/bin/env python import RPi.GPIO as GPIO import time LedPin=11 def setup(): GPIO.setmode(GPIO.BOARD) GPIO.setup(LedPin, GPIO.OUT) GPIO.output(LedPin, GPIO.HIGH) def loop(): while True: print('...Laser on') GPIO.output(LedPin, GPIO.LOW) time.sleep(0.5) print('Laser off ...') GPIO.output(LedPin, GPIO.HIGH) time.sleep(0.5) def destroy(): GPIO.output(LedPin, GPIO.HIGH) GPIO.cleanup() 7 1 if __name__=='__main__': setup() try: loop() except KeyboardInterrupt: destroy() 运行程序,可以看到激光的发射,直到按Ctrl+C键结束运行。 注意,千万不要将激光对着眼睛照射! 3.4 开关 本节介绍轻触开关、倾斜开关、振动开关、干簧管和触摸开关的使用。 3.4.1 轻触开关 轻触开关是使用最为频繁的电子部件,内部由一对轻触拨盘组成,按下时闭合导通,松开时自动弹 开断开,如图3.29所示。 使用轻触开关作为树莓派的输入设备,按下按钮时,GPIO 将变为低电平(0V)。通过编程检测 GPIO 的状态,如果GPIO 变为低电平,则表示按下按钮。原理如图3.30所示。 图3.29 轻触开关 图3.30 轻触开关的原理 1.电路连接 树莓派的功能名、BCM 编码、物理引脚与轻触开关模块的引脚之间的关系如表3.7所示,与双色 LED模块的引脚之间的关系如表3.8所示。 表3.7 树莓派与轻触开关引脚之间的关系 功 能 名BCM 编码(T型转接板) 物理引脚(BOARD 编码) 轻触开关模块的引脚 GPIO.0 17 11 SIG 5V 5V 5V VCC GND GND GND GND 72 表3.8 树莓派与双色LED 引脚之间的关系 功 能 名BCM 编码(T型转接板) 物理引脚(BOARD 编码) 双色LED 模块的引脚 GPIO.1 18 12 R GPIO.2 27 13 G GND GND GND GND 轻触开关的连线如图3.31所示,实物如图3.32所示。 图3.31 轻触开关的连线图3.32 轻触开关的实物 2.软件编写 在book目录下新建文件ch3.4.1.py,代码如下: #!/usr/bin/env python import RPi.GPIO as GPIO BtnPin=11 Gpin=12 Rpin=13 def setup(): GPIO.setmode(GPIO.BOARD) GPIO.setup(Gpin, GPIO.OUT) GPIO.setup(Rpin, GPIO.OUT) GPIO.setup(BtnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.add_event_detect(BtnPin, GPIO.BOTH, callback=detect, bouncetime=200) def Led(x): if x==0: GPIO.output(Rpin, 1) 7 3 GPIO.output(Gpin, 0) if x==1: GPIO.output(Rpin, 0) GPIO.output(Gpin, 1) def Print(x): if x==0: print(' ***********************') print(' * Button Pressed! *') print(' ***********************') def detect(chn): Led(GPIO.input(BtnPin)) Print(GPIO.input(BtnPin)) def loop(): while True: pass def destroy(): GPIO.output(Gpin, GPIO.HIGH) GPIO.output(Rpin, GPIO.HIGH) GPIO.cleanup() if __name__=='__main__': setup() try: loop() except KeyboardInterrupt: destroy() 如果需要实时监控引脚的状态变化,可以有两种方式。 最简单原始的方式是每隔一段时间检查输入的信号值,这种方式被称为轮询。如果程序读取的时 机错误,则很可能会丢失输入信号。轮询是在循环中执行的,这种方式占用比较多的处理器资源。 另一种响应GPIO 输入的方式是使用中断(边缘检测),边缘是指信号从高到低的变换(下降沿)或 从低到高的变换(上升沿)。下面两个函数可以进行检测。 wait_for_edge()用于阻止程序的继续执行,直到检测到一个边沿。 add_event_detect()函数用于对引脚进行监听,一旦引脚输入状态发生了改变,调用event_detected()函 数,返回True。 GPIO.add_event_detect(BtnPin,GPIO.BOTH,callback=detect,bouncetime=200):对BtnPin (引脚11)添加一个事件函数,触发条件是GPIO.BOTH(捕获到上升沿GPIO.RISING、捕获到下降沿 GPIO.FALLING、两者都有GPIO.BOTH),检测到上升沿或下降沿后执行detect()。bouncetime=200 是延迟200ms的意思,就是当检测到后,进入这个中断,延迟200ms才会执行这个中断里面的程序,这 就是软件去抖。 74 运行程序,按下按钮,LED 发出绿光,松开按钮,绿光消失。 3.2 倾斜开关 4. 带有金属球的球形倾斜开关用于检测小角度的倾斜,如图3. 33 所示。 在倾斜开关中,金属球以不同的倾斜角度移动,当它向任意一侧倾斜时,只要倾斜度和力度满足条 件,开关就会通电, 34 所示。 从而输出低电平信号。原理如图3. 图3.倾斜开关图3.倾斜开关的原理 33 34 1. 电路连接 树莓派的功能名、BCM 编码、 10 所示。 9所示, 物理引脚与倾斜开关模块的引脚之间的关系如表3.与双色 LED 模块的引脚之间的关系如表3. 表3.树莓派与倾斜开关引脚之间的关系 9 功能名BCM 编码(T型转接板) 物理引脚(BOARD 编码) 倾斜开关模块的引脚 GPIO.0 17 11 SIG 5V 5V 5V VCC GND GND GND GND 表3.树莓派与双色LED 引脚之间的关系 10 功能名BCM 编码(T型转接板) 物理引脚(BOARD 编码) 双色LED 模块的引脚 GPIO.1 18 12 R GPIO.2 27 13 G GND GND GND GND 倾斜开关的连线如图3.35 所示,实物如图3. 36 所示。 2. 软件编写 在book目录下新建文件c4.py,代码如下: h3.2. 7 5 图3.35 倾斜开关的连线 图3.36 倾斜开关的实物 #!/usr/bin/env python import RPi.GPIO as GPIO TiltPin=11 Gpin=12 Rpin=13 def setup(): GPIO.setmode(GPIO.BOARD) GPIO.setup(Gpin, GPIO.OUT) GPIO.setup(Rpin, GPIO.OUT) GPIO.setup(TiltPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.add_event_detect(TiltPin, GPIO.BOTH, callback=detect, bouncetime=200) def Led(x): if x==0: GPIO.output(Rpin, 1) GPIO.output(Gpin, 0) if x==1: GPIO.output(Rpin, 0) GPIO.output(Gpin, 1) def Print(x): if x==0: print ' *************' print ' * Tilt! *' print ' *************'