FreeBSD和I2C

2021-02-17 18:03:32

I2C是一种通信协议,最初设计用于外围设备之间的板间通信,例如处理器与系统中的EEPROM通讯。如今,它还用于与传感器的短距离通信-并非设计目的,但无论如何它都能工作。维基百科上有关于I2C的说法:

I2C(集成电路间),发音为I-squared-C,是Philips半导体公司(现为NXP Semiconductors)于1982年发明的一种同步,多主机,多从机,分组交换,单端,串行通信总线。它广泛用于在板内短距离通信中将低速外围IC连接到处理器和微控制器。或者,I2C拼写为I2C(发音为I-two-C)或IIC(发音为I-I-C)。 (感谢维基百科!)

我一直在使用一些来自SparkFun的基于I2C的传感器。它们具有QWIIC连接器,可轻松从SparkFuns OpenLog Artemis与他们交谈。 OpenLog Artemis可以将传感器数据记录到SD卡,也可以将自己显示为串行设备,在串行设备中以类似CSV的格式从传感器流式传输数据。它的效果很好,我强烈推荐整个QWIIC生态系统。

有时,我需要使用一些基于FreeBSD的系统中的QWIIC传感器之一,而无需使用OpenLog Artemis。在这种情况下,我将从12月开始使用带有FreeBSD的Raspberry PI Zero(13电流)。这很容易,因为QWIIC系统只是其下面的普通I2C,因此使用其中之一将传感器直接连接到RPI的GPIO引脚很容易。

在FreeBSD领域中,我们拥有i2c(8),这是一个用于读写I2C设备的用户空间实用程序。在学习本课程中要使用的实际传感器之前,我将首先介绍基本用法。

首先,我需要一些带有I2C总线的硬件,该硬件已在FreeBSD中公开。我正在使用Raspberry PI Zero,并且I2C总线在dmesg中如下所示:

[root @ pizero1〜]#grep I2C /var/run/dmesg.boot iicbus0:< OFW I2C总线>在iichb0上 iic0:< I2C通用I / O>。在iicbus0上 [root @ pizero1〜]#

我连接的第一个传感器是SparkFun TMP117温度传感器。根据连接指南,此传感器的默认I2C地址为0x48,与连接硬件并使用-s标志运行i2c(8)以使其扫描I2C总线中的设备后所看到的相符:

[root @ pizero1〜]#i2c -s 硬件可能不支持START / STOP扫描;尝试不太可靠的读取方法。 扫描/ dev / iic0上的I2C设备:48 [root @ pizero1〜]#

连接附加传感器后,该传感器的默认I2C地址为0x60,总线扫描也可以看到该设备:

[root @ pizero1〜]#i2c -sv 开发人员:/ dev / iic0,地址:0x0,读/写:r,偏移量:0x00,宽度:8,计数:1 硬件可能不支持START / STOP扫描;尝试不太可靠的读取方法。 扫描/ dev / iic0上的I2C设备:48 60 [root @ pizero1〜]#

从传感器读取很简单。我指定我要使用-d r读取(表示已读取),使用-c 2读取的数据长度(表示2个字节),以及使用-a 48读取的设备地址:

[root @ pizero1〜]#i2c -a 48 -d r -c 2 -m tr 0天67 [root @ pizero1〜]#为true;约会; i2c -a 48 -d r -c 2 -m tr;睡1完毕 星期日十二月20 00:51:45 UTC 2020 0天67 星期日十二月20 00:51:46世界标准时间2020 0天67 星期日十二月20 00:51:48世界标准时间2020 0天66 星期日十二月20 00:51:49 UTC 2020 0天66 ^ C [root @ pizero1〜]#

经过一番尝试和错误之后,我还添加了-m tr来将寻址模式设置为完全传输,这是该I2C总线所需的,以便使所有工作正常。

显示的读数是一个十六进制值,正好是-c 2请求的两个字节。

