转载地址:http://blog.csdn.net/yuzeze/article/details/51890555

利用Linux内核自带的IIC总线驱动,按系统提供的框架,用ioctl方法对eeprom设备进行读写操作,并分别按单字节及多字节读写方式,对外提供函数接口,以供外部程序方便调用。

  程序由3个文件组成,分别为头文件<eeprom_io.h>,函数实现文件<eeprom_io.c>,及测试程序<test.c>。
<eeprom_io.h>

/* **************************************************************************
 * File name:   eeprom_io.h
 * Function:    eeprom读写操作
 * Description: 利用系统提供的I2C总线驱动实现eeprom设备的读写方法,
 *              对外开放4个函数接口, 分别为:
 *              单字节写入函数: int eeprom_byte_write(u8 pos, u8 data)
 *              单字节读取函数: u8 eeprom_byte_read(u8 pos)
 *              多字节写入函数: int eeprom_page_write(u8 pos, u8 *data, int size)
 *              多字节读取函数: int eeprom_page_read(u8 pos, u8 *data, int size)
 * Author & Date: Joshua Chan, 2011/12/18
 * **************************************************************************/
#ifndef _EEPROM_IO_H
#define _EEPROM_IO_H#include <linux/i2c.h>
#include <linux/i2c-dev.h>/* I2C总线ioctl方法所使用的结构体 */
typedef struct i2c_rdwr_ioctl_data ioctl_st;typedef unsigned char u8;
typedef unsigned int u32;/* eeprom的slave_address, 对于AT24C08, 容量为1024 bytes, 由于byte_address
   仅有8位, 只能表示0 ~ 255 bytes, 故此需在slave_address中分出2位来配合
   byte_address一起寻址, 而slave_address可以取值0x50, 0x51, 0x52, 0x53,
   配合byte_address刚好可以实现0 ~ 1023 bytes的寻址, 另外byte_address
   取值范围从0 ~ 255, 若大于255则按其值对256取余计算 */
enum eeprom_address {    eeprom_addr0 = 0x50,
    eeprom_addr1 = 0x51,
    eeprom_addr2 = 0x52,
    eeprom_addr3 = 0x53,
};#define DEV_PATH "/dev/i2c/0"  //设备文件路径
#define I2C_M_WR          0    //定义写标志
#define MAX_MSG_NR        2    //根据AT24C08手册, 最大消息数为2
#define EEPROM_BLOCK_SIZE 256  //每个block容量256 bytes
#define EEPROM_PAGE_SIZE  16   //AT24C08页大小为16字节
#define I2C_MSG_SIZE (sizeof(struct i2c_msg))/* 自定义eeprom参数结构体 */
typedef struct eeprom_data {    u8 slave_addr;
    u8 byte_addr;
    u8 len;
    u8 *buf;
} eeprom_st;/* 从eeprom的pos位置处读取1个字节
   @pos: eeprom的byte_address, 取值范围为0 ~ 255
   返回值为读取的字节数据 */
extern u8 eeprom_byte_read(u8 pos);/* 将1个字节数据写入eeprom的pos位置
   @pos: eeprom的byte_address, 取值范围为0 ~ 255
   @data: 待写入的字节数据 */
extern int eeprom_byte_write(u8 pos, u8 data);/* 从eeprom的pos位置开始读取size长度数据
   @pos: eeprom的byte_address, 取值范围为0 ~ 255
   @data: 接收数据的缓冲区
   @size: 待读取的数据长度, 取值范围为1 ~ 16 */
extern int eeprom_page_read(u8 pos, u8 *data, int size);/* 自eeprom的pos位置开始写入数据
   @pos: eeprom的byte_address, 取值范围为0 ~ 255
   @data: 待写入的数据
   @size: 待写入数据的长度, 取值范围为1 ~ 16 */
extern int eeprom_page_write(u8 pos, u8 *data, int size);#endif

<eeprom_io.c>

