STC8H系列单片机入门教程之IIC总线基础知识(七)

目录

一、IIC总线概述

 二、IIC总线时序

三、IIC三种通信方式

四、IIC总线模式 

五、IIC上拉电阻阻值选择 

六、IIC常见问题

七、IIC总线调试神器

八、软件模拟IIC读写EEPROM


一、IIC总线概述

IIC总线两线制包括:串行数据SDA(Serial Data)、串行时钟SCL(Serial Clock)。总线必须由主机(通常为MCU)控制,主机产生串行时钟(SCL)控制总线的传输方向,并产生起始和停止条件;

IIC总线特征:同步串行半双工(同一时刻只能是一种身份);

对于多个从机,每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问;

 二、IIC总线时序

IIC一次完整通信

1、主机发送起始条件(主机占用总线,唤醒总线所有的从机);

2、主机发送器件地址(总线上所有的从机就会拿这个器件跟自身进行比较,匹配成功的那个从机就会回复一个应答信号给主机,并根据方向位来决定数据传输方向);

3、进行有效数据交流(每传输完一个直接数据都要给应答);

4、主机发送停止信号(释放总线,结束本次通信)。

起始信号:当 SCL 线是高电平时 ,SDA 线从高电平向低电平切换,表示通讯的起始;

停止信号:当 SCL 线是高电平时 ,SDA 线由低电平向高电平切换,表示通讯的停止。

起始和停止信号一般由主机产生,其示意图如下。

数据有效性

IIC 使用 SDA信号线来传输数据,使用 SCL信号线进行数据同步。SDA数据线在 SCL的每个时钟周期传输一位数据。传输时,SCL为高电平的时候 SDA 表示的数据有效,即此时的 SDA 为高电平时表示数据“1”,为低电平时表示数据“0”。当 SCL为低电平时,SDA的数据无效,一般在这个时候 SDA 进行电平切换,为下一次表示数据做好准备。每次数据传输都以字节为单位,每次传输的字节数不受限制。

 地址及数据方向

IIC 总线上的每个设备都有自己的独立地址,主机发起通讯时,通过 SDA 信号线发送设备地址,也叫从机地址来查找从机。IIC 协议规定设备地址可以是 7位、8位或 10 位,实际中 7 位的地址应用比较广泛。紧跟设备地址的一个数据位用来表示数据传输方向,它是数据方向位(R/W),可以是第 8位(设备地址是7位)或第 11 位(设备地址是10位)。数据方向位为“1”时表示主机由从机读数据,该位为“0”时表示主机向从机写数据。如下图表示从机地址是7位,数据方向位为第8位。

响应

IIC 的数据和地址传输都带响应。响应包括“应答(ACK)”和“非应答(NACK)”两种信号。作为数据接收端时,当设备(无论主从机)接收到 IIC 传输的一个字节数据或地址后,若希望对方继续发送数据,则需要向对方发送“应答(ACK)”信号,发送方会继续发送下一个数据;若接收端希望结束数据传输,则向对方发送“非应答(NACK)”信号,发送方接收到该信号后会产生一个停止信号,结束信号传输。传输时主机产生时钟,在第 9个时钟时,数据发送端会释放 SDA的控制权,由数据接收端控制 SDA,若 SDA 为高电平,表示非应答信号(NACK),低电平表示应答信号。

三、IIC三种通信方式

 1、只读:主机只读取数据

2、只写:主机仅发送数据

3、有读有写 

四、IIC总线模式 

五、IIC上拉电阻阻值选择 

六、IIC常见问题

1、IIC总线的地址错误,要注意区分7位地址、8位地址和10位地址,以及读写位的设置。

2、IIC总线的时序错误,要注意起始信号、停止信号、数据有效性和应答信号的生成和检测,以及时钟频率和上升时间的控制。

3、IIC总线的电压错误,要注意匹配主从设备的电压水平,以及使用合适的上拉电阻和串联电阻。

4、IIC总线的硬件错误,要注意检查供电电压、主输入时钟、GPIO配置、信号线走线等是否正确。

5、IIC总线的软件错误,要注意检查驱动代码、设备树配置、中断处理等是否正确。 

七、IIC总线调试神器

逻辑分析仪 

逻辑分析仪是一种电子测试工具,具有广泛的应用领域,其中包括分析IIC(Inter-Integrated  Circuit,即串行双向通信总线)的输入信号。通过使用逻辑分析仪,工程师可以对IIC总线上的信号进行深入分析,从而更好地理解协议的解析过程。

协议解析:逻辑分析仪能够解析IIC协议的各个阶段,从而帮助工程师确认设备是否按照协议要求进行通信。

八、软件模拟IIC读写EEPROM

#include "STC8H.h"

#define I2C_SDA	P24
#define I2C_SCL	P25

