i2c 驱动gpio模拟i2c

1. 简介:

gpio模拟i2c驱动可以解决i2c控制器不足的问题,但是,相对的可能要占用更多的cpu时间,此程序依然使用的是jz2440开发板


2. 内核提供的代码分析:

我们从 i2c-gpio.c 开始,文件路径:drivers/i2c/busses

(1)i2c的gpio的私有的数据 结构体如下:

[cpp]  view plain  copy
 print ?
  1. struct i2c_gpio_private_data {  
  2.     struct i2c_adapter adap;  
  3.     struct i2c_algo_bit_data bit_data;  
  4.     struct i2c_gpio_platform_data pdata;  
  5. };  

其中第一个成员 i2c_adapter 不在展开,他提供了i2c的通信方法

第二个成员i2c_algo_bit_data,功能和参数写在函数中,他提供了操作具体硬件上的方法

[cpp]  view plain  copy
 print ?
  1. /* --- Defines for bit-adapters --------------------------------------- */  
  2. /* 
  3.  * 这个结构体中包含了对线的操作的函数,从名字上我们可以看出 
  4.  */  
  5. struct i2c_algo_bit_data {  
  6.     void *data;     /* private data for lowlevel routines */  
  7.     void (*setsda) (void *data, int state); /* 一些操作线的高低电平的函数 */  
  8.     void (*setscl) (void *data, int state);  
  9.     int  (*getsda) (void *data);  
  10.     int  (*getscl) (void *data);  
  11.     int  (*pre_xfer)  (struct i2c_adapter *);  
  12.     void (*post_xfer) (struct i2c_adapter *);  
  13.   
  14.     /* local settings */  
  15.     int udelay;     /* half clock cycle time in us, 
  16.                    minimum 2 us for fast-mode I2C, 
  17.                    minimum 5 us for standard-mode I2C and SMBus, 
  18.                    maximum 50 us for SMBus */  
  19.     int timeout;        /* 单位 jiffies */  
  20. };  

第三个成员i2c_gpio_platform_data,用于保存具体的硬件资源

[cpp]  view plain  copy
 print ?
  1. /** 
  2.  * struct i2c_gpio_platform_data - Platform-dependent data for i2c-gpio 
  3.  * @sda_pin: GPIO pin ID to use for SDA 
  4.  * @scl_pin: GPIO pin ID to use for SCL 
  5.  * @udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz 
  6.  * @timeout: clock stretching timeout in jiffies. If the slave keeps 
  7.  *  SCL low for longer than this, the transfer will time out. 
  8.  * @sda_is_open_drain: SDA is configured as open drain, i.e. the pin 
  9.  *  isn't actively driven high when setting the output value high. 
  10.  *  gpio_get_value() must return the actual pin state even if the 
  11.  *  pin is configured as an output. 
  12.  * @scl_is_open_drain: SCL is set up as open drain. Same requirements 
  13.  *  as for sda_is_open_drain apply. 
  14.  * @scl_is_output_only: SCL output drivers cannot be turned off. 
  15.  */  
  16. struct i2c_gpio_platform_data {  
  17.     unsigned int    sda_pin; /* sda 对应的引脚 */  
  18.     unsigned int    scl_pin; /* scl 对应的引脚 */  
  19.     int     udelay;  /* 信号触发延时,直接决定SCL引脚的频率:(500/udelay)kHz */  
  20.     int     timeout; /* 如果从设备的SCL低电平保持大于timeout jiffies,传输过程认为超时 */  
  21.     unsigned int    sda_is_open_drain:1; /* 将SDA引脚设置成开漏输出,开漏的意思是,如果设置成开漏,引脚外部没有上拉,高电平输不出来 */  
  22.     unsigned int    scl_is_open_drain:1; /* 将SCL引脚设置成开漏输出 */  
  23.     unsigned int    scl_is_output_only:1;/*  */  
  24. };  

(2)i2c_gpio_setsda_dir,设置 i2c_gpio_platform_data 结构体中的 SDA 引脚的方向:1输入,0输出

[cpp]  view plain  copy
 print ?
  1. /* 改变SDA引脚的方向 */  
  2. static void i2c_gpio_setsda_dir(void *data, int state)  
  3. {  
  4.     struct i2c_gpio_platform_data *pdata = data; /*  */  
  5.   
  6.     if (state)  
  7.         gpio_direction_input(pdata->sda_pin);  
  8.     else  
  9.         gpio_direction_output(pdata->sda_pin, 0);  
  10. }  