/* ***************************************************************************
 * File name:   eeprom_io.c
 * Function:    eeprom读写操作
 * Description: 利用系统提供的I2C总线驱动实现eeprom设备的读写方法,
 *              对外开放4个函数接口, 分别为:
 *              单字节写入函数: int eeprom_byte_write(u8 pos, u8 data)
 *              单字节读取函数: u8 eeprom_byte_read(u8 pos)
 *              多字节写入函数: int eeprom_page_write(u8 pos, u8 *data, int size)
 *              多字节读取函数: int eeprom_page_read(u8 pos, u8 *data, int size)
 * Author & Date: Joshua Chan, 2011/12/18
 * **************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include "eeprom_io.h"/* 对设备进行初始化设置, 设置超时时间及重发次数, 参数为设备文件描述符 */
static int eeprom_init(int fd)
{    ioctl(fd, I2C_TIMEOUT, 4);
    ioctl(fd, I2C_RETRIES, 2);
    return 0;
}/* 初始化一个ioctl_st结构, 并预分配空间 */
static ioctl_st *ioctl_st_init(void)
{    ioctl_st *iocs;    iocs = malloc(sizeof(ioctl_st));
    if (!(iocs)) {        perror("malloc iocs:");
        return NULL;
    }    iocs->msgs = malloc(I2C_MSG_SIZE * MAX_MSG_NR);
    if (!(iocs->msgs)) {        perror("malloc iocs->msgs");
        return NULL;
    }    iocs->msgs[0].buf = malloc(EEPROM_PAGE_SIZE + 1);
    if (!(iocs->msgs[0].buf)) {        perror("malloc iocs->msgs[0].buf");
        return NULL;
    }    iocs->msgs[1].buf = malloc(EEPROM_PAGE_SIZE + 1);
    if (!(iocs->msgs[1].buf)) {        perror("malloc iocs->msgs[1].buf");
        return NULL;
    }    return iocs;
}/* 销毁ioctl_st结构, 释放空间 */
static void ioctl_st_release(ioctl_st *iocs)
{    free(iocs->msgs[0].buf);
    free(iocs->msgs[1].buf);
    free(iocs->msgs);
    free(iocs);
}/* 根据eeprom_st结构生成page_read时序所需的ioctl_st结构 */
static void page_read_st_gen(ioctl_st *iocs, eeprom_st *eeps)
{    int size = eeps->len;    iocs->nmsgs = 2;  //page_read需2次start信号    /* 第1次信号 */
    iocs->msgs[0].addr = eeps->slave_addr;  //填入slave_addr
    iocs->msgs[0].flags = I2C_M_WR;         //write标志
    iocs->msgs[0].len = 1;                  //信号长度1字节
    iocs->msgs[0].buf[0] = eeps->byte_addr; //填入byte_addr    /* 第2次信号 */
    iocs->msgs[1].addr = eeps->slave_addr;  //填入slave_addr
    iocs->msgs[1].flags = I2C_M_RD;         //read标志
    iocs->msgs[1].len = size;               //信号长度: 待读数据长度
    memset(iocs->msgs[1].buf, 0, size);     //先清零, 待读数据将自动存放于此
}/* 用ioctl方法从eeprom中读取数据 */
static int page_read(int fd, ioctl_st *iocs, eeprom_st *eeps)
{    int ret;
    int size = eeps->len;    page_read_st_gen(iocs, eeps);
    ret = ioctl(fd, I2C_RDWR, (u32)iocs);
    if (ret == -1) {        perror("ioctl");
        return ret;
    }    /* 将读取的数据从ioctl结构中复制到用户buf */
    memcpy(eeps->buf, iocs->msgs[1].buf, size);
    //    printf("read byte ioctl ret = %d\n", ret);    return ret;
}/* 从eeprom的pos位置开始读取size长度数据
   @pos: eeprom的byte_address, 取值范围为0 ~ 255
   @data: 接收数据的缓冲区
   @size: 待读取的数据长度, 取值范围为1 ~ 16 */