#define AT24C02_ADDR 0xA0 //AT24C02的地址

unsigned char read_byte = 0;

void soft_delay(unsigned int ms)
{
	unsigned int i,j;
	for(i = 0;i < ms;i++)
		for(j = 0;j < 200;j++);
}

/****************************************************************************************
* @名称 		void i2c_start(void)
* @功能 		I2C起始信号
* @输入参数     none
* @返回 		none
****************************************************************************************/
void i2c_start(void)
{
	I2C_SDA=1;
	I2C_SCL=1;
	I2C_SDA=0;
	I2C_SCL=0;	
}

/****************************************************************************************
* @名称 		void i2c_stop(void)
* @功能 		I2C停止信号
* @输入参数     none
* @返回 		none
****************************************************************************************/
void i2c_stop(void)
{
	 I2C_SDA=0;
	 I2C_SCL=1;
	 I2C_SDA=1;
}

/****************************************************************************************
* @名称 		void i2c_send_ack(bit ack)
* @功能 		主机发送应答
* @输入参数     ack - 应答
* @返回 		none
****************************************************************************************/
void i2c_send_ack(bit ack)
{
	I2C_SDA=ack;
	I2C_SCL=1;
	I2C_SCL=0;
}

/****************************************************************************************
* @名称 		void i2c_read_ack(void)
* @功能 		主机接收应答
* @输入参数     none
* @返回 		ack - 应答信号
****************************************************************************************/
bit i2c_read_ack(void)
{
	bit ack=0;
	I2C_SDA=1;//释放总线
	I2C_SCL=1;
	ack=I2C_SDA;
	I2C_SCL=0;
	return ack;
}

/****************************************************************************************
* @名称 		void i2c_read_ack(void)
* @功能 		I2C总线主机发送一个字节数据
* @输入参数     byte - 待发送的字节
* @返回 		none
****************************************************************************************/
void i2c_write_byte(unsigned char byte)
{
	unsigned char i=0;
	for(i=0;i<8;i++)
	{
		I2C_SDA = byte&(0x80>>i);
		I2C_SCL = 1;
		soft_delay(1);
		I2C_SCL = 0;
		soft_delay(1);
	}
}

/****************************************************************************************
* @名称 		void i2c_read_byte(void)
* @功能 		I2C总线主机接收一个字节数据
* @输入参数     none
* @返回 		byte - 接收到的字节
****************************************************************************************/
unsigned char i2c_read_byte(void)
{
	unsigned char i,byte=0;
	
	I2C_SDA = 1;//释放总线
	for(i=0;i<8;i++)
	{
		I2C_SCL = 1;
		if(I2C_SDA == 1) 
		{
			byte|=(0x80>>i);
		}//I2C_SDA上的数据已经是从机发送的数据
		soft_delay(1);
		I2C_SCL = 0;
		soft_delay(1);
	}
	return byte;
}

/****************************************************************************************
* @名称 		void at24C02_write_byte(unsigned char word_address,unsigned char byte)
* @功能 		向AT24C02中的某个地址写入一个字节数据
* @输入参数     word_address - 数据地址
* @输入参数     byte - 写入的字节数据
* @返回 		none
****************************************************************************************/
void at24C02_write_byte(unsigned char word_address,unsigned char byte)
{
	bit ack = 0;
	i2c_start();
	i2c_write_byte(AT24C02_ADDR);
	ack = i2c_read_ack();
	i2c_write_byte(word_address);
	ack = i2c_read_ack();
	i2c_write_byte(byte);
	ack = i2c_read_ack();
	i2c_stop();
}

/*
     *函数名:	  AT24C02_Readbyte(unsigned char word_address)
     *函数功能:  主机读取AT24C02的指定地址的数据
     *输入:	  word_address:数据的地址
     *输出:	  byte:被读取的字节数据
*/
unsigned char at24C02_read_byte(unsigned char word_address)
{
	unsigned char byte = 0;
	bit ack = 0;
	i2c_start();
	i2c_write_byte(AT24C02_ADDR);
	ack = i2c_read_ack();
	i2c_write_byte(word_address);
	ack = i2c_read_ack();
	i2c_start();
	i2c_write_byte(AT24C02_ADDR|0x01);
	ack = i2c_read_ack();
	byte = i2c_read_byte();
	i2c_send_ack(1);
	i2c_stop();
	return byte;
}

/*主函数*/
void main(void)
{
	unsigned char i = 0;
	
	P2M1 = 0X00; P2M0 = 0XCF; //设置P24/P25为准双向口
	
	while(1)
	{
		at24C02_write_byte(0x01,i);
		soft_delay(20);
		read_byte = at24C02_read_byte(0x01);
		soft_delay(20);
	}
}

  • 12
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芯航路IOT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值