如果你跟随本系列博客阅读到此,那么我相信,你已经能够使用树莓派的GPIO接口做许多有趣的事情了。但是不知你是否有发现,GPIO功能接口无论是输入还是输出,都只有高电平或低电平这两种选项,抽象到数学中,即只有0和1两种数值选项,这种离散数值的信号我们将其称为数字信号。更多时候,我们需要使用的元件并非只有开和关两种状态,这时候就需要用数值连续的信号来表达,这种连续的信号我们称之为模拟信号。本篇博客,我们将初步涉猎在树莓派上如何处理模拟信号。
一、树莓派模数转换模块基础
其实,直接使用GPIO的功能引脚并非完全不能处理模拟信号,我们知道无论需要多少种状态信号,通过GPIO的电平高低来处理都是无法实现的,但是你一定还记得PWM脉冲宽度调制技术,这其实就是一种将数字信号转换成模拟信号的方式,例如在前面的RGB实验中,我们曾使用PWM技术来控制3种发光二极管的发光明暗程度,如果将二极管的全亮定义为值1,全暗定义为值0,则在明暗之间可以通过设置不同的占空比来实现,例如需要亮度值为0.5时,只需要设置占空比为50%即可。通过PWM技术,虽然我们每个精确的时刻输出的依然是数字信号(0或1),但最终作用到元件上的信号是模拟的,这就完成了最简单的数模转换。
同样的道理,对于某些外接元件来说,其输出的信号也可能是模拟的,例如温度、光亮传感器,如果直接通过GPIO来获取这些元件的信号是模拟的,解析会非常困难,这时我们就需要一个数模转换模块来帮助我们将其转换为数字信号。
1、关于模数转换
数模转换器,又称D/A转换器,简称DAC。用来把数字量转换成模拟量的器件,关于数模转换器的电路和工作原理,不在本篇博客的核心讨论范围内,如果你有兴趣可以查阅数字电路和模拟电路的相关书籍。对其对应,模数转换器,又称为A/D转换器,简称ADC。用来把模拟信号转换为数字信号。树莓派本身没有集成模数转换模块,我们需要外接一个转换单元,在本实验中,我们采用基于PCF8591芯片的模数转换模块。
2、PCF8591芯片
其AIN0到AIN3都是模拟输入引脚,其用来输入外接元件的模拟信号,它还有1个模拟输入引脚AOUT,用来输出模拟信号。
A0,A1,A2这3个引脚用来进行硬件地址编程,在嵌入式编程中,每个可编程的引脚我们将其理解为一个二进制位,3个引脚可以表达0-7这8个数字(000,001,010,011,100,101,110,111),因此在同一个I2C总线上,实际可以同时连接8个PCF8591芯片进行工作(I2C总线我们后面会介绍)。
VSS是接地引脚,VDD是工作电压引脚,AGND是模拟信号接地引脚,VREF是基准电源引脚。
OSC引脚为外部时钟输入端或内部时钟输出端,EXT如果接地,表示使用内部时钟,否则表示使用外部时钟。
SCL和SDA是I2C总线接口引脚,我们使用这两个引脚来进行数据传输,后面会介绍。
下面是PCF8591工作的电路原理图:
温馨提示,在阅读本篇博客时,难度可能要比本系列的前几篇博客大,你可能会感觉云里雾里,不要着急,后面我们会通过实验来帮助你理解模数转换以及I2总线的工作方式,掌握了这些,你的树莓派开发本领将进一步提升。
3、PCF8591实验模块
上一小节我们介绍了PCF8591芯片的引脚用法,实际在本实验中,我们并不会直接使用这个芯片,而是使用基于PCF8591芯片的一个工作模块,如下图所示:
如上图所示,此模块功能非常丰富,我们逐一介绍。
左边一列引脚作用分别为:
AOUT :内部芯片的DA 输出接口
AIN0 :内部芯片的模拟输入接口 0
AIN1 :内部芯片的模拟输入接口 1
AIN2 :内部芯片的模拟输入接口 2
AIN3 :内部芯片的模拟输入接口 3
右边一列引脚的作用为:
SCL :I2C 通信接口
SDA :I2C 通信接口
GND :模块地
VCC :电源接口 外接 3.3v-5v
除此之外,P4,P5,P6三个地方我们可以通过接短路帽的方式来选择是否接入相关功能。
P4:接上短路帽,表示将热敏电阻接入电路。
P5:接上短路帽,表示将光敏电阻接入电路。
P6:接上短路帽,表示将0-5V的可调节电压接入电路。
如果P4,P5,P6都不接短路帽,可以使用外部元件通过4个AIN引脚进行输入。关于这几个功能如何使用,后面我们会介绍。
此模块的工作示意图如下:
4.I2C总线基础知识
I2C总线是有Philips公司开发的一种简单、双向的同步串行总线。只需要两根线即可实现连接在总线上的设备间进行通信。在I2C总线的通讯协议中,SDA用来传输数据,SCL是串行的时钟线,传输流程如下图所示:
只看图你可能会感觉非常疑惑,结合树莓派工作起来,其实要理解并不复杂,在I2C协议中,树莓派就是主机,连接的PCF8591就是从机,主机与从机间无论是发送数据还是接受数据,都是由主机先发起,形象化的流程如下:
1.主机触发开始通信条件(SDA和SCL电平满足一定条件)。
2.通过地址找到要通信的从机(即PCF8591的3个地址编程引脚设置的地址)。
3.主机发送工作命令,即指定要从从机读数据还是写数据,读哪个通道的数据等(PCF8591有4个输入通道)。
4.收到数据会发送ACK回执。
5.结束此次通讯后,主机发送完成指令给从机(SDA和SCL电平满足一定条件)。
5.几个重要的指标概念
1.位数
ADC元件的位数非常重要,它描述了一种可读概念,以PCF8591为例,其实8位的数模转换芯片,也就是说其输出的数字量是0到255之间的数值,一共256种(2的8次方)。
2.基准电压
基准电压用来标准数模转换芯片输出的数值与电压之间关系,例如基准电压为5V,则0到255这256个刻度相当于将5V的电压平均分成了255份,数值没增加1,相当于电压约增加0.019V。
二、实验:测定温度和光亮度
现在,我们已经准备好了需要使用到的基础知识,可以开始我们的试验了。PCF8591自带光感与温度传感器,我们尝试使用这两个传感器来读取环境的温度与亮度。
1、连线
首先,我们可以先使用3个短路帽将PCF8591模块的P4、P5、P6都进行短接,如下图所示:
短接后,相当于我们将PCF8591模块自带的可调节输出电压、光感信号输出和温度信号输出都接入了电路,可以直接通过I2C总线对其数据进行获取。
之后,我们将PCF8591模块模块的SCL、SDA分别连接树莓派对应功能的引脚,GND进行接地,VCC接5V。关于找到树莓派上这些引脚的位置,可以参考下面博客:
https://my.oschina.net/u/2340880/blog/5123429
笔者这里使用扩展板来接线,会更加直观方便,如下图所示:
现在,我们已经完成了接线部分的工作。
2、代码编写
因为需要使用到树莓派的I2C总线功能,在开始编码前,我们需要将树莓派的I2C功能开启,打开树莓派的配置页面,在其interfaces选项中打开SPI和I2C选项,如下图所示。
我们先将完整的实验代码奉上:
#coding:utf-8
#SMBus (System Management Bus,系统管理总线)
import smbus #在程序中导入“smbus”模块
import time
bus = smbus.SMBus(1) #创建一个smbus实例
# 数据读取的方法
def read(chn): #channel
if chn == 0:
#发送一个控制字节到设备 表示要读取AIN0通道的数据
bus.write_byte(0x48,0x00)
if chn == 1:
#发送一个控制字节到设备 表示要读取AIN1通道的数据
bus.write_byte(0x48,0x01)
if chn == 2:
#发送一个控制字节到设备 表示要读取AIN2通道的数据
bus.write_byte(0x48,0x02)
if chn == 3:
#发送一个控制字节到设备 表示要读取AIN3通道的数据
bus.write_byte(0x48,0x03)
bus.read_byte(0x48) # 空读一次,消费掉无效数据
return bus.read_byte(0x48) # 返回某通道输入的模拟值A/D转换后的数字值
if __name__ == "__main__":
while True:
print('电位计 AIN3 = ', 0.0196 * read(3)) #电位计模拟信号转化的数字值
print('光敏电阻 AIN0 = ', 255 - read(0)) #光敏电阻模拟信号转化的数字
print('热敏电阻 AIN1 = ',255-read(1)) #热敏电阻模拟信号转化的数字值
time.sleep(2)