虫子 IIC 基本通讯

举报
虫子VV 发表于 2022/06/23 00:26:47 2022/06/23
【摘要】 I^2^C协议的简单应用 I^2^C协议总体概述 I^2^C协议规则 ==I^2^C协议的数据有效性== ==I^2^C协议的起始信号、停止信号== ==I^2^C协议的通讯格式== I^2^C协议的数据读写三种方式 I^2^C 协议单向发送数据 比如显示设备,一般情况下我们只需要==写入数据==,传输过程如下 I^2^协议发送地址后立即读取数据 比如传感器设备,一般情况下我们只需要读出数...

I^2^C协议的简单应用

I^2^C协议总体概述

I^2^C 总线,是飞利浦推出的一种串行总线,是具备多主机系统所需的包括总线仲裁、高低速兼容的高性能==同步==

I^2^C总线的硬件,是由一根数据线SDA,一根==时钟线SCL==构成。==(由于有时钟线才有同步功能)==不同的器件,都是==并联==接在这两条线上。通过不同的==硬件地址==来识别通信对象。

image-20211122145113275

I^2^C总线==必须都接==上拉电阻接到电源VCC ,电阻大小要根据设备实际测量。==总线空闲时候==,==SDA和SCL都是高电平==。当其中一个设备拉低总线,整条线就全是低电平,器件与器件之间是“与”逻辑关系。

image-20211123101613426

I^2^C总线可能会有多个主机进行互相控制多个从机,多个主机通信就会出现仲裁的情况。我们51 单片机主要是单主机通信 ==多主机仲裁我们不概述==

I^2^C协议,是在同一根SDA线上进行==双向通信==,属于==半双工类==。I^2^C协议首先是发送从机硬件地址,然后发送命令,再发送数据/寄存器编号或者读取数据。I^2^C协议可以多字节连续读写数据

I^2^C协议规则

==I^2^C协议的数据有效性==

规定,必须是在SCL的低电平期间,才能改变SDA的电平状态。SCL高电平期间SDA线必须是稳定的,否则会错误的识别成起始信号或者停止信号。

image-20211123143241408

==I^2^C协议的起始信号、停止信号==

SCL高电平期间,==SDA下降沿==是起始信号,之后就是总线忙碌,比如发送设备唯一地址

SCL高电平期间,==SDA上升沿==是终止信号。之后是总线的空闲

==起始信号和终止信号,都是主机发送==

image-20211123145912135

==I^2^C协议的通讯格式==

I^2^C协议,起始信号之后,可以连续传输多个字节。然后以停止信号结束这一帧数据的传输。第一字节是 7位硬件地址 + 1位传输方向控制位。地址是根据硬件配置的,比如AT24C02的地址是4位固定 +3位接地,可以挂8个相同的AT24C02芯片。只有地址匹配的设备,才会处理总线上的数据

image-20211123151456148

I^2^C协议,每个字节必须是==8 + ACK==位。字节是先传输高位后传输低位。标准 I^2^C协议是每位4微秒以上。但是有些器件是兼容各种速度的。
==应答信号==是接收端接收数据后,把 A SDA 拉低。告诉发送端已经接收完毕。
==非应答信号==是接收端未能拉低,或者单片机读取数据的最后一个字节不需要应答。

image-20211123152241688

I^2^C协议的数据读写三种方式

I^2^C 协议单向发送数据

比如显示设备,一般情况下我们只需要==写入数据==,传输过程如下

image-20211123153814649

①首先是起始信号 S
②然后是发送 7 位从机地址+传输方向位,0写。
③SCL 拉高,判断 ACK ,再拉低 SCL 。
④发送第 1个字节,一般情况下都是指令,或者寄存器地址。
⑤SCL拉高,判断 ACK ,再拉低 SCL 。
⑥发送第2个字节,一般情况下都是数据。
⑦SCL拉高,判断 ACK ,再拉低 SCL 。
⑧可以继续传输数据,或者停止。

I^2^协议发送地址后立即读取数据

比如传感器设备,一般情况下我们只需要读出数据,传输过程如下:

image-20211123155049282

①首先是起始信号 S
②然后是发送 7 位从机地址+传输方向位,1 读。
③SCL 拉高,判断 ACK ,再拉低 SCL 。
④读取第 1 个字节,一般情况下都是指令,或者寄存器地址。
⑤发送应答 ACK
⑥读取第 2个字节,一般情况下都是数据。
⑦发送应答 ACK ,或者不应答 NACK 。
⑧可以继续传输数据,或者停止。

I^2^协议先指定寄存器地址,再读取该寄存器的数据

比如存储芯片,一般情况下我们要先制定存储地址,再读取数据。传输过程如下:

image-20211123161904716

①首先是起始信号 S
②然后是发送7位从机地址+传输方向位,0 写。
③SCL 拉高,判断 ACK ,再拉低 SCL 。
④写数据,一般是写某个寄存器地址或者指令。
⑤SCL 拉高,判断 ACK ,再拉低 SCL 。
⑥ 再次起始信号 S
⑦然后是发送 7 位从机地址+传输方向位,1 读。
⑧SCL 拉高,判断 ACK ,再拉低 SCL 。
⑨写数据,一般是写某个寄存器地址或者指令。
⑩读取字节,一般情况下都是数据。
11.发送应答 ACK ,或者不应答 NACK 。
12 .可以继续传输数据,或者停止

