查看I2C 总线精要的源代码
←
I2C 总线精要
跳转到:
导航
,
搜索
因为以下原因,你没有权限编辑本页:
您刚才请求的操作只有这个用户组中的用户才能使用:
用户
您可以查看并复制此页面的源代码:
== Notes == <source lang=bash> Board I2C / TWI pins Uno, Ethernet A4 (SDA), A5 (SCL) Mega2560 20 (SDA), 21 (SCL) Leonardo 2 (SDA), 3 (SCL) Due 20 (SDA), 21 (SCL), SDA1, SCL1 </source> <br> == 概述 == 由 Philips (现 NXP) 于 80 年代开发,是一种很可靠的低速外设总线,广泛应用于 PC 和嵌入式系统:各种 I2C 接口的传感器、OLED 显示屏、SMBus (System Management Bus, )、PMBus (Power Management Bus)、IPMI (Intelligent Platform Management Interface)、DDC (Display Data Channel)、ATCA (Advanced Telecom Computing Architecture)...... 两根线: SDA, SCL,皆拉高 (pull-up),总线空闲时,两线皆为高电平 * SDA : Serial Data Line, holds Data or address signal * SCL : Serial Clock Line, holds Clock signal * IO must be open drain (or open collector in TTL) [[文件:I2C data transfer 640.png]] [[文件:I2c com.png]] * 7bit 地址,保留 16 个,可用 112;标准模式 (100 Kbit/s)、低速模式 (10 Kbit/s) * 10bit 地址;快速模式 (400 Kbit/s)、高速模式 (3.4 Mbit/s) '''数据传输:''' * 7bit mode: 发送 7bit 的address (MSB) 及一位的 W(0) / R(1) 后,该 address 的 slave 端会发送一个 Ack (acknowledge) 位,ACK = 0 表设定成功 (Slave 把 SDA 拉到 LOW),开始数据传送 * 每次传一个字节,每个字节都跟著一个 ACK bit,由 Slave 端发送(把 SDA 拉 LOW),否则 Master 认为字节写失败,发出 STOP 信号或是重新发送 START 信号 * 在每个 byte 之间 Slave 端可以把 SCL 拉低来强制传输暂停 * SDA 只能在 SCL 为 LOW 时改变 * 在 SCL 为 HIGH 时,SDA 必须是 stable 的,除非 Start/Stop condition '''10bit mode:''' 用两个 byte 来传送 address。第一个 byte 的前五位需为 “1111 0” 来表示要使用 10-bit addressing [[文件:I2c-10bit-addr.gif]] <br><br> == 开始位 == Start Condition SDA,SCL 皆为高电平时,拉低 SDA <source lang=cpp> void i2c_start(void) { SDA = 1; // i2c start bit sequence SCL = 1; i2c_delay(); SDA = 0; i2c_delay(); SCL = 0; i2c_delay(); } </source> <br> == 结束位 == Stop Condition SCL 上升沿后, SDA 从 0 拉到 1 <source lang=cpp> void i2c_stop() { SDA = 0; // i2c stop bit sequence i2c_delay(); SCL = 1; i2c_delay(); SDA = 1; i2c_delay(); } </source> <br> == 状态图 == === 主发从收 === * 开始位后,发 7 位地址,随后读写位为 0 (Write) * 收到 slave 反馈的 ACK 位后,开始写字节 * 每写一个字节,需要收到 slave 反馈的 ACK (SDA = 0) 后才开始下一个字节传输,否则传输中止,抛出出错异常 * 写完所有字节,则发送 Stop condition,Slave 收到 Stop condition 后,才会中止数据接收。。。 [[文件:I2c flow chart master tx slave rx.jpg | 950px]] <br> === 主收从发 === * 开始位后,发 7 位地址,随后读写位为 1 (Read) * 收到 slave 反馈的 ACK 位后,<b>立即</b>开始读取数据 <------ * 每读一个字节,需要给一个 ACK (SDA = 0),如果是最后一个字节,则需给一个 NACK (SDA = 1) [[文件:I2c flow chart master rx slave tx.jpg | 950px]] <br> <br><br> == 版本 == The history of I²C specification releases: * In 1982, the original 100 kHz I²C system was created as a simple internal bus system for building control electronics with various Philips chips. * In 1992, Version 1 added 400 kHz Fast-mode (Fm) and a 10-bit addressing mode to increase capacity to 1008 nodes. This was the first standardized version. * In 1998, Version 2 added 3.4 MHz High-speed mode (Hs) with power-saving requirements for electric voltage and current. * In 2000, Version 2.1 clarified version 2, without significant functional changes. * In 2007, Version 3 added 1 MHz Fast-mode plus (Fm+) (using 20 mA drivers), and a device ID mechanism. * In 2012, Version 4 added 5 MHz Ultra Fast-mode (UFm) for new USDA (data) and USCL (clock) lines using push-pull logic without pull-up resistors, and added an assigned manufacturer ID table. It is only a unidirectional bus. * In 2012, Version 5 corrected mistakes. * In 2014, Version 6 corrected two graphs. This is the most recent standard <br> == 软件模拟 == To initialize the ports set the output resisters to 0 and the tristate registers to 1 which disables the outputs and allows them to be pulled high by the resistors. The following 4 functions provide the primitive start, stop, read and write sequences. All I2C transactions can be built up from these. <source lang=cpp> SDA = SCL = 1; SCL_IN = SDA_IN = 0; void i2c_dly(void) { } void i2c_start(void) { SDA = 1; // i2c start bit sequence i2c_dly(); SCL = 1; i2c_dly(); SDA = 0; i2c_dly(); SCL = 0; i2c_dly(); } void i2c_stop(void) { SDA = 0; // i2c stop bit sequence i2c_dly(); SCL = 1; i2c_dly(); SDA = 1; i2c_dly(); } unsigned char i2c_rx(char ack) { char x, d=0; SDA = 1; for(x=0; x<8; x++) { d <<= 1; do { SCL = 1; } while(SCL_IN==0); // wait for any SCL clock stretching i2c_dly(); if(SDA_IN) d |= 1; SCL = 0; } if(ack) SDA = 0; else SDA = 1; SCL = 1; i2c_dly(); // send (N)ACK bit SCL = 0; SDA = 1; return d; } bit i2c_tx(unsigned char d) { char x; static bit b; for(x=8; x; x--) { if(d&0x80) SDA = 1; else SDA = 0; SCL = 1; d <<= 1; SCL = 0; } SDA = 1; SCL = 1; i2c_dly(); b = SDA_IN; // possible ACK bit SCL = 0; return b; } </source> ;使用示例: The 4 primitive functions above can easily be put together to form complete I2C transactions. Here's and example to start an SRF08 ranging in cm: <source lang=cpp> i2c_start(); // send start sequence i2c_tx(0xE0); // SRF08 I2C address with R/W bit clear i2c_tx(0x00); // SRF08 command register address i2c_tx(0x51); // command to start ranging in cm i2c_stop(); // send stop sequence </source> Now after waiting 65mS for the ranging to complete (I've left that to you) the following example shows how to read the light sensor value from register 1 and the range result from registers 2 & 3. <source lang=cpp> i2c_start(); // send start sequence i2c_tx(0xE0); // SRF08 I2C address with R/W bit clear i2c_tx(0x01); // SRF08 light sensor register address i2c_start(); // send a restart sequence i2c_tx(0xE1); // SRF08 I2C address with R/W bit set lightsensor = i2c_rx(1); // get light sensor and send acknowledge. Internal register address will increment automatically. rangehigh = i2c_rx(1); // get the high byte of the range and send acknowledge. rangelow = i2c_rx(0); // get low byte of the range - note we don't acknowledge the last byte. i2c_stop(); // send stop sequence </source> <br><br> == 参考 == * [https://www.nxp.com/docs/en/user-guide/UM10204.pdf I2C-bus specification and user manual] * https://en.wikipedia.org/wiki/I%C2%B2C * http://www.robot-electronics.co.uk/i2c-tutorial * https://learn.sparkfun.com/tutorials/i2c * http://wiki.csie.ncku.edu.tw/embedded/I2C <br><br> <br><br> <br><br> <br><br> <br><br> <br><br> <br><br> <br><br> <br><br> <br><br> <br><br> <br><br> <br><br> <br><br> <br><br>
返回到
I2C 总线精要
。
个人工具
登录
名字空间
页面
讨论
变换
查看
阅读
查看源代码
查看历史
操作
搜索
导航
首页
社区专页
新闻动态
最近更改
随机页面
帮助
工具箱
链入页面
相关更改
特殊页面