树莓派-5-GPIO的应用实验

【树莓派4B学习】一、环境搭建、开机及登录树莓派4B
【树莓派4B学习】二、树莓派4B介绍与一些必要的软件安装配置
【树莓派4B学习】三、接入USB摄像头,搭建Python2.7.16+OpenCV3.2.0开发环境
【树莓派4B学习】四、使用USB摄像头和motion实现监控
【树莓派4B学习】五、树莓派4B的OpenCV基本操作
【树莓派4B学习】六、树莓派4BOpenCV的视频/摄像头基本操作
【树莓派4B学习】七、树莓派4B的GPIO基础操作

1 wiringPi和BCM和BOARD编码

1.1 管脚信息

树莓派上提供了一组GPIO(General Purpose Input Output,即通用输入/输出)接口,这些接口可以用于做一些电子相关的实验:控制一些硬件设备,如最常见的发光二极管、电机等,或者读取一些信号的状态,如开关、传感器等。这里需要注意的是,树莓派中的GPIO只支持数字输入输出,即1和0对应高电平3.3V和低电平0V,因此必要的时候可能需要数模转换。

树莓派中执行:
$gpio readall得到关于树莓派管脚的信息
树莓派-5-GPIO的应用实验_第1张图片
RXD是Receive Data接收数据的引脚
TXD是Transmit Data发送数据的引脚

比如,BOARD编码中的37号引脚
在wiringPi 中的编码就是25号引脚
在BCM 中的编码就是26号引脚
它们的功能都是GPIO.25(通用输入输出管脚25)

在wiringPi中, 你要使用GPIO.25号管脚, 你就得驱动25
而在BCM中, 你要使用GPIO.25号管脚, 你就得驱动26
树莓派-5-GPIO的应用实验_第2张图片

1.2 使用场合

BOARD编码和BCM一般都在python库中使用。

import RPi.GPIO as GPIO  //引入RPi.GPIO库
GPIO.setmode(GPIO.BCM) //设置引脚编号为BCM编码方式;
GPIO.setmode(GPIO.BOARD) //设置GPIO引脚为BOARD编码方式。

而wiringPi一般用于C++等平台。

LIBS += -lwiringPi
#include "wiringPi.h"
wiringPiSetup();

1.3 I2C总线

I2C总线介绍
树莓派-5-GPIO的应用实验_第3张图片
SDA----串行数据线----Serial Data Line 
SCL-----串行控制线----Serial Control Line 
通过对SCL和SDA线高低电平时序的控制,来产生I2C总线协议所需要的信号进行数据的传递。在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平。

SDA在SCL 高电平期间由高电平跳变为低电平,然后由主机发送一个字节的数据.数据传送完毕,由主机发出停止信号,SDA在SCL 高电平期间由低电平跳变为高电平。

1.4 SPI总线

SPI详细解释
SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。

(1)MISO– Master Input Slave Output,主设备数据输入,从设备数据输出;(2)MOSI– Master Output Slave Input,主设备数据输出,从设备数据输入;

2 RPI.GPIO

在这里插入图片描述
树莓派-5-GPIO的应用实验_第4张图片

2.1 参考资料

参考树莓派基础实验1:双色LED灯实验
参考树莓派基础实验2:RGB-LED实验
参考树莓派基础实验3:七彩LED灯闪烁实验
参考树莓派基础实验4:继电器实验
参考树莓派基础实验5:激光传感器实验
参考树莓派基础实验6:轻触开关按键实验
参考树莓派基础实验7:倾斜开关实验
参考树莓派基础实验8:振动开关实验
参考树莓派基础实验9:蜂鸣器实验
参考树莓派基础实验10:干簧管传感器实验
参考树莓派基础实验11:U型光电传感器实验
参考树莓派基础实验12:PCF8591模数转换器实验
参考树莓派基础实验13:雨滴探测传感器实验
参考树莓派基础实验14:PS2操纵杆实验
参考树莓派基础实验15:电位器传感器实验
参考树莓派基础实验16:霍尔传感器实验
参考树莓派基础实验17:温度传感器实验
参考树莓派基础实验18:声音传感器实验
参考树莓派基础实验19:光敏传感器实验
参考树莓派基础实验20:火焰报警传感器实验
参考树莓派基础实验21:烟雾报警传感器实验
参考树莓派基础实验22:红外遥控传感器实验
参考树莓派基础实验23:触摸开关传感器实验
参考树莓派基础实验24:超声波测距传感器实验
参考树莓派基础实验25:DS18B20温度传感器实验
参考树莓派基础实验26:旋转编码器实验
参考树莓派基础实验27:温湿度传感器DHT11 实验
参考树莓派基础实验28:红外避障传感器实验
参考树莓派基础实验29:I2C LCD1602实验
参考树莓派基础实验30:BMP180气压传感器实验
参考树莓派基础实验31:MPU6050陀螺仪加速度传感器实验
参考树莓派基础实验32:DS1302实时时钟模块实验
参考树莓派基础实验33:TCRT5000红外循迹传感器实验
参考树莓派基础实验34:L298N模块驱动直流电机实验
参考树莓派基础实验35:USB TO TTL模块实验
参考树莓派基础实验36:通用串口通信实验

2.2 SDK

import RPi.GPIO as GPIO

2.2.1 SDK说明PWM