从该传感器读取温度时,由于温度存储在设备的第一个寄存器中,因此我无需在i2c(8)命令中添加-o来指定偏移量。如果要读取下一个寄存器(用于TMP117的寄存器是存储配置的位置),则可以使用-o 1: [root @ pizero1〜]#i2c -a 48 -d r -c 2 -m tr -o 1 22 20 [root @ pizero1〜]#

TMP117中的所有寄存器均为16位(或2个字节),但是I2C命令可以读取或写入任意数量的字节,只需使用-c指定宽度即可。

尝试读取比寄存器大小更多的数据只会导致返回FF字节:

[root @ pizero1〜]#i2c -a 48 -d r -c 2 -m tr 0c bc [root @ pizero1〜]#i2c -a 48 -d r -c 4 -m tr 0c bc ff ff [root @ pizero1〜]#i2c -a 48 -d r -c 40 -m tr 0c bd ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff [root @ pizero1〜]#

i2c(8)实用程序还使将值写回到设备变得容易。 TMP117传感器在寄存器2和3中具有可编程的低阈值和高阈值。第一个传感器的默认阈值为0x6000,对其进行更改与读取非常相似,不同之处在于,我们希望将字节写入stdin:

[root @ pizero1〜]#i2c -a 48 -d r -c 2 -m tr -o 2 60 00 [root @ pizero1〜]#echo -en" \ x60 \ x01" | i2c -a 48 -d w -c 2 -m tr -o 2 [root @ pizero1〜]#i2c -a 48 -d r -c 2 -m tr -o 2 60 01 [root @ pizero1〜]#echo -en" \ x60 \ x00" | i2c -a 48 -d w -c 2 -m tr -o 2 [root @ pizero1〜]#i2c -a 48 -d r -c 2 -m tr -o 2 60 00 [root @ pizero1〜]#

读取TMP117传感器的数据表后,我了解到温度读数以16位值的形式存储在第一个寄存器中,这意味着我对i2c(8)使用-c 2,因此它从I2c(8)读取了两个字节(16位)。传感器。

TMP117的数据表中有关于温度存储寄存器的说法:结果寄存器中的数据为二进制补码格式,数据宽度为16位,分辨率为7.8125m°C。 。

二进制补码是一种广泛使用的便捷方式,用于处理二进制中的带符号(负)数字。基本上,最高有效位用于指示紧随其后的是正数还是负数。

下表来自TMP117数据表,它以摄氏度显示一些样品温度,这些读数以十进制,两个补码二进制和十六进制表示的含义:

我在使用补码格式方面工作不多,所以我首先在Python中熟悉了它。我从SO借用了以下函数,并通过重现上表中的值开始了它:

[root @ pizero1〜]#cat twos.py #!/ usr / bin / env python3 导入系统 def twos(binary_str,bytecount): 整数= int(binary_str,字节数) bytes = integer.to_bytes(bytecount,byteorder =" big",signed = False) 返回int.from_bytes(bytes,byteorder =" big",signed = True) 打印(twos(sys.argv [1],int(sys.argv [2]))) [root @ pizero1〜]#

[root @ pizero1〜]#echo" $(python twos.py 1000000000000000 2)* 0.0078125" |公元前 -256.0000000 [root @ pizero1〜]#echo" $(python twos.py 1111001110000000 2)* 0.0078125" |公元前 -25.0000000 [root @ pizero1〜]#echo" $(python twos.py 1111111111110000 2)* 0.0078125" |公元前 -.1250000 [root @ pizero1〜]#echo" $(python twos.py 1111111111111111 2)* 0.0078125" |公元前 -.0078125 [root @ pizero1〜]#echo" $(python twos.py 0000000000000000 2)* 0.0078125" |公元前 0 [root @ pizero1〜]#echo" $(python twos.py 0000000000000001 2)* 0.0078125" |公元前 .0078125 [root @ pizero1〜]#echo" $(python twos.py 0000000000010000 2)* 0.0078125" |公元前 .1250000 [root @ pizero1〜]#echo" $(python twos.py 0000000010000000 2)* 0.0078125" |公元前 1.0000000 [root @ pizero1〜]#echo" $(python twos.py 0000110010000000 2)* 0.0078125" |公元前 25.0000000 [root @ pizero1〜]#echo" $(python twos.py 0011001000000000 2)* 0.0078125" |公元前 100.0000000 [root @ pizero1〜]#echo" $(python twos.py 0111111111111111 2)* 0.0078125" |公元前 255.9921875 [root @ pizero1〜]#

