关于smbus和PCF8591的一些笔记
b y 57 by \ 57 by 57
其实这个事情,PPT上已经讲的很清楚了,但是还是有必要记一下,因为smbus这个玩意它没文档(或者说是我找不到文档)……
首先, I 2 C I^2C I2C的通信原理什么的就不赘述了,前面的PPT都有,master和slaver,高电平和低电平的各种转换……至少有两个PPT都是讲这个的,也讲得很清楚。
那我下面主要说说smbus里面的一些代码为什么要那么用吧,这些是PPT里没有讲得太清楚的,hmmm,至少我是这么觉得,所以我写一下,也希望能帮到大家。
首先得了解一些 I 2 C I^2C I2C通信的原理和PCF8591通信的原理。
这张PPT讲述的是为什么器件的地址为0x48。
然后就是控制字格式,上面讲的是在 I 2 C I^2C I2C总线协议中,启动条件之后的第一个字节是发送的器件地址,那么第二个字节发送的就是其控制字,这个将被储存到PCF8591的控制寄存器中。
嗯哼,PPT上的字比较小,我在这里就手打一遍,这个关系到之后的smbus的用法啊!
-
最高位默认为0.
-
第6位是选择是否允许模拟电压输出,在 D → A D\rightarrow A D→A的时候设置为1, A → D A\rightarrow D A→D的时候设置为0或者1,都可以。
-
第5和4位是选择模拟电压输出方式的,00表示的是单端输入,我们这里就用00,还有其他的输入见下图(作为补充了解):
-
其中,Three differential inputs 三差分输入
-
10:单端差分混合
-
11:二差分输入
-
图源网络,侵删。
-
-
第3位默认为0.
-
第2位是自动增量使能位,也就是说,如果这一位置为1,那么每一次A/D转换(模数转换)后通道数目将会变化(即增1).
-
第1位和第0位是AD转换时候选择的,选择的是把哪一个通道输入的电压转换为数字量。
哦吼,到这里我相信你已经可以推测出来咱们PPT的代码里面的smbus里面的那几个比较核心一点的,比如说bus.write_byte(address, 0x40)
,bus.read_byte(address)
,bus.write_byte_data(address, 0x40, temp)
具体是什么了。
当然,如果你还是不是很清楚,请继续往下看。
I 2 C I^2C I2C协议无非存和取,那么这些函数肯定代表着存取操作。这里先给出来,write表示存,read表示取。或者说这些存取,表示的是往PCF8591里写东西,和从PCF8591里往出读东西。(具体原理看讲 I 2 C I^2C I2C的PPT)
知道了以上,下面开始分析代码。
def setup(Addr):
global address
address = Addr
我们看到PCF8591.py
的代码,里面首先就是一个setup()
,设置了address,这里设置address,可以往后看,后面在调用这个setup()
的时候,设置了地址为0x48.这里的0x48的得到,就是通过上面的第一个PPT图里的指示得到的。当然,也可以用sudo i2cdetect -y 1
来做,但是知道原理就更牛辣!23333
def read(chn):
try:
if chn == 0:
bus.write_byte(address, 0x40)
if chn == 1:
bus.write_byte(address, 0x41)
if chn == 2:
bus.write_byte(address, 0x42)
if chn == 3:
bus.write_byte(address, 0x43)
bus.read_byte(address)
except Exception as e:
print("Address: %s" % address)
print(e)
return bus.read_byte(address)
这里是读东西,从四个不同的通道里读入东西,chn表示选择通道的编号。像write_byte()
,这里是上面的第二个PPT图,即给
I
2
C
I^2C
I2C设备发送一下控制字。0x40
、0x41
这些,转换成二进制不就是1000000,1000001吗?再加上最高位默认为0,这不正好就是一个控制字吗?用0x40
来看,补上最高位默认的0,就成为了0100 0000
,对应一下,就成了:允许模拟电压输出+单端输入+不启动通道的自动增量+AD转换通道设置为0号通道.
然后,bus.write_byte(address,balabala)
之后,就开始bus.read_byte(address)
,就是从address的位置开始读东西了。这就完成了一次
I
2
C
I^2C
I2C的通信了。读完之后把读到的东西返回一下,这个read函数就结束了(毕竟咱的代码里还有其他地方要用到读入的东西,所以read函数肯定不是只启动一次通信那么简单,还要保存这样那样,比如当这个文件被当作main执行的时候就会有一个print("AIN0 = ",read(0)的操作))。
def write(val):
try:
temp = val
temp = int(temp)
bus.write_byte_data(address, 0x40, temp)
except Exception as e:
print("Error: Device address: 0x%4X" % address)
print(e)
这个里面跟上面有一些不同,在于这个里面是使用的write_byte_data(address, 0x40, temp)
,跟上面的write_byte()
不同。这样理解就好了:write_byte_data()
,不仅完成了write_byte()
的告诉
I
2
C
I^2C
I2C设备控制字是什么的指令,还增加了一步往
I
2
C
I^2C
I2C设备中写入数据的步骤。这个写入的数据也就是第三个参数。再或者这么说,write_byte_data()
,直接完成了一次
I
2
C
I^2C
I2C的通信。
将read()
与write()
比较,发现,read()
是通过write_byte()
发送控制字+read_byte()
读取数据打出的一套从
I
2
C
I^2C
I2C设备取值的组合拳,而write()
只是用了write_byte_data()
就完成了一整套往
I
2
C
I^2C
I2C设备中写数据的招式。
这些弄懂了,看代码就小意思了吧!
以上。
晚上手打,错误难免,请大家指正!