(3)i2c_gpio_setsda_val,设置SDA引脚上的值高/低,state可以的取值是GPIO_HIGHT / GPIO_LOW

[cpp]  view plain  copy
 print ?
  1. /* 
  2.  * 改变 SDA 引脚上的电平. This is only 
  3.  * valid for pins configured as open drain (i.e. setting the value 
  4.  * high effectively turns off the output driver.) 
  5.  */  
  6. static void i2c_gpio_setsda_val(void *data, int state)  
  7. {  
  8.     struct i2c_gpio_platform_data *pdata = data;  
  9.   
  10.     gpio_set_value(pdata->sda_pin, state);  
  11. }  

(4)i2c_gpio_setscl_dir,设置 SDA 引脚的输入输出方向:1入,0出

[cpp]  view plain  copy
 print ?
  1. /* Toggle SCL by changing the direction of the pin. */  
  2. static void i2c_gpio_setscl_dir(void *data, int state)  
  3. {  
  4.     struct i2c_gpio_platform_data *pdata = data;  
  5.   
  6.     if (state)  
  7.         gpio_direction_input(pdata->scl_pin);  
  8.     else  
  9.         gpio_direction_output(pdata->scl_pin, 0);  
  10. }  

(5)i2c_gpio_setscl_val,设置 SCL 引脚上的高低电平,state可以取值是GPIO_HIGHT / GPIO_LOW

[cpp]  view plain  copy
 print ?
  1. /* 
  2.  * Toggle SCL by changing the output value of the pin. This is used 
  3.  * for pins that are configured as open drain and for output-only 
  4.  * pins. The latter case will break the i2c protocol, but it will 
  5.  * often work in practice. 
  6.  */  
  7. static void i2c_gpio_setscl_val(void *data, int state)  
  8. {  
  9.     struct i2c_gpio_platform_data *pdata = data;  
  10.   
  11.     gpio_set_value(pdata->scl_pin, state);  
  12. }  

(6)得到 SDA , SCL 引脚上的电平,返回值的取值是 GPIO_HIGHT /GPIO_LOW

[cpp]  view plain  copy
 print ?
  1. static int i2c_gpio_getsda(void *data)  
  2. {  
  3.     struct i2c_gpio_platform_data *pdata = data;  
  4.   
  5.     return gpio_get_value(pdata->sda_pin);  
  6. }  
  7.   
  8. static int i2c_gpio_getscl(void *data)  
  9. {  
  10.     struct i2c_gpio_platform_data *pdata = data;  
  11.   
  12.     return gpio_get_value(pdata->scl_pin);  
  13. }  

(7)然后我们来看看模块的初始化和退出

[cpp]  view plain  copy
 print ?
  1. static int __init i2c_gpio_init(void)  
  2. {  
  3.     int ret;  
  4.   
  5.     ret = platform_driver_register(&i2c_gpio_driver); /* 将驱动注册到系统中 */  
  6.     if (ret)  
  7.         printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret);  
  8.   
  9.     return ret;  
  10. }  
  11. subsys_initcall(i2c_gpio_init);  
  12.   
  13. static void __exit i2c_gpio_exit(void)  
  14. {  
  15.     platform_driver_unregister(&i2c_gpio_driver); /*  相应的释放函数 */  
  16. }  
  17. module_exit(i2c_gpio_exit);  

(8)注册的这个驱动 i2c_gpio_driver 如下

[cpp]  view plain  copy
 print ?
  1. static struct platform_driver i2c_gpio_driver = {  
  2.     .driver     = {  
  3.         .name   = "i2c-gpio",  
  4.         .owner  = THIS_MODULE,  
  5.         .of_match_table = of_match_ptr(i2c_gpio_dt_ids),  
  6.     },  
  7.     .probe      = i2c_gpio_probe,  
  8.     .remove     = __devexit_p(i2c_gpio_remove),  
  9. };  

其中的 of_match_ptr 由于用的是平台文件的匹配方式,CONFIG_OF 这个宏(跟设备树有关)没有开启,因此,此处的 of_match_ptr 返回值是 i2c_gpio_dt_ids