class PWM(builtins.object)
Pulse Width Modulation class脉冲宽度调制
举例p_R = GPIO.PWM(11, 2000)  # 设置频率为 2KHz
*************************************************************
ChangeDutyCycle(...)
Change the duty cycle
更改占空比 
(1)dutycycle
between 0.0 and 100.0
*************************************************************
ChangeFrequency(...)
Change the frequency
frequency - frequency in Hz (freq > 1.0)
*************************************************************
函数start(...)初始占空比
Start software PWM
(1)dutycycle 
the duty cycle (0.0 to 100.0)
举例p_R.start(0) # 初始占空比为0
*************************************************************
函数stop(...)停止PWM
Stop software PWM

2.2.2 SDK说明静态函数

(1)函数setmode(…)

函数setmode(...)
Set up numbering mode to use for channels.
BOARD——Use Raspberry Pi board numbers
BCM————Use Broadcom GPIO 00..nn numbers

例如GPIO.setmode(GPIO.BOARD)
例如GPIO.setmode(GPIO.BCM)
(2)函数setup(…)

函数setup(...)
设置针脚模式
Set up a GPIO channel or list of channels with a direction 
and (optional) pull/up down control
参数(1)channel        
either board pin number or BCM number depending on which mode is set.
参数(2)direction      
IN or OUT
参数(3)[pull_up_down] 
PUD_OFF (default), PUD_UP or PUD_DOWN
参数(4)[initial]      
Initial value for an output channel

例如GPIO.setup(11, GPIO.OUT)设置引脚模式为输出

有多种方式将GPIO的输入导入到程序中:
polling(轮询式 )轮询式如果程序在错误的时间读取值,可能会错过输入。
interrupt( 中断式 )( edge detection 边缘检测 )这里采用中断式。

如果您没有将输入引脚连接到任何东西,它将“浮动”。
换句话说,读取的值是未定义的,因为它没有连接到任何东西,直到你按下按钮或开关。
它可能会由于接收电源干扰而改变很大的值。

为了解决这个问题,我们使用一个向上拉或向下拉电阻器。
这样,就可以设置输入的默认值。
可以使用硬件或者软件实现上下拉电阻。
在硬件方式中,常常在输入通道与3.3V(上拉)或0V(下拉)之间使用10K电阻。
GPIO模块允许您在编程中这样配置:
例如GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)
例如GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
(3)函数output(…)

函数output(...)
Output to a GPIO channel or list of channels
参数(1)channel 
either board pin number or BCM number depending on which mode is set.
参数(2)value   
0/1 or False/True or LOW/HIGH

例如GPIO.output(11, 1)高电平
例如GPIO.output(12, 0)低电平

(4)函数input(…)

函数input(...)
Input from a GPIO channel.  
Returns HIGH=1=True or LOW=0=False
参数(1)channel 
either board pin number or BCM number depending on which mode is set.

(5)捕捉引脚的电平改变
我们很多时候并不关心电平值, 而关心电平从低到高,或从高到低的变化(如编码器测速/按键按下弹开等), 为避免主程序忙于其它事情错过引脚的电平改变, 有两种方式:
wait_for_edge() 函数
event_detected() 函数
(5-1)函数wait_for_edge(…)

函数wait_for_edge(...)
Wait for an edge.  
Returns the channel number or None on timeout.
参数(1)channel      
either board pin number or BCM number depending on which mode is set.
参数(2)edge         
RISING, FALLING or BOTH
参数(3)[bouncetime] 
time allowed between calls to allow for switchbounce
参数(4)[timeout]    
timeout in ms

wait_for_edge()函数是为了阻止程序的执行,直到检测到边缘为止。换句话说,等待按钮按下的示例可以改写成:
GPIO.wait_for_edge(channel, GPIO.RISING)

注意检测的边缘参数有:
GPIO.RISING,上升沿
GPIO.FALLING,下降沿
GPIO.BOTH, 升降沿
这样用几乎不占用CPU,如果你只希望在确定的时间段内查询,可以使用 timeout 参数:

#wait for up to 5 seconds for a rising edge (timeout is in milliseconds)
channel = GPIO.wait_for_edge(channel, GPIO_RISING, timeout=5000)
if channel is None:
    print('Timeout occurred')
else:
    print('Edge detected on channel', channel)

(5-2)函数event_detected(…)

函数event_detected(...)
Returns True if an edge has occurred on a given GPIO.  
You need to enable edge detection using add_event_detect() first.
(1)channel 
either board pin number or BCM number depending on which mode is set.

event_detected()函数被设计用来与其他事物一起在循环中使用, 不同于polling轮询, 它不会在CPU忙于处理其他事物时错过输入状态的变化。 这使得使用Pygame 或 PyQt 时非常有用,因为其中有一个主循环监听和及时响应GUI事件的基础。

只要检测到指定参数的边缘事件(上升沿, 下降沿 或 升降沿)发生时,调用GPIO.event_detected(channel)的值就为"ture"(真)。

#Note that you can detect events for GPIO.RISING, GPIO.FALLING or GPIO.BOTH.
#add rising edge detection on a channel
GPIO.add_event_detect(channel, GPIO.RISING)  
do_something()
if GPIO.event_detected(channel):
    print('Button pressed')

不过需要自己新建一个线程去循环检测event_detected()的值,还算是比较麻烦的。

可采用另一种办法轻松检测状态,这种方式是直接传入一个回调函数:GPIO通过在add_event_detect()函数中添加callback参数,RPI.GPIO为回调函数运行第二个线程。这意味着回调函数可以与主程序同时运行,以立即响应边缘。
(6)函数add_event_detect(…)

