[新手分享]Linux(mini2440)应用层使用adxl345模块(i2c/smbus)
本帖最后由 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
代码// i2c 应用层调试,读写挂载在i2c总线上的adxl345,
// 与eeprom公用一个设配文件
// 设置从设备,mini2440 参考其给的例子,完全在应用层
// 驱动层到 /dev/i2c/0 这个设备的过程完全没有涉及,
// 对于eeprom配合原始的i2c -w 和 i2c -r 检查结果
///@filename adxl345-helloworld.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#define ADDRESS 0x53 // adxl345地址
#define DEV "/dev/i2c/0" //设配文件,与原先的eeprom一样,通过地址区分
#define DEVID 0x00 // adxl345器件id的寄存器地址,见数据手册
unsigned char adxl_read(int fd, unsigned char reg);
int main(int argc, char* argv[])
{
int fd;
int ret = 0;
// 1打开 ,从设备打开
fd = open(DEV, O_RDWR);
if (fd<0) {
perror("open:");
return -1;
}
// 2 设置从设备地址
ret = ioctl(fd, I2C_SLAVE, ADDRESS);
if (ret<0) {
perror("ioctl:");
goto CLOSE;
}
// 3 操作:读取器件id
ret = adxl_read(fd, DEVID);
printf("器件ID=0x%02x\n", DEVID, ret);
CLOSE:
close(fd);
return 0;
}
unsigned char adxl_read(int fd, unsigned char reg)
{
union i2c_smbus_data data; //数据联合体
struct i2c_smbus_ioctl_data args; //参数结构
int ret;
// 读数据
args.read_write = I2C_SMBUS_READ; //读
args.command = reg; //读取的位置(寄存器地址)
args.size = I2C_SMBUS_BYTE_DATA; //1个字节的数据
args.data = &data; //保存数据到data联合体
ret = ioctl(fd, I2C_SMBUS, &args);
if (ret!=0) { //非零错误
perror("ioctl[读取]");
return 0xff;
}
return data.byte;
}编译arm-linux-gcc adxl345-helloworld.c -o app -Wall运行
在mini2440开发板上运行:# ./app
器件ID=0xe5如果内核设置了一些i2c调试信息,则`cat /proc/kmsg` 可以看到(这里有些出入,应该是以前调试的显示,读写有些多余)<7>i2c i2c-0: ioctl, cmd=0x703, arg=0x53
<7>i2c i2c-0: ioctl, cmd=0x720, arg=0xbecf1cf4
<7>i2c i2c-0: master_xfer W, addr=0x53, len=1
<7>s3c-i2c s3c2440-i2c: START: 000000d0 to IICSTAT, a6 to DS
<7>s3c-i2c s3c2440-i2c: iiccon, 000000e0
<7>s3c-i2c s3c2440-i2c: STOP
<7>s3c-i2c s3c2440-i2c: master_complete 0
<7>i2c i2c-0: ioctl, cmd=0x720, arg=0xbecf1cf4
<7>i2c i2c-0: master_xfer R, addr=0x53, len=1
<7>s3c-i2c s3c2440-i2c: START: 00000090 to IICSTAT, a7 to DS
<7>s3c-i2c s3c2440-i2c: iiccon, 000000e0
<7>s3c-i2c s3c2440-i2c: READ: Send Stop
<7>s3c-i2c s3c2440-i2c: STOP
<7>s3c-i2c s3c2440-i2c: master_complete 03.2 例2:读取传感器数值
功能:仅实现了能读三轴加速度.
代码
大部分代码与上面一样,增加了一个写入一个字节的函数`adxl_write()`,一个读取2个字节数据的函数`adxl_read_short()`///@filename adxl345-simplest-use.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <unistd.h>
#define ADDRESS 0x53 // adxl345地址
#define DEV "/dev/i2c/0" //设配文件,与原先的eeprom一样,通过地址区分
#define DEVID 0x00 // adxl345器件id的寄存器地址,见数据手册
#define POWER_CTL 0x2D
#define DATAX0 0x32
#define DATAX1 0x33
#define DATAY0 0x34
#define DATAY1 0x35
#define DATAZ0 0x36
#define DATAZ1 0x37
unsigned char adxl_read(int fd, unsigned char reg);
int adxl_write(int fd, unsigned char reg, unsigned char val);
signed shortadxl_read_short(int fd, unsigned char reg);
int main(int argc, char* argv[])
{
int fd;
int ret = 0;
signed short int x,y,z;//三轴加速度
// 1打开 ,从设备打开
fd = open(DEV, O_RDWR);
if (fd<0) {
perror("open:");
return -1;
}
// 2 设置从设备地址
ret = ioctl(fd, I2C_SLAVE, ADDRESS);
if (ret<0) {
perror("ioctl:");
goto CLOSE;
}
// 3 操作:读取器件id
ret = adxl_read(fd, DEVID);
printf("器件ID=0x%02x\n", DEVID, ret);
// 4 设置->启动,具体参见芯片手册.
// 这里仅设置有限的读取数值功能.其实太复杂的还没搞懂:P
adxl_write(fd, POWER_CTL, 0x28);
// 5 循环测量(读取三轴加速度)
for (;;) {
x = adxl_read_short(fd, DATAX0);
y = adxl_read_short(fd, DATAY0);
z = adxl_read_short(fd, DATAZ0);
printf("x=%5d y=%5d z=%5d\n", x,y,z);
usleep(100*1000);
}
CLOSE:
close(fd);
return 0;
}
unsigned char adxl_read(int fd, unsigned char reg)
{
union i2c_smbus_data data; //数据联合体
struct i2c_smbus_ioctl_data args; //参数结构
int ret;
// 读数据
args.read_write = I2C_SMBUS_READ; //读
args.command = reg; //读取的位置(寄存器地址)
args.size = I2C_SMBUS_BYTE_DATA; //1个字节的数据
args.data = &data; //保存数据到data联合体
ret = ioctl(fd, I2C_SMBUS, &args);
if (ret!=0) { //非零错误
perror("ioctl[读取]");
return 0xff;
}
return data.byte;
}
int adxl_write(int fd, unsigned char reg, unsigned char val)
{
union i2c_smbus_data data;
struct i2c_smbus_ioctl_data args;
int ret;
data.byte = val; //数据
args.read_write = I2C_SMBUS_WRITE; //写[与上面读相对应]
args.command = reg; //地址
args.size = I2C_SMBUS_BYTE_DATA; //1个字节大小的数据
args.data = &data; //保存数据
ret = ioctl(fd, I2C_SMBUS, &args);
if (ret!=0) {
perror("写入ioctl错误");
return -1;
}
return 0;
}
signed shortadxl_read_short(int fd, unsigned char reg)
{
union i2c_smbus_data data;
struct i2c_smbus_ioctl_data args;
int ret;
args.read_write = I2C_SMBUS_READ; //读
args.command = reg; //地址
args.size = I2C_SMBUS_WORD_DATA; //2字节大小的数据(short型)
args.data = &data; //保存数据
ret = ioctl(fd, I2C_SMBUS, &args);
if (ret!=0) {
perror("读取short ioctl错误");
return -1; //这个数值不妥,但是就先这样吧:)
}
return data.word;
}编译arm-linux-gcc adxl345-simplest-use.c -o app -Wall运行# ./app
器件ID=0xe5
x=-70 y=214 z=123
x=-46 y=274 z= 92
x= 21 y=153 z= -154
x= -274 y=209 z=-20
x= -512 y=189 z=135
x= -512 y=296 z=415
x= 4 y= -194 z=160
x= 40 y=254 z=210
x=277 y= -160 z=244
x=498 y= 30 z= -181
x= -369 y=-83 z=-14
x= -167 y= 55 z=-36我承认我在瞎晃XD.
3.3 例3:然后,没有了
参考数据手册,发觉更多的知识.勇敢的少年啊,快去创造奇迹:D
本文代码保存在[这里](https://github.com/zodiac1111/i2c-test),也包括中间折腾的一些东西.
暂时对adxl345的折腾就到这里.驱动层搞不定啊.
ps:
代码没高亮不太习惯
本文载自我的(http://1.gbzdsq.com:4567/dev/driver-adxl345)初来乍到,请大牛们轻拍 谢谢LZ分享
页:
[1]