int eeprom_page_read(u8 pos, u8 *data, int size)
{    int fd;
    u8 *buf = data;
    eeprom_st eeps;
    ioctl_st *iocs = ioctl_st_init();    fd = open(DEV_PATH, O_RDONLY);
    if (fd < 0) {        perror("open eeprom");
        return 0;
    }    /* 判断要读取数据的长度size有效性 */
    if (size > 16)
        size = 16;
    else if (size < 1)
        return 0;    if (size > (EEPROM_BLOCK_SIZE - pos))
        size = EEPROM_BLOCK_SIZE - pos;    eeprom_init(fd);
    eeps.slave_addr = eeprom_addr0;
    eeps.byte_addr = pos;
    eeps.len = size;
    eeps.buf = buf;    page_read(fd, iocs, &eeps);
    ioctl_st_release(iocs);
    close(fd);    return size;
}/* 根据eeprom_st结构生成page_write时序所需的ioctl_st结构 */
static void page_write_st_gen(ioctl_st *iocs, eeprom_st *eeps)
{    int size = eeps->len;    iocs->nmsgs = 1;  //page_write只需1次start信号    iocs->msgs[0].addr = eeps->slave_addr;  //填入slave_addr
    iocs->msgs[0].flags = I2C_M_WR;         //write标志
    iocs->msgs[0].len = size + 1; //信号长度: 待写入数据长度 + byte_addr长度
    iocs->msgs[0].buf[0] = eeps->byte_addr; //第1字节为byte_addr
    memcpy((iocs->msgs[0].buf + 1), eeps->buf, size); //copy待写数据
}/* 用ioctl方法向eeprom中写入数据 */
static int page_write(int fd, ioctl_st *iocs, eeprom_st *eeps)
{    int ret;    page_write_st_gen(iocs, eeps);
    ret = ioctl(fd, I2C_RDWR, (u32)iocs);
    if (ret == -1) {        perror("ioctl");
        return ret;
    }    printf("write byte ioctl ret = %d\n", ret);    return ret;
}/* 自eeprom的pos位置开始写入数据
   @pos: eeprom的byte_address, 取值范围为0 ~ 255
   @data: 待写入的数据
   @size: 待写入数据的长度, 取值范围为1 ~ 16 */
int eeprom_page_write(u8 pos, u8 *data, int size)
{    int fd;
    u8 *buf = data;
    eeprom_st eeps;
    ioctl_st *iocs = ioctl_st_init();    fd = open(DEV_PATH, O_WRONLY);
    if (fd < 0) {        perror("open eeprom");
        return 0;
    }    /* 判断要读取数据的长度size有效性 */
    if (size > 16)
        size = 16;
    else if (size < 1)
        return 0;    if (size > (EEPROM_BLOCK_SIZE - pos))
        size = EEPROM_BLOCK_SIZE - pos;    eeprom_init(fd);
    eeps.slave_addr = eeprom_addr0;
    eeps.byte_addr = pos;
    eeps.len = size;
    eeps.buf = buf;    page_write(fd, iocs, &eeps);
    ioctl_st_release(iocs);
    close(fd);    return size;
}/* 从eeprom的pos位置处读取1个字节
   @pos: eeprom的byte_address, 取值范围为0 ~ 255
   返回值为读取的字节数据 */
u8 eeprom_byte_read(u8 pos)
{    u8 buf;
    eeprom_page_read(pos, &buf, 1);    return buf;
}/* 将1个字节数据写入eeprom的pos位置
   @pos: eeprom的byte_address, 取值范围为0 ~ 255
   @data: 待写入的字节数据 */
int eeprom_byte_write(u8 pos, u8 data)
{    int ret;
    u8 buf = data;
    ret = eeprom_page_write(pos, &buf, 1);    return ret;
}

<test.c>

/* *************************************************************
 * File name:   eeprom_test.c
 * Function:    eeprom读写操作
 * Description: eeprom读写操作测试程序
 * Author & Date: Joshua Chan, 2011/12/18
 * *************************************************************/
#include "eeprom_io.h"int main(int argc, char *argv[])
{    u8 pos = 3;
    u8 data[5] = {32, 15, 99, 250, 6};    eeprom_byte_write(pos, data[0]);  //单字节写操作    data[0] = eeprom_byte_read(pos);  //单字节读操作    eeprom_page_write(pos, data, 5);  //多字节写操作    eeprom_page_read(pos, data, 5);   //多字节读操作    return 0;
}

