IIC总线

本文介绍了IIC总线的基本原理,包括开始、结束和应答信号,并展示了STM32如何通过IIC与24C02 EEPROM进行通信。详细给出了IIC驱动代码和24C02的读写操作,同时阐述了IIC在物联网中的重要性及其在主从设备间通信的角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

IIC(Inter ——Integrated Circuit)总线简介

IIC是两线式串行总线,用于连接微控制器和它的外围设备。
是飞利浦公司开发的,对,是那个电动剃须刀。


提示:以下是本篇文章正文内容,下面案例可供参考

一、IIC简介—更详细

它是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送(比如MPU6050和STM32),速度400kbps

——他们在传送数据过程中用的三种信号:开始、结束、应答。

开始:SCL为高电平,SDA从高电跳变→ SDA低电,开始传送。
结束:SCL为高电平,SDA从低电→SDA高电,结束传送。
应答:有接收到才有应答嘛,所以,ic接收到8bit数据后,返回特定低电平,表示收到。
应答,用于给CPU判断IC是否出现故障。

总的来说就是数据线拉低的时候开始传送,时钟线是有规律的,按照自己设置的频率大小,会决定传送的快慢。
下面贴图:
在这里插入图片描述

看不太懂的时序图

二、STM32与24C02

24C02是什么呢, EEPROM 芯片(电可擦除ROM),

1.一些概念(有空看看)

ROM、RAM、PROM(可编程ROM)、EPROM(可擦除ROM)、EEPROM(电可擦除ROM)

ROM:只读存储器(Read-Only Memory,ROM)以非破坏性读出方式工作,只能读出无法写入信息。信息一旦写入后就固定下来,即使切断电源,信息也不会丢失,所以又称为固定存储器。

EEPROM:是一种断电后仍能保留数据的计算机储存芯片——即非易失性的(非挥发性)。

详细戳这里

2.上代码

最好将项目导入SI后进行查看,逻辑清晰许多。

IIC驱动代码如下(示例):

//初始化 IIC
void IIC_Init(void)
{ 
GPIO_InitTypeDef GPIO_InitStructure;
//RCC->APB2ENR|=1<<4;//先使能外设 IO PORTC 时钟
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );
 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
IIC_SCL=1;
IIC_SDA=1;
}
//产生 IIC 起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda 线输出
IIC_SDA=1; 
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
delay_us(4);
IIC_SCL=0;//钳住 I2C 总线,准备发送或接收数据
} 
//产生 IIC 停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda 线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1; 
IIC_SDA=1;//发送 I2C 总线结束信号
delay_us(4); 
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA 设置为输入 
IIC_SDA=1;delay_us(1); 
IIC_SCL=1;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出 0 
return 0; 
} 
//产生 ACK 应答
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//不产生 ACK 应答 
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
} 
//IIC 发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答 
void IIC_Send_Byte(u8 txd)
{ 
 u8 t; 
SDA_OUT(); 
 IIC_SCL=0;//拉低时钟开始数据传输
 for(t=0;t<8;t++)
 { 
 IIC_SDA=(txd&0x80)>>7;
 txd<<=1; 
delay_us(2); //对 TEA5767 这三个延时都是必须的
IIC_SCL=1;
delay_us(2); 
IIC_SCL=0;
delay_us(2);
 }
} 
//读 1 个字节,ack=1 时,发送 ACK,ack=0,发送 nACK 
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA 设置为输入
 for(i=0;i<8;i++ )
{
IIC_SCL=0; 
 delay_us(2);
IIC_SCL=1;
 receive<<=1;
 if(READ_SDA)receive++; 
delay_us(1); 
 }
 if (!ack)
 IIC_NAck();//发送 nACK
 else
 IIC_Ack(); //发送 ACK 
 return receive;
}

实现包括 IIC 的初始化(IO 口)、IIC 开始、IIC 结束、ACK、IIC
读写等功能

iic.h文件

#define SDA_IN() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}
#define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}

直接通过寄存器操作设置 IO 口的模式为输入还是输出

3.24C02代码——iic应用

