BananaPI Leaf S3 - 驱动MPU6050六轴陀螺仪的开发
大信(QQ:8125036)
上次的实验已经初步的掌握了Banana PI的开发环境和掌握简便的开发方法。
这次再尝试使用BananaPI连接其它硬件来做一些功能测试。这次首先使用一个设备MPU6050传感器,它是一款六轴陀螺仪,使用i2c的方式与主机进行通讯。
MPU6050是一款6轴运动处理传感器。集成了三轴加速度,三轴角速度,以及一个可扩展的数字运动处理器DMP(Digital Mo
tion Processor:数字运动处理器),能够通过I2C协议进行传输数据,本次目标就是将MPU6050使用I2C协议与Banana PI Leaf S3进行通讯,获取角速度、加速度以及温度数据,使用串口显示在电脑上。
关于MPU6050笔者在之前的一个实验中已经对它有详细的介绍,需要了解的可以点这个链接看一下。这里不再重复赘述了。
https://bbs.elecfans.com/jishu_2273503_1_1.html
一、连接MPU6050传感器 首先连接Banana PI Leaf S3
开发板与MPU6050传感器,这里使用开发板的硬i2c口,即PIN15,PIN16脚。具体连线如下图;
实物连线如下图:
然后看MPU6050的驱动c/c++例程,主要看它的初始化,以及读取数据的,写入数据的控制命令,以及数据读取后的处理方法,其主要的参数定义如下,需要着重关注MPU的内部寄存器地址,以及其参数含义,这些寄存器的操作,需要在Banana PI LeafS3上完成
- #define DEV_ADDR 0x68
- #define SMPLRT_DIV 0x19 //陀螺仪采样率,典型值:0x07(125Hz)
- #define CONFIG 0x1A //低通滤波频率,典型值:0x06(5Hz)
- #define GYRO_CONFIG 0x1B //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
- #define ACCEL_CONFIG 0x1C //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
- #define ACCEL_XOUT_H 0x3B
- #define ACCEL_XOUT_L 0x3C
- #define ACCEL_YOUT_H 0x3D
- #define ACCEL_YOUT_L 0x3E
- #define ACCEL_ZOUT_H 0x3F
- #define ACCEL_ZOUT_L 0x40
- #define TEMP_OUT_H 0x41
- #define TEMP_OUT_L 0x42
- #define GYRO_XOUT_H 0x43
- #define GYRO_XOUT_L 0x44
- #define GYRO_YOUT_H 0x45
- #define GYRO_YOUT_L 0x46
- #define GYRO_ZOUT_H 0x47
- #define GYRO_ZOUT_L 0x48
- #define PWR_MGMT_1 0x6B //电源管理,典型值:0x00(正常启用)
- #define WHO_AM_I 0x75 //IIC地址寄存器(默认数值0x68,只读)
- #define SlaveAddressW 0xD0 //IIC写入时的地址字节数据,+1为读取
- #define SlaveAddressR 0xD1 //IIC写入时的地址字节数据,+1为读取
- bool check()
- {
- char temp;
- temp = MPU6050_ReadOneByte(WHO_AM_I);
- if(temp==0x68)
- return true;
- else
- return false;
- }
- Void mpu6050_Initation()
- {
- MPU6050_WriteOneByte(PWR_MGMT_1, 0x00); //解除休眠状态
- time_delay(200);
- //MPU6050_WriteOneByte(PWR_MGMT_1, 0x80); //复位
- MPU6050_WriteOneByte(SMPLRT_DIV, 0x07);
- MPU6050_WriteOneByte(CONFIG, 0x06);
- MPU6050_WriteOneByte(GYRO_CONFIG, 0x18);
- MPU6050_WriteOneByte(ACCEL_CONFIG, 0x01);
- }
二、MucroPython下的I2C 使用方法 查询MicroPython的文档,可以看到有关i2c的用法,该开发板的I2C有两种使用方式,分别是硬I2C , 和软I2C
硬I2C端口定义如下,
I2C(0)
scl
16
sda
15
硬I2C micropython操作代码如下:
from machine import Pin, I2C
i2c = I2C(1, scl=Pin(16), sda=Pin(15), freq=400000)
软I2C硬I2C操作代码如下:
在使用软I2C下,任何两个空余的GPIO 都可以用来作为I2C的接口,通过软件对端口电平的翻转来模拟出I2C的通讯时序。
from machine import Pin, SoftI2C i2c = SoftI2C(scl=Pin(5), sda=Pin(4), freq=100000)i2c.scan()
# scan for devicesi2c.readfrom(0x3a, 4)
# read 4 bytes from device with address 0x3ai2c.writeto(0x3a, '12')
# write '12' to device with address 0x3abuf = bytearray(10)
# create a buffer with 10 bytesi2c.writeto(0x3a, buf)
# write the given buffer to the peripheral
有了操作代码后,就可以尝试使用micropython在命令行去读写mpu6050设备了。读写尝试如下;
- >>>
- >>> import machine #引入硬件库
- >>> import utime #引入时间函数库
- >>> from machine import Pin, I2C #引入I2C硬设备
- >>>
- >>> i2c = I2C(0, scl=Pin(16), sda=Pin(15)) #设定SCL,SDA 脚
- >>> i2c.scan() #扫描该脚下的所有I2C设备
- [104] #获得地址为 104, 即0x68的I2C设备
- >>>
到此说明已经操作成功MPU6050设备了,下一步该开发读取数据了。
三、编写MicroPython代码获取MPU6050的传感器数据下面就在上面建立连接的基础上,继续编写代码,完成设备的校验,以及传感器数据的读取。
- from machine import Pin, I2C
- import machine
- import utime
-
- DEV_ADDR=0x68
-
- PWR_MGMT_1=0x6B
- SMPLRT_DIV=0x19
- CONFIG=0x06
- GYRO_CONFIG=0x18
- ACCEL_CONFIG=0x01
- ACCEL_XOUT_H=0x3B
-
- i2c = I2C(0, scl=Pin(16), sda=Pin(15), freq=100000)
- i2c.scan()
-
- i2c.writeto_mem(DEV_ADDR, PWR_MGMT_1, bytearray([0]))
- i2c.writeto_mem(DEV_ADDR, SMPLRT_DIV, bytearray([0x07]));
- i2c.writeto_mem(DEV_ADDR, CONFIG, bytearray([0x06]));
- i2c.writeto_mem(DEV_ADDR, GYRO_CONFIG, bytearray([0x18]));
- i2c.writeto_mem(DEV_ADDR, ACCEL_CONFIG, bytearray([0x01]));
-
- i2c.readfrom_mem(DEV_ADDR, ACCEL_XOUT_H, 14)
执行结果如下图:
四、优化脚本代码模块虽然上面完成了整个I2C的连接,到设备验证,数据读取,但作为软件开发,需要将开发好的模块提供给业务应用人员进一步开发应用,因此不能只使用交互命令行的方式来交付代码成果。
需要把验证通过的交互式代码进行适当的分装,成为函数或者类,形成自定义的末块,让调用者不必关心外设的读写实现细节等,直接调用完成应用的业务逻辑。
代码优化后如下:
mpu6050操作库代码
- import machine
-
- class accel():
- def __init__(self, i2c, addr=0x68):
- self.iic = i2c
- self.addr = addr
- self.iic.start()
- self.iic.writeto(self.addr, bytearray([107, 0]))
- self.iic.stop()
-
- def get_raw_values(self):
- self.iic.start()
- a = self.iic.readfrom_mem(self.addr, 0x3B, 14)
- self.iic.stop()
- return a
-
- def get_ints(self):
- b = self.get_raw_values()
- c = []
- for i in b:
- c.append(i)
- return c
-
- def bytes_toint(self, firstbyte, secondbyte):
- if not firstbyte & 0x80:
- return firstbyte << 8 | secondbyte
- return - (((firstbyte ^ 255) << 8) | (secondbyte ^ 255) + 1)
-
- def get_values(self):
- raw_ints = self.get_raw_values()
- vals = {}
- vals["AcX"] = self.bytes_toint(raw_ints[0], raw_ints[1])
- vals["AcY"] = self.bytes_toint(raw_ints[2], raw_ints[3])
- vals["AcZ"] = self.bytes_toint(raw_ints[4], raw_ints[5])
- vals["Tmp"] = self.bytes_toint(raw_ints[6], raw_ints[7]) / 340.00 + 36.53
- vals["GyX"] = self.bytes_toint(raw_ints[8], raw_ints[9])
- vals["GyY"] = self.bytes_toint(raw_ints[10], raw_ints[11])
- vals["GyZ"] = self.bytes_toint(raw_ints[12], raw_ints[13])
- return vals # returned in range of Int16
- # -32768 to 32767
-
- def val_test(self):
- from time import sleep
- while 1:
- print(self.get_values())
- sleep(0.05)
调用代码:
- import mpu6050
- from machine import SoftI2C,Pin
- import utime
-
- i2c = SoftI2C(scl=Pin(21), sda=Pin(22))
- accel = mpu6050.accel(i2c)
- while True:
- accel_dict = accel.get_values()
- print(accel_dict)
- utime.sleep(3)
五、开发试用总结
通过很短的时间的使用,完成Banana PI Leaf S3开发板连接上了MPU6050六轴传感器,有了micropython的支持,连接I2C设备和使用I2C变的非常简单容易,只要写几行代码就完成I2C总线的控制,简单的读写函数就可以完成对外设寄存器的读写,顺利的读取到数据。完全抛弃了示波器,逻辑分析仪等大凶器来调试硬件通讯了,大大简化了硬件开发难度,降低了硬件开发门槛,使得开发者只要了解外设的寄存定义和数据结构的定义就能很快的开发出相应的应用出来。
可以看到有了micropython使得I2C这样的硬件开发变得非常简单容易,而且也不容易出错,