Using Python smbus on a Raspberry Pi - confused with syntax
我正在尝试在Raspberry Pi上使用python-smbus与I2C进行MMA7660加速度计芯片通信。
在下面的代码中,我正在读取芯片的寄存器0x00、0x01、0x02和0x03,并且得到的值完全相同。查看这些值并倾斜芯片,我可以看到它们都对应于寄存器0x00,即X值寄存器。
输出:
1 2 3 4 5 6 7 8 9 10 11 12 | ... 1 1 1 2 3 3 3 3 1 1 1 1 59 60 60 60 51 51 51 51 58 58 58 58 3 3 3 3 62 62 62 62 58 58 58 58 62 62 62 62 ... |
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | import smbus import time bus = smbus.SMBus(1) # I2C address for MMA7660 addr = 0x4C try: bus.write_byte_data(addr, 0x07, 0x00) bus.write_byte_data(addr, 0x06, 0x10) bus.write_byte_data(addr, 0x08, 0x00) bus.write_byte_data(addr, 0x07, 0x01) except IOError, err: print err while True: try: x = bus.read_byte_data(addr,0x00) y = bus.read_byte_data(addr,0x01) z = bus.read_byte_data(addr,0x02) tr = bus.read_byte_data(addr,0x03) print x, y, z, tr time.sleep(0.25) except: print 'exiting...' break |
我在smbus语法上做错什么了吗?我确实在这里查看了文档。
我已经验证了芯片的工作原理-我可以使用Arduino与它进行良好的通信,并按照与上述相同的顺序设置寄存器。
更新#1(2013年6月28日):
根据Sylvain的评论,我为以下代码附加了SDA / SCL行的示波器输出:
1 2 | bus.write_byte(addr, 0x01) print bus.read_byte(addr) |
更新#2:
我想Raspberry Pi上的I2C存在一个已知问题-没有"重复启动"。
https://raspberrypi.stackexchange.com/questions/7138/mma8452-i2c-module
根据Linux SMBus规范:
1 2 3 4 5 6 7 | SMBus Read Byte: i2c_smbus_read_byte_data() ============================================ This reads a single byte from a device, from a designated register. The register is specified through the Comm byte. S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P |
但是当我尝试时,示波器在重复启动(S)之前清楚地显示了STOP(P)。
所以我想我很不高兴在Pi上使用I2C硬件与MMA7760进行通信。
如果您一次读取所有需要的寄存器,则可以正常工作:
1 2 3 4 5 6 7 8 | import smbus bus = smbus.SMBus(1) Register = bus.read_i2c_block_data(0x4c, 0x99,4) acc_x = Register[0]*1.0 acc_y = Register[1]*1.0 acc_z = Register[2]*1.0 acc_tilt = Register[3] |
我绝对不确定这是问题所在,但根据规格p22:
MMA7660FC is read using it’s internally stored register address as address pointer, the same way the stored register address
is used as address pointer for a write. The pointer generally auto-increments after each data byte is read using the same rules
as for a write (Table 5). Thus, a read is initiated by first configuring the device’s register address by performing a write (Figure 11)
followed by a repeated start. The master can now read 'n' consecutive bytes from it, with the first data byte being read from the
register addressed by the initialized register address.
据我了解,要从寄存器"读取",必须先写入寄存器地址,然后盲目读取一个字节。我不知道
1 2 3 4 5 6 7 8 9 10 11 | bus.write_byte(addr,0x00) x = bus.read_byte(addr) bus.write_byte(addr,0x01) y = bus.read_byte_data(addr) bus.write_byte(addr,0x02) z = bus.read_byte(addr) bus.write_byte(addr,0x03) tr = bus.read_byte(addr) |
也许甚至可以工作:
1 2 3 4 5 6 | bus.write_byte(addr,0x00) x = bus.read_byte(addr) y = bus.read_byte_data(addr) z = bus.read_byte(addr) tr = bus.read_byte(addr) |
Raspberry PI I2C内核驱动程序在特定时间内不支持重复启动。但是,尽管必须显式激活此功能,但I2C内核驱动程序已经更新,现在支持重复启动。
设置联合转账\\'on \\'
设置合并转账\\'off \\'
可在此处找到信息:http://raspberrypi.znix.com/hipidocs/topic_i2c_rs_and_cs.htm
在查看您的示例以及为MMA7455编写的类之后,我能够编写以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import smbus import time import os import math # Define a class for the accelerometer readings class MMA7660(): bus = smbus.SMBus(1) def __init__(self): self.bus.write_byte_data(0x4c, 0x07, 0x00) # Setup the Mode self.bus.write_byte_data(0x4c, 0x06, 0x10) # Calibrate self.bus.write_byte_data(0x4c, 0x08, 0x00) # Calibrate self.bus.write_byte_data(0x4c, 0x07, 0x01) # Calibrate def getValueX(self): return self.bus.read_byte_data(0x4c, 0x00) def getValueY(self): return self.bus.read_byte_data(0x4c, 0x01) def getValueZ(self): return self.bus.read_byte_data(0x4c, 0x02) mma = MMA7660() for a in range(1000): x = mma.getValueX() y = mma.getValueY() z = mma.getValueZ() print("X=", x) print("Y=", y) print("Z=", z) time.sleep(0.2) os.system("clear") |
那应该可以解决问题。