收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
SCL=1; //首先把时钟线拉高
delay\_us(4);//延时函数
SDA=1; //在SCL为高的情况下把SDA拉高
delay\_us(4); //延时函数
}
#### 开始信号:
**SCL保持高电平,SDA由高电平变为低电平后,延时(>4.7us),SCL变为低电平。**
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411104124610.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)
代码表示:
//产生IIC起始信号
//1.先拉高SDA,再拉高SCL,空闲状态
//2.拉低SDA
void IIC_Start() //启动信号
{
SDA=1; //确保SDA线为高电平
delay_us(5);
SCL=1; //确保SCL高电平
delay_us(5);
SDA=0; //在SCL为高时拉低SDA线,即为起始信号
delay_us(5);
SCL=0; //钳住I2C总线,准备发送或接收数据
}
#### 停止信号
**停止信号:SCL保持高电平。SDA由低电平变为高电平。**
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200407161528542.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)
//产生IIC停止信号
//1.先拉低SDA,再拉低SCL
//2.拉高SCL
//3.拉高SDA
//4.停止接收数据
void IIC_Stop(void)
{
IIC_SCL=0;
IIC_SDA=0; //STOP:当SCL高时,数据由低变高
delay\_us(4);
IIC_SCL=1;
IIC_SDA=1; //发送I2C总线结束信号
delay\_us(4);
}
在起始条件产生后,总线处于忙状态,由本次数据传输的主从设备独占,其他I2C器件无法访问总线;而在停止条件产生后,本次数据传输的主从设备将释放总线,总线再次处于空闲状态。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411104137162.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)
#### 数据有效性
**IIC信号在数据传输过程中,当SCL=1高电平时,数据线SDA必须保持稳定状态,不允许有电平跳变,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。**
**SCL=1时 数据线SDA的任何电平变换会看做是总线的起始信号或者停止信号。**
也就是在IIC传输数据的过程中,SCL时钟线会频繁的转换电平,以保证数据的传输
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200407162837546.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)
![img](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvNTg0Mjk3LzIwMTUwMS8xMDE0MzQ1Mjc1MDc1MTUucG5n?x-oss-process=image/format,png)
#### 应答信号
每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据,
**应答信号:主机SCL拉高,读取从机SDA的电平,为低电平表示产生应答**
* **应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;**
* **应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。**
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200407171913110.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)
\*\*每发送一个字节(8个bit)\*\*在一个字节传输的8个时钟后的第九个时钟期间,接收器接收数据后必须回一个ACK应答信号给发送器,这样才能进行数据传输。
**应答出现在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,1表示非应答,**
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411104200168.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)
//主机产生应答信号ACK
//1.先拉低SCL,再拉低SDA
//2.拉高SCL
//3.拉低SCL## 标题
void I2C_Ack(void)
{
IIC_SCL=0; //先拉低SCL,使得SDA数据可以发生改变
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(5);
IIC_SCL=0;
}
//主机不产生应答信号NACK
//1.先拉低SCL,再拉高SDA
//2.拉高SCL
//3.拉低SCL
void I2C_NAck(void)
{
IIC_SCL=0; //先拉低SCL,使得SDA数据可以发生改变
IIC_SDA=1; //拉高SDA,不产生应答信号
delay_us(2);
IIC_SCL=1;
delay_us(5);
IIC_SCL=0;
}
等待应答信号:
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
char IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
IIC_SDA=1;delay\_us(1);
IIC_SCL=1;delay\_us(1);
while(IIC_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC\_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
#### IIC数据传送
#### 数据传送格式
**SDA线上的数据在SCL时钟“高”期间必须是稳定的,只有当SCL线上的时钟信号为低时,数据线上的“高”或“低”状态才可以改变。输出到SDA线上的每个字节必须是8位,数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。**
**当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA线,回传给主设备一个应答位ACK, 此时才认为一个字节真正的被传输完成** ,如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。
![img](https://imgconvert.csdnimg.cn/aHR0cDovL3d3dy5lbWJlZGRlZGxpbnV4Lm9yZy5jbi91cGxvYWRzL2FsbGltZy8xMzAzMTcvMTIxOTQ1Mi5wbmc?x-oss-process=image/format,png)
**IIC写数据:**
![img](https://imgconvert.csdnimg.cn/aHR0cDovL3d3dy5lbWJlZGRlZGxpbnV4Lm9yZy5jbi91cGxvYWRzL2FsbGltZy8xMzAzMTcvMTIxOTQ1My5wbmc?x-oss-process=image/format,png)
多数从设备的地址为7位或者10位,一般都用七位。
**八位设备地址=7位从机地址+读/写地址,**
再给地址添加一个方向位位用来表示接下来数据传输的方向,
* 0表示主设备向从设备(write)写数据,
* 1表示主设备向从设备(read)读数据
IIC的每一帧数据由9bit组成,
如果是**发送数据**,则包含 **8bit数据+1bit ACK,**
如果是**设备地址数据**,则**8bit包含7bit设备地址 1bit方向**
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411151616581.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)
>
> **在起始信号后必须传送一个从机的地址(7位) 1~7位为7位接收器件地址,第8位为读写位,用“0”表示主机发送数据(W),“1”表示主机接收数据 (R), 第9位为ACK应答位,紧接着的为第一个数据字节,然后是一位应答位,后面继续第2个数据字节。**
>
>
>
**IIC发送一个字节数据:**
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
//IIC_SCL=0;
//在SCL上升沿时准备好数据,进行传送数据时,拉高拉低SDA,因为传输一个字节,一个SCL脉冲里传输一个位。
//数据传输过程中,数据传输保持稳定(在SCL高电平期间,SDA一直保持稳定,没有跳变)
//只有当SCL被拉低后,SDA才能被改变
//总结:在SCL为高电平期间,发送数据,发送8次数据,数据为1,SDA被拉高,数据为0,SDA被拉低。
//传输期间保持传输稳定,所以数据线仅可以在时钟SCL为低电平时改变。
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
//IIC_SDA=txd&0x80; //获取最高位
//获取数据的最高位,然后数据左移一位
//如果某位为1,则SDA为1,否则相反
if(txd&0x80)
IIC_SDA=1;
else
IIC_SDA=0;
txd<<=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
或者:
//IIC_SDA=txd&0x80; //获取最高位
//获取数据的最高位,然后右移7位,假设为 1000 0000 右移7位为 0000 0001
// 假设为 0000 0000 右移7位为 0000 0000
//如果某位为1,则SDA为1,否则相反
IIC_SDA=((txd&0x80)>>7);
txd<<=1;
**IIC读取一个字节数据:**
//读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发送数据
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411104227304.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411160446820.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)
**Start**: IIC开始信号,表示开始传输。
**DEVICE\_ADDRESS:**: 从设备地址,就是7位从机地址
**R/W**: W(write)为写,R(read)为读
**ACK**: 应答信号
**WORD\_ADDRESS** : 从机中对应的寄存器地址 比方说访问 OLED中的 某个寄存器
**DATA**: **发送的数据**
**STOP**: 停止信号。结束IIC
主机要向从机写数据时:
>
> 1. **主机首先产生START信号**
> 2. **然后紧跟着发送一个从机地址,这个地址共有7位,紧接着的第8位是数据方 向位(R/W),0表示主机发送数据(写),1表示主机接收数据(读)**
> 3. **主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,若相同,则认为自己正在被主机寻址,根据R/T位将自己确定为发送器和接收器**
> 4. **这时候主机等待从机的应答信号(A)**
> 5. **当主机收到应答信号时,发送要访问从机的那个地址, 继续等待从机的应答信号**
> 6. **当主机收到应答信号时,发送N个字节的数据,继续等待从机的N次应答信号,**
> 7. **主机产生停止信号,结束传送过程。**
>
>
>
#### IIC读数据:
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020041116021182.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)
主机要从从机读数据时
>
> 1. **主机首先产生START信号**
> 2. **然后紧跟着发送一个从机地址,注意此时该地址的第8位为0,表明是向从机写命令,**
> 3. **这时候主机等待从机的应答信号(ACK)**
> 4. **当主机收到应答信号时,发送要访问的地址,继续等待从机的应答信号,**
> 5. **当主机收到应答信号后,主机要改变通信模式(主机将由发送变为接收,从机将由接收变为发送)所以主机重新发送一个开始start信号,然后紧跟着发送一个从机地址,注意此时该地址的第8位为1,表明将主机设 置成接收模式开始读取数据,**
> 6. **这时候主机等待从机的应答信号,当主机收到应答信号时,就可以接收1个字节的数据,当接收完成后,主机发送非应答信号,表示不在接收数据**
> 7. **主机进而产生停止信号,结束传送过程。**
>
>
>
#### 以AT24C02为例子
24C02是一个2K Bit的串行EEPROM存储器(掉电不丢失),内部含有256个字节。在24C02里面有一个8字节的页写缓冲器。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411233728215.png)
A0,A1,A2:硬件地址引脚
WP:写保护引脚,接高电平只读,接地允许读和写
SCL和SDA:IIC总线
可
以看出对于不同大小的24Cxx,具有不同的从器件地址。由于24C02为2k容量,也就是说只需要参考图中第一行的内容:
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020041116204029.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)
芯片的寻址:
AT24C设备地址为如下,前四位固定为1010,A2~A0为由管脚电平。AT24CXX EEPROM Board模块中默认为接地。A2~A0为000,最后一位表示读写操作。所以AT24Cxx的读地址为0xA1,写地址为0xA0。
也就是说如果是
**写24C02的时候**,**从器件地址为10100000(0xA0);
读24C02的时候,从器件地址为10100001(0xA1)。**
片内地址寻址:
**芯片寻址可对内部256B中的任一个进行读/写操作,其寻址范围为00~FF,共256个寻址单位。**
对应的修改 A2A1A0 三位数据即可
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411161834991.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)
**向AT24C02中写数据**
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411233850496.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)
操作时序:
>
> 1. **MCU先发送一个开始信号(START)启动总线**
![img](https://img-blog.csdnimg.cn/img_convert/1b3601737262e735cce89d17b584264d.png)
![img](https://img-blog.csdnimg.cn/img_convert/66361579d2acfc97ca5528db6fc3898a.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**
TM3,size_16,color_FFFFFF,t_70)
操作时序:
>
> 1. **MCU先发送一个开始信号(START)启动总线**
[外链图片转存中...(img-48Msk9nM-1715883674579)]
[外链图片转存中...(img-d72Yol70-1715883674580)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**