在上一篇博客中,咱们介绍了在树莓派中使用模数转换芯片的基本方法,若是你对上一篇博文中介绍的内容已经有了深刻的理解,那后面的应用试验对你来讲将很是容易。若是不是,那么我建议你先将以前介绍的内容在研究一下:python
https://blog.51cto.com/u_11643026/3180290canvas
如今,若是你决定继续本篇博客的学习,那么我认为你已经了解了PCF8591芯片的基本用法,明白了PCF8591的接线方式,I2C总线的基本工做原理以及PCF8591的设置命令的意义和读数据的方法。markdown
在本系列博客的上一篇文章中,咱们经过读取PCF8591实验模块自带的可调节电压输出、光敏传感器和热敏传感器实现了对当前环境信息的的读取,除了能够读取当前设置的输出电压外,咱们还能够得到当前的环境的温度和亮度。PCF8591实验模块自带的传感器可让咱们很方便的进行实验,其实在实际应用中,更多时候咱们须要从AIN0到AIN3引脚来获取外接传感器的模拟信号。如今,咱们尝试下经过AIN0和AIN1两个输入引脚来获取外接光敏和热敏传感器的数据。ide
咱们这里的小实验将使用光敏和热敏传感器。函数
光敏传感器可以感应光纤的明暗变化,其实现此功能的核心在于光敏电阻,只作光敏电阻的经常使用材料有硫化镉、硫化铝等。这些材料在特定波长的光波照射下,其阻值会产生明显的变化。本次实验,咱们使用的光敏传感器模块以下图所示:oop
能够看到,此模块的核心是一个光敏电阻,提供了可调节灵敏度的功能单元和两个LED指示灯,其中一个LED是电源指示灯,接通电源后会亮,另外一个LED灯是电平指示灯,当光亮达到阈值时,输出引脚输出低电平,此LED灯亮,当光亮度较暗时,输出引脚输出高电平,此LED灯不亮。咱们再看此模块的4个引脚:学习
VCC:电源引脚编码
GND:接地引脚3d
DO:数字信号输出引脚(高低电平)code
AO:模拟信号输出引脚
本次实验咱们使用的热敏模块的功能与上面将的光敏模块相似,以下图所示:
此热敏模块一样包含两个LED指示灯、灵敏度调节单元和4个引脚,引脚以下:
VCC:电源引脚
GND:接地引脚
DO:数字信号输出引脚(高低电平)
AO:模拟信号输出引脚
本次实验,咱们使用PCF8591读取光敏和热敏传感器的模拟信号,将其转换成数字信号被树莓派程序处理,同时,咱们使用树莓派的GPIO端口来读取传感器自己输出的数字信号,首先,咱们先肯定要使用的PCF8591的输入引脚和要使用的树莓派GPIO引脚。
PCF8591输入引脚使用:AINO和AIN1,其中AINO读取光敏模拟信号,AIN1读取热敏模拟信号。
GPIO输入引脚使用:GPIO17和GPIO18(BCM编码方式),其中17引脚读取光敏数字信号,18引脚读取热敏数字信号。
PCF8591 | 树莓派功能引脚 |
---|---|
SCL | SCL |
SDA | SDA |
GND | GND |
VCC | 5V |
光敏传感器 | 树莓派/PCF8591 |
---|---|
VCC | 树莓派3.3V |
GND | 树莓派GND |
DO | 树莓派GPIO11(物理引脚) |
AO | PCF8591 AIN0 |
热敏传感器 | 树莓派/PCF8591 |
---|---|
VCC | 树莓派3.3V |
--- | --- |
GND | 树莓派GND |
--- | --- |
DO | 树莓派GPIO12(物理引脚) |
--- | --- |
AO | PCF8591 AIN1 |
--- | --- |
连线最终以下图所示:
和以前相比,咱们此次直接在树莓派上链接了3个元件,连线也复杂了不少,只要按照上面的表格,注意引脚的正确便可。
步入正题,先上代码:
#coding:utf-8 #SMBus (System Management Bus,系统管理总线) import smbus #在程序中导入“smbus”模块 import RPi.GPIO as GPIO import time bus = smbus.SMBus(1) #建立一个smbus实例 # 经过PCF8591读取模拟信号 # 数据亮度的模拟数据 def readLight(): #发送一个控制字节到设备 表示要读取AIN0通道的数据 bus.write_byte(0x48,0x40) bus.read_byte(0x48) # 空读一次,消费掉无效数据 return bus.read_byte(0x48) # 返回某通道输入的模拟值A/D转换后的数字值 def readTemperature(): #发送一个控制字节到设备 表示要读取AIN1通道的数据 bus.write_byte(0x48,0x41) bus.read_byte(0x48) # 空读一次,消费掉无效数据 return bus.read_byte(0x48) # 返回某通道输入的模拟值A/D转换后的数字值 # 经过GPIO读取数字信号 # 设置使用的引脚编码模式 GPIO.setmode(GPIO.BOARD) # 光敏模块的数字输出引脚 BCM 17 LP = 11 # 热敏模块的数字输出引脚 BCM 18 TP = 12 # 引脚初始化 GPIO.setup(LP, GPIO.IN) GPIO.setup(TP, GPIO.IN) while True: print('--------分割线----------') print('亮度数字信号:', GPIO.input(LP)) print('亮度模拟信号:', readLight()) print('温度数字信号:', GPIO.input(TP)) print('温度模拟信号:', readTemperature()) time.sleep(2)
上面的代码有着比较详尽的注释,这里咱们无需多说,在树莓派上运行此代码,便可观察到控制台的数据输出。
若是你顺利完成了上面的实验,先别急着庆祝,你会发现,和本系列前面几篇博客的内容较比,到目前为止咱们并无介绍新的知识,同时也没有作什么新颖的事情。的确如此,可是经过上面实验的练习,能够帮助你更深刻的理解数模/模数转换的应用场景,而且让你可以更加灵活的对I2C总线与通用GPIO串口结合进行使用。下面咱们要来作一些好玩的事情了,不知道你小时候是否有玩过“大把机”,这是一种摇杆游戏机,摇杆能够朝上下左右4个方向转动,也能够从中间按下。一般,上下左右用来控制游戏人物的行动方向,按下用来进行人物跳跃。如今,咱们要来作一个简单的游戏,为树莓派链接操纵杆,控制游戏程序页面上圆球的行为,其中方向控制圆球的移动,按下操纵杆则使圆球变色。
此实验所使用的操纵杆以下图所示:
能够看到,此元件有5个引脚:
GND:接地引脚
+5V:5V电源引脚
VRX:横向坐标模拟信号输出引脚
VRY:纵向坐标模拟信号输出引脚
SW:按钮数字信号输出引脚
操做杆内部实际上封装了双向的电阻器,其阻值会根据摇杆的方向变更产生变化,从而影响引脚信号的产生变化。
我相信,如今连线对你来讲应该是最简单的工做了。操纵杆有模拟信号输出同时也有数字信号输出,咱们依然须要结合PCF8591与树莓派GPIO一块儿使用。关于PCF8591的接线上面有介绍,这里再也不重复。操做杆的接线方式以下:
操纵杆 | 树莓派/PCF8591 |
---|---|
GND | 树莓派GND |
+5V | 树莓派5.5V |
VRX | PCF8591 AIN0 |
VRY | PCF8591 AIN1 |
SW | 树莓派GPIO 11(物理引脚) |
对于本实验来讲,有涉及到UI开发,咱们依然采用Python自带的Tkinter库,其有很好的移植性,而且其提供了Canvas画布,咱们能够灵活的渲染所须要的图形。示例代码以下:
#coding:utf-8 # 导入UI模块 import tkinter as Tkinter #SMBus (System Management Bus,系统管理总线) import smbus #在程序中导入“smbus”模块 import RPi.GPIO as GPIO # 导入树莓派GPIO模块 import time # 导入定时器模块 import threading # 主页面设置 top = Tkinter.Tk() top.geometry('500x300') top.title("操纵杆控制圆球") # 当前圆球的坐标 currentX = 0 currentY = 0 # 当前圆球的颜色是否红色 currentColor = True # 进行窗口的初始化 canvas = Tkinter.Canvas(top, width=500, height=300, borderwidth=0, highlightthickness=0) canvas.grid() # 进化画布的初始化 circle = canvas.create_oval(currentX, currentY, 100, 100, fill="red", outline="") # 定义移动圆球的方法 def moveCircle(c, x, y): global currentX, currentY moveX = x moveY = y if x >= 0: if x + currentX > 400: moveX = 400 - currentX currentX = 400 else: currentX += x else: if x + currentX < 0: moveX = -currentX currentX = 0 else: currentX += x if y >= 0: if y + currentY > 200: moveY = 200 - currentY currentY = 200 else: currentY += y else: if y + currentY < 0: moveY = -currentY currentY = 0 else: currentY += y canvas.move(c, moveX, moveY) # 定义改变圆球颜色的方法 def changeColor(c): global currentColor canvas.itemconfig(c, fill= 'red' if currentColor else 'blue') currentColor = not currentColor bus = smbus.SMBus(1) #建立一个smbus实例 # 经过PCF8591读取模拟信号 # 摇杆X引脚的模拟数据 def readX(): #发送一个控制字节到设备 表示要读取AIN0通道的数据 bus.write_byte(0x48,0x40) bus.read_byte(0x48) # 空读一次,消费掉无效数据 return bus.read_byte(0x48) # 返回某通道输入的模拟值A/D转换后的数字值 # 摇杆Y引脚的模拟数据 def readY(): #发送一个控制字节到设备 表示要读取AIN1通道的数据 bus.write_byte(0x48,0x41) bus.read_byte(0x48) # 空读一次,消费掉无效数据 return bus.read_byte(0x48) # 返回某通道输入的模拟值A/D转换后的数字值 # 经过GPIO读取数字信号 # 设置使用的引脚编码模式 GPIO.setmode(GPIO.BOARD) # 按键使用引脚 BCM 17 BTN = 11 # 引脚初始化 设置下拉高电平 GPIO.setup(BTN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # 建立定时器函数,用来检查摇杆动做 def fun_timer(): global timer x = readX() y = readY() press = GPIO.input(BTN) print('X:', x) print('Y:', y) print('按钮:', press) if x <= 10: moveCircle(circle, -10, 0) if x >= 245: moveCircle(circle, 10, 0) if y <= 10: moveCircle(circle, 0, -10) if y >= 245: moveCircle(circle, 0, 10) timer = threading.Timer(0.2, fun_timer) timer.start() timer = threading.Timer(0.2, fun_timer) timer.start() # 定义GPIO输入端口的回调 def btnCallback(channel): if not GPIO.input(channel): changeColor(circle) # 添加输入引脚电平变化的回调函数 GPIO.add_event_detect(BTN, GPIO.FALLING, callback=btnCallback, bouncetime=200) top.mainloop()
上面的代码有些长,可是有详尽的注释,关于UI开发方面的内容不是咱们本系列博客的重点,这里咱们不作过多介绍。moveCircle函数是核心的圆球移动函数,内部经过边界断定逻辑能够确保圆球不会移动到视图界面外。changeColor方法用来修改圆球的颜色,这里咱们让每次按键后在红绿颜色间进行切换。readX和readY函数咱们无需作过多介绍了,其经过PCF8591的AIN0和AIN1来传输摇杆的横纵坐标信号。GPIO的相关操做咱们也很是熟悉了,咱们经过注册回调函数来监听操做杆按钮按下的行为。
在树莓派上运行上面的代码,尝试操做下,感觉下使用操纵杆控制页面元素的喜悦吧。
观察上面的示例代码,你会发现,咱们使用了一些临界值来做为触发方向动做的阈值,例如10,245这种,这是由于PCF8591是8位的数模转换模块,即其转换出的数字量在0-255之间(包括0和255),对于本实验来讲,咱们并无让摇杆元件传输的模拟量发挥正真的做用,想一下,你是否可以根据操做杆的旋转程度来调整圆球移动的速度呢?动手试试吧!
专一技术,懂的热爱,愿意分享,作个朋友
QQ:316045346