函数add_event_detect(...)
Enable edge detection events for a particular GPIO channel.
参数(1)channel      
either board pin number or BCM number depending on which mode is set.
参数(2)edge         
RISING, FALLING or BOTH
参数(3)[callback]   
A callback function for the event (optional)
参数(4)[bouncetime] 
Switch bounce timeout in ms for callback

例如这里添加了回调函数callback这个参数,就不需要GPIO.event_detected(channel)函数了。

def my_callback(channel):
    print('This is a edge event callback function!')
    print('Edge detected on channel %s'%channel)
    print('This is run in a different thread to your main program')
GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback) 

例如如果你想要不止一个回调函数:

def my_callback_one(channel):
    print('Callback one')
def my_callback_two(channel):
    print('Callback two')
GPIO.add_event_detect(channel, GPIO.RISING)
GPIO.add_event_callback(channel, my_callback_one)
GPIO.add_event_callback(channel, my_callback_two)
#请注意,在这种情况下,回调函数是按顺序运行的,而不是并发的。
#这是因为只有一个线程用于回调,其中每个回调都按照它们被定义的顺序运行。

由于存在开关抖动(用示波器可以看到),每次按下开关会调用多次回调函数,这不是我们希望的,有两种方式处理开关抖动:①在开关两个引脚之间添加一个0.1uF的电容。②软件消抖。③二者结合使用。
  使用软件消抖时, 给回调函数添加一个弹跳时间的参数( bouncetime= ), 弹跳时间(参照单片机可以为10~20ms)在ms级别, 下面的程序用200ms来消抖:

#add rising edge detection on a channel, 
#ignoring further edges for 200ms for switch bounce handling
GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback, bouncetime=200)

(7)函数add_event_callback(…)

函数add_event_callback(...)
Add a callback for an event already defined using add_event_detect()
参数(1)channel      
either board pin number or BCM number depending on which mode is set.
参数(2)callback     
a callback function

(8)函数remove_event_detect(…)

函数remove_event_detect(...)
Remove edge detection for a particular GPIO channel
参数(1)channel 
either board pin number or BCM number depending on which mode is set.

由于某些原因, 你的程序可能不希望用边缘检测了,可以停止它们:
GPIO.remove_event_detect(channel)
(9)函数cleanup(…)

函数cleanup(...)
重置GPIO状态
Clean up by resetting all GPIO channels that have been used by this program to INPUT with no pullup/pulldown and no event detection
(1)[channel]
individual channel or list/tuple of channels to clean up.  
Default - clean every channel that has been used.

例如GPIO.cleanup() # 释放资源

(10)函数getmode(…)

函数getmode(...)
Get numbering mode used for channel numbers.
Returns BOARD, BCM or None

(11)函数gpio_function(…)

函数gpio_function(...)
Return the current GPIO function (IN, OUT, PWM, SERIAL, I2C, SPI)
(1)channel 
either board pin number or BCM number depending on which mode is set.

(12)函数setwarnings(…)

函数setwarnings(...)
Enable or disable warning messages

2.2.3 SDK说明DATA

DATA
BCM = 11
BOARD = 10
BOTH = 33
FALLING = 32
HARD_PWM = 43
HIGH = 1
I2C = 42
IN = 1
LOW = 0
OUT = 0
PUD_DOWN = 21
PUD_OFF = 20
PUD_UP = 22
RISING = 31
RPI_INFO = {'MANUFACTURER': 'Sony', 'P1_REVISION': 3, 'PROCESSOR': 'BC...
RPI_REVISION = 3
SERIAL = 40
SPI = 41
UNKNOWN = -1
VERSION = '0.7.0'

FILE
    /usr/lib/python3/dist-packages/RPi/GPIO/__init__.py

2.2.4 SDK应用

(1)开发环境Thonny python IDE【python3.7.3】
(2)导入模块,设置常量、板载模式。
Raspberry Pi有三种引脚编号方法:Board根据引脚的物理位置编号;由C语言GPIO库wiringpi指定的编号;由BCM2837 SOC指定的编号。

import RPi.GPIO as GPIO   #导入控制GPIO的模块,RPi.GPIO
import time #导入时间模块,提供延时、时钟和其它时间函数
colors = [0xFF00, 0x00FF, 0x0FF0, 0xF00F]   #颜色列表
GPIO.setmode(GPIO.BOARD) #设置引脚编号模式为板载模式,即树莓派上的物理位置编号
#GPIO.setmode(GPIO.BCM) #或者为BCM模式

R、G、B均为255时就合成了白光,R、G、B均为0时就形成了黑色。
00000000–0x00–0
11111111–0xFF–255
(3)初始化LED灯,输入输出模式、初始电平、频率、占空比。

GPIO.setup(11, GPIO.OUT)   # 设置针脚模式为输出(或者输入GPIO.IN)
GPIO.output(11, GPIO.LOW) #设置针脚为低电平,关掉LED灯
GPIO.setup(12, GPIO.OUT)   # 设置针脚模式为输出(或者输入GPIO.IN)
GPIO.output(12, GPIO.LOW) #设置针脚为低电平,关掉LED灯

p_R = GPIO.PWM(11, 2000)  # 设置频率为 2KHz
p_G = GPIO.PWM(12, 2000)  # 设置频率为 2KHz

p_R.start(0) # 初始占空比为0(范围:0.0 <= dc <= 100.0,0为关闭状态)
p_G.start(0) # p.start(dc) dc代表占空比

PWM的频率决定了输出的数字信号on (1) 和 off(0 )的切换速度。频率越高,切换就越快。
占空比:指一串理想脉冲序列中,正脉冲的持续时间与脉冲总周期的比值。
(4)通过更改占空比调整各基色的亮度,进而设置LED的发光颜色。

#将颜色的刺激量转换为占空比对应的值
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 & 0xFF00) >> 8    
	G_val = (col & 0x00FF) >> 0
    
	#将颜色的刺激量转换为占空比对应的值
	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)

