嵌入式linux开发笔记: I2C
1. 初步编程框架
为了实现I2C Controller对I2C Device之间的通信,程序框架可以分拆为4个子程序。
1> I2C_controller.c
/* 有一个i2c_controller数组用来存放各种不同芯片的操作结构体 */
void register_i2c_controller()
{
}
/* 根据名字来选择某款I2C控制器 */
void select_i2c_controller(char *name)
{
}
/* 实现 i2c_transfer 接口函数 */
int i2c_transfer(i2c_msg msgs, int num)
{
}
2> S3C2440_I2C_controller.c
/* 实现i2c_controller
.init
.master_xfer
.name
*/
3>I2C_test.c
void i2c_test(void)
{
/* 初始化: 选择I2C控制器 */
/* 提供菜单供测试 */
}
4> at24cxx.c
int at24cxx_write(unsigned int addr, unsigned char *data, int len)
{
/* 构造i2c_msg */
/* 调用i2c_transfer */
}
int at24cxx_read(unsigned int addr, unsigned char *data, int len)
{
/* 构造i2c_msg */
/* 调用i2c_transfer */
}
2. I2C controller程序框架
1> i2c_controller.h
//首先设计几个结构体,这些结构体应包含在头文件i2c_controller.h中。
#ifndef _I2C_CONTROLLER_H
#define _I2C_CONTROLLER_H
typedef struct i2c_msg {
unsigned int addr; /* 7bits */
int flags; /* 0 - write, 1 - read */
int len;
int cnt_transferred;
unsigned char *buf;
}i2c_msg, *p_i2c_msg;
typedef struct i2c_controller {
int (*int)(void);
int (*master_xfer)(i2c_msg msgs, int num);
char *name;
}i2c_controller, *p_i2c_controller;
#endif /* _I2C_CONTROLLER_H */
2> i2c_controller.c
#include "i2c_controller.h"
#define I2C_CONTROLLER_NUM 10
/* 有一个i2c_controller数组用来存放各种不同芯片的操作结构体 */
static p_i2c_controller p_i2c_controllers[I2C_CONTROLLER_NUM];
static p_i2c_controller p_i2c_con_selected;
void register_i2c_controller(p_i2c_controller *p)
{
int i;
for (i = 0; i < I2C_CONTROLLER_NUM; i++)
{
if (!p_i2c_controllers[i])
{
p_i2c_controllers[i] = p;
return;
}
}
}
/* 根据名字来选择某款I2C控制器 */
int select_i2c_controller(char *name)
{
int i;
for (i = 0; i < I2C_CONTROLLER_NUM; i++)
{
if (p_i2c_controllers[i] && !strcmp(name, p_i2c_controllers[i]->name))
{
p_i2c_con_selected = p_i2c_controllers[i];
return 0;
}
}
return -1;
}
/* 实现 i2c_transfer 接口函数 */
int i2c_transfer(i2c_msg msgs, int num)
{
return p_i2c_con_selected->master_xfer(msgs, num);
}
void i2c_init(void)
{
/* 注册下面的I2C控制器 */
s3c2440_i2c_con_add();
/* 选择某款I2C控制器 */
/* 调用它的init函数 */
}
3> s3c2440_i2c_controller.c
#include "i2c_controller.h"
#include "../s3c2440_soc.h"
void i2c_interrupt_func(int irq)
{
/* 每传输完一个数据将产生一个中断 */
/* 对于每次传输, 第1个中断是"已经发出了设备地址" */
}
void s3c2440_i2c_con_init(void)
{
/* 设置时钟 */
/* [7] : IIC-bus acknowledge enable bit, 1-enable in rx mode
* [6] : 时钟源, 0: IICCLK = fPCLK /16; 1: IICCLK = fPCLK /512
* [5] : 1-enable interrupt
* [4] : 读出为1时表示中断发生了, 写入0来清除并恢复I2C操作
* [3:0] : Tx clock = IICCLK/(IICCON[3:0]+1).
* Tx Clock = 100khz = 50Mhz/16/(IICCON[3:0]+1)
*/
IICCON = (0<<6) | (1<<5) | (30<<0);
/* 注册中断处理函数 */
register_irq(27, i2c_interrupt_func);
}
void do_master_tx(p_i2c_msg msg)
{
msg->cnt_transferred = 0;
/* 设置寄存器启动传输 */
/* 1. 配置为 master tx mode */
/* 2. 把从设备地址写入IICDS */
IICDS = msg->addr<<1;
/* 3. IICSTAT = 0xf0 , 数据即被发送出去, 将导致中断产生 */
IICSTAT = 0xf0;
/* 后续的传输由中断驱动 */
/* 循环等待中断处理完毕 */
while (msg->cnt_transferred != msg->len);
}
void do_master_rx(p_i2c_msg msg)
{
msg->cnt_transferred = 0;
/* 设置寄存器启动传输 */
/* 1. 配置为 Master Rx mode */
/* 2. 把从设备地址写入IICDS */
IICDS = (msg->addr<<1)|(1<<0);
/* 3. IICSTAT = 0xb0 , 从设备地址即被发送出去, 将导致中断产生 */
IICSTAT = 0xb0;
/* 后续的传输由中断驱动 */
/* 循环等待中断处理完毕 */
while (msg->cnt_transferred != msg->len);
}
int s3c2440_master_xfer(p_i2c_msg msgs, int num)
{
int i;
for (i = 0; i < num; i++)
{
if (msgs[i]->flags == 0)/* write */
do_master_tx(msgs[i]);
else
do_master_rx(msgs[i]);
}
}
/* 实现i2c_controller
.init
.master_xfer
.name
*/
static i2c_controller s3c2440_i2c_con = {
.name = "s3c2440",
.init = s3c2440_i2c_con_init,
.master_xfer = s3c2440_master_xfer,
};
void s3c2440_i2c_con_add(void)
{
register_i2c_controller(&s3c2440_i2c_con);
}
4> at24cxx.c
int at24cxx_write(unsigned int addr, unsigned char *data, int len)
{
/* 构造i2c_msg */
/* 调用i2c_transfer */
}
int at24cxx_read(unsigned int addr, unsigned char *data, int len)
{
/* 构造i2c_msg */
/* 调用i2c_transfer */
}
5> i2c_test.c
void i2c_test(void)
{
/* 初始化: 选择I2C控制器 */
/* 提供菜单供测试 */
}
3. I2c 中断
1> i2c_controller.h
#ifndef _I2C_CONTROLLER_H
#define _I2C_CONTROLLER_H
typedef struct i2c_msg {
unsigned int addr; /* 7bits */
int flags; /* 0 - write, 1 - read */
int len;
int cnt_transferred;
int err;
unsigned char *buf;
}i2c_msg, *p_i2c_msg;
typedef struct i2c_controller {
int (*int)(void);
int (*master_xfer)(i2c_msg msgs, int num);
char *name;
}i2c_controller, *p_i2c_controller;
#endif /* _I2C_CONTROLLER_H */
2> i2c_controller.c
#include "i2c_controller.h"
#define I2C_CONTROLLER_NUM 10
/* 有一个i2c_controller数组用来存放各种不同芯片的操作结构体 */
static p_i2c_controller p_i2c_controllers[I2C_CONTROLLER_NUM];
static p_i2c_controller p_i2c_con_selected;
void register_i2c_controller(p_i2c_controller *p)
{
int i;
for (i = 0; i < I2C_CONTROLLER_NUM; i++)
{
if (!p_i2c_controllers[i])
{
p_i2c_controllers[i] = p;
return;
}
}
}
/* 根据名字来选择某款I2C控制器 */
int select_i2c_controller(char *name)
{
int i;
for (i = 0; i < I2C_CONTROLLER_NUM; i++)
{
if (p_i2c_controllers[i] && !strcmp(name, p_i2c_controllers[i]->name))
{
p_i2c_con_selected = p_i2c_controllers[i];
return 0;
}
}
return -1;
}
/* 实现 i2c_transfer 接口函数 */
int i2c_transfer(i2c_msg msgs, int num)
{
return p_i2c_con_selected->master_xfer(msgs, num);
}
void i2c_init(void)
{
/* 注册下面的I2C控制器 */
s3c2440_i2c_con_add();
/* 选择某款I2C控制器 */
/* 调用它的init函数 */
}
3> s3c2440_i2c_controller.c
#include "i2c_controller.h"
#include "../s3c2440_soc.h"
static p_i2c_msg p_cur_msg;
void i2c_interrupt_func(int irq)
{
int index;
unsigned int iicstat = IICSTAT;
p_cur_msg->cnt_transferred++;
/* 每传输完一个数据将产生一个中断 */
/* 对于每次传输, 第1个中断是"已经发出了设备地址" */
if (p_cur_msg->flags == 0) /* write */
{
/* 对于第1个中断, 它是发送出设备地址后产生的
* 需要判断是否有ACK
* 有ACK : 设备存在
* 无ACK : 无设备, 出错, 直接结束传输
*/
if (p_cur_msg->cnt_transferred == 0) /* 第1次中断 */
{
if (iicstat & (1<<0))
{ /* no ack */
/* 停止传输 */
IICSTAT = 0xd0;
IICCON &= ~(1<<4);
p_cur_msg->err = -1;
delay(1000);
return;
}
}
if (p_cur_msg->cnt_transferred < p_cur_msg->len)
{
/* 对于其他中断, 要继续发送下一个数据
*/
IICDS = p_cur_msg->buf[p_cur_msg->cnt_transferred];
IICCON &= ~(1<<4);
}
else
{
/* 停止传输 */
IICSTAT = 0xd0;
IICCON &= ~(1<<4);
p_cur_msg->err = -1;
delay(1000);
}
}
else /* read */
{
/* 对于第1个中断, 它是发送出设备地址后产生的
* 需要判断是否有ACK
* 有ACK : 设备存在, 恢复I2C传输, 这样在下一个中断才可以得到第1个数据
* 无ACK : 无设备, 出错, 直接结束传输
*/
if (p_cur_msg->cnt_transferred == 0) /* 第1次中断 */
{
if (iicstat & (1<<0))
{ /* no ack */
/* 停止传输 */
IICSTAT = 0x90;
IICCON &= ~(1<<4);
p_cur_msg->err = -1;
delay(1000);
return;
}
else /* ack */
{
/* 恢复I2C传输 */
IICCON &= ~(1<<4);
return;
}
}
/* 非第1个中断, 表示得到了一个新数据
* 从IICDS读出、保存
*/
if (p_cur_msg->cnt_transferred < p_cur_msg->len)
{
index = p_cur_msg->cnt_transferred - 1;
p_cur_msg->buf[index] = IICDS;
/* 恢复I2C传输 */
IICCON &= ~(1<<4);
}
else
{
/* 发出停止信号 */
IICSTAT = 0x90;
IICCON &= ~(1<<4);
delay(1000);
}
}
}
void s3c2440_i2c_con_init(void)
{
/* 设置时钟 */
/* [7] : IIC-bus acknowledge enable bit, 1-enable in rx mode
* [6] : 时钟源, 0: IICCLK = fPCLK /16; 1: IICCLK = fPCLK /512
* [5] : 1-enable interrupt
* [4] : 读出为1时表示中断发生了, 写入0来清除并恢复I2C操作
* [3:0] : Tx clock = IICCLK/(IICCON[3:0]+1).
* Tx Clock = 100khz = 50Mhz/16/(IICCON[3:0]+1)
*/
IICCON = (1<<7) | (0<<6) | (1<<5) | (30<<0);
/* 注册中断处理函数 */
register_irq(27, i2c_interrupt_func);
}
int do_master_tx(p_i2c_msg msg)
{
p_cur_msg = msg;
msg->cnt_transferred = -1;
msg->err = 0;
/* 设置寄存器启动传输 */
/* 1. 配置为 master tx mode */
/* 2. 把从设备地址写入IICDS */
IICDS = msg->addr<<1;
/* 3. IICSTAT = 0xf0 , 数据即被发送出去, 将导致中断产生 */
IICSTAT = 0xf0;
/* 后续的传输由中断驱动 */
/* 循环等待中断处理完毕 */
while (!msg->err && msg->cnt_transferred != msg->len);
if (msg->err)
return -1;
else
return 0;
}
int do_master_rx(p_i2c_msg msg)
{
p_cur_msg = msg;
msg->cnt_transferred = -1;
msg->err = 0;
/* 设置寄存器启动传输 */
/* 1. 配置为 Master Rx mode */
/* 2. 把从设备地址写入IICDS */
IICDS = (msg->addr<<1)|(1<<0);
/* 3. IICSTAT = 0xb0 , 从设备地址即被发送出去, 将导致中断产生 */
IICSTAT = 0xb0;
/* 后续的传输由中断驱动 */
/* 循环等待中断处理完毕 */
while (!msg->err && msg->cnt_transferred != msg->len);
if (msg->err)
return -1;
else
return 0;
}
int s3c2440_master_xfer(p_i2c_msg msgs, int num)
{
int i;
int err;
for (i = 0; i < num; i++)
{
if (msgs[i]->flags == 0)/* write */
err = do_master_tx(msgs[i]);
else
err = do_master_rx(msgs[i]);
if (err)
return err;
}
return 0;
}
/* 实现i2c_controller
.init
.master_xfer
.name
*/
static i2c_controller s3c2440_i2c_con = {
.name = "s3c2440",
.init = s3c2440_i2c_con_init,
.master_xfer = s3c2440_master_xfer,
};
void s3c2440_i2c_con_add(void)
{
register_i2c_controller(&s3c2440_i2c_con);
}
4> at24cxx.c
int at24cxx_write(unsigned int addr, unsigned char *data, int len)
{
/* 构造i2c_msg */
/* 调用i2c_transfer */
}
int at24cxx_read(unsigned int addr, unsigned char *data, int len)
{
/* 构造i2c_msg */
/* 调用i2c_transfer */
}
5> i2c_test.c
void i2c_test(void)
{
/* 初始化: 选择I2C控制器 */
/* 提供菜单供测试 */
}
5. Final OK
1> I2ccontroller.h
#ifndef _I2C_CONTROLLER_H
#define _I2C_CONTROLLER_H
typedef struct i2c_msg {
unsigned int addr; /* 7bits */
int flags; /* 0 - write, 1 - read */
int len;
int cnt_transferred;
int err;
unsigned char *buf;
}i2c_msg, *p_i2c_msg;
typedef struct i2c_controller {
int (*init)(void);
int (*master_xfer)(p_i2c_msg msgs, int num);
char *name;
}i2c_controller, *p_i2c_controller;
#endif /* _I2C_CONTROLLER_H */
2> i2c_controller.c
#include "i2c_controller.h"
#define I2C_CONTROLLER_NUM 10
/* 有一个i2c_controller数组用来存放各种不同芯片的操作结构体 */
static p_i2c_controller p_i2c_controllers[I2C_CONTROLLER_NUM];
static p_i2c_controller p_i2c_con_selected;
void register_i2c_controller(p_i2c_controller *p)
{
int i;
for (i = 0; i < I2C_CONTROLLER_NUM; i++)
{
if (!p_i2c_controllers[i])
{
p_i2c_controllers[i] = p;
return;
}
}
}
/* 根据名字来选择某款I2C控制器 */
int select_i2c_controller(char *name)
{
int i;
for (i = 0; i < I2C_CONTROLLER_NUM; i++)
{
if (p_i2c_controllers[i] && !strcmp(name, p_i2c_controllers[i]->name))
{
p_i2c_con_selected = p_i2c_controllers[i];
return 0;
}
}
return -1;
}
/* 实现 i2c_transfer 接口函数 */
int i2c_transfer(p_i2c_msg msgs, int num)
{
return p_i2c_con_selected->master_xfer(msgs, num);
}
void i2c_init(void)
{
/* 注册下面的I2C控制器 */
s3c2440_i2c_con_add();
/* 选择某款I2C控制器 */
select_i2c_controller("s3c2440");
/* 调用它的init函数 */
p_i2c_con_selected->init();
}
3> s32440_controller.c
#include "i2c_controller.h"
#include "../s3c2440_soc.h"
static p_i2c_msg p_cur_msg;
int isLastData(void)
{
if (p_cur_msg->cnt_transferred == p_cur_msg->len - 1)
return 1; /* 正要开始传输最后一个数据 */
else
return 0;
}
void resume_iic_with_ack(void)
{
unsigned int iiccon = IICCON;
iiccon |= (1<<7); /* 回应ACK */
iiccon &= ~(1<<4); /* 恢复IIC操作 */
IICCON = iiccon;
}
void resume_iic_without_ack(void)
{
unsigned int iiccon = IICCON;
iiccon &= ~((1<<7) | (1<<4)); /* 不回应ACK, 恢复IIC操作 */
IICCON = iiccon;
}
void i2c_interrupt_func(int irq)
{
int index;
unsigned int iicstat = IICSTAT;
unsigned int iiccon;
//printf("i2c_interrupt_func! flags = %d\n\r", p_cur_msg->flags);
p_cur_msg->cnt_transferred++;
/* 每传输完一个数据将产生一个中断 */
/* 对于每次传输, 第1个中断是"已经发出了设备地址" */
if (p_cur_msg->flags == 0) /* write */
{
/* 对于第1个中断, 它是发送出设备地址后产生的
* 需要判断是否有ACK
* 有ACK : 设备存在
* 无ACK : 无设备, 出错, 直接结束传输
*/
if (p_cur_msg->cnt_transferred == 0) /* 第1次中断 */
{
if (iicstat & (1<<0))
{ /* no ack */
/* 停止传输 */
IICSTAT = 0xd0;
IICCON &= ~(1<<4);
p_cur_msg->err = -1;
printf("tx err, no ack\n\r");
delay(1000);
return;
}
}
if (p_cur_msg->cnt_transferred < p_cur_msg->len)
{
/* 对于其他中断, 要继续发送下一个数据
*/
IICDS = p_cur_msg->buf[p_cur_msg->cnt_transferred];
IICCON &= ~(1<<4);
}
else
{
/* 停止传输 */
IICSTAT = 0xd0;
IICCON &= ~(1<<4);
delay(1000);
}
}
else /* read */
{
/* 对于第1个中断, 它是发送出设备地址后产生的
* 需要判断是否有ACK
* 有ACK : 设备存在, 恢复I2C传输, 这样在下一个中断才可以得到第1个数据
* 无ACK : 无设备, 出错, 直接结束传输
*/
if (p_cur_msg->cnt_transferred == 0) /* 第1次中断 */
{
if (iicstat & (1<<0))
{ /* no ack */
/* 停止传输 */
IICSTAT = 0x90;
IICCON &= ~(1<<4);
p_cur_msg->err = -1;
printf("rx err, no ack\n\r");
delay(1000);
return;
}
else /* ack */
{
/* 如果是最后一个数据, 启动传输时要设置为不回应ACK */
/* 恢复I2C传输 */
if (isLastData())
{
resume_iic_without_ack();
}
else
{
resume_iic_with_ack();
}
return;
}
}
/* 非第1个中断, 表示得到了一个新数据
* 从IICDS读出、保存
*/
if (p_cur_msg->cnt_transferred < p_cur_msg->len)
{
index = p_cur_msg->cnt_transferred - 1;
p_cur_msg->buf[index] = IICDS;
/* 如果是最后一个数据, 启动传输时要设置为不回应ACK */
/* 恢复I2C传输 */
if (isLastData())
{
resume_iic_without_ack();
}
else
{
resume_iic_with_ack();
}
}
else
{
/* 发出停止信号 */
IICSTAT = 0x90;
IICCON &= ~(1<<4);
delay(1000);
}
}
}
void s3c2440_i2c_con_init(void)
{
/* 配置引脚用于I2C*/
GPECON &= ~((3<<28) | (3<<30));
GPECON |= ((2<<28) | (2<<30));
/* 设置时钟 */
/* [7] : IIC-bus acknowledge enable bit, 1-enable in rx mode
* [6] : 时钟源, 0: IICCLK = fPCLK /16; 1: IICCLK = fPCLK /512
* [5] : 1-enable interrupt
* [4] : 读出为1时表示中断发生了, 写入0来清除并恢复I2C操作
* [3:0] : Tx clock = IICCLK/(IICCON[3:0]+1).
* Tx Clock = 100khz = 50Mhz/16/(IICCON[3:0]+1)
*/
IICCON = (1<<7) | (0<<6) | (1<<5) | (30<<0);
/* 注册中断处理函数 */
register_irq(27, i2c_interrupt_func);
}
int do_master_tx(p_i2c_msg msg)
{
p_cur_msg = msg;
msg->cnt_transferred = -1;
msg->err = 0;
/* 设置寄存器启动传输 */
/* 1. 配置为 master tx mode */
IICCON |= (1<<7); /* TX mode, 在ACK周期释放SDA */
IICSTAT = (1<<4);
/* 2. 把从设备地址写入IICDS */
IICDS = msg->addr<<1;
/* 3. IICSTAT = 0xf0 , 数据即被发送出去, 将导致中断产生 */
IICSTAT = 0xf0;
/* 后续的传输由中断驱动 */
/* 循环等待中断处理完毕 */
while (!msg->err && msg->cnt_transferred != msg->len);
if (msg->err)
return -1;
else
return 0;
}
int do_master_rx(p_i2c_msg msg)
{
p_cur_msg = msg;
msg->cnt_transferred = -1;
msg->err = 0;
/* 设置寄存器启动传输 */
/* 1. 配置为 Master Rx mode */
IICCON |= (1<<7); /* RX mode, 在ACK周期回应ACK */
IICSTAT = (1<<4);
/* 2. 把从设备地址写入IICDS */
IICDS = (msg->addr<<1)|(1<<0);
/* 3. IICSTAT = 0xb0 , 从设备地址即被发送出去, 将导致中断产生 */
IICSTAT = 0xb0;
/* 后续的传输由中断驱动 */
/* 循环等待中断处理完毕 */
while (!msg->err && msg->cnt_transferred != msg->len);
if (msg->err)
return -1;
else
return 0;
}
int s3c2440_master_xfer(p_i2c_msg msgs, int num)
{
int i;
int err;
for (i = 0; i < num; i++)
{
if (msgs[i].flags == 0)/* write */
err = do_master_tx(&msgs[i]);
else
err = do_master_rx(&msgs[i]);
if (err)
return err;
}
return 0;
}
/* 实现i2c_controller
.init
.master_xfer
.name
*/
static i2c_controller s3c2440_i2c_con = {
.name = "s3c2440",
.init = s3c2440_i2c_con_init,
.master_xfer = s3c2440_master_xfer,
};
void s3c2440_i2c_con_add(void)
{
register_i2c_controller(&s3c2440_i2c_con);
}
4>at24cxx.c
#include "i2c_controller.h"
#define AT24CXX_ADDR 0x50
int at24cxx_write(unsigned int addr, unsigned char *data, int len)
{
i2c_msg msg;
int i;
int err;
unsigned char buf[2];
for (i = 0; i < len; i++)
{
buf[0] = addr++;
buf[1] = data[i];
/* 构造i2c_msg */
msg.addr = AT24CXX_ADDR;
msg.flags = 0; /* write */
msg.len = 2;
msg.buf = buf;
msg.err = 0;
msg.cnt_transferred = -1;
/* 调用i2c_transfer */
err = i2c_transfer(&msg, 1);
if (err)
return err;
}
return 0;
}
5> i2c_test.c
void do_write_at24cxx(void)
{
unsigned int addr;
unsigned char str[100];
int err;
/* 获得地址 */
printf("Enter the address of sector to write: ");
addr = get_uint();
if (addr > 256)
{
printf("address > 256, error!\n\r");
return;
}
printf("Enter the string to write: ");
gets(str);
printf("writing ...\n\r");
err = at24cxx_write(addr, str, strlen(str)+1);
printf("at24cxx_write ret = %d\n\r", err);
}
void do_read_at24cxx(void)
{
unsigned int addr;
int i, j;
unsigned char c;
unsigned char data[100];
unsigned char str[16];
int len;
int err;
int cnt = 0;
/* 获得地址 */
printf("Enter the address to read: ");
addr = get_uint();
if (addr > 256)
{
printf("address > 256, error!\n\r");
return;
}
/* 获得长度 */
printf("Enter the length to read: ");
len = get_int();
err = at24cxx_read(addr, data, len);
printf("at24cxx_read ret = %d\n\r", err);
printf("Data : \n\r");
/* 长度固定为64 */
for (i = 0; i < 4; i++)
{
/* 每行打印16个数据 */
for (j = 0; j < 16; j++)
{
/* 先打印数值 */
c = data[cnt++];
str[j] = c;
printf("%02x ", c);
}
printf(" ; ");
for (j = 0; j < 16; j++)
{
/* 后打印字符 */
if (str[j] < 0x20 || str[j] > 0x7e) /* 不可视字符 */
putchar('.');
else
putchar(str[j]);
}
printf("\n\r");
}
}
void i2c_test(void)
{
char c;
/* 初始化 */
i2c_init();
while (1)
{
/* 打印菜单, 供我们选择测试内容 */
printf("[w] Write at24cxx\n\r");
printf("[r] Read at24cxx\n\r");
printf("[q] quit\n\r");
printf("Enter selection: ");
c = getchar();
printf("%c\n\r", c);
/* 测试内容:
* 3. 编写某个地址
* 4. 读某个地址
*/
switch (c)
{
case 'q':
case 'Q':
return;
break;
case 'w':
case 'W':
do_write_at24cxx();
break;
case 'r':
case 'R':
do_read_at24cxx();
break;
default:
break;
}
}
}
I2C 硬件原理