I2C 总线的工作原理及使用方法
eeskill 2021-09-24

大家好,通过前一期的学习,我们已经对ICD2 仿真烧写器和增强型PIC 实验板的使用方法及学习方式有所了解与熟悉,学会了如何用单片机来控制发光管、继电器、蜂鸣器、按键、数码管、RS232 串口、步进电机、温度传感器等资源,体会到了学习板的易用性与易学性,看了前几期实例,当你实验成功后一定很兴奋,很有成就感吧!现在我们就趁热打铁,再向上跨一步,一起来学习一下I2C 总线的工作原理及使用方法,这样我们可以将一些我们要保存的数据存储到I2C总线的非易失存储器中,实现断电保持的功能,比如:你设置了一个密码,但不至于这个设备断过电以后就要重新设置过,我们可以将密码数据写在非易失存储器里面,还有如汽车的量程表的读数是不断累计的,可以通过不断访问I2C 存储器实现。

一、I2C总线特点

I2C 总线是主从结构,单片机是主器件,存储器是从器件。一条总线可以带多个从器件( 也可以有多主结构),I2C 总线的SDA 和SCL 是双向的,开路门结构,通过上拉电阻接正电源。进行数据传输时,SDA 线上的数据必须在时钟的高电平周期保持稳定。数据线的高或低电平状态只有在SCL 线的时钟信号是低电平时才能改变,如图1 所示。

图1 数据位的有效性规定

在SCL 线是高电平时,SDA 线从高电平向低电平切换表示起始条件;当SCL 是高电平时SDA 线由低电平向高电平切换表示停止条件如图2 所示。

图2 起始和停止信号

发送到SDA 线上的每个字节必须为8 位。

可以由高位到低位传输多个字节。每个字节后必须跟一个响应位(ACK)。响应时钟脉冲由主机产生。主机释放SDA 线从机将SDA 线拉低,并在时钟脉冲的高电平期间保持稳定。如图3 示。当主机接受数据时,它收到最后一个数据字节后,必须向从机发出一个结束传送的信号。这个信号是由主机对从机的“非应答”来实现的。然后,从机释放SDA 线,以允许主机产生终止或重复起始信号。

图3 字节格式与应答

二、数据帧格式

(1)主机向从机发送数据,数据的传送方向在传输过程中不改变,如图4 所示。

图4 主机向从机发送数据

注:阴影部分:表示主机向从机发送数据;无阴影部分:表示主机向从机读取数据。

A:表示应答;:表示非应答。S:起始信号;P :终止信号。

(2)主机在第一个字节后,立即向从机读取数据,如图5 所示。

图5 主机在第一个字节后立即读从机

(3)复合格式,如图6 所示。传输改变方向的时候,起始条件和从机地址都会被重复,但R/ W-位取反。如果主机接收器发送一个停止或重复起始信号,它之前应该发送了一个不响应信号()。

图6 复合格式

由以上格式可见,无论哪种传输方式,起始信号、终止信号和地址均由主机发出(图中阴影部分),数据字节的传送方向则由寻址字节中的方向位规定,每个字节的传送都必须有应答位(A 或)。

下面通过24C02 实例在增强型PIC 实验板上编程,其硬件原理图如图7 所示,U7 为实验板上24C02 芯片,SDA 与单片机的RB5 口相连,SCL 与单片机RB4 相连,七段数码管D5、D7、D8 组成了显示单元,字形码的数据通过RC 口送入,各数码管的显示片选信号分别不同的RA 口进行控制。

图7 读/ 写AT24C 系列存储器原理图

在MPLab IDE 软件中新建工程,加入源程序代码,同时进行芯片型号的选择和配置位的设置,我们实验所用的芯片型号为PIC16F877A。

编写的程序代码如下,其中程序流程图如图8 所示。

三、软件流程图

图8 I2C 总线读/ 写数据流程图

四、软件代码

/**********/

/* 目标器件:PIC16F877A */

/* 晶振:4.0MHZ */

/* 编译环境:MPLAB V7.51 */

/**********/

/**********

包含头文件

**********/

#include<pic.h>

/**********

数据定义

**********/

#define address 0xa

#define nop() asm("nop")

#define OP_READ 0xa1

// 器件地址以及读取操作

#define OP_WRITE 0xa0

// 器件地址以及写入操作

/**********

端口定义

**********/

#define SCL RB4

#define SDA RB5

#define SCLIO TRISB4

#define SDAIO TRISB5

/**********

共阴LED 段码表

**********/

const char table[]={0xC0,0xF9,0xA4,0x

B0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x

83,0xC6,0xA1,0x86,0x8E};

/**********

函数功能: 延时子程序

**********/

void delay()

{

int i;

for(i=0;i<100;i++)

{;}

}