(5)处理

def loop():
	while True: #循环函数
		for col in colors:  #遍历颜色列表
			setColor(col) #设置颜色
			time.sleep(0.5) #延时0.5秒
			
def destroy():
	p_R.stop()  #停止PWM
	p_G.stop()  #停止PWM
	GPIO.output(11, GPIO.LOW)  # 关掉所有led灯
	GPIO.output(12, GPIO.LOW)  # 关掉所有led灯
	GPIO.cleanup()  #重置GPIO状态
if __name__ == "__main__":
	try:   #用try-except代码块来处理可能引发的异常
		loop()
	except KeyboardInterrupt:  #用户中断(control+C),则执行destroy()函数
		destroy()

2.3 LED灯实验

2.3.1 小双色LED灯实验

树莓派学习笔记1:python控制双色LED灯
树莓派基础实验1:双色LED灯实验

实现红绿LED 灯交替闪亮,并间隔2秒。
注意:GPIO 输出High 电平为3.3v。
注意小双色LED灯引脚从上往下依次是:
-接地
Board11–R
Board12–G

# encoding=utf-8
import RPi.GPIO as GPIO
import time

pins = {'pin_R':11, 'pin_G':12}  #引脚字典
sleep_time =2

GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
for i in pins:
	GPIO.setup(pins[i], GPIO.OUT)   # Set pins' mode is output
	GPIO.output(pins[i], GPIO.LOW) # Set pins to low(0V) to off led

def loop():	
	while True:
            GPIO.output(pins['pin_R'], GPIO.HIGH)   # give high
            time.sleep(sleep_time)
            GPIO.output(pins['pin_R'], GPIO.LOW)  # give low
            
            GPIO.output(pins['pin_G'], GPIO.HIGH)  # give high
            time.sleep(sleep_time)
            GPIO.output(pins['pin_G'], GPIO.LOW)
def destroy():
	for i in pins:
		GPIO.output(pins[i], GPIO.LOW)    # Turn off all leds
	GPIO.cleanup()

if __name__ == "__main__":
	try:
		loop()
	except KeyboardInterrupt:
		destroy()

中断ctrl+c。

2.3.2 三色LED灯实验

红-绿-蓝-白,三色变换

import RPi.GPIO as GPIO   #导入控制GPIO的模块,RPi.GPIO
import time     #导入时间模块,提供延时、时钟和其它时间函数
GPIO.setmode(GPIO.BOARD) #设置引脚编号模式为板载模式,即树莓派上的物理位置编号


GPIO.setup(11, GPIO.OUT)   # 设置针脚模式为输出(或者输入GPIO.IN)
GPIO.output(11, GPIO.LOW) #设置针脚为低电平,关掉LED灯
GPIO.setup(12, GPIO.OUT)   # 设置针脚模式为输出(或者输入GPIO.IN)
GPIO.output(12, GPIO.LOW) #设置针脚为低电平,关掉LED灯
GPIO.setup(13, GPIO.OUT)   # 设置针脚模式为输出(或者输入GPIO.IN)
GPIO.output(13, GPIO.LOW) #设置针脚为低电平,关掉LED灯

#11-R
#12-G
#13-B

def loop():
    while True:
        #Red       
        GPIO.output(11, GPIO.HIGH)
        GPIO.output(12, GPIO.LOW)
        GPIO.output(13, GPIO.LOW)
        time.sleep(1)   #延时0.5秒
        #Green       
        GPIO.output(11, GPIO.LOW)
        GPIO.output(12, GPIO.HIGH)
        GPIO.output(13, GPIO.LOW)
        time.sleep(1)   #延时0.5秒
        #Blue      
        GPIO.output(11, GPIO.LOW)
        GPIO.output(12, GPIO.LOW)
        GPIO.output(13, GPIO.HIGH)
        time.sleep(1)   #延时0.5秒
        #White      
        GPIO.output(11, GPIO.HIGH)
        GPIO.output(12, GPIO.HIGH)
        GPIO.output(13, GPIO.HIGH)
        time.sleep(1)   #延时0.5秒

def destroy():
	GPIO.output(11, GPIO.LOW)    # 关掉所有led灯
	GPIO.output(12, GPIO.LOW)    # 关掉所有led灯
	GPIO.output(13, GPIO.LOW)    # 关掉所有led灯
	GPIO.cleanup()     #重置GPIO状态
if __name__ == "__main__":
	try:         #用try-except代码块来处理可能引发的异常
		loop()
	except KeyboardInterrupt: #如果中断(control+C),则执行destroy()函数
		destroy()

2.3.3 七彩LED灯实验

5v供电
“红线”连接7彩LED模块VCC端子S;
“黑线”连接7彩LED模块GND端子-。
7彩LED模块内置有控制灯闪烁的芯片,不需要编程,通电即可看到实验效果。

2.4 继电器实验

常闭——继电器被激活时断开,未激活时连接。
常开——继电器被激活时连接,未激活时断开。

board11——SIG 耦合对应 NC常闭——G
5V——DC+ 耦合对应COM——5V
GND——DC- 耦合对应 NO常开——R

