一、前言
接近式传感器是一种用于检测物体距离和接近状态的传感器,具备探测距离、非接触式、抗干扰性能和快速响应等特点。它们在自动化、机器人、安防、工厂生产线以及触摸屏技术等领域得到广泛应用,帮助实现物体检测、位置控制和安全保护等功能。此次项目通过树莓派RP2040来控制VCNL4010芯片,以达到能够检测的功能。
二、芯片介绍
1.RP2040:
本次项目用的是12指神探 - 基于RP2040的逻辑/协议/信号调试助手(十二指神探)用于控制接近式传感器:
十二指神探
硬件技术规格:
- 基于RP2040微控制器
- 板上2MB Flash
- 板上12MHz晶体
- 板上有5V转3.3V 的同步降压转换芯片,提供最高800mA电流
- 板上一颗红色LED用来指示3.3V正常
- 板上一颗绿色LED用来提供给编程使用
- 做成双排2.54mm间距的连接器,可以方便插在面包板上或其它扩展板上,灵活地支持各种功能
管脚定义
2.VNCL4010:
VCNL 是 Vishay 公司推出的一系列集成了近距离传感器和环境光传感器功能的芯片系列。其中比较常见的型号是 VCNL4010。VCNL4010 是一款完全集成的接近和环境光传感器。全集成意味着封装中包含了红外线发射器。它具有 16 位分辨率。它包括一个信号处理集成电路,具有标准 I2C 通信接口,具有中断功能。
VCNL4010顶部图
VCNL4010底部图
VCNL4010 是一款完全集成的接近和环境光传感器。它将红外线发射器、用于近距离测量的 PIN 光电二极管、环境光传感器和信号处理集成电路集成在一个封装内,并带有一个 16 位 ADC。该器件提供环境光感应,支持传统背光和显示屏亮度自动调节,并提供接近感应,最大限度地减少可能导致掉线和启动摄像头的意外触摸输入。这款独立式单元件的探测距离最远可达 20 厘米(7.9 英寸),大大简化了消费和工业应用中接近传感器的使用和设计,因为无需机械屏障来光学隔离发射器和检测器。
VCNL4010详细方框图
以下是 VCNL4010 芯片的主要功能:
-
接近度测量:VCNL4010 能够测量物体与传感器之间的接近度或距离。通过红外发射器和接收器,它可以发射红外光并测量光的反射,从而计算出物体与传感器之间的距离。这种功能可用于手势识别、物体检测、避障等应用。
-
环境光测量:VCNL4010 内部集成了一个环境光传感器,能够测量周围环境的光强度。它可以检测光照水平的变化,用于自动调节背光亮度、环境光补偿等应用。
-
数字接口:VCNL4010 通过 I²C(Inter-Integrated Circuit)总线与主控制器进行通信。它采用数字接口,使得与微控制器或处理器的连接简单方便,可以轻松集成到各种系统中。
-
低功耗模式:VCNL4010 支持多种低功耗模式,可以降低功耗并延长电池寿命。在不需要连续测量时,可以将芯片置于省电模式,以节约能源。
-
智能滤波和环境补偿:VCNL4010 芯片具备智能滤波算法和环境补偿技术,可以减少杂散光对测量结果的影响,并对环境变化做出补偿,提供更稳定和准确的测量结果。
总之,VCNL4010 芯片结合了接近度传感器和环境光传感器的功能,具备测量接近度和环境光强度的能力,并通过数字接口与主控制器进行通信,适用于多种应用,如手势识别、自动灯光控制、距离检测等。
三、原理框图介绍:
接近式传感器原理图
VCNL4010 使用标准 I2C 2 线接口与 MCU 通信,以读取数据和配置设置,兼容频率高达 3.4MHz 的所有 I2C 模式。标准串行数字接口可访问 "接近信号 "和 "光强度",无需外部控制器进行复杂的计算和编程。此外,当发生接近事件或环境光线变化时,可编程中断功能(路由至 十二指神探插座上的 I/O 引脚)可为主机 MCU 提供唤醒功能,从而无需连续轮询,减少了处理开销。
我使用的是十二指神探CH2与CH3口建立与传感器的I2C通讯,CH2与VCNL4010的4号管脚相连,作为SDA,CH3与5号管脚相连作为SCL,CH0与6号脚相连作为中断(interrupt)。
具体流程:
-
连接硬件:首先,将VCNL4010模块连接到RP2040。通常使用I2C总线来进行通信。确保正确连接模块的电源和地线,并将I2C数据线(SDA)和时钟线(SCL)分别连接到RP2040的对应引脚。
-
初始化:在程序中,首先需要初始化I2C总线和VCNL4010模块。通过设置适当的寄存器配置,可以启用所需的功能,例如环境光感应和近距离接近检测。
-
环境光与接近检测:VCNL4010具有环境光感应功能,可以测量周围环境的光照强度。除了环境光感应,VCNL4010还可以进行近距离接近检测。通过发送命令到VCNL4010,RP2040可以启动近距离接近检测功能。VCNL4010使用红外光发射器和接收器来检测物体与传感器的距离。当有物体靠近传感器时,VCNL4010会输出相应的信号,RP2040可以读取该信号并进行处理。
-
数据处理和应用:RP2040读取VCNL4010的环境光和接近检测数据后,可以根据实际需求进行进一步处理和应用。例如,根据环境光强度调整显示屏亮度,或者根据物体接近程度触发某些操作。
工作流程图
接近式传感器PCB板图
接近式传感器扩展板正面
接近式传感器扩展板背面
四、主要代码片段及其说明
首先进行了VCNL4010的初始化,配置了他的各个寄存器:
VCNL4010_I2CADDR_DEFAULT = const(0x13)
VCNL4010_COMMAND = const(0x80)
VCNL4010_PRODUCTID = const(0x81)
VCNL4010_PROXRATE = const(0x82)
VCNL4010_IRLED = const(0x83)
VCNL4010_AMBIENTPARAMETER = const(0x84)
VCNL4010_AMBIENTDATA = const(0x85)
VCNL4010_PROXIMITYDATA = const(0x87)
VCNL4010_INTCONTROL = const(0x89)
VCNL4010_PROXINITYADJUST = const(0x8A)
VCNL4010_INTSTAT = const(0x8E)
VCNL4010_MODTIMING = const(0x8F)
VCNL4010_MEASUREAMBIENT = const(0x10)
VCNL4010_MEASUREPROXIMITY = const(0x08)
VCNL4010_AMBIENTREADY = const(0x40)
VCNL4010_PROXIMITYREADY = const(0x20)
上面各项都是它的寄存器地址,第一行为I2C的总线地址,后面我们将介绍我们所要用到的地址,例如0x08为开启接近测量,0x10为开启环境光测量,0x80为开启命令,0x8E为开启中断等
然后我们再进行读写函数的定义:
def read_u8(dev, i2c, address):
BUFFER = bytearray(1)
BUFFER[0] = address & 0xFF
i2c.writeto(dev, BUFFER, False)
i2c.readfrom_into(19, BUFFER, True)
return BUFFER[0]
def read_u16BE(dev, i2c, address):
BUFFER = bytearray(1)
BUFFER[0] = address & 0xFF
BUFFER2 = bytearray(2)
BUFFER2[0] = address & 0xFF
i2c.writeto(dev, BUFFER, False)
i2c.readfrom_into(19, BUFFER2, True)
return (BUFFER2[0] << 8) | BUFFER2[1]
def write_u8(dev, i2c, address,val):
BUFFER = bytearray(2)
BUFFER[0] = address & 0xFF
BUFFER[1] = val & 0xFF
i2c.writeto(dev, BUFFER, False)
第一个为用于从指定地址读取单字节数据。将地址按位与上0xFF后赋值给 BUFFER[0],确保地址只占一个字节。使用 i2c.writeto() 方法向指定的设备 dev 写入 BUFFER 数组,并设置 False 参数表示不发送停止位。第二个为于从指定地址读取两个字节的大端序(Big Endian)数据。第三个定义的函数为将指定的地址和值封装到一个字节数组中,并使用I2C总线的writeto()方法将数组内容写入到指定的设备。其中,地址和值都经过处理,确保它们只占一个字节。这样可以向特定设备的特定地址写入一个字节的数据。
定义一个大类为VCNL4010:
class VCNL4010:
def __init__(self,i2c):
self.i2cInterface = i2c
def startup(self, address = VCNL4010_I2CADDR_DEFAULT): #初始化传感器
self.address = address
data = read_u8(self.address, self.i2cInterface, VCNL4010_PRODUCTID)
self.setLEDcurrent(20) #获取当前LED的电流设置,将LED电流设置为20mA
self.setFrequency(VCNL4010_16_625)
write_u8(self.address, self.i2cInterface, VCNL4010_INTCONTROL, 0x08) #使用write_u8函数向指定的地址写入一个字节的数据,
return (data & 0xF0) == 0x20
def setFrequency(self, freq):
write_u8(self.address, self.i2cInterface, VCNL4010_MODTIMING, freq)
def setLEDcurrent(self, current_10mA):
if current_10mA > 20 :
current_10mA = 20
write_u8(self.address, self.i2cInterface, VCNL4010_IRLED, current_10mA)
def getLEDcurrent(self, current_10mA):
return read_u8(self.address, self.i2cInterface, VCNL4010_IRLED)
def readAmbientLux(self):
status = read_u8(self.address, self.i2cInterface, VCNL4010_INTSTAT)
status &= ~0x80
write_u8(self.address, self.i2cInterface, VCNL4010_INTSTAT, status) #进行环境光的测量
write_u8(self.address, self.i2cInterface, VCNL4010_COMMAND, VCNL4010_MEASUREAMBIENT) # 等待结果,然后读取并返回 16 位数值。
while True:
result = read_u8(self.address, self.i2cInterface, VCNL4010_COMMAND)
if result & VCNL4010_AMBIENTREADY:
return read_u16BE(self.address, self.i2cInterface, VCNL4010_AMBIENTDATA)
def readProximity(self):
status = read_u8(self.address, self.i2cInterface, VCNL4010_INTSTAT)
status &= ~0x80
write_u8(self.address, self.i2cInterface, VCNL4010_INTSTAT, status) #进行近距离测量
write_u8(self.address, self.i2cInterface, VCNL4010_COMMAND, VCNL4010_MEASUREPROXIMITY) # 等待结果,然后读取并返回 16 位数值。
while True:
result = read_u8(self.address, self.i2cInterface, VCNL4010_COMMAND)
if result & VCNL4010_PROXIMITYREADY:
return read_u16BE(self.address, self.i2cInterface, VCNL4010_PROXIMITYDATA)
在这里我们控制VCNL4010传感器
第一段初始化传感器,并设置一些默认参数。其中address参数为传感器的I2C地址,默认为VCNL4010_I2CADDR_DEFAULT。在初始化过程中,会首先读取传感器的产品ID,然后设置LED电流为20mA,设置频率为VCNL4010_16_625,配置中断控制寄存器,最后返回初始化结果。
倒数第二段代码为用于读取环境光亮度的值。将status与0x80按位取反并进行位与运算,目的是清除最高比特位上的标志位。再次使用write_u8函数向指定的地址写入一个字节的数据,该地址为self.address,接口为self.i2cInterface,寄存器地址为VCNL4010_INTSTAT,写入的数据为status,即清除了最高比特位上的标志位。通过逻辑与运算判断result的特定比特位是否被置位。如果result的特定比特位被置位,表示环境光测量已经完成,即检测到环境光亮度已经准备好。此时,使用read_u16BE函数从指定的地址读取一个16位的大端字节序的数据,该地址为self.address,接口为self.i2cInterface,寄存器地址为VCNL4010_AMBIENTDATA,将读取的数据作为环境光亮度的值返回。如果result的特定比特位未被置位,则继续循环,直到检测到环境光亮度已经准备好。
最后一段代码为读取接近传感器的值。大致的过程与上述读取环境光亮度的值很相似,只是一些特定的寄存器需要修改。
主函数:
import machine
from machine import I2C
from vcnl4010 import VCNL4010
i2c = I2C(1,scl=machine.Pin(23),sda=machine.Pin(22))
vcnl = VCNL4010(i2c)
vcnl.startup()
for i in range(5):
print("Proximity:", vcnl.readProximity() * 256 / 65535)
通过主函数我们将MicroPython中的machine模块和vcnl4010模块来读取VCNL4010光照和接近传感器的值。配置方法如上,首先导入了vcnl4010模块,并创建了一个VCNL4010对象vcnl,将i2c作为参数传递给VCNL4010的构造函数,以便于初始化VCNL4010传感器。然后,使用vcnl.startup()方法来启动VCNL4010传感器。接下来,进入一个循环,循环5次。在每次循环中,调用vcnl.readProximity()方法来读取接近传感器的值,乘以256除以65535,得到接近传感器的值,并打印输出。
工作运行时图片
五、结语
此传感器有一些功能还没仔细研究,并且也是第一次接触micropython这一类语言,所以有些地方会出错,还望大家提出错误地方,多多包涵。在环境光检测哪里,由于本人操作失误,将环境光换算公式写错,导致出来的数据与实际存在的数据相差太多,所以将此部分删除,并且正在认真钻研中。在此项目中,学会如何使用Kicad,花了四五天了解了Micropython语言,学习了电路相关的各个模块,这样的历练不可或缺,并且也使我学习到了更多的东西。
这是来到硬禾学堂暑期实践营的第一个项目,从画图到最后调试成功过程中,经历过许多坎坷与曲折,例如画PCB时的一些封装最后与实际有的器件不匹配,没有与物料管理员进行一个及时的沟通;调试扩展模块时出现一些代码的错误,查找相关手册与说明才解决此类问题。我觉得此次实践给我带来最大的一个感受就是——要不断地试错,在试错中加强自己的技能与沟通相关的素养,如果你自己不亲自的走过这一流程,你永远不知道这个流程是什么样子,不知道中途会出现什么错误,这也是一个工程师应该具备的。非常感谢硬禾学堂能给我这个机会。也希望在接下来的学习生涯中,自己要更努力,也会一如既往支持硬禾学堂后面的活动。