Linux下的eeprom读写操作相关推荐

  1. linux中i2c读写函数,Linux下的eeprom读写操作(IIC)

    /* *************************************************************************** * File name: eeprom_i ...

  2. Linux下按扇区读写块设备,Linux下按扇区读写块设备

    本文介绍Linux下按扇区读写块设备(示例TF卡),实际应用是在Android系统上,主要方法如下: 1.找到sdcard的挂载点,在android2.1系统下应该为/dev/block/mmcblk ...

  3. Linux下对文件的操作及添加新用户

    Linux下对文件的操作及添加新用户 一.对文件的操作 1.打包压缩文件 2.解压缩文件 3.对文件操作的其他命令 二.创建新用户 一.对文件的操作 1.打包压缩文件 2.解压缩文件 3.对文件操作的 ...

  4. Linux下如何避免误操作执行 rm

    转载自 Linux下如何避免误操作执行 rm 最近IT圈子流行着一个段子: 某个蠢萌的程序员,不小心在公司的服务器上输入了 rm -rf/ 指令,结果......现在还没出狱呢. 当然,绝大部分程序员 ...

  5. linux 下卸载nginx的操作步骤

    linux 下卸载nginx的操作步骤 1.执行命令,看nginx是否在运行 ps -ef|grep nginx 2.如上图,发现nginx是在运行状态,所以停止nginx服务 注意,要进入到ngin ...

  6. linux下git的相关操作指令

    linux下git的相关操作指令 git版本管理工具 1.克隆仓库git clone "url" 2.上传2.1标记:告诉git工具需要管理那些文件了git add [filena ...

  7. linux下C语言编程操作数据库(sqlite3)

    前言:C语言中通过调用 sqlite 的函数接口来实现对数据库的管理(创建数据库.创建表格.插入数据.查询.数据.删除数据等),掌握sqlite数据库的语法,以及sqlite提供的函数接口,那么在li ...

  8. linux gcc编译下的文件读写操作

    linux下的文件操作 所有目录             1.文件及文件系统的定义             2.linux文件的类型             3.linux文件的权限          ...

  9. linux下c语言读写文件操作,linux下的系统级c语言文件读写操作

    最近初次接触Linux这么高端的东西,有种进城的感觉.进了linux,发现城里人说话做事的方式都很不一样. 个人感觉,初次接触linux主要的痛点在于命令行交互的方式,这就要求我接受城里人的思维,wh ...

最新文章

  1. 《NoSQL精粹》思维导图读书笔记
  2. python colormap(颜色映射)自定义
  3. 实战SSM_O2O商铺_32【商品】商品编辑之Dao层的实现
  4. 编译器优化陷阱之典型代码
  5. 前端学习(3309):redux项目创建和概况
  6. 英雄联盟祖安服务器要维护多久,祖安玩家的春天!英雄联盟将回归队内语音,娱乐玩家遭殃了?...
  7. matlab破损皮革定位,matlab-code-of-TDOAFDOa 干扰源定位代码,应该在 的求解过程中有帮助。 276万源代码下载- www.pudn.com...
  8. Flutter fvm 多版本管理
  9. 在Linux系统下生产者消费者,Linux线程编程之生产者消费者问题
  10. “新闻”频道“最新更新”有问题吗?
  11. 阶段1 语言基础+高级_1-3-Java语言高级_1-常用API_1_第7节 Arrays工具类_17_Arrays练习:字符串倒序...
  12. 我所遭遇过的游戏中间件--Kynapse
  13. ASP.NET MVC + ADO.NET EF 项目实战(三):引入jQuery
  14. ZoomIt下载,ZoomIt下载地址分享
  15. 如何突破四维空间,进入五维空间
  16. Android POS开发
  17. Redis 使用 scan 命令代替 keys
  18. 微型计算机增刊2016,科幻世界·2016年增刊
  19. XTP dockingpane的使用方法
  20. 常用数据结构与经典算法 简单讲解与示例代码

热门文章

  1. Unity学习日记--2D 精灵移动跳跃
  2. 37~python 字符串
  3. 基于Δ-Σ模数转换器的梳状滤波器的设计与matlab仿真
  4. PDF文件JAVA去水印源码,java pdf增加水印示例源码
  5. Android仿苹果iphone数字锁屏解锁功能
  6. 苹果cms vod.html,苹果cms,怎么可以修改vod\seach.html接口,增加搜索时的内置条件?...
  7. fiddler抓包工具的使用
  8. 2018年60家新创公司排行榜
  9. 4K高清视频素材,拿去不谢。
  10. 三菱FX1s与3台台达MS300变频器通讯程序