注意小双色LED灯引脚从上往下依次是:
引脚-接地
引脚R
引脚G

import RPi.GPIO as GPIO
import time

RelayPin = 11    # pin11

def setup():
	GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
	GPIO.setup(RelayPin, GPIO.OUT)
	GPIO.output(RelayPin, GPIO.LOW)

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.LOW)
	GPIO.cleanup()                     # Release resource

if __name__ == '__main__':     # Program start from here
	setup()
	try:
		loop()
	# When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
	except KeyboardInterrupt:  
		destroy()

2.5 激光传感器实验

引脚S接Board11
引脚-接GND

import RPi.GPIO as GPIO
import time

LedPin = 11    # pin11

def setup():
	GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
	GPIO.setup(LedPin, GPIO.OUT)   # Set LedPin's mode is output
	GPIO.output(LedPin, GPIO.LOW) # Set LedPin LOW(0V) to off led

def loop():
	while True:
		print '...Laser off'
		GPIO.output(LedPin, GPIO.LOW)  # led off
		time.sleep(0.5)
		print 'Laser on...'
		GPIO.output(LedPin, GPIO.HIGH) # led on
		time.sleep(0.5)

def destroy():
	GPIO.output(LedPin, GPIO.LOW))     # led off
	GPIO.cleanup()                     # Release resource

if __name__ == '__main__':     # Program start from here
	setup()
	try:
		loop()
	# When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
	except KeyboardInterrupt:  
		destroy()

2.6 开关实验

2.6.1 按键开关实验

按键模块引脚,从上往下依次是:
引脚S接Board11
引脚中间VCC接5V
引脚-接GND

小双色LED灯引脚,从上往下依次是:
引脚-接GND
引脚中间R接Board12
引脚G接Board13

import RPi.GPIO as GPIO

BtnPin = 11
Rpin   = 12
Gpin   = 13

def setup():
	GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
	GPIO.setup(Gpin, GPIO.OUT)     # Set Green Led Pin mode to output
	GPIO.setup(Rpin, GPIO.OUT)     # Set Red Led Pin mode to output
	# Set BtnPin's mode is input, and pull up to high level(3.3V)
	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):         #控制双色LED灯闪烁的函数
	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('    *   Button is down!   *')
		print('    ***********************')
	elif x == 1:
		print('    ***********************')
		print('    *   Button is up !   *')
		print('    ***********************')

def detect(chn):
	Led(GPIO.input(BtnPin))    #控制双色LED灯闪烁
	Print(GPIO.input(BtnPin))  #打印按键是否按下的提示消息

def loop():
	while True:
		pass  #pass 不做任何事情,一般用做占位语句。

def destroy():
	GPIO.output(Gpin, GPIO.LOW)       # Green led off
	GPIO.output(Rpin, GPIO.LOW)       # Red led off
	GPIO.cleanup()                     # Release resource

if __name__ == '__main__':     # Program start from here
	setup()
	try:
		loop()
	# When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
	except KeyboardInterrupt:  
		destroy()

2.6.2 倾斜开关实验

带有金属球的球形倾斜开关。它用于检测小角度的倾斜。
倾斜模块引脚,从上往下依次是:
引脚S接Board11
引脚中间VCC接5V
引脚-接GND

小双色LED灯引脚,从上往下依次是:
引脚-接GND
引脚中间R接Board12
引脚G接Board13

import RPi.GPIO as GPIO

TiltPin = 11
Rpin   = 12
Gpin   = 13

def setup():
	GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
	GPIO.setup(Gpin, GPIO.OUT)     # Set Green Led Pin mode to output
	GPIO.setup(Rpin, GPIO.OUT)     # Set Red Led Pin mode to output
	# Set BtnPin's mode is input, and pull up to high level(3.3V)
	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):        #控制双色LED灯闪烁的函数
	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('    *************')

def detect(chn):
	Led(GPIO.input(TiltPin))    #控制双色LED灯闪烁
	Print(GPIO.input(TiltPin))  #打印按键是否倾斜的提示消息
def loop():
	while True:
		pass

def destroy():
	GPIO.output(Gpin, GPIO.LOW)       # Green led off
	GPIO.output(Rpin, GPIO.LOW)       # Red led off
	GPIO.cleanup()                     # Release resource

if __name__ == '__main__':     # Program start from here
	setup()
	try:
		loop()
	# When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
	except KeyboardInterrupt:  
		destroy()

2.6.3 震动开关实验

振动开关也称为弹簧开关或振动传感器,是一种电子开关。它会产生振动力,并将结果传送给电路装置,从而触发其工作。它包含以下部分:导电振动弹簧,开关主体,触发销和包装壳。
震动模块引脚,从上往下依次是:
引脚S接Board11
引脚中间VCC接5V
引脚-接GND

小双色LED灯引脚,从上往下依次是:
引脚-接GND
引脚中间R接Board12
引脚G接Board13

import RPi.GPIO as GPIO
import time

VibratePin = 11
Rpin   = 12
Gpin   = 13

tmp = 0

def setup():
	GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
	GPIO.setup(Gpin, GPIO.OUT)     # Set Green Led Pin mode to output
	GPIO.setup(Rpin, GPIO.OUT)     # Set Red Led Pin mode to output
	GPIO.setup(VibratePin, GPIO.IN, pull_up_down=GPIO.PUD_UP) 
   # Set BtnPin's mode is input, and pull up to high level(3.3V)