#include "24cxx.h" 
#include "delay.h" 
//初始化 IIC 接口
void AT24CXX_Init(void)
{
IIC_Init();
}
//在 AT24CXX 指定地址读出一个数据
//ReadAddr:开始读数的地址 
//返回值 :读到的数据
u8 AT24CXX_ReadOneByte(u16 ReadAddr)
{ 
u8 temp=0;
 IIC_Start(); 
if(EE_TYPE>AT24C16)
{
IIC_Send_Byte(0XA0); //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr>>8);//发送高地址 
}else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1)); //发送器件地址 0XA0,写数据 
IIC_Wait_Ack(); 
IIC_Send_Byte(ReadAddr%256); //发送低地址
IIC_Wait_Ack(); 
IIC_Start(); 
IIC_Send_Byte(0XA1); //进入接收模式 
IIC_Wait_Ack();
 temp=IIC_Read_Byte(0); 
 IIC_Stop();//产生一个停止条件 
return temp;
}
//在 AT24CXX 指定地址写入一个数据
//WriteAddr :写入数据的目的地址 
//DataToWrite:要写入的数据
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{
 IIC_Start(); 
if(EE_TYPE>AT24C16)
{
IIC_Send_Byte(0XA0); //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(WriteAddr>>8);//发送高地址 
}else IIC_Send_Byte(0XA0+((WriteAddr/256)<<1)); //发送器件地址 0XA0,写数据
IIC_Wait_Ack(); 
 IIC_Send_Byte(WriteAddr%256); //发送低地址
IIC_Wait_Ack(); 
IIC_Send_Byte(DataToWrite); //发送字节 
IIC_Wait_Ack(); 
 IIC_Stop(); //产生一个停止条件
delay_ms(10); //对于 EEPROM 器件,每写一次要等待一段时间,否则写失败!
}
//在 AT24CXX 里面的指定地址开始写入长度为 Len 的数据
//该函数用于写入 16bit 或者 32bit 的数据.
//WriteAddr :开始写入的地址 
//DataToWrite:数据数组首地址
//Len :要写入数据的长度 2,4
void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
{ 
u8 t;
for(t=0;t<Len;t++) AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff); 
} 
//在 AT24CXX 里面的指定地址开始读出长度为 Len 的数据
//该函数用于读出 16bit 或者 32bit 的数据.
//ReadAddr :开始读出的地址
//返回值 :数
//Len :要读出数据的长度 2,4
u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
{ 
u8 t; u32 temp=0;
for(t=0;t<Len;t++)
{
temp<<=8;
temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1); 
}
return temp; 
}
//检查 AT24CXX 是否正常
//这里用了 24XX 的最后一个地址(255)来存储标志字.
//如果用其他 24C 系列,这个地址要修改
//返回 1:检测失败
//返回 0:检测成功
u8 AT24CXX_Check(void)
{
u8 temp;
temp=AT24CXX_ReadOneByte(255);//避免每次开机都写 AT24CXX 
if(temp==0X55)return 0; 
else//排除第一次初始化的情况
{
AT24CXX_WriteOneByte(255,0X55);
 temp=AT24CXX_ReadOneByte(255); 
if(temp==0X55)return 0;
}
return 1; 
}
//在 AT24CXX 里面的指定地址开始读出指定个数的数据
//ReadAddr :开始读出的地址 对 24c02 为 0~255
//pBuffer :数据数组首地址
//NumToRead:要读出数据的个数
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
{
while(NumToRead)
{
*pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
NumToRead--;
}
} 
//在 AT24CXX 里面的指定地址开始写入指定个数的数据
//WriteAddr :开始写入的地址 对 24c02 为 0~255
//pBuffer :数据数组首地址
//NumToWrite:要写入数据的个数
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
while(NumToWrite--)
{
AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
WriteAddr++;
pBuffer++;
}
}

总结

(1)主CPU和其附属芯片之间最常用的接口,尤其是各种传感器,因此在物联网时代非常重要。

(2)三根线:GND、SCL、SDA,串行、电平式。

(3)总线式结构,可以一对多,总线上可以挂上百个器件,用从地址来区分。

(4)主从式,由主设备来发起通信及总线仲裁,从设备被动响应。

(5)通信速率一般(kbps级别),不适合语音、视频等信息类型。
通讯访问接口使用模拟接口和硬件接口:
软件模拟接口:优点:接口单一,可移植性高,一般只需要改 IO 就可以完
成通讯过程。缺点:占用 CPU,速率慢,如果要求速度高或者对时序要求高的
业务里面就不能使用。
硬件接口:优点:由于是硬件完成,所以速度快,但是依然也会占用 cpu 缺
点:每一个平台都需要单独调整一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值