贴个IIC的代码和MPU6050寄存器地址的文档(MOVE版)
Posted eternal-wisdom
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了贴个IIC的代码和MPU6050寄存器地址的文档(MOVE版)相关的知识,希望对你有一定的参考价值。
IIC代码:
里面的UV_Delay()那几个要自己定义一下。还有那几个子函数也要自己定义在一个头文件里面。比如:
#ifndef _IIC_H #define _IIC_H #define UV_Delay() delay5us() #define UV_SDA_SET() P2^0 = 1 #define UV_SDA_RESET() P2^0 = 0 #define UV_SCL_SET() P2^1 = 1 #define UV_SCL_RESET() P2^1 = 0 //void Fasong_data(unsigned char DevAddress, unsigned char RegAddress, unsigned char Massageess); //char Jieshou_data(unsigned char DevAddress, unsigned char RegAddress); void IIC_Start(); void IIC_Stop(); void UV_SCL_single_clock(); unsigned char IIC_ACKme(); void IIC_ACKher(unsigned char MyAnswer) void IIC_Sent_iBit(unsigned short i, unsigned short store); unsigned short IIC_Rcev_iBit(unsigned short i) #endif
/* UV_SDA_SET() UV_SDA_RESET() UV_SCL_SET() UV_SCL_RESET() UV_Delay() */ /** *\\filename IIC communication protocol example\\IIC通信协议举例 *\\author *\\version 1.0.1 *\\date forgeted *\\brief This is a simple example for IIC communication protocol and save as * .txt format, to be easy to move. * \\这是一个简单的IIC通信协议的例子,保存为txt格式以便于搬运。 * functions: * IIC_Start() \\\\起始IIC信号 * IIC_Stop() \\\\终止IIC信号 * UV_SCL_single_clock() \\\\时钟线SCL产生一个脉冲的功能 * IIC_ACKme() \\\\她回答我 * IIC_ACKher(unsigned char MyAnswer) \\\\我回答她 * IIC_Sent_iBit(unsigned short i, unsigned short store) \\\\发送i个比特\\\\这两个还可以优化一下发送缓冲区 * IIC_Rcev_iBit(unsigned short i) \\\\接收i个比特 * */ #define is == #define Yes 1 /*********************************************************************************************** void Fasong_data(unsigned char DevAddress, unsigned char RegAddress, unsigned char Massageess) IIC_Start(); IIC_Sent_iBit(8, DevAddress); IIC_ACKme(); IIC_Sent_iBit(8, RegAddress); IIC_ACKme(); IIC_Sent_iBit(8, Massageess); IIC_ACKme(); IIC_Stop(); char Jieshou_data(unsigned char DevAddress, unsigned char RegAddress) uint8_t The_Massage_I_Recived_Just_Now; IIC_Start(); IIC_Sent_iBit(8, DevAddress); IIC_ACKme(); IIC_Sent_iBit(8, RegAddress); IIC_ACKme(); IIC_Start(); IIC_Sent_iBit(8, DevAddress+1); IIC_ACKme(); The_Massage_I_Recived_Just_Now = IIC_Rcev_iBit(8); IIC_ACKher(1); IIC_Stop(); return The_Massage_I_Recived_Just_Now; *************************************************************************************************/ /************************************************************************************************* For example: #define MPU6050 0xD0 #define WHO_AM_I 0x75 #define PWR_MGMT_1 0x6B \\\\比如发送个 0x00⬇ Fasong_data(MPU6050, PWR_MGMT_1, 0x00); \\\\接收的数据放到The_Data_I_Recived unsigned char The_Data_I_Recived; \\\\设备地址⬇ ⬇设备中WHO_AM_I寄存器的地址 The_Data_I_Recived = Jieshou_data(MPU6050, WHO_AM_I); *************************************************************************************************/ void IIC_Start()//IIC protocol start signal UV_SDA_SET();//Set SDA line to high level UV_SCL_SET();//Set SCL line to high level UV_Delay();//Wait a minute UV_SDA_RESET();//SDA line falling to low level when SCL line is high level UV_Delay();//Wait a minute UV_SCL_RESET();//And SCL line also falling to low level UV_Delay();//Wait minute void IIC_Stop()//IIC protocol stop signal UV_SDA_RESET();//Make sure that SDA line is low level so that SDA line is stop state UV_SCL_SET();//Rase the SCL line prepare for stop SCL line state UV_Delay();//Wait a minute UV_SDA_SET();//Rasing for stop this transmission UV_Delay();//Wait a minute void UV_SCL_single_clock() UV_Delay(); UV_SCL_SET(); UV_Delay(); UV_SCL_RESET(); UV_Delay(); unsigned char IIC_ACKme() unsigned char HerAnswer; HerAnswer=UV_SDA_State; UV_SCL_single_clock(); return HerAnswer; void IIC_ACKher(unsigned char MyAnswer) if(MyAnswer is Yes) UV_SDA_SET(); else UV_SDA_RESET(); UV_SCL_single_clock(); void IIC_Sent_iBit(unsigned short i, unsigned short store)//After start signal, following the simple shift while(i) if((store>>(i-1))&0x01)//Transfer the MSB to SDA line UV_SDA_SET();//"1" level correspond to high level else UV_SDA_RESET();//"0" level correspond to low level UV_SCL_single_clock(); i--;//"i" shift the position of the transfer bit back to "if" //When "i" subtract to "0", transmission will be end unsigned short IIC_Rcev_iBit(unsigned short i)//Old way, receive "i" bits\' data, just simple shift unsigned short store=0;//A before state is both lines is low level while(i) store<<=1;//Shift the position for next bit UV_SCL_SET();//Rasing SCL line will put the bit from the slave device up to the SDA line UV_Delay();//Wait a minute store|=UV_SDA_State;//Load the bit in store UV_SCL_RESET();//SCL line return to low level for next bit UV_Delay();//Wait a minute i--;//"i" shift the position of the receive bit back to "if" retuen store;
MPU6050寄存器值:
#define AUX_VDDIO 0x01 //1 #define SMPLRT_DIV 0x19 //2 #define CONFIG 0x1A //3 #define GYRO_CONFIG 0x1B //4 #define ACCEL_CONFIG 0x1C //5 #define FF_THR 0x1D //6 #define FF_DUR 0x1E //7 #define MOT_THR 0x1F //8 #define MOT_DUR 0x20 //9 #define ZRMOT_THR 0x21 //10 #define ZRMOT_DUR 0x22 //11 #define FIFO_EN 0x23 //12 #define I2C_MST_CTRL 0x24 //13 #define I2C_SLV0_ADDR 0x25 //14 #define I2C_SLV0_REG 0x26 //15 #define I2C_SLV0_CTRL 0x27 //16 #define I2C_SLV1_ADDR 0x28 //17 #define I2C_SLV1_REG 0x29 //18 #define I2C_SLV1_CTRL 0x2A //19 #define I2C_SLV2_ADDR 0x2B //20 #define I2C_SLV2_REG 0x2C //21 #define I2C_SLV2_CTRL 0x2D //22 #define I2C_SLV3_ADDR 0x2E //23 #define I2C_SLV3_REG 0x2F //24 #define I2C_SLV3_CTRL 0x30 //25 #define I2C_SLV4_ADDR 0x31 //26 #define I2C_SLV4_REG 0x32 //27 #define I2C_SLV4_DO 0x33 //28 #define I2C_SLV4_CTRL 0x34 //29 #define I2C_SLV4_DI 0x35 //30 #define I2C_MST_STATUS 0x36 //31 #define INT_PIN_CFG 0x37 //32 #define INT_ENABLE 0x38 //33 #define INT_STATUS 0x3A //34 #define ACCEL_XOUT_H 0x3B //35 #define ACCEL_XOUT_L 0x3C //36 #define ACCEL_YOUT_H 0x3D //37 #define ACCEL_YOUT_L 0x3E //38 #define ACCEL_ZOUT_H 0x3F //39 #define ACCEL_ZOUT_L 0x40 //40 #define TEMP_OUT_H 0x41 //41 #define TEMP_OUT_L 0x42 //42 #define GYRO_XOUT_H 0x43 //43 #define GYRO_XOUT_L 0x44 //44 #define GYRO_YOUT_H 0x45 //45 #define GYRO_YOUT_L 0x46 //46 #define GYRO_ZOUT_H 0x47 //47 #define GYRO_ZOUT_L 0x48 //48 #define EXT_SENS_DATA_00 0x49 //49 #define EXT_SENS_DATA_01 0x4A //50 #define EXT_SENS_DATA_02 0x4B //51 #define EXT_SENS_DATA_03 0x4C //52 #define EXT_SENS_DATA_04 0x4D //53 #define EXT_SENS_DATA_05 0x4E //54 #define EXT_SENS_DATA_06 0x4F //55 #define EXT_SENS_DATA_07 0x50 //56 #define EXT_SENS_DATA_08 0x51 //57 #define EXT_SENS_DATA_09 0x52 //58 #define EXT_SENS_DATA_10 0x53 //59 #define EXT_SENS_DATA_11 0x54 //60 #define EXT_SENS_DATA_12 0x55 //61 #define EXT_SENS_DATA_13 0x56 //62 #define EXT_SENS_DATA_14 0x57 //63 #define EXT_SENS_DATA_15 0x58 //64 #define EXT_SENS_DATA_16 0x59 //65 #define EXT_SENS_DATA_17 0x5A //66 #define EXT_SENS_DATA_18 0x5B //67 #define EXT_SENS_DATA_19 0x5C //68 #define EXT_SENS_DATA_20 0x5D //69 #define EXT_SENS_DATA_21 0x5E //70 #define EXT_SENS_DATA_22 0x5F //71 #define EXT_SENS_DATA_23 0x60 //72 #define MOT_DETECT_STATUS 0x61 //73 #define I2C_SLV0_DO 0x63 //74 #define I2C_SLV1_DO 0x64 //75 #define I2C_SLV2_DO 0x65 //76 #define I2C_SLV3_DO 0x66 //77 #define I2C_MST_DELAY_CTRL 0x67 //78 #define SIGNAL_PATH_RESET 0x68 //79 #define MOT_DETECT_CTRL 0x69 //80 #define USER_CTRL 0x6A //81 #define PWR_MGMT_1 0x6B //82 #define PWR_MGMT_2 0x6C //83 #define FIFO_COUNTH 0x72 //84 #define FIFO_COUNTL 0x73 //85 #define FIFO_R_W 0x74 //86 #define WHO_AM_I 0x75 //87 #define MPU_Address 0xD0 //88
驱动程序实例:mpu6050(IIC + cdev)
在我们实际开发中,I2C 总线驱动一般芯片原厂会提供,我们开发一般是设计设备驱动。
本文结合之前对Linux内核的IIC子系统的分析 ,以及对字符设备的cdev接口的分析,本文将编写基于IIC总线与cdev接口的MPU6050设备的实例代码并对其进行分析。
IIC子系统分析:详见Linux IIC总线驱动框架。
字符设备的cdev接口分析:详见Linux字符设备驱动(一):cdev接口。
硬件接口:
CPU:s5pv210;
挂载IIC总线编号:0。
IIC从设备驱动挂载在IIC总线下,IIC总线管理着IIC从设备的设备信息(i2c_client)与设备驱动(i2c_driver)。因此,IIC从设备驱动的编写分为两个部分:注册IIC从设备信息、编写IIC从设备驱动程序。
1. 注册IIC从设备信息
在/kernel/arch/arm/mach-s5pv210/mach-x210.c文件中添加如下信息,向Linux内核注册IIC从设备信息。
static struct i2c_board_info mpu6050_i2c_devs0[] __initdata = { { I2C_BOARD_INFO("mpu6050", 0x2b),//构建i2c_board_info结构体,0x2b为从设备的地址 }, }; static void __init smdkc110_machine_init(void) { ... ... i2c_register_board_info(0, mpu6050_i2c_devs0, ARRAY_SIZE(mpu6050_i2c_devs0));//向内核注册IIC从设备信息,0表示该从设备挂载在IIC总线适配器0 ... ... }
2. 编写IIC从设备驱动程序
(1)mpu6050_common.h
将mpu6050_common.h文件添加至/kernel/drivers/i2c/busses目录下。
#ifndef _MPU6050_COMMON_H_ #define _MPU6050_COMMON_H_ #define MPU6050_MAGIC ‘K‘ //mpu6050数据结构 union mpu6050_data { struct { short x; short y; short z; }accel; struct { short x; short y; short z; }gyro; unsigned short temp; }; //mpu6050的ioctl的命令定义 #define GET_ACCEL _IOR(MPU6050_MAGIC, 0, union mpu6050_data)//读取加速度计的数据 #define GET_GYRO _IOR(MPU6050_MAGIC, 1, union mpu6050_data)//读取陀螺仪的数据 #define GET_TEMP _IOR(MPU6050_MAGIC, 2, union mpu6050_data)//读取温度的数据 #endif
(2)mpu6050_dev.h
mpu6050_dev.h文件是mpu6050的寄存器地址的定义文件,将其添加至添加至/kernel/drivers/i2c/busses目录下。
#ifndef _MPU6050_DEV_H_ #define _MPU6050_DEV_H_ #define SMPLRT_DIV 0x19 //陀螺仪采样率,典型值:0x07(125Hz) #define CONFIG 0x1A //低通滤波频率,典型值:0x06(5Hz) #define GYRO_CONFIG 0x1B //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s) #define ACCEL_CONFIG 0x1C //加速计自检、测量范围及高通滤波,典型值:0x18(不自检,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 //陀螺仪z轴角速度数据寄存器(高位) #define GYRO_ZOUT_L 0x48 //陀螺仪z轴角速度数据寄存器(低位) #define PWR_MGMT_1 0x6B //电源管理,典型值:0x00(正常启用) #define WHO_AM_I 0x75 //IIC地址寄存器(默认数值0x68,只读) #define SlaveAddress 0x68 //MPU6050-I2C地址寄存器 #endif
(3)mpu6050.c
#include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/i2c.h> #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/cdev.h> #include "mpu6050_dev.h" #include "mpu6050_common.h" #define DEV_MINOR 100 //IIC从设备的起始次设备号 #define DEV_CNT 1 //IIC从设备的个数 #define DEV_NAME "mpu6050" //IIC从设备名称 static struct i2c_client *mpu6050_client; static struct cdev mpu6050_dev; static dev_t mpu6050_devnum; //设备号 static struct class *mpu6050_class;//设备类 /* * 功能:向mpu6050从设备写入数据 * * 参数:struct i2c_client *client:指向mpu6050从设备 * const unsigned char reg:需写入的mpu6050的寄存器 * const unsigned char val:写入的数值 */ static void mpu6050_write_byte(struct i2c_client *client, const unsigned char reg, const unsigned char val) { char txbuf[2] = {reg, val};//数据缓存buffer //封装msg struct i2c_msg msg[2] = { [0] = { .addr = client->addr, .flags= 0, .len = sizeof(txbuf), .buf = txbuf, }, }; i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));//与从设备进行数据通信 } /* * 功能:向mpu6050从设备读取数据 * * 参数:struct i2c_client *client:指向mpu6050从设备 * const unsigned char reg:需读取的mpu6050的寄存器 * * 返回值:char:读取的数据 */ static char mpu6050_read_byte(struct i2c_client *client,const unsigned char reg) { char txbuf[1] = {reg};//数据缓冲buffer char rxbuf[1] = {0}; //封装msg struct i2c_msg msg[2] = { [0] = { .addr = client->addr, .flags = 0, .len = sizeof(txbuf), .buf = txbuf, }, [1] = { .addr = client->addr, .flags = I2C_M_RD, .len = sizeof(rxbuf), .buf = rxbuf, }, }; i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); //与从设备进行数据通信 return rxbuf[0]; } //mpu6050硬件初始化 static void mpu6050_init(struct i2c_client *client) { mpu6050_write_byte(client, PWR_MGMT_1, 0x00); mpu6050_write_byte(client, SMPLRT_DIV, 0x07); mpu6050_write_byte(client, CONFIG, 0x06); mpu6050_write_byte(client, GYRO_CONFIG, 0x18); mpu6050_write_byte(client, ACCEL_CONFIG, 0x0); } static int mpu6050_open(struct inode *ip, struct file *fp) { return 0; } static int mpu6050_release(struct inode *ip, struct file *fp) { return 0; } static long mpu6050_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { int res = 0; union mpu6050_data data = {{0}}; switch(cmd) { //读取加速度计的数据 case GET_ACCEL: data.accel.x = mpu6050_read_byte(mpu6050_client,ACCEL_XOUT_L); data.accel.x|= mpu6050_read_byte(mpu6050_client,ACCEL_XOUT_H)<<8; data.accel.y = mpu6050_read_byte(mpu6050_client,ACCEL_YOUT_L); data.accel.y|= mpu6050_read_byte(mpu6050_client,ACCEL_YOUT_H)<<8; data.accel.z = mpu6050_read_byte(mpu6050_client,ACCEL_ZOUT_L); data.accel.z|= mpu6050_read_byte(mpu6050_client,ACCEL_ZOUT_H)<<8; break; //读取陀螺仪的数据 case GET_GYRO: data.gyro.x = mpu6050_read_byte(mpu6050_client,GYRO_XOUT_L); data.gyro.x|= mpu6050_read_byte(mpu6050_client,GYRO_XOUT_H)<<8; data.gyro.y = mpu6050_read_byte(mpu6050_client,GYRO_YOUT_L); data.gyro.y|= mpu6050_read_byte(mpu6050_client,GYRO_YOUT_H)<<8; data.gyro.z = mpu6050_read_byte(mpu6050_client,GYRO_ZOUT_L); data.gyro.z|= mpu6050_read_byte(mpu6050_client,GYRO_ZOUT_H)<<8; printk("gyro:x %d, y:%d, z:%d ",data.gyro.x,data.gyro.y,data.gyro.z); break; //读取温度的数据 case GET_TEMP: data.temp = mpu6050_read_byte(mpu6050_client,TEMP_OUT_L); data.temp|= mpu6050_read_byte(mpu6050_client,TEMP_OUT_H)<<8; printk("temp: %d ",data.temp); break; default: printk(KERN_INFO "invalid cmd"); break; } printk("acc:x %d, y:%d, z:%d ",data.accel.x,data.accel.y,data.accel.z); res = copy_to_user((void *)arg,&data,sizeof(data)); return sizeof(data); } //mpu6050操作集 static const struct file_operations mpu6050_fops = { .owner = THIS_MODULE, .open = mpu6050_open, .release = mpu6050_release, .unlocked_ioctl = mpu6050_ioctl, }; static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev; mpu6050_client = client; /*****************************初始化硬件设备******************************/ //初始化mpu6050 mpu6050_init(client); dbg("probe:name = %s,flag =%d,addr = %d,adapter = %d,driver = %s ", client->name, client->flags,client->addr,client->adapter->nr,client->driver->driver.name ); /*********************************创建接口********************************/ cdev_init(&mpu6050_dev, &mpu6050_fops); //关联dev与fops alloc_chrdev_region(&mpu6050_devnum, DEV_MINOR, DEV_CNT, DEV_NAME);//自动分配设备号 cdev_add(&mpu6050_dev, mpu6050_devnum, DEV_CNT); //添加设备至设备链表 mpu6050_class = class_create(THIS_MODULE,DEV_NAME); //创建设备类 dev = device_create(mpu6050_class, NULL , mpu6050_devnum, "%s%d", DEV_NAME);//创建mpu6050设备 if (IS_ERR(dev)) { dbg("device create error "); goto out; } return 0; out: return -1; } static int mpu6050_remove(struct i2c_client *client) { dbg("remove "); device_destroy(mpu6050_class, mpu6050_devnum); class_destroy(mpu6050_class); unregister_chrdev_region(mpu6050_devnum,DEV_CNT); return 0; } //与mpu6050的设备信息匹配 static struct i2c_device_id mpu6050_ids[] = { {"mpu6050",0x2b}, {} }; //声明mpu6050_ids是i2c类型的一个设备表 MODULE_DEVICE_TABLE(i2c,mpu6050_ids); //定义并初始化从设备驱动信息 static struct i2c_driver mpu6050_driver = { .probe = mpu6050_probe, .remove = mpu6050_remove, .id_table = mpu6050_ids, .driver = { .name = "mpu6050", .owner = THIS_MODULE, }, }; static int __init mpu6050_i2c_init(void) { return i2c_add_driver(&mpu6050_driver);//注册设备驱动 } static void __exit mpu6050_i2c_exit(void) { i2c_del_driver(&mpu6050_driver); //注销设备驱动 } MODULE_AUTHOR("Lin"); MODULE_DESCRIPTION("mpu6050 driver"); MODULE_LICENSE("GPL"); module_init(mpu6050_i2c_init); module_exit(mpu6050_i2c_exit);
以上是关于贴个IIC的代码和MPU6050寄存器地址的文档(MOVE版)的主要内容,如果未能解决你的问题,请参考以下文章
STM32CubeMX移植MPU6050的DMP库读取角度信息