def Led(x):	#控制双色LED灯闪烁的函数
	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):	#打印按键是否切换开关的提示消息
	global tmp
	if x != tmp:
		if x == 0:
			print('    **********')
			print('    *     ON *')
			print('    **********')
	
		if x == 1:
			print('    **********')
			print('    * OFF    *')
			print('    **********')
		tmp = x
def loop():
	state = 0
	while True:
		if GPIO.input(VibratePin):  #每当振动产生时
			state = state + 1
			if state > 1:
				state = 0
			Led(state)
			Print(state)
			time.sleep(1)
def destroy():
	GPIO.output(Gpin, GPIO.LOW)       # Green led off
	GPIO.output(Rpin, GPIO.LOW)       # Red led off
	GPIO.cleanup()                     # Release resource

if __name__ == '__main__':     # Program start from here
	setup()
	try:
		loop()
	# When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
	except KeyboardInterrupt:  
		destroy()

2.6.4 迷你磁簧开关实验

磁簧开关(Reed Switch)也称之为干簧管,它是一个通过所施加的磁场操作的电开关。基本型式是将两片磁簧片密封在玻璃管内,两片虽重叠,但中间间隔有一小空隙。当外来磁场时将使两片磁簧片接触,进而导通。 一旦磁体被拉到远离开关,磁簧开关将返回到其原来的位置。可以用来计数或限制位置。

迷你磁簧模块引脚,从上往下依次是:
引脚S接Board11
引脚中间VCC接5V
引脚-接GND

小双色LED灯引脚,从上往下依次是:
引脚-接GND
引脚中间R接Board12
引脚G接Board13

import RPi.GPIO as GPIO
ReedPin = 11
Rpin = 12
Gpin = 13