[cpp]  view plain  copy
 print ?
  1. #if defined(CONFIG_OF)  
  2. static const struct of_device_id i2c_gpio_dt_ids[] = {  
  3.     { .compatible = "i2c-gpio", },  
  4.     { /* sentinel */ }  
  5. };  
  6.   
  7. MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids);  
  8. #endif  

可以看到,即使 i2c_gpio_dt_ids 也依赖于 CONFIG_OF 这个宏,因此 .of_match_table 没有定义,根据匹配的规则,最后检查的是 .name ,这要是有 设备的名字是 i2c-gpio 就能匹配上了,匹配上,将调用 i2c_gpio_probe,此部分代码加到,部分代码将用语言代替他的实现

[cpp]  view plain  copy
 print ?
  1. static int __devinit i2c_gpio_probe(struct platform_device *pdev)  
  2. {  
  3.     struct i2c_gpio_private_data *priv;  
  4.     struct i2c_gpio_platform_data *pdata;  
  5.     struct i2c_algo_bit_data *bit_data;  
  6.     struct i2c_adapter *adap;  
  7.     int ret;  
  8.   
  9.     priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);  
  10.   
  11.     adap = &priv->adap;  
  12.     bit_data = &priv->bit_data;  
  13.     pdata = &priv->pdata;  
  14.   
  15.     if (pdev->dev.of_node) { /* 没有设备树,执行 else */  
  16.         ret = of_i2c_gpio_probe(pdev->dev.of_node, pdata);  
  17.         if (ret)  
  18.             return ret;  
  19.     } else {  
  20.         if (!pdev->dev.platform_data) return -ENXIO;  
  21.         memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));  
  22.     }  
  23.   
  24.     /* 检查 SDA 和 SCL 引脚是不是有效 */  
  25.   
  26.     if (pdata->sda_is_open_drain) { /* 这里实现的是当输出的时候,将开漏打开,引脚上有上拉电阻,输入的时候,关闭开漏,引脚上无上拉电阻 */  
  27.         gpio_direction_output(pdata->sda_pin, 1); /* 将 SDA 引脚设置成输出,并且输出为 1 */  
  28.         bit_data->setsda = i2c_gpio_setsda_val;  
  29.     } else {  
  30.         gpio_direction_input(pdata->sda_pin);  
  31.         bit_data->setsda = i2c_gpio_setsda_dir;  
  32.     }  
  33.   
  34.     if (pdata->scl_is_open_drain || pdata->scl_is_output_only) {  
  35.         gpio_direction_output(pdata->scl_pin, 1);  
  36.         bit_data->setscl = i2c_gpio_setscl_val;  
  37.     } else {  
  38.         gpio_direction_input(pdata->scl_pin);  
  39.         bit_data->setscl = i2c_gpio_setscl_dir;  
  40.     }  
  41.   
  42.     if (!pdata->scl_is_output_only) /* 绑定i2c_algo_bit_data结构体 bit_data 中的 getscl 函数 */  
  43.         bit_data->getscl = i2c_gpio_getscl;   
  44.     bit_data->getsda = i2c_gpio_getsda; /* 绑定i2c_algo_bit_data结构体 bit_data 中的 getsda 函数 */  
  45.   
  46.     if (pdata->udelay) /* 绑定udelay,用于设置scl的频率 */  
  47.         bit_data->udelay = pdata->udelay;  
  48.     else if (pdata->scl_is_output_only) /* 默认的,并且 scl 设置成单输出,频率是 10kHz */  
  49.         bit_data->udelay = 50;           /* 10 kHz */  
  50.     else  
  51.         bit_data->udelay = 5;            /* 100 kHz */  
  52.   
  53.     if (pdata->timeout)  
  54.         bit_data->timeout = pdata->timeout;  
  55.     else  
  56.         bit_data->timeout = HZ / 10;     /* 默认100 ms */  
  57.   
  58.     bit_data->data = pdata;  
  59.   
  60.     adap->owner = THIS_MODULE;  
  61.     snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); /* i2c_adapter 的名字 */  
  62.     adap->algo_data = bit_data;  
  63.     adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;  
  64.     adap->dev.parent = &pdev->dev;  
  65.     adap->dev.of_node = pdev->dev.of_node;  
  66.   
  67.     /* 
  68.      * 如果 "dev->id" 是负数,我们认为是0. 
  69.      * The reason to do so is to avoid sysfs names that only make 
  70.      * sense when there are multiple adapters. 
  71.      */  
  72.     adap->nr = (pdev->id != -1) ? pdev->id : 0;  
  73.     ret = i2c_bit_add_numbered_bus(adap); /* adapter 跟 i2c总线关联,如果 nr = -1,i2c的号自动分配,得到适配器,返回0成功 */  
  74.     if (ret)  
  75.         goto err_add_bus;  
  76.   
  77.     of_i2c_register_devices(adap); /* CONFIG_OF_I2C和CONFIG_OF_I2C_MODULE都没定义,不执行这句 */  
  78.   
  79.     platform_set_drvdata(pdev, priv); /* ... */  
  80.   
  81.     dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n",  
  82.          pdata->sda_pin, pdata->scl_pin,  
  83.          pdata->scl_is_output_only  
  84.          ? ", no clock stretching" : "");  
  85.   
  86.     return 0;  
  87.   
  88. err_add_bus:  
  89.     gpio_free(pdata->scl_pin);  
  90. err_request_scl:  
  91.     gpio_free(pdata->sda_pin);  
  92. err_request_sda:  
  93.     return ret;  
  94. }  

