【转载】GPIO模拟i2c通信
I2C总线的通信过程(见图4-8)主要包含三个主要阶段:起始阶段、数据传输阶段和终止阶段。

1. 起始阶段
在I2C总线不工作的情况下,SDA(数据线)和SCL(时钟线)上的信号均为高电平。如果此时主机需要发起新的通信请求,那么需要首先通过SDA和SCL发出起始标志。当SCL为高电平时,SDA电平从高变低,这一变化表示完成了通信的起始条件。
在起始条件和数据通信之间,通常会有延时要求,具体的指标会在设备厂商的规格说明书中给出。
2. 数据传输阶段
I2C总线的数据通信是以字节(8位)作为基本单位在SDA上进行串行传输的。一个字节的传输需要9个时钟周期。其中,字节中每一位的传输都需要一个时钟周期,当新的SCL到来时,SCL为低电平,此时数据发送方根据当前传输的数据位控制SDA的电平信号。如果传输的数据位为"1",就将SDA电平拉高;如果传输的数据位为"0",就将SDA的电平拉低。当SDA上的数据准备好之后,SCL由低变高,此时数据接收方将会在下一次SCL信号变低之前完成数据的接收。当8位数据发送完成后,数据接收方需要一个时钟周期以使用SDA发送ACK信号,表明数据是否接收成功。当ACK信号为"0"时,说明接收成功;为"1"时,说明接收失败。每个字节的传输都是由高位(MSB)到低位(LSB)依次进行传输。
I2C总线协议中规定,数据通信的第一个字节必须由主机发出,内容为此次通信的目标设备地址和数据通信的方向(读/写)。在这个字节中,第1~7位为目标设备地址,第0位为通信方向,当第0位为"1"时表示读,即后续的数据由目标设备发出主机进行接收;当第0位为"0"时表示写,即后续的数据由主机发出目标设备进行接收。在数据通信过程中,总是由数据接收方发出ACK信号。
3. 终止阶段
当主机完成数据通信,并终止本次传输时会发出终止信号。当SCL 是高电平时,SDA电平由低变高,这个变化意味着传输终止。
下面给出了模拟I2C总线进行读写的伪代码,用以说明如何使用GPIO实现I2C通信:
#define SDA 254 //定义SDA所对应的GPIO接口编号
#define SCL 255 //定义SCL所对应的GPIO接口编号
#define OUTP 1 //表示GPIO接口方向为输出
#define INP 0 //表示GPIO接口方向为输入
/* I2C起始条件 */
int i2c_start()
{
//初始化GPIO口
set_gpio_direction(SDA, OUTP); //设置SDA方向为输出
set_gpio_direction (SCL, OUTP); //设置SCL方向为输出
set_gpio_value(SDA, ); //设置SDA为高电平
set_gpio_value(SCL, ); //设置SCL为高电平
delay(); //延时
//起始条件
set_gpio_value(SDA, ); //SCL为高电平时,SDA由高变低
delay();
}
/* I2C终止条件 */
void i2c_stop()
{
set_gpio_value(SCL, );
set_gpio_direction(SDA, OUTP);
set_gpio_value(SDA, );
delay();
set_gpio_value(SDA, ); //SCL高电平时,SDA由低变高
}
/*
I2C读取ACK信号(写数据时使用)
返回值 :0表示ACK信号有效;非0表示ACK信号无效
*/
unsigned char i2c_read_ack()
{
unsigned char r;
set_gpio_direction(SDA, INP); //设置SDA方向为输入
set_gpio_value(SCL,); // SCL变低
r = get_gpio_value(SDA); //读取ACK信号
delay();
set_gpio_value(SCL,); // SCL变高
delay();
return r;
}
/* I2C发出ACK信号(读数据时使用) */
int i2c_send_ack()
{
set_gpio_direction(SDA, OUTP); //设置SDA方向为输出
set_gpio_value(SCL,); // SCL变低
set_gpio_value(SDA, ); //发出ACK信号
delay();
set_gpio_value(SCL,); // SCL变高
delay();
}
/* I2C字节写 */
void i2c_write_byte(unsigned char b)
{
int i;
set_gpio_direction(SDA, OUTP); //设置SDA方向为输出
for (i=; i>=; i--) {
set_gpio_value(SCL, ); // SCL变低
delay();
set_gpio_value(SDA, b & (<<i)); //从高位到低位依次准备数据进行发送
set_gpio_value(SCL, ); // SCL变高
delay();
}
i2c_read_ack(); //检查目标设备的ACK信号
}
/* I2C字节读 */
unsigned char i2c_read_byte()
{
int i;
unsigned char r = ;
set_gpio_direction(SDA, INP); //设置SDA方向为输入
for (i=; i>=; i--) {
set_gpio_value(SCL, ); // SCL变低
delay();
r = (r <<) | get_gpio_value(SDA); //从高位到低位依次准备数据进行读取
set_gpio_value(SCL, ); // SCL变高
delay();
}
i2c_send_ack(); //向目标设备发送ACK信号
return r;
}
/*
I2C读操作
addr:目标设备地址
buf:读缓冲区
len:读入字节的长度
*/
void i2c_read(unsigned char addr, unsigned char* buf, int len)
{
int i;
unsigned char t;
i2c_start(); //起始条件,开始数据通信
//发送地址和数据读写方向
t = (addr << ) | ; //低位为1,表示读数据
i2c_write_byte(t);
//读入数据
for (i=; i<len; i++)
buf[i] = i2c_read_byte();
i2c_stop(); //终止条件,结束数据通信
}
/*
I2C写操作
addr:目标设备地址
buf:写缓冲区
len:写入字节的长度
*/
void i2c_write (unsigned char addr, unsigned char* buf, int len)
{
int i;
unsigned char t;
i2c_start(); //起始条件,开始数据通信
//发送地址和数据读写方向
t = (addr << ) | ; //低位为0,表示写数据
i2c_write_byte(t);
//写入数据
for (i=; i<len; i++)
i2c_write_byte(buf[i]);
i2c_stop(); //终止条件,结束数据通信
}
【转载】GPIO模拟i2c通信的更多相关文章
- gpio模拟i2c驱动
前段时间做项目,需要gpio模拟i2c通信,最后参考了一些资料,然后编写了一个程序.现在发出来,以免以后忘记,也为一些需要的朋友提供参考.不喜勿喷哈. /* 说明:该程序是基于atmel公司的sama ...
- S5PV210之GPIO模拟I2c时序之pcf8591与at24xx linux3.0.8驱动
目录:一. 说明 二. 驱动程序说明及问题 三. 案例一 四. 案例二 一. 说明 mini210开发板上带了at24c08, 看了linux内核自带的at24.c的驱动程序,编译下载到看 ...
- STM32F207 两路ADC连续转换及GPIO模拟I2C给MT9V024初始化参数
1.为了更好的方便调试,串口必须要有的,主要打印一些信息,当前时钟.转换后的电压值和I2C读出的数据. 2.通过GPIO 模拟I2C对镁光的MT9V024进行参数初始化.之前用我以前公司SP0A19芯 ...
- I2C总线以及GPIO模拟I2C
·I2C总线的一些特征: 1. 只要求两条总线,一条串行数据线(SDA),一条串行时钟线(SCL) 2. 两个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机系统软件设定的地址:主机可 ...
- gpio模拟I2C,驱动pcf8574T
一.pcf8574T介绍 查看pcf8574T的数据手册, A表示读或写,当A为1的时候表示读,当A为0的时候表示写.现把地址控制线,即A2.A1.A0全部接地,可以得到读控制指令为0x41,写控制指 ...
- GPIO实现I2C协议模拟(2)
接着上一节继续补充 结合上一节的描述 写Slave的过程如下(BYTE) 读Slave的过程如下(BYTE) 分为两段 第一段 ,写OFFSET,第二段读数据 WORD的方式与BYTE大同异 读行为 ...
- GPIO实现I2C协议模拟(1)
最近需要用GPIO模拟I2C协议,如果是在Linux下面比较简单,但在Windows下面,是否有没Linux那么简单了. 索性自己对I2C协议还有一些了解,翻了SPEC并结合示波器量出的实际信号分析, ...
- GPIO模拟SPI
上次用gpio模拟i2c理解i2c协议.相同的,我用gpio模拟spi来理解spi协议. 我用的是4线spi,四线各自是片选.时钟.命令/数据.数据. 数据在时钟上升沿传递,数据表示的是数据还是命令由 ...
- STM32F10x_模拟I2C读写EEPROM
Ⅰ.写在前面 说到IIC,大家都应该不会陌生,我们初学单片机的时候或多或少都知道或了解过,甚至使用I2C控制过器件.但是,有多少人真正去深入理解,或者深入研究过I2C通信协议呢? 1.我们有必要学习I ...
随机推荐
- 彻底理解Promise对象——用es5语法实现一个自己的Promise(上篇)
本文同步自我的个人博客: http://mly-zju.github.io/ 众所周知javascript语言的一大特色就是异步,这既是它的优点,同时在某些情况下也带来了一些的问题.最大的问题之一,就 ...
- 3631: [JLOI2014]松鼠的新家
3631: [JLOI2014]松鼠的新家 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 707 Solved: 342[Submit][Statu ...
- 算法模板——splay区间反转 2
实现功能:同splay区间反转 1(基于BZOJ3223 文艺平衡树) 这次改用了一个全新的模板(HansBug:琢磨了我大半天啊有木有),大大简化了程序,同时对于splay的功能也有所完善 这里面没 ...
- Xamarin自定义布局系列——ListView的一个自定义实现ItemsControl(横向列表)
在以前写UWP程序的时候,了解到在ListView或者ListBox这类的列表空间中,有一个叫做ItemsPannel的属性,它是所有列表中子元素实际的容器,如果要让列表进行横向排列,只需要在Xaml ...
- RxJava 笔记
前言 目前 RxJava 是安卓开发圈内最流行的库之一,本来准备研究研究,但看了扔物线写的<给 Android 开发者的 RxJava 详解>后,觉得生无可恋,哦不,是觉得已经写无可写. ...
- 卸载php+apache+mysql
一.卸载删除 mysql 1 sudo apt-get autoremove --purge mysql-server-5.0 2 sudo apt-get remove mysql-server ...
- (23)IO之打印流 PrintStream & Printwriter
PrintStream PrintStream可以接受文件和其他字节输出流,所以打印流是对普通字节输出流的增强,其中定义了很多的重载的print()和println(),方便输出各种类型的数据. Pr ...
- CentOS最小化安装后启用无线连接网络
想要链接无线就需要无线工具包. yum install -y wireless-tools安装完成之后就有 iwconfig,iwlist,iw等命令行工具了. 首先启动无线网卡,记得开启无线开关, ...
- strspn 和strcspn
1.strcspn头文件:#inclued<string.h>定义函数:size_t strcspn(const char *s, const char * reject);函数说明:st ...
- 如何使用bootstrap
前言: 前几天,本想做一个登陆界面,但自己写form表单必然很丑,所以想用下bootstarp框架,之前听别人说bootstrap很牛的样子.但我完全不会bootstrap... 下载&目录 ...