def setup():
	GPIO.setmode(GPIO.BOARD)  # Numbers GPIOs by physical location
	GPIO.setup(Gpin, GPIO.OUT)  # Set Green Led Pin mode to output
	GPIO.setup(Rpin, GPIO.OUT)  # Set Red Led Pin mode to output
	# Set BtnPin's mode is input, and pull up to high level(3.3V)
	GPIO.setup(ReedPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
	GPIO.add_event_detect(ReedPin, GPIO.BOTH, callback=detect, bouncetime=200)
def Led(x):	#控制双色LED灯闪烁的函数
	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('    *   Detected Magnetic Material!   *')
		print('    ***********************************')

def detect(chn):
	Led(GPIO.input(ReedPin))    #控制双色LED灯闪烁的函数
	Print(GPIO.input(ReedPin))  #打印检测到磁性物质
	print(GPIO.input(ReedPin)) #验证GPIO.input(ReedPin)的值
def loop():
	while True:
		pass

def destroy():
	GPIO.output(Gpin, GPIO.LOW)  # Green led off
	GPIO.output(Rpin, GPIO.LOW)  # Red led off
	GPIO.cleanup()   # Release resource

if __name__ == '__main__':  # Program start from here
	setup()
	try:
		loop()
	# When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
	except KeyboardInterrupt:
		destroy()

2.7 蜂鸣器实验

蜂鸣器是音频信号装置,蜂鸣器可分为有源蜂鸣器和无源蜂鸣器。
有源蜂鸣器直接接上额定电源就可以连续发声;
无源蜂鸣器则和电磁扬声器一样,需要接在音频输出电路中才能周期性地振动发声。

有源蜂鸣器内置振荡源,所以通电时会发出声音。但无源蜂鸣器没有这种内置振荡源,所以如果使用直流信号,他不会发出轰鸣声;相反,你需要使用频率在2k到5k之间的方波来驱动它。由于有内置振荡电路,所以有源蜂鸣器通常比无源蜂鸣器昂贵。

2.7.1 有源蜂鸣器

引脚S接Board11
引脚中间VCC接3.3V
引脚-接GND
通过改变输入到蜂鸣器的信号电平,低电平是响,高电平是停止响来控制蜂鸣器。

import RPi.GPIO as GPIO
import time

Buzzer = 11    # pin11

def setup(pin):
	global BuzzerPin
	BuzzerPin = pin
	GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
	GPIO.setup(BuzzerPin, GPIO.OUT)
	GPIO.output(BuzzerPin, GPIO.HIGH)

def on():
	GPIO.output(BuzzerPin, GPIO.LOW)	
	#低电平是响
def off():
	GPIO.output(BuzzerPin, GPIO.HIGH)
	#高电平是停止响
def beep(x):    #响3秒后停止3秒
	on()
	time.sleep(x)
	off()
	time.sleep(x)

def loop():
	while True:
		beep(3)

def destroy():
	GPIO.output(BuzzerPin, GPIO.HIGH)
	GPIO.cleanup()                     # Release resource

if __name__ == '__main__':     # Program start from here
	setup(Buzzer)
	try:
		loop()
	# When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
	except KeyboardInterrupt:  
		destroy()

2.7.2 无源蜂鸣器

引脚S接Board11
引脚中间VCC接3.3V
引脚-接GND
使用无源蜂鸣器,只要输出不同频率的PWM波,即可发出不同的音符。不同的音符组合起来就是一个曲子了。

import RPi.GPIO as GPIO
import time

Buzzer = 11

CL = [0, 131, 147, 165, 175, 196, 211, 248]          
   # C调低音符的频率列表,第一位为0是占位用,后面不使用
   #除0外,依次是1do、2re、3mi、4fa、5sol、6la、7si
CM = [0, 262, 294, 330, 350, 393, 441, 495]          
   # Frequency of Middle C notes

CH = [0, 525, 589, 661, 700, 786, 882, 990]           
  # Frequency of High C notes

song_0 = [CL[1], CL[2], CL[3], CL[4], CL[5], CL[6], CL[7],
	CM[1], CM[2], CM[3], CM[4], CM[5], CM[6], CM[7], 
	CH[1], CH[2], CH[3], CH[4], CH[5], CH[6], CH[7] ]
 # song_0表示从低音do依次到高音si的音符列表
beat_0 = [2, 2, 2, 2, 2, 2, 2,                         
	2, 2, 2, 2, 2, 2, 2,  
	2, 2, 2, 2, 2, 2, 2  ]
 # song_0的节拍, 2表示2个1/8节拍。一个1/8节拍为0.5秒延迟。
song_1 = [CM[3], CM[5], CM[6], CM[3], CM[2], CM[3], CM[5], CM[6], 
	CH[1], CM[6], CM[5], CM[1], CM[3], CM[2], CM[2], CM[3], 
	CM[5], CM[2], CM[3], CM[3], CL[6], CL[6], CL[6], CM[1],
	CM[2], CM[3], CM[2], CL[7], CL[6], CM[1], CL[5] ]
# Notes of song1
beat_1 = [1, 1, 3, 1, 1, 3, 1, 1,                         
	1, 1, 1, 1, 1, 1, 3, 1, 
	1, 3, 1, 1, 1, 1, 1, 1, 
	1, 2, 1, 1, 1, 1, 1, 1, 
	1, 1, 3 ]
# Beats of song 1, 1 means 1/8 beats
song_2 = [CM[1], CM[1], CM[1], CL[5], CM[3], CM[3], CM[3], CM[1], 
	CM[1], CM[3], CM[5], CM[5], CM[4], CM[3], CM[2], CM[2], 
	CM[3], CM[4], CM[4], CM[3], CM[2], CM[3], CM[1], CM[1], 
	CM[3], CM[2], CL[5], CL[7], CM[2], CM[1]]
# Notes of song2
beat_2 = [1, 1, 2, 2, 1, 1, 2, 2,                         
	1, 1, 2, 2, 1, 1, 3, 1, 
	1, 2, 2, 1, 1, 2, 2, 1, 
	1, 2, 2, 1, 1, 3 ]
# Beats of song 2, 1 means 1/8 beats,0.5 second


def setup():
	GPIO.setmode(GPIO.BOARD)  # Numbers GPIOs by physical location
	GPIO.setup(Buzzer, GPIO.OUT) # Set pins' mode is output
	global Buzz # Assign a global variable to replace GPIO.PWM 
	Buzz = GPIO.PWM(Buzzer, 440)  # 440 is initial frequency.
	Buzz.start(50) # Start Buzzer pin with 50% duty ration
def loop():
    while True:
  #--------------------------------------------
        print('\n\n    Playing Low C notes...')
        for i in range(0, 7):         # Play song 0的C调低音音符
            Buzz.ChangeFrequency(song_0[i])
            # 根据歌曲的音符改变频率
            print(i)      #打印i的值
            time.sleep(beat_0[i] * 0.5)
            # 根据节拍列表每个音符延迟1秒,2 beats*0.5s=1s
        print('\n\n    Playing Middle C notes...')
        for i in range(7, 14):         # Play song 0
            Buzz.ChangeFrequency(song_0[i]) # Change the frequency along the song note
            print(i)
            time.sleep(beat_0[i] * 0.5)     # delay a note for beat * 0.5s
        print('\n\n    Playing High C notes...')
        for i in range(14, 21):         # Play song 0
            Buzz.ChangeFrequency(song_0[i]) # Change the frequency along the song note
            print(i)
            time.sleep(beat_0[i] * 0.5)     # delay a note for beat * 0.5s
        Buzz.ChangeFrequency(3)  #一首曲子结束,间隔3秒
        time.sleep(3)
   #--------------------------------------------
        print('\n    Playing song 1...')
        for i in range(0, len(song_1)):         # Play song 1
            Buzz.ChangeFrequency(song_1[i]) # Change the frequency along the song note
            time.sleep(beat_1[i] * 0.5)     # delay a note for beat * 0.5s
        Buzz.ChangeFrequency(3) #一首曲子结束,间隔3秒
        time.sleep(3)                          
    #--------------------------------------------
        print('\n\n    Playing song 2...')
        for i in range(0, len(song_2)):         # Play song 1
            Buzz.ChangeFrequency(song_2[i]) # Change the frequency along the song note
            time.sleep(beat_2[i] * 0.5)     # delay a note for beat * 0.5s
        Buzz.ChangeFrequency(3)
        time.sleep(3)
def destory():
	Buzz.stop()      # Stop the buzzer
	GPIO.output(Buzzer, 1) # Set Buzzer pin to High
	GPIO.cleanup()  # Release resource

if __name__ == '__main__': # Program start from here
	setup()
	try:
		loop()
	# When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
	except KeyboardInterrupt:       
		destory()

2.8 土壤湿度传感器

土壤湿度检测模块如下:
树莓派-5-GPIO的应用实验_第5张图片
首先,传感器模块选的是常见的YL-69,电阻型传感器,如上图。
树莓派-5-GPIO的应用实验_第6张图片
YL-69有模拟输出(AO口)和数字输出(DO口),由于树莓派的GPIO只支持数字输出,所以AO口悬空。
将VCC连接物理接口2,
GND引脚连接物理接口14,
DO引脚连接物理接口40,对应的BCM编码为21。
树莓派-5-GPIO的应用实验_第7张图片
电源连通之后,电源灯会亮起:
树莓派-5-GPIO的应用实验_第8张图片
调节传感器上的旋钮(蓝色的菊花),这个是灵敏度的校准,也是个阈值,直到在干燥空气中不让DO-LED亮起。

倒一杯水,或者没有水的话,舔一下传感器的触角,DO-LED应该会亮起,这时候就校准好了。然后就能爆代码了!

这个传感器在干燥时候输出的是高电平,遇到水输出低电平。根据这个原理,把代码爆成这样:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
import RPi.GPIO as GPIO
import time

channel = 21 #管脚40,参阅树莓派引脚图,物理引脚40对应的BCM编码为21

GPIO.setmode(GPIO.BCM)
GPIO.setup(channel, GPIO.IN)

while True:
   if GPIO.input(channel) == GPIO.LOW:
           print("土壤检测结果:潮湿")
   else:
           print("土壤检测结果:干燥")
   time.sleep(1)

运行,当把传感器触角放在空气和放在水中时,会显示不同的输出
树莓派-5-GPIO的应用实验_第9张图片

2.9 温湿度传感器DHT11

DHT11温湿度传感器编程思路以及代码的实现
树莓派下DHT11温湿度传感器控制程序(python)

利用树莓派连接DHT11读取温湿度
参考Adafruit Python DHT现成包
参考树莓派与DHT11温度传感器的那些事儿
DHT11是一个数字传感器,由两个不同的传感器组成一个封装。该传感器包含一个NTC(负温度系数)温度传感器,一个电阻型湿度传感器和一个8位微控制器,用于转换来自这些传感器的模拟信号并产生数字输出。

NTC(Negative Temperature Coefficient)是指随温度上升电阻呈指数关系减小、具有负温度系数的热敏电阻现象和材料。

DHT11是一款有已校准数字信号输出的温湿度传感器。 其精度湿度±5%RH, 温度±2℃,量程湿度20-90%RH, 温度0~50℃。

(2)DHT11和RaspberryPi接线图
将DHT11传感器的VCC和GND引脚连接到RaspberryPi的+5V和GND,然后将传感器的数据输出连接到GPIO4,即RaspberryPi的物理引脚7。

树莓派-5-GPIO的应用实验_第10张图片
为何在树莓派上用dht11测温湿度得到的两个数值一直都是255?
按照时序要求来 255一看就是没按照时序 读数全是1 数据线根本没被启动才会读出来ff。

sudo apt-get update
sudo apt-get install build-essential python-dev
(1)从 GitHub 获取 Adafruit 库:
sudo git clone https://github.com/adafruit/Adafruit_Python_DHT.git
cd Adafruit_Python_DHT
(2)给 Python 2 和 Python 3 安装该库:
sudo python setup.py install
sudo python3 setup.py install

树莓派4b 使用dht11/dht22测温注意
由于下载的Adafruit_DHT驱动未支持4b处理器BCM2711,需在打开文件
/home/pi/Adafruit_Python_DHT/Adafruit_DHT/platform_detect.py

在代码段
elif match.group(1) == 'BCM2837':
   # Pi 3b+
   return 3
后添加如下代码段
elif match.group(1) == 'BCM2711':
   # Pi 4b
   return 3
然后输入命令安装Adafruit Python DHT Sensor函数库
cd Adafruit_Python_DHT/
sudo python setup.py install
sudo python3 setup.py install

2.9.1 使用示例程序

Adafruit 提供了示例程序,运行下面的命令测试。

cd /home/pi
cd Adafruit_Python_DHT
cd examples
python AdafruitDHT.py 11 4

树莓派-5-GPIO的应用实验_第11张图片

2.9.2 使用Adafruit库自定义Python程序

import Adafruit_DHT
# 设置传感器类型DHT11,DHT22或AM2302
sensor=Adafruit_DHT.DHT11
# Set GPIO sensor is connected to
gpio=4
# 读取15次,每次间隔2秒
humidity, temperature = Adafruit_DHT.read_retry(sensor, gpio)
if humidity is not None and temperature is not None:
  print('Temp={0:0.1f}*C  Humidity={1:0.1f}%'.format(temperature, humidity))
else:
  print('Failed to get reading. Try again!')

树莓派-5-GPIO的应用实验_第12张图片

2.5 温度传感器DS18b20

参考树莓派+温度传感器实现室内温度监控

树莓派-5-GPIO的应用实验_第13张图片
(1)允许单总线接口

$ sudo raspi-config
进入interfacing options
enable one-wire interface
重启

(2)完成接线
该模块使用的是单总线数字温度传感器 DS18B20,外界供电电压范围为 3.0 V 至 5.5 V,无需备用电源。
测量温度范围为-55 ° C 至+125 ℃ , 华氏相当于是67 ° F 到 257° F。
其中 -10 °C 至+85 ° C 范围内精度为±0.5 ° C 。

GND-----Board----9
DQ-------Board----7
VCC-----Board----1

(3)升级内核
$ sudo apt-get update
$ sudo apt-get upgrade

3 异常及解决

(1)树莓派4B gpio readall 出现Oops - unable to determine board type… model: 17
树莓派使用GPIO接口是基于wiringPi的。
树莓派-5-GPIO的应用实验_第14张图片解决方案:
$wget https://project-downloads.drogon.net/wiringpi-latest.deb
#sudo dpkg -i wiringpi-latest.deb
树莓派-5-GPIO的应用实验_第15张图片

你可能感兴趣的:(树莓派,自动驾驶,物联网,linux)