看起来效果很好。从读数到摄氏也很容易,我再次测试了表中的值:

[root @ pizero1〜]#python -c' print(round(int.from_bytes(bytearray.fromhex(" 8000"),byteorder =" big",signed = True )* 0.0078125,8))' -256.0 [root @ pizero1〜]#python -c' print(round(int.from_bytes(bytearray.fromhex(" F380"),byteorder =" big",signed = True )* 0.0078125,8))' -25.0 [root @ pizero1〜]#python -c' print(round(int.from_bytes(bytearray.fromhex(" FFF0"),byteorder =" big",signed = True )* 0.0078125,8))' -0.125 [root @ pizero1〜]#python -c' print(round(int.from_bytes(bytearray.fromhex(" FFFF"),byteorder =" big",signed = True )* 0.0078125,8))' -0.0078125 [root @ pizero1〜]#python -c' print(round(int.from_bytes(bytearray.fromhex(" 0000"),byteorder =" big",signed = True )* 0.0078125,8))' 0.0 [root @ pizero1〜]#python -c' print(round(int.from_bytes(bytearray.fromhex(" 0001"),byteorder =" big",signed = True )* 0.0078125,8))' 0.0078125 [root @ pizero1〜]#python -c' print(round(int.from_bytes(bytearray.fromhex(" 0010"),byteorder =" big",signed = True )* 0.0078125,8))' 0.125 [root @ pizero1〜]#python -c' print(round(int.from_bytes(bytearray.fromhex(" 0080"),byteorder =" big",signed = True )* 0.0078125,8))' 1.0 [root @ pizero1〜]#python -c' print(round(int.from_bytes(bytearray.fromhex(" 0C80"),byteorder =" big",signed = True )* 0.0078125,8))' 25.0 [root @ pizero1〜]#python -c' print(round(int.from_bytes(bytearray.fromhex(" 3200"),byteorder =" big",signed = True )* 0.0078125,8))' 100.0 [root @ pizero1〜]#python -c' print(round(int.from_bytes(bytearray.fromhex(" 7FFF"),byteorder =" big",signed = True )* 0.0078125,8))' 255.9921875 [root @ pizero1〜]#

这意味着可以像这样从传感器获取读数并将其转换为摄氏温度:

[root @ pizero1〜]#i2c -a 48 -d r -c 2 -m tr 0分81分 [root @ pizero1〜]#python -c" print(round(int.from_bytes(bytearray.fromhex(' 0c 81'),byteorder =' big',signed =是的)* 0.0078125,8))" 25.0078125 [root @ pizero1〜]#

PI Zero价格便宜,并且与TMP117一起,您还可以使用基于FreeBSD的出色的高精度温度测量设置,价格约为160-丹麦克朗(仅20欧元以上)。

由于QWIIC传感器可以通过菊花链连接,因此可以通过更多传感器轻松扩展设置,以测量更多东西。如果解释数据非常棘手,则大多数传感器都具有现有的高质量Arduino库(TMP117也不例外)。

下一步是看看如何在SparkFuns Qwiic_Py Python软件包中获得FreeBSD支持,这需要在Qwiic_I2C_Py中获得FreeBSD支持,而这又取决于在smbus2中获得FreeBSD支持。 我最近注册了Github赞助商,这意味着现在可以很容易地赞助我和我的工作。如果这篇文章或我的其他著作,软件或服务对您有帮助,那么您可以考虑成为赞助商。