搜索
bottom↓
回复: 1

[新手分享]Linux(mini2440)应用层使用adxl345模块(i2c/smbus)

[复制链接]

出0入0汤圆

发表于 2013-10-31 10:32:13 | 显示全部楼层 |阅读模式
本帖最后由 zodiac1111 于 2013-10-31 10:36 编辑

某宝入手个adxl345模块玩玩,spi的接口搞半天弄不来,看到i2c的.使用mini2440/s3c2440 kernel2.6.32有i2c的驱动.就试着使用了一下.貌似基本的读写功能可以实现.
应用层实现的.完全新手向,没啥技术含量.大牛要请轻拍.咱就学过点软件.都比较浅显的.希望不会误导比我还新的新手 = =.

在mini2440(linux)上通过i2c使用adxl345三轴加速度传感器.使用s3c2440自带的i2c平台驱动.在应用层实现驱动.因为我还没有搞清楚i2c/smbus :(.

可以最简单的实现读取三轴加速度.比较丑陋正在完善中,期待其与[官方的adxl345驱动](http://wiki.analog.com/resources ... /input-misc/adxl345)相比:P .

暂时缺陷:虽然能读到数据,但是对于adxl345操作流程不甚了解,各寄存器需要再详细阅读datasheet.

个人理解的总体大致流程(i2c-smbus-flow.svg):


1 硬件

需要连接好adxl345和mini2440的线路.
VCC,GND,SDA,SCL

2 内核&驱动层

不用任何改动,因为不是内核层的驱动.只要mini2440支持平台(s3c2440)的i2c支持即可.测试能和原来的eeprom通讯应该就没问题.

使用驱动层驱动是`drivers/i2c/busses/i2c-s3c2410.c`s3c2440的平台驱动.和`drivers/i2c/i2c-dev.c`(实现设备文件操作).

3 应用层

这个驱动是且仅是在应用层完成的,具体看下面两个最简示例吧.

3.1 例1:你好,世界!

最简单文件,相当于一个helloworld程序,目的是验证adxl345芯片和连线正常.

功能:读取芯片id:DEVID[0x00]

代码
  1. // i2c 应用层调试,读写挂载在i2c总线上的adxl345,
  2. // 与eeprom公用一个设配文件
  3. // 设置从设备,mini2440 参考其给的例子,完全在应用层
  4. // 驱动层到 /dev/i2c/0 这个设备的过程完全没有涉及,
  5. // 对于eeprom配合原始的i2c -w 和 i2c -r 检查结果
  6. ///@filename adxl345-helloworld.c
  7. #include <stdio.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <sys/ioctl.h>
  11. #include <linux/i2c-dev.h>
  12. #include <linux/i2c.h>
  13. #define ADDRESS 0x53                 // adxl345地址
  14. #define DEV "/dev/i2c/0"         //设配文件,与原先的eeprom一样,通过地址区分
  15. #define DEVID         0x00                 // adxl345器件id的寄存器地址,见数据手册
  16. unsigned char adxl_read(int fd, unsigned char reg);
  17. int main(int argc, char* argv[])
  18. {
  19.         int fd;
  20.         int ret = 0;
  21.         // 1  打开 ,从设备打开
  22.         fd = open(DEV, O_RDWR);
  23.         if (fd<0) {
  24.                 perror("open:");
  25.                 return -1;
  26.         }
  27.         // 2 设置从设备地址
  28.         ret = ioctl(fd, I2C_SLAVE, ADDRESS);
  29.         if (ret<0) {
  30.                 perror("ioctl:");
  31.                 goto CLOSE;
  32.         }
  33.         // 3 操作:读取器件id
  34.         ret = adxl_read(fd, DEVID);
  35.         printf("器件ID[0x%02x]=0x%02x\n", DEVID, ret);
  36.         CLOSE:
  37.         close(fd);
  38.         return 0;
  39. }

  40. unsigned char adxl_read(int fd, unsigned char reg)
  41. {
  42.         union i2c_smbus_data data;                 //数据联合体
  43.         struct i2c_smbus_ioctl_data args;        //参数结构
  44.         int ret;
  45.         // 读数据
  46.         args.read_write = I2C_SMBUS_READ;        //读
  47.         args.command = reg;                        //读取的位置(寄存器地址)
  48.         args.size = I2C_SMBUS_BYTE_DATA;        //1个字节的数据
  49.         args.data = &data;                        //保存数据到data联合体
  50.         ret = ioctl(fd, I2C_SMBUS, &args);
  51.         if (ret!=0) {     //非零错误
  52.                 perror("ioctl[读取]");
  53.                 return 0xff;
  54.         }
  55.         return data.byte;
  56. }
复制代码
编译
  1. arm-linux-gcc adxl345-helloworld.c -o app -Wall
复制代码
运行

在mini2440开发板上运行:
  1. [root@FriendlyARM plg]# ./app
  2. 器件ID[0x00]=0xe5
复制代码
如果内核设置了一些i2c调试信息,则`cat /proc/kmsg` 可以看到(这里有些出入,应该是以前调试的显示,读写有些多余)
  1. <7>i2c i2c-0: ioctl, cmd=0x703, arg=0x53
  2. <7>i2c i2c-0: ioctl, cmd=0x720, arg=0xbecf1cf4
  3. <7>i2c i2c-0: master_xfer[0] W, addr=0x53, len=1
  4. <7>s3c-i2c s3c2440-i2c: START: 000000d0 to IICSTAT, a6 to DS
  5. <7>s3c-i2c s3c2440-i2c: iiccon, 000000e0
  6. <7>s3c-i2c s3c2440-i2c: STOP
  7. <7>s3c-i2c s3c2440-i2c: master_complete 0
  8. <7>i2c i2c-0: ioctl, cmd=0x720, arg=0xbecf1cf4
  9. <7>i2c i2c-0: master_xfer[0] R, addr=0x53, len=1
  10. <7>s3c-i2c s3c2440-i2c: START: 00000090 to IICSTAT, a7 to DS
  11. <7>s3c-i2c s3c2440-i2c: iiccon, 000000e0
  12. <7>s3c-i2c s3c2440-i2c: READ: Send Stop
  13. <7>s3c-i2c s3c2440-i2c: STOP
  14. <7>s3c-i2c s3c2440-i2c: master_complete 0
复制代码
3.2 例2:读取传感器数值

功能:仅实现了能读三轴加速度.

代码

大部分代码与上面一样,增加了一个写入一个字节的函数`adxl_write()`,一个读取2个字节数据的函数`adxl_read_short()`
  1. ///@filename adxl345-simplest-use.c
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <sys/ioctl.h>
  6. #include <linux/i2c-dev.h>
  7. #include <linux/i2c.h>
  8. #include <unistd.h>
  9. #define ADDRESS 0x53                 // adxl345地址
  10. #define DEV "/dev/i2c/0"         //设配文件,与原先的eeprom一样,通过地址区分
  11. #define DEVID         0x00                 // adxl345器件id的寄存器地址,见数据手册
  12. #define POWER_CTL         0x2D
  13. #define DATAX0                0x32
  14. #define DATAX1                0x33
  15. #define DATAY0                0x34
  16. #define DATAY1                 0x35
  17. #define DATAZ0                 0x36
  18. #define DATAZ1                 0x37
  19. unsigned char adxl_read(int fd, unsigned char reg);
  20. int adxl_write(int fd, unsigned char reg, unsigned char val);
  21. signed short  adxl_read_short(int fd, unsigned char reg);
  22. int main(int argc, char* argv[])
  23. {
  24.         int fd;
  25.         int ret = 0;
  26.         signed short int x,y,z;//三轴加速度
  27.         // 1  打开 ,从设备打开
  28.         fd = open(DEV, O_RDWR);
  29.         if (fd<0) {
  30.                 perror("open:");
  31.                 return -1;
  32.         }
  33.         // 2 设置从设备地址
  34.         ret = ioctl(fd, I2C_SLAVE, ADDRESS);
  35.         if (ret<0) {
  36.                 perror("ioctl:");
  37.                 goto CLOSE;
  38.         }
  39.         // 3 操作:读取器件id
  40.         ret = adxl_read(fd, DEVID);
  41.         printf("器件ID[0x%02x]=0x%02x\n", DEVID, ret);
  42.         // 4 设置->启动,具体参见芯片手册.
  43.         //   这里仅设置有限的读取数值功能.其实太复杂的还没搞懂:P
  44.         adxl_write(fd, POWER_CTL, 0x28);
  45.         // 5 循环测量(读取三轴加速度)
  46.         for (;;) {
  47.                 x = adxl_read_short(fd, DATAX0);
  48.                 y = adxl_read_short(fd, DATAY0);
  49.                 z = adxl_read_short(fd, DATAZ0);
  50.                 printf("x=%5d y=%5d z=%5d\n", x,y,z);
  51.                 usleep(100*1000);
  52.         }
  53. CLOSE:
  54.         close(fd);
  55.         return 0;
  56. }

  57. unsigned char adxl_read(int fd, unsigned char reg)
  58. {
  59.         union i2c_smbus_data data;                 //数据联合体
  60.         struct i2c_smbus_ioctl_data args;        //参数结构
  61.         int ret;
  62.         // 读数据
  63.         args.read_write = I2C_SMBUS_READ;        //读
  64.         args.command = reg;                        //读取的位置(寄存器地址)
  65.         args.size = I2C_SMBUS_BYTE_DATA;        //1个字节的数据
  66.         args.data = &data;                        //保存数据到data联合体
  67.         ret = ioctl(fd, I2C_SMBUS, &args);
  68.         if (ret!=0) {     //非零错误
  69.                 perror("ioctl[读取]");
  70.                 return 0xff;
  71.         }
  72.         return data.byte;
  73. }
  74. int adxl_write(int fd, unsigned char reg, unsigned char val)
  75. {
  76.         union i2c_smbus_data data;
  77.         struct i2c_smbus_ioctl_data args;
  78.         int ret;
  79.         data.byte = val;                        //数据
  80.         args.read_write = I2C_SMBUS_WRITE;        //写[与上面读相对应]
  81.         args.command = reg;                        //地址
  82.         args.size = I2C_SMBUS_BYTE_DATA;        //1个字节大小的数据
  83.         args.data = &data;                        //保存数据
  84.         ret = ioctl(fd, I2C_SMBUS, &args);
  85.         if (ret!=0) {
  86.                 perror("写入ioctl错误");
  87.                 return -1;
  88.         }
  89.         return 0;
  90. }
  91. signed short  adxl_read_short(int fd, unsigned char reg)
  92. {
  93.         union i2c_smbus_data data;
  94.         struct i2c_smbus_ioctl_data args;
  95.         int ret;
  96.         args.read_write = I2C_SMBUS_READ;        //读
  97.         args.command = reg;                        //地址
  98.         args.size = I2C_SMBUS_WORD_DATA;        //2字节大小的数据(short型)
  99.         args.data = &data;                        //保存数据
  100.         ret = ioctl(fd, I2C_SMBUS, &args);
  101.         if (ret!=0) {
  102.                 perror("读取short ioctl错误");
  103.                 return -1;                         //这个数值不妥,但是就先这样吧:)
  104.         }
  105.         return data.word;
  106. }
复制代码
编译
  1. arm-linux-gcc adxl345-simplest-use.c -o app -Wall
复制代码
运行
  1. [root@FriendlyARM plg]# ./app
  2. 器件ID[0x00]=0xe5
  3. x=  -70 y=  214 z=  123
  4. x=  -46 y=  274 z=   92
  5. x=   21 y=  153 z= -154
  6. x= -274 y=  209 z=  -20
  7. x= -512 y=  189 z=  135
  8. x= -512 y=  296 z=  415
  9. x=    4 y= -194 z=  160
  10. x=   40 y=  254 z=  210
  11. x=  277 y= -160 z=  244
  12. x=  498 y=   30 z= -181
  13. x= -369 y=  -83 z=  -14
  14. x= -167 y=   55 z=  -36
复制代码
我承认我在瞎晃XD.

3.3 例3:然后,没有了

参考数据手册,发觉更多的知识.勇敢的少年啊,快去创造奇迹:D
本文代码保存在[这里](https://github.com/zodiac1111/i2c-test),也包括中间折腾的一些东西.
暂时对adxl345的折腾就到这里.驱动层搞不定啊.

ps:
代码没高亮不太习惯
本文载自我的[wiki](http://1.gbzdsq.com:4567/dev/driver-adxl345)初来乍到,请大牛们轻拍

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2013-10-31 11:40:07 | 显示全部楼层
谢谢LZ分享
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-9 13:06

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表