/**********

函数功能: 开始信号

**********/

void start()

{

SDA=1;

nop();

SCL=1;

nop();nop();nop();nop();nop();

SDA=0;

nop();nop();nop();nop();nop();

SCL=0;

nop();nop();

}

/**********

函数功能: 停止信号

**********/

void stop()

{

SDA=0;

nop();

SCL=1;

nop();nop();nop();nop();nop();

SDA=1;

nop();nop();nop();nop();

}

/**********

函数功能: 读取数据

出口参数:read_data

**********/

unsigned char shin()

{

unsigned char i,read_data;

for(i=0;i<8;i++)

{ nop();nop();nop();

SCL=1;

nop();nop();

read_data《=1;

if(SDA == 1)

read_data=read_data+1;

nop();

SCL=0;

}

return(read_data);

}

/**********

函数功能: 向EEPROM 写数据

入口参数:write_data

出口参数:ack_bit

**********/

bit shout(unsigned char write_data)

{

unsigned char i;

unsigned char ack_bit;

for(i = 0; i < 8; i++)

{

if(write_data&0x80)

SDA=1;

else

SDA=0;

nop();

SCL = 1;

nop();nop();nop();nop();nop();

SCL = 0;

nop();

write_data 《= 1;

}

nop();nop();

SDA = 1;

nop();nop();

SCL = 1;

nop();nop();nop();

ack_bit = SDA; // 读取应答

SCL = 0;

nop();nop();

return ack_bit;

// 返回AT24Cxx 应答位

}

/**********

函数功能: 向指定地址写数据

入口参数:addr,write_data

**********/

void write_byte(unsigned char addr,

unsigned char write_data)

{

start();

shout(OP_WRITE);

shout(addr);

SDAIO = 0;

// 在写入数据前SDA 应设置为输出

shout(write_data);

stop();

delay();

}

/**********

函数功能: 向指定地址读数据

入口参数:random_addr

出口参数:read_data

**********/

unsigned char read_random(unsigned

char random_addr)

{ unsigned char read_data;

start();

shout(OP_WRITE);

shout(random_addr);

start();

shout(OP_READ);

SDAIO = 1;

// 读取数据前SDA 应设置为输入

read_data = shin();

stop();

return(read_data);

}

/**********

函数功能: 显示子程序

入口参数:k

**********/

void display(unsigned char k)

{

TRISA=0X00;

// 设置A 口全为输出

PORTC=table[k/1000];

// 显示千位

PORTA=0xEF;

delay();

PORTC=table[k/100%10];

// 显示百位

PORTA=0xDF;

delay();

PORTC = table [k/ 10%10] ;

// 显示十位

PORTA=0xFB;

delay();

PORTC=table[k%10]; // 显示个位

PORTA=0xF7;

delay();

}

/**********

函数功能: 主程序

**********/

void main()

{

unsigned char eepromdata;

TRISB=0X00;

OPTION&=~(1《7);

// 设置RB 口内部上拉电阻有效

TRISC=0X00;

PORTB=0X00;

PORTC=0xff;

TRISA=0X00;

eepromdata=0;

write_byte(0x01,0x55);

// 向0x01 地址写入0x55(85) 的数据

delay();

write_byte(0x02,0xaa);

// 向0x02 地址写入0xAA(170) 的数据

delay();

eepromdata=read_random(0x02);

// 读取其中一个地址内的数据来验证

while(1)

{

display(eepromdata);

}

}

编好程序后将编译好的HEX 码通过ICD2仿真烧写器烧入单片机芯片,上电运行,主程序中在0x01 地址写入了“0x55”, 在0x02 地址写入了“0xaa”,然后在while 循环中读出0x02地址的值,也就是我们之前写入的“0x55”,读出后显示在数码管上,我们可以看到数码管显示“170”,即“0xaa”相应的十进制数。

作为初学者的读者一定对有些语句会有点疑问,可以看程序中的注释部份,24c 系列IC 数据手册和源程序相结合来进行分析。

声明: 本文转载自其它媒体或授权刊载,目的在于信息传递,并不代表本站赞同其观点和对其真实性负责,如有新闻稿件和图片作品的内容、版权以及其它问题的,请联系我们及时删除。(联系我们,邮箱:evan.li@aspencore.com )
0
评论
热门推荐
  • 相关技术文库
  • 工业
  • 安防
  • 航空
  • CAN
  • 风电风机故障诊断远程无线管理方案

    风电行业作为可再生能源领域中最具前景的发电方式之一,在全球范围内分布广泛。但是,在风机发生故障时,却总是措手不及。本文将提供可行的方案,能够为解决故障带来便利。   风电行业现状概述 随着“碳中和”和“碳达峰”的热度疯涨,新能源行业势必崛起。风

    04-27
  • 如何将CAN总线升级成CAN FD?

    如何快速升级到CAN FD? 小致百科课堂 · ▴ 点击视频,关注查看更多 ▴ 21世纪初,CAN总线技术迎来了CAN FD时代,数据传输的速率不断提高的同时,极大地缩短了数据传输,尤其是程序下载的时间。那么如何才能将手头的CAN总线升级成CAN FD呢? 致远电子为您提供3

    04-22
  • 一张表看电机的分类

    据说尼古拉·特斯拉(Nikola Tesla)于1888年发明了交流电机。从那时起,由于各种元素创新,例如电机的组成材料(磁铁、钢板等),半导体元器件的材料、部件技术和控制技术等,使电机有了长足发展。例如,在1900年代初期开发的输出功率为5马力的感应电机,在2

    04-21
  • 解析电机的旋转动作和发电作用

    电机的旋转原理 作为电机基础知识,我们将介绍电机原理相关的内容。 关于电流、磁场和力 首先,为了便于后续电机原理说明,我们来回顾一下有关电流、磁场和力的基本定律/法则。虽然有一种怀旧的感觉,但如果平时不常使用磁性元器件,就很容易忘记这些知识。

    04-14
  • 运动控制T型曲线速度规划的matlab、 C语言实现

    ★ 本文介绍了运动控制中常用的梯形速度曲线规划的原理和程序实现,最后给出了测试结果; ” 1 前言 2 理论分析 3 matlab 实现 4 测试结果 5 C语言实现 6 总结 1 前言 在伺服系统以及控制系统的加减速动作中,为了让速度更加平滑,可以引入T型速度曲线规划(T

    03-31
  • CAN总线和RS485总线应用概述

    CAN总线和RS485总线的定义 CAN是控制器局域网络(Controller Area Network, CAN)的简称,是由研发和生产汽车电子产品著称的德国BOSCH公司开发了的,并最终成为国际标准(ISO11898)。是国际上应用最广泛的现场总线之一。在北美和西欧,CAN总线协议已经成为

    03-30
  • 传感器这么多种,你都知道怎么工作的吗

    布料张力测量及控制原理 ▼ 直滑式电位器控制气缸活塞行程 ▼ 压阻式传感器测量液位的工作原理 ▼ MQN型气敏电阻结构及测量电路 ▼ 气泡式水平仪的工作原理 ▼ 扩散硅式压力传感器 ▼ 应变加速度感应器 ▼ 称重式料位计 ▼ 电子皮带秤重示意图 ▼ 电子吊车秤

    03-26
  • 一文看懂I2C(FPGA实测I2C波形)

    据非官方统计,90%电子行业的公众号都介绍过3种串行通讯协议:UART、SPI和I2C。这3种串行协议也是电子开发行业最常用的协议。前面介绍了 及其 , 。本篇文章介绍I2C通讯协议及其FPGA实测波形。 文末有【I2C官方标准文档下载方法】。 有哪些内容 I2C是什么 5种

    03-25
  • 红电线,黄电线,绿电线,各种颜色电线都代表什么?

    1、依导线颜色标志电路 黑色——装置和设备的内部布线。 棕色——直流电路的正极。 红色——三相电路的C相; 半导体三极管的集电极; 半导体二极管、整流二极管或可控硅管的阴极。 黄色——三相电路的A相; 半导体三极管的基极; 可控硅管和双向可控硅管的控

    03-26
  • 总线隔离后接地出现通讯异常该如何改善?

    在已为大家介绍隔离后接地的ESD作用机理,那么面对总线隔离后由于接地而出现的通讯异常问题该如何改善,本文将为大家介绍对应的改善措施以及电路作用详解。    前言 为保证总线网络的通讯稳定性,通讯接口通常会做隔离,隔离的主要目的: 安规考虑:保护设备

    03-19
  • 常用的电气电路图集

    1 单相照明双路互备自投供电电路 2 双路三相电源自投电路 3 茶炉水加热自动控制电路 4 简单的温度控制器电路 5 简易晶闸管温度自动控制电路 6 用双向晶闸管控制温度电路 7 XCT-101动圈式温度调节仪控温电路 8 电接点压力式温度表控温电路 9 TDA-8601型温度指

    03-08
  • 常见CAN总线干扰现象

    CAN总线由其高可靠和实时性被广泛应用于新能源汽车、轨道交通、医疗、工程机械等行业,但是由于大部分行业工作环境都比较恶劣,所以提高总线抗干扰能力是目前行业用户最为关注的方向。   常见CAN总线干扰现象 如下为一条流水线有两路CAN总线,一条总线有22个

    03-11
下载排行榜
更多
EE直播间
更多
广告
X
广告