相应的要有删除函数

[cpp]  view plain  copy
 print ?
  1. static int __devexit i2c_gpio_remove(struct platform_device *pdev)  
  2. {  
  3.     struct i2c_gpio_private_data *priv;  
  4.     struct i2c_gpio_platform_data *pdata;  
  5.     struct i2c_adapter *adap;  
  6.   
  7.     priv = platform_get_drvdata(pdev);  
  8.     adap = &priv->adap;  
  9.     pdata = &priv->pdata;  
  10.   
  11.     i2c_del_adapter(adap); /* 删除适配器 */  
  12.     gpio_free(pdata->scl_pin);  
  13.     gpio_free(pdata->sda_pin);   
  14.   
  15.     return 0;  
  16. }  

要用这个文件,需要做的是让内核支持,我用的内核版本是3.4.112

make menuconfig

选择 Device Drivers --->

<*> I2C support  --->

I2C Hardware Bus support  ---> 

<*> GPIO-based bitbanging I2C


重新将uImage放到开发板上,在根文件系统下会多出个节点:

./sys/bus/platform/drivers/i2c-gpio


3. 实例

对于上边的程序,在driver中已经存在,对于我们需要做的是编写 设备程序

设备可以在用户板级的配置文件中编写,也可以单独的写一个模块,然后加载,以下程序采用后者

由于手头上有个 mpu6050,所以,就以mpu6050为例,采用的传感器的小板子是 GY-521

mpu6050_gpio_dev.c

[cpp]  view plain  copy
 print ?
  1. #include <linux/kernel.h>  
  2. #include <linux/module.h>  
  3. #include <linux/platform_device.h>  
  4. #include <linux/i2c-gpio.h>  
  5. #include <mach/regs-gpio.h>  
  6. #include <mach/hardware.h>  
  7. #include <linux/i2c.h>  
  8. #include <linux/delay.h>  
  9.   
  10. MODULE_LICENSE("GPL");  
  11.   
  12. static struct i2c_gpio_platform_data i2c_gpio_adapter_data = {       
  13.     .sda_pin = S3C2410_GPB(8), /* 选用的引脚都是没有外部上拉电阻的 */  
  14.     .scl_pin = S3C2410_GPB(7),  
  15.     .udelay = 50, //5,100kHz 50,10kHz  
  16.     .timeout = 200,       
  17.     /* .sda_is_open_drain = 1, */ /* 从这里可以推测的是这里是设置芯片,如果是 0,则,这个引脚不设置成开漏的模式 */  
  18.     /* .scl_is_open_drain = 1, */  
  19.     /* .scl_is_output_only = 1, */  
  20. };  
  21.   
  22. static void mxs_nop_release(struct device *dev)  
  23. {  
  24.     printk("mpu6050_i2c_gpio_dev release\n");  
  25. }  
  26.   
  27. static struct platform_device i2c_gpio = {       
  28.     .name = "i2c-gpio",  
  29.     .id = 1,  
  30.     .dev = {  
  31.         .platform_data = &i2c_gpio_adapter_data,  
  32.         .release = mxs_nop_release,  
  33.     },       
  34. };       
  35.   
  36. static int mpu6050_i2c_gpio_dev_init(void)  
  37. {  
  38.     printk("mpu6050_i2c_gpio_dev_init.\n");  
  39.   
  40.     platform_device_register(&i2c_gpio);  
  41.   
  42.     return 0;  
  43. }  
  44.   
  45. static void mpu6050_i2c_gpio_dev_exit(void)  
  46. {  
  47.     printk("mpu6050_dev_exit.\n");  
  48.   
  49.     platform_device_unregister(&i2c_gpio);  
  50. }  
  51.   
  52. module_init(mpu6050_i2c_gpio_dev_init);  
  53. module_exit(mpu6050_i2c_gpio_dev_exit);  

Makefile

[cpp]  view plain  copy
 print ?
  1. ifeq ($(KERNELRELEASE),)  
  2.   
  3. #KERNELDIR ?= /lib/modules/$(shell uname -r)/build   
  4. KERNELDIR ?= ~/wor_lip/linux-3.4.112  
  5. PWD := $(shell pwd)  
  6.   
  7. modules:  
  8.     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules  
  9.   
  10. modules_install:  
  11.     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install  
  12.   
  13. clean:  
  14.     rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules* Module*  
  15.   
  16. .PHONY: modules modules_install clean  
  17.   
  18. else  
  19.     obj-m := mpu6050_gpio_dev.o  
  20. endif  

【1】将编译生成的文件,拷贝到开发板的文件系统中去,加载后出现匹配成功的字符,会在 /dev 文件夹下创建 i2c-1 ,还有一个 i2c-0 是用控制器控制的i2c接口,前边章节有讲

【2】我们使用的时候只需要像 i2c驱动二:devfs文件系统中的方法一样就行,只需要将读取的文件改成 i2c-1 即可,应用程序如下

mpu6050_devfs.c

[cpp]  view plain  copy
 print ?
  1. #include <stdio.h>  
  2. #include <linux/i2c.h>  
  3. #include <linux/i2c-dev.h>  
  4. #include <unistd.h>  
  5. #include <fcntl.h>  
  6. #include <sys/ioctl.h>  
  7.   
  8. #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))  
  9.   
  10. #define SMPLRT_DIV      0x19  
  11. #define CONFIG          0x1A  
  12. #define GYRO_CONFIG     0x1B  
  13. #define ACCEL_CONFIG    0x1C  
  14. #define ACCEL_XOUT_H    0x3B  
  15. #define ACCEL_XOUT_L    0x3C  
  16. #define ACCEL_YOUT_H    0x3D  
  17. #define ACCEL_YOUT_L    0x3E  
  18. #define ACCEL_ZOUT_H    0x3F  
  19. #define ACCEL_ZOUT_L    0x40  
  20. #define TEMP_OUT_H      0x41  
  21. #define TEMP_OUT_L      0x42  
  22. #define GYRO_XOUT_H     0x43  
  23. #define GYRO_XOUT_L     0x44  
  24. #define GYRO_YOUT_H     0x45  
  25. #define GYRO_YOUT_L     0x46  
  26. #define GYRO_ZOUT_H     0x47  
  27. #define GYRO_ZOUT_L     0x48  
  28. #define PWR_MGMT_1      0x6B  
  29.   
  30. #define ADDR_MPU6050    0x68  
  31.   
  32. static int mpu6050_read_byte(int fd, unsigned char reg)  
  33. {  
  34.     int ret = 0;  
  35.     unsigned char txbuf[1] = {reg};  
  36.     unsigned char rxbuf[1];  
  37.     struct i2c_rdwr_ioctl_data mpu_data;  
  38.   
  39.     ioctl(fd, I2C_TIMEOUT, 1);  
  40.     ioctl(fd, I2C_RETRIES, 2);  
  41.   
  42.     struct i2c_msg msg[] = {  
  43.         {  
  44.             .addr = ADDR_MPU6050, /* 设备的地址 */  
  45.             .flags= 0, /* 0 是写,I2C_RDWR 是读 */  
  46.             .len = ARRAY_SIZE(txbuf), /* msg 的长度 */  
  47.             .buf = txbuf  
  48.         },  
  49.         {ADDR_MPU6050, I2C_M_RD, ARRAY_SIZE(rxbuf), rxbuf},  
  50.     };  
  51.     mpu_data.msgs = msg;  
  52.     mpu_data.nmsgs = ARRAY_SIZE(msg);  
  53.   
  54.     ret = ioctl(fd, I2C_RDWR, &mpu_data);  
  55.     if (ret < 0) {  
  56.         printf("ret = %d\n", ret);  
  57.         return ret;  
  58.     }  
  59.   
  60.     return rxbuf[0];  
  61. }  
  62.   
  63. static int mpu6050_write_byte(int fd, unsigned char reg, unsigned char val)  
  64. {  
  65.     unsigned char txbuf[2] = {reg, val};  
  66.     struct i2c_rdwr_ioctl_data mpu_data;  
  67.   
  68.     ioctl(fd, I2C_TIMEOUT, 1);  
  69.     ioctl(fd, I2C_RETRIES, 2);  
  70.   
  71.     struct i2c_msg msg[] = {  
  72.         {ADDR_MPU6050, 0, ARRAY_SIZE(txbuf), txbuf},  
  73.     };  
  74.     mpu_data.msgs = msg;  
  75.     mpu_data.nmsgs = ARRAY_SIZE(msg);  
  76.   
  77.     ioctl(fd, I2C_RDWR, &mpu_data);  
  78.   
  79.     return 0;  
  80. }  
  81.   
  82. static void read_mpu6050(int fd)  
  83. {  
  84.     unsigned short accel_x = 0, accel_y = 0, accel_z = 0;  
  85.     unsigned short gyro_x = 0, gyro_y = 0, gyro_z = 0;  
  86.     unsigned short temp = 0;  
  87.   
  88.     mpu6050_write_byte(fd, PWR_MGMT_1, 0x00);  
  89.     mpu6050_write_byte(fd, SMPLRT_DIV, 0x07);  
  90.     mpu6050_write_byte(fd, CONFIG, 0x06);  
  91.     mpu6050_write_byte(fd, GYRO_CONFIG, 0x18);  
  92.     mpu6050_write_byte(fd, ACCEL_CONFIG, 0x01);  
  93.   
  94.     while(1) {  
  95.         accel_x = mpu6050_read_byte(fd, ACCEL_XOUT_L);  
  96.         accel_x |= mpu6050_read_byte(fd, ACCEL_XOUT_H) << 8;  
  97.   
  98.         accel_y =  mpu6050_read_byte(fd, ACCEL_YOUT_L);  
  99.         accel_y |= mpu6050_read_byte(fd, ACCEL_YOUT_H) << 8;  
  100.   
  101.         accel_z = mpu6050_read_byte(fd, ACCEL_ZOUT_L);  
  102.         accel_z |= mpu6050_read_byte(fd, ACCEL_ZOUT_H) << 8;  
  103.   
  104.         printf("acceleration data: x = %04x, y = %04x, z = %04x\n", accel_x, accel_y, accel_z);  
  105.   
  106.         gyro_x = mpu6050_read_byte(fd, GYRO_XOUT_L);  
  107.         gyro_x |= mpu6050_read_byte(fd, GYRO_XOUT_H) << 8;  
  108.   
  109.         gyro_y = mpu6050_read_byte(fd, GYRO_YOUT_L);  
  110.         gyro_y |= mpu6050_read_byte(fd, GYRO_YOUT_H) << 8;  
  111.   
  112.         gyro_z = mpu6050_read_byte(fd, GYRO_ZOUT_L);  
  113.         gyro_z |= mpu6050_read_byte(fd, GYRO_ZOUT_H) << 8;  
  114.   
  115.         printf("gyroscope data: x = %04x, y = %04x, z = %04x\n", gyro_x, gyro_y, gyro_z);  
  116.   
  117.         temp = mpu6050_read_byte(fd, TEMP_OUT_L);  
  118.         temp |= mpu6050_read_byte(fd, TEMP_OUT_H) << 8;  
  119.   
  120.         printf("temperature data: %x\n", temp);  
  121.   
  122.         usleep(1000*1000);  
  123.     }  
  124. }  
  125.   
  126. int main(int argc, const char *argv[])  
  127. {  
  128.     int fd;  
  129.   
  130.     fd = open("/dev/i2c-1", O_RDWR);  
  131.     if (fd < 0)  
  132.         perror("open error");  
  133.   
  134.     read_mpu6050(fd);  
  135.       
  136.     close(fd);  
  137.     return 0;  
  138. }  

【1】编译命令别忘了:

arm-none-linux-gnueabi-gcc mpu6050_devfs.c -o mpu6050_devfs -march=armv4t

【2】以下是运行成功的打印信息

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值