image-20211123162554713

代码思路分析

image-20211125103906990

IIC初始化

//IIC初始化
void IIC_Init()
{
	P2M1 &= 0x3f;
	P2M0 &= 0x3f;    //配置P2.6,P2.7为标准输入输出口
	SDA_GPIO = 1; 
	SCL_GPIO = 1;    //默认情况下数据和时钟都是高电平
}

IIC开始信号

//IIC起始信号
void IIC_Start()
{
	SDA_GPIO = 1;   //开始数据是高电平
	SCL_GPIO = 1;   //开始时钟是高电平 
	IIC_Delay();    //延时一小会
	SDA_GPIO = 0;   //数据脚拉成低电平
	IIC_Delay();    //然后再延时一小会
	SCL_GPIO = 0;   //再把时钟线拉成低电平
	IIC_Delay();    //然后再延时一小会
}

IIC停止信号

//IIC停止信号
void IIC_Stop()
{
	SCL_GPIO = 1;   //时钟线拉成高电平
	SDA_GPIO = 0;   //数据线保持低电平
	IIC_Delay();    //然后再延时一小会
	SDA_GPIO = 0;   //数据线拉高
	IIC_Delay();    //然后再延时一小会
}

以下不解读了,直接说我不想解读了,没时间

#include "all.h"

//IIC微秒级别延时
void IIC_Delay()
{
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}

//IIC初始化
void IIC_Init()
{
	P2M1 &= 0x3f;
	P2M0 &= 0x3f;    //配置P2.6,P2.7为标准输入输出口
	SDA_GPIO = 1; 
	SCL_GPIO = 1;    //默认情况下数据和时钟都是高电平
}
//IIC起始信号
void IIC_Start()
{
	SDA_GPIO = 1;   //开始数据是高电平
	SCL_GPIO = 1;   //开始时钟是高电平 
	IIC_Delay();    //延时一小会
	SDA_GPIO = 0;   //数据脚拉成低电平
	IIC_Delay();    //然后再延时一小会
	SCL_GPIO = 0;   //再把时钟线拉成低电平
	IIC_Delay();    //然后再延时一小会
}

//IIC停止信号
void IIC_Stop()
{
	SDA_GPIO = 0;   //数据线保持低电平
	SCL_GPIO = 1;   //时钟线拉成高电平
	IIC_Delay();    //然后再延时一小会
	SDA_GPIO = 0;   //数据线拉高
	IIC_Delay();    //然后再延时一小会
}

//IIC写入一个字节    向总线发送一个字节
void IIC_Write_Byte(u8 IIC_Byte)
{
	u8 i = 0;//8个数据位
	SCL_GPIO = 0;   //时钟线保持低电平
	SDA_GPIO = 1;   //数据线拉到高电平
	for(i = 0;i<8;i++)
	{
		//先发高位
		SDA_GPIO = (bit)(IIC_Byte & 0x80)
		//高位发完后再移位
		IIC_Byte = IIC_Byte << 1;
		SCL_GPIO = 1;   //时钟线拉到高电平
		IIC_Delay();    //再延时一小会
		SCL_GPIO = 0;   //时钟线拉到低电平
		IIC_Delay();    //然后再延时一小会
	}
}

//IIC读取字节
u8 IIC_Read_Byte()
{
	u8 i = 0;
	u8 value = 0;
	SCL_GPIO = 0;   //时钟线保持低电平
	SDA_GPIO = 1;   //数据线拉到高电平
	for(i = 0;i<8;i++)
	{
		value = (value<<1)|SDA_GPIO;
		SCL_GPIO = 1;   //时钟线拉到高电平
		IIC_Delay();    //再延时一小会
		SCL_GPIO = 0;   //时钟线拉到低电平
		IIC_Delay();    //然后再延时一小会
	}
	return value;
}
//IIC读应答
u8 IIC_Read_Ack()
{
	//应答变量
	u8 Ack = 1;
	u8 i = 0;
	SCL_GPIO = 1;   //时钟线拉到高电平
	IIC_Delay();    //再延时一小会
	while(Ack && i<5)
	{
		Ack = SDA_GPIO;
		i++;
	}
	SCL_GPIO = 0;   //时钟线拉到低电平
	return Ack;
}
//IIC写应答
//单片机发送应答给从机
void IIC_Read_Ack(u8 ack) 
{
	SDA_GPIO = ack;	
	IIC_Delay();    //再延时一小会
	SCL_GPIO = 1;   //时钟线拉到高电平
	IIC_Delay();    //再延时一小会
	SCL_GPIO = 0;   //时钟线拉到低电平
	IIC_Delay();    //再延时一小会
	SDA_GPIO = 1;   //数据线再拉成高电平
	IIC_Delay();    //再延时一小会
}

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。