嵌入式学习笔记——IIC通信

2023-05-16

IIC通信

  • 前言
  • IIC概述
    • 通信特征
    • 物理拓扑结构
    • IIC通信的流程
    • IIC的特点:
  • STM32的IIC通信
    • GPIO模拟IIC
      • IIC的时序组成(主机对从机写入数据)
        • 1.起始信号
        • 2.器件地址与读写位
        • 3.从机应答信号
        • 5.传输的数据与结束信号
      • IIC的时序组成(主机对从从机获取数据)
        • 1.数据接收
        • 2.主机发送应答信号
  • IIC初始化代码
  • 总结
  • M4系列目录
  • 写在后面的话

前言

本文接着之前的M4系列介绍,对另外一个十分常见的通信总线进行一个介绍,就是IIC总线。

IIC概述

通信特征

首先,还是找个免费劳动力来做一个官方的介绍,下面这一段话非常全面的介绍了IIC的各个特征,用之前提到的通信特征来总结,IIC是一种串行,同步,半双工,板级有线通信。与SPI对比,其少了一个数据线,只有一个数据线,因此只能实现半双工通信。
在这里插入图片描述

物理拓扑结构

第二段是描述了IIC的拓扑结构,IIC一共有两个线,一根时钟线SCL,用来提供主从通信的时钟基准,另外一根是SDA数据线,用来传输数据用;之所以称作为总线,与前面的SPI一样,表明其可以同时挂接多个设备,设备之间可以进行通信。一主多从的物理拓扑图如下图所示:
在这里插入图片描述

在这里插入图片描述
与上一篇的SPI对比可以发现少了CS片选线,那么主机是怎么选择通信的对象的呢,注意上面的简介中提到了一个地址的概念,IIC的通信就是通过地址来确定通信的对象的,根据原理图和芯片手册获取到对应器件的信息后,主机将地址发送到总线上,从设备接收地址信息进行判断,如果地址与自己的地址一致,则给主机一个反馈信号,进而二者建立通信;而地址不对应的从器件是不会有反馈的。具体的地址信息放到后面做介绍,这里做个了解即可。
除了上面的一主多从模式,IIC还有多主多从的拓扑结构,结构图如下图所示:
在这里插入图片描述
这样的连接方式可以实现多个主机操作同一组IIC从设备。

IIC通信的流程

这里对IIC的通信流程做个大致的介绍,如下图所示,假设此时A为主设备,也就是我们的单片机,B设备就是常用的IIC从机AT24cxx。
第一个通信目标是:A将数据写入B
其通信流程如下:
1.微控制器 A 主机 寻址微控制器 B 从机
2.微控制器 A 主机 发送器 发送数据到微控制器 B 从机 接收器
3.微控制器 A 终止传输,总线空闲,两条线路都恢复高电平
在这里插入图片描述
第二个通信的目标是: A从B中读取数据,其具体的通信流程如下:这里需要补充一点,在IIC总线中,主机才有对时钟线的操作权利,从机是没有的,因此,从机并不能主动给主机传输数据,必须要接收到主机给从机相应的获取指令后,才可以将数据传输到数据线上,进而被主机接收。因此A从B中获取数据的流程如下:
1.微控制器 A 主机 寻址微控制器 B 从机
2.微控制器 A 主机 接收器 从微控制器 B 从机 发送器 接收数据
3.微控制器 A 终止传输总线空闲,两条线路都恢复高电平

IIC的特点:

•1. 只要求两条总线线路 一条串行数据线 SDA 一条串行时钟线 SCL
• 2.每个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机 从机关系软件设定地址 主机可以作为主机发送器或主机接收器
• 3.它是一个真正的多主机总线 如果两个或更多主机同时初始化数据传输可以通过冲突检测和仲裁防止数据被破坏
4.串行的 8 位双向数据传输位速率在标准模式下可达 100kbit/s ;快速模式下可达 400kbit/s; 高速模式下可达 3.4Mbit/s,此处可以发现,IIC的最高传输速率是不如SPI的。
• 5.片上的滤波器可以滤去总线数据线上的毛刺波 保证数据完整
• 6. 连接到相同总线的 IC 数量只受到总线的最大电容 400pF 限制
以上描述来自——IIC总线规范
广州周立功单片机发展有限公司 Tel: (020)38730976 38730977 Fax:38730925 http://www.zlgmcu.com
关于IIC的一些更详细的介绍可以参考以下几篇文章,上面的图片也是来自这两篇博客:
关于为什么要加上拉电阻以及电阻阻值的计算在里面也有描述。
一文搞懂I2C通信总线——http://t.csdn.cn/RjJob
IIC原理超详细讲解—值得一看——http://t.csdn.cn/zkq43

STM32的IIC通信

关于STM32的IIC通信,与SPI类似,也是有两种方案来解决一种是使用控制器来实现,另一种是配置STM32内部的控制器来实现通信,实际使用过程中常用的反而是IO模拟的方式,STM32内部的IIC控制器数量是3个,数量不算多
在这里插入图片描述
虽然每个IIC控制器都对应有两组IO口,但是我们去数据手册的复用映射表查看就知道了,支持IIC控制器服用的IO口,大多都有着其他的复用功能,复用为IIC后其他的功能就需要找其他IO口,而且其他的复用功能,并不能很好地使用IO模拟来实现,而IIC可以通过IO模拟很好地实现,也就是说,只要是GPIO口理论上就可以实现IIC的时序模拟,因此大多是的IIC通信都是使用的IO模拟。
在这里插入图片描述
当然,使用控制器的IIC会有更高的传输速率以及稳定性,但是其配置过程也是十分复杂的,一不留神就会配置错误导致通信不上,这里我们后面做个对比即可。
由于常用的是GPIO模拟的IIC,所以本文就重点介绍一下IO模拟的IIC实现过程。

GPIO模拟IIC

使用GPIO模拟的IIC,参考之前的SPI模拟时序,第一件事就是要看IIC通信的时序图,然后根据时序图来实现IIC的模拟时序。

IIC的时序组成(主机对从机写入数据)

来看一下IIC通信的完整数据帧,这里用的是7位器件地址,一位读写位,八位数据位,一次传输两个数据的情况为例。
在这里插入图片描述
从上图可以看出完整的数据传输包含了1.开始信号;2.器件地址;3.读写位;4.应答信号;5.传输的数据;6.结束信号。而且观察上图可以发现:
SDA 线上的数据在时钟的高电平周期保持稳定; SDA线的高或低电平状态只有在 SCL 线的时钟信号是低电平时才能改变;也就是说,时钟线高电平期间,数据线是只读的不能操作,而时钟线低电平期间,数据线是可写的,可以写入对应的高低电平。
在这里插入图片描述
接下来及分别对这里面的各个部分进行介绍。

1.起始信号

起始条件一般由主机产生。
在 SCL 线是高电平时 SDA 线从高电平向低电平切换,表示起始信号;
在这里插入图片描述
根据这个时序图可以大致知道起始信号的样子,但是还不知道其具体的持续时间,这时就需要打开对应的芯片手册进行查看了,在芯片手册的读写周期范围里面会有具体的时间要求,根据以下表格,可以写出起始信号的伪代码。
在这里插入图片描述

起始条件函数
{
   时钟线拉低
   delay_us(5);//IIC的延时时间    时间只能大于表中的时间,不能小于表中时间
   数据线拉高     //为数据线的下降沿做准备
   
   时钟线拉高
    delay_us(5);//IIC的延时时间  空闲时间不得少于4.7us这里给个5us
   数据线拉低

   时钟线拉低    //安全模式  维持完整周期
}

上面的是手册给出的示意图,接下来来看一个实际的示波器抓取的波形,如下图所示:
原图链接——http://www.eepw.com.cn/article/234058.htm
橙色框内的就是起始信号,时钟线和数据线都是先被拉高,然后持续一段时间,随后,数据线拉低,这时一个起始信号就已经完成了,不过为了保证能够正确的接收数据,时钟线也会被拉低,因为只有在时钟线低电平的时候数据线才能被操作。
在这里插入图片描述

2.器件地址与读写位

传输过程中是高位先发的MSB。
在这里插入图片描述
在起始条件 S 后,发送了一个从机地址 这个地址共有 7 位(下图中红色框内的器件地址),紧接着的第 8 位是数据方向位 R/ W 0 表示主机对从机写入数据,写 1 表示主机需要从从机中读取数据。
在这里插入图片描述
IIC每次传输的都是一个八位数据,起始信号发送完毕后需要紧跟一个8位数据,这个八位数据的高七位是从器件的地址,最低位是读写位,为了方便理解这里还是直接看个实例,假设我们使用AT24C02作为从器件,那么它的器件地址就是如下图所示的,其中前四位是厂商规定的,1010,而后面的三位A0-A2是由硬件电路来确定的。
在这里插入图片描述
如下图,硬件连接中A0-A2都是被拉低了,所以此时的7位器件地址位:101 0000(0x60)
而其对其写入数据的时的写地址为:1010 0000 (0xA0)
读地址为1010 0001(0XA1)
在这里插入图片描述
在这里插入图片描述
同样的,可以来看一下实际的示波器抓取的波形,下图中的器件地址是011 1000 也就是0x38,最后一位的读写位是0,标明是写入数据,因此最终发送的八位数据是0111 0000(0x70)。
在这里插入图片描述
通过上面的两个图,可以模拟出发送八位数据的时序,这里还需要再提示一下,前面说过,IIC通信过程中,只有在时钟线拉低的情况下,数据线才能被操作,因此,我们在写入每一位之前都需要保证,时钟线是拉低的状态才可以。伪代码如下:

发送数据:时钟低电平状态发送   发送8次
发送数据(地址)函数(数据)
{
  for(u8 i=0;i<8;i++)//发8次
{
  时钟线拉低
  If(data & 0x80 >>i)//高位先发
  {
     数据线拉高
  }
  Else
  {
    数据线拉低
  }
  拉高时钟线
}
调用接收应答函数
拉低时钟线  //安全模式
}

在介绍应答信号之前还需要插播一个小知识,注意如果被问到IIC总线可以挂接多少个从器件时,可以参考如下的描述作答。
在这里插入图片描述

3.从机应答信号

接下来就是应答信号,关于应答位,首先它只有一位,也只有两个状态,要么是0,要么是1;其中0表示应答成功,1表示应答失败。
在这里插入图片描述

数据传输必须带响应;相关的响应时钟脉冲由主机产生,在响应的时钟脉冲期间,发送器(主机)释放 SDA 线(拉高);
在响应的时钟脉冲期间 接收器必须将 SDA 线拉低(0)使它在这个时钟脉冲的高电平期间保持稳定的低电平,此时表示应答成功;否则,也就是数据线没有保持在低电平,说明应答失败。
在这里插入图片描述
在使用IO模拟的时候,我们需要获取SDA管脚的高低电平来判断是否应答成功,这里又涉及到了一个知识点,前面发送数据以及起始信号时,SDA一直是作为数据脚的,此时需要判断高低电平,既要做输入又要做输出,这时,根据之前GPIO的介绍,有两种方案,一是发送时配置为推挽输出,到了要接收的时候再配置一遍IO口,将其转换为无上下拉的输入模式,也就是需要我们不断地切换模式;
另外一个方案是配置为开漏输出,此时GPIO的高端MOS被屏蔽了,无法输出高电平,当GPIO的ODR配置为1时,SDA数据线不再受此GPIO的控制,而是有上拉电阻拉成空闲状态,由从机控制SDA的高低电平。此时直接使用IDR进行读取即可。
而且还需要注意,前面提到过,时钟线是交给主机控制的(也有例外,但是大部分是这样),而数据线的写操作,必须在时钟线拉低的情况下才可以,因此,为了从机能够操作数据线,还需要使用主机为其提供一个低电平的时钟信号。
在这里插入图片描述
同样的,注意示波器的波形,此时从机也是正常将SDA拉低了,说明从机应答正常,接下来可以开始传输数据了。
伪代码如下:

u8 主机接收从机应答函数
{
  //数据线模式  输入模式
  拉低时钟线
  拉高数据线     //让数据线处于空闲  可以接收数据
  
  拉低时钟线     //让从机发送应答
  拉高时钟线     //主机接收应答
  If(数据线状态)//检测到高表示应答失败
  return 1
  else
  return 0
  
  拉低时钟线    //安全模式
}

5.传输的数据与结束信号

关于数据传输,与前面提到的地址写入是一致的,在操作的时候根据芯片手册的指令表,写入对应功能的数据即可。
接下来就是结束信号了,当数据传输完成后,需要一个结束信号,来告诉从机通信结束。当 SCL 是高电平时,SDA 线由低电平向高电平切换表示停止条件;结束信号的时序图如下图所示:
在这里插入图片描述
实际的示波器图形如下图所示:

在这里插入图片描述
根据时序图,以及上面的时间要求,可以写出结束信号的伪代码:

停止条件函数
{
  拉低时钟线
  数据线拉低     //为上升沿做准备
  
  拉高时钟线
  delay_us(5);
  拉高数据线
	delay_us(5);
}

至此,关于主机对从机写入数据的时序模拟就结束了,实际使用过程中,根据对应的时序图调用对应的函数即可,例如对于AT24C02写入数据
在这里插入图片描述
代码流程如下:
①发送一个起始信号
②器件写地址
③接收应答
④器件的存储上的绝对地址
⑤接收应答
⑥写入数据
⑦接收应答
⑧停止信号

IIC的时序组成(主机对从从机获取数据)

上面介绍了主机对从机写入数据的过程以及所需要函数逻辑,也就是主机 发送器发送到从机 接收器 的传输;方向不会改变,一直是主机发送数据,从机接收数据后做应答,主机检测应答,然后继续发送数据,直到数据发送完成后,主机发送结束信号。
在这里插入图片描述
实际使用过程中,对于IIC的从设备,往往是一些传感器和存储器,不仅需要对其写入对应的数据,还需要进行获取数据,获取的具体流程与上面的发送大致一样,但是数据接收和应答这个需要修改一下。
在第一个字节(读地址)后;主机立即读从机 。
此时的第一次响应还是由从机产生,之后就变成了从机发送数据,主机接收数据,每次接受一个数据后主机发送个应答位。直到数据接收完成,最后一个数据接收完成后,主机会发送一个非应答信号,告诉从机接收结束,紧接着主机产生结束信号,接收此次通信。
在这里插入图片描述
可以注意到,在读取数据时,起始信号,读地址发送,从机应答,结束信号都是与前面一样的,只是多了一个数据接收以及一个主机应答的操作,根据IIC的通信需求,每次接收完一个八位数据位后接收端就需要返回给发送端一个应答,只有应答信号正常时才会进行下一步操作,前面的数据发送是主机MCU的发送器发送给从机的接收器的,从机接收八位数据后会返回一个应答位,主机检测应答正常后继续发送。而此时的读取数据是从机发送器发送数据,主机的接收器接收数据当主机接收了八位数据后,需要给从机返回一个应答位,以便于从机下一位的数据发送,当接收最后一位数据后,主机需要产生一个非应答信号告诉从机接收完成。

1.数据接收

前面提到过,只有在时钟线拉高的情况下才可以进行数据的接收,而且一次接收就需要接收八位,且是高位在前,因此,接收数据的伪代码如下:

u8 接收数据函数
{
  u8 data
  //数据线切换成输入模式
  拉低时钟线
  拉高数据线     //让数据线处于空闲  可以接收数据

  for(u8 i=0;i<8;i++)
  {
	拉低时钟线    //从机发送数据
	拉高时钟线    //主句可以开始接受数据
	data = data << 1;  //先进行左移再接收
	if(数据线)
	{
 	  data |= 1;
	}
  }
 //调用发送应答函数
 拉低时钟线   ///安全模式
}

2.主机发送应答信号

除了接收八位数据以外,就是需要给从机发送应答信号,来告诉它是否传输成功,其实思路与之前的接收应答位差不多,就是在时钟拉低的时候将数据线对应拉高或者拉低就可以了,其中拉低表示应答成功,拉高表示应答失败。
伪代码如下:

发送应答函数(ack)
{
  拉低时钟线
  delay_us(5);  //此时间需要从参考对应的从设备的数据手册 
  if(ack==0)
  拉低数据线      //主机发送应答信号
  else
  拉高数据线	//主机发送非应答信号
  delay_us(1);  
  拉高时钟线      //主机帮从机拉高时钟线从而 从机获取应答
  delay_us(5);   
  拉低时钟线     //安全模式
}

还是举个例子吧,假设需要从AT24C02中读取一个字节其时序流程如下图所示:
在这里插入图片描述
具体的流程如下:
①开始信号
②发送写地址
③接收应答
④发送绝对地址//需要读取的数据的地址
⑤接收应答
⑥开始信号
⑦发送读地址
⑧接收应答
⑨读取一个字节
⑩发送非应答
⑪停止信号

IIC初始化代码

由于笔者手头没有IIC的器件了,所以此处就只留一个IIC的初始化代码了。
根据前面的介绍,一个IIC的模拟时序需要有以下的函数:
1.GPIO口的初始化,SCL初始化为推挽输出,SDA初始化为开漏输出,这里笔者用开漏输出,如果想要推挽输出,然后通信过程中切换GPIO模式的,可以去看一下正点原子的代码,他们的就是使用的推挽输出,然后接收时再配置为输入模式。
2.编写起始信号代码,结束信号代码,发送数据代码,接受数据代码,接受应答的代码,发送应答的代码。
IIC的代码如下:

#include "stm32f4xx.h"                  // Device header

#include "iic.h"

static void delay_us(u32 us)
{
	u32 i = 168 / 4 * us;
	while(i)
	{
		i--;
	}
}


/*******************************************
*函数名    :iic_IO_init
*函数功能  :IIC管脚初始化配置
*函数参数  :无
*函数返回值:无
*函数描述  :
						SCL-----PB8   通用推挽输出
						SDA-----PB9   通用开漏输出
*********************************************/
void iic_IO_init(void)
{
	//端口时钟使能
	RCC->AHB1ENR |= (1<<1);
	//端口模式配置
	GPIOB->MODER &= ~((3<<16) | (3<<18));   //清零
	GPIOB->MODER |= ((1<<16) | (1<<18));    //通用输出
	//端口输出类型配置
	GPIOB->OTYPER &= ~(1<<8);     //推挽
	GPIOB->OTYPER |= (1<<9);      //开漏
	//端口输出速度配置
	GPIOB->OSPEEDR &= ~((3<<16) | (3<<18)); //2M
	//IO口保持电平
	GPIOB->ODR |= (1<<8);
	GPIOB->ODR |= (1<<9);
}


/*******************************************
*函数名    :iic_star
*函数功能  :IIC其实信号函数
*函数参数  :无
*函数返回值:无
*函数描述  :
*********************************************/
void iic_star(void)
{
	//时钟线拉低
	SCL_L;
	//数据线高电平
	SDA_OUT_H;
	
	//时钟线拉高
	SCL_H;
	delay_us(5);   
	//数据线拉低
	SDA_OUT_L;
	delay_us(5);   
	
	//安全
	SCL_L;
}


/*******************************************
*函数名    :iic_stop
*函数功能  :IIC停止信号函数
*函数参数  :无
*函数返回值:无
*函数描述  :
*********************************************/
void iic_stop(void)
{
	SCL_L;
	SDA_OUT_L;
	
	SCL_H;
	delay_us(5);   
	SDA_OUT_H;
	delay_us(5);   
}




/*******************************************
*函数名    :iic_send_ack
*函数功能  :IIC发送应答函数
*函数参数  :u8 ack
*函数返回值:无
*函数描述  :
						ack  0    应答
            ack  1    不应答
						主机发送应答表示继续接收数据
            主机发送不应答表示不再接收数据
*********************************************/
void iic_send_ack(u8 ack)
{
	SCL_L;
	delay_us(5);   
	if(ack == 0)
	{
		SDA_OUT_L;       //应答信号
	}
	else
	{
		SDA_OUT_H;       //不应答信号
	}
	delay_us(1);   
	
	SCL_H;
	delay_us(5);   
	
	
	SCL_L;     //安全
}


/*******************************************
*函数名    :iic_get_ack
*函数功能  :主机检测应答函数
*函数参数  :无
*函数返回值:u8
*函数描述  :
						应答返回值是0
            不应答返回值是1
*********************************************/
u8 iic_get_ack(void)
{
	u8 ack = 0;
	
	/*将IO口切换为输入*/
	SCL_L;
	SDA_OUT_H;          //切换输入
	
	/*检测应答*/
	SCL_L;              //主机帮助从机拉低时钟线从机才自动发送应答信号
	delay_us(5);   
	SCL_H;              //主机可以读数据线
	delay_us(5);   
	if(SDA_INT )
	{
		ack = 1;
	}
	else
	{
		ack = 0;
	}
	
	//安全
	SCL_L;
	
	return ack;
}


/*******************************************
*函数名    :iic_send_byte
*函数功能  :主机通过IIC发送一个字节函数
*函数参数  :u8 data
*函数返回值:无
*函数描述  :
*********************************************/
void iic_send_byte(u8 data)
{
	u8 i;
	
	for(i=0;i<8;i++)
	{
		SCL_L;            //可以写数据
		delay_us(5);   
		if(data & 0x80)  
			SDA_OUT_H;
		else             
			SDA_OUT_L;
		delay_us(1);   
		SCL_H;            //主机帮助从机拉高时钟线,从机才可以读这一位数据
		delay_us(5);   
		
		data = data << 1; //下一位数据
	}

	//安全
	SCL_L;
}



/*******************************************
*函数名    :iic_read_byte
*函数功能  :主机通过IIC接收一个字节函数
*函数参数  :无
*函数返回值:u8
*函数描述  :
*********************************************/
u8 iic_read_byte(void)
{
	u8 data;    
	u8 i;
	
	/*将IO口切换为输入*/
	SCL_L;
	SDA_OUT_H;
	
	/*读数据*/
	for(i=0;i<8;i++)
	{
		SCL_L;             //主机帮助从机拉低时钟线
		delay_us(5);   
		SCL_H;             //主机可以读数据
		delay_us(5);   
		data = data << 1;
		if(SDA_INT) 
			data= data | 0x01;		
	}
	
	//安全
	SCL_L;
	
	return data;
}


需要特别提醒的是IIC的延时一定要准确,一定一定要准确,大部分的软件模拟IIC通信异常都是延时的问题。

总结

关于IIC的介绍就先记录到此,关于控制器实现IIC的大家可以自己搜索一下,下面两篇文章中也有详细介绍,这路笔者不再做介绍了,文中如有不足,欢迎大家批评指正,关于IIC和SPI的实际使用,后面有机会再做补充,因为手上的最小系统板实在是外设有限,目前只能介绍这么多了。

STM32硬件I2C与软件模拟I2C超详解http://t.csdn.cn/8ljI9
【STM32】入门(七):I2C硬件控制方式http://t.csdn.cn/1zZHP

M4系列目录

1.嵌入式学习笔记——概述
2.嵌入式学习笔记——基于Cortex-M的单片机介绍
3.嵌入式学习笔记——STM32单片机开发前的准备
4.嵌入式学习笔记——STM32硬件基础知识
5.嵌入式学习笔记——认识STM32的 GPIO口
6.嵌入式学习笔记——使用寄存器编程操作GPIO
7.嵌入式学习笔记——寄存器实现控制LED小灯
8.嵌入式学习笔记——使用寄存器编程实现按键输入功能
9.嵌入式学习笔记——STM32的USART通信概述
10.嵌入式学习笔记——STM32的USART相关寄存器介绍及其配置
11.嵌入式学习笔记——STM32的USART收发字符串及串口中断
12.嵌入式学习笔记——STM32的中断控制体系
13.嵌入式学习笔记——STM32寄存器编程实现外部中断
14.嵌入式学习笔记——STM32的时钟树
15.嵌入式学习笔记——SysTick(系统滴答)
16.嵌入式学习笔记——M4的基本定时器
17.嵌入式学习笔记——通用定时器
18.嵌入式学习笔记——PWM与输入捕获(上)
19.嵌入式学习笔记——PWM与输入捕获(下)
20.嵌入式学习笔记——ADC模数转换器
21.嵌入式学习笔记——DMA
22.嵌入式学习笔记——SPI通信
23.嵌入式学习笔记——SPI通信的应用
24嵌入式学习笔记——IIC通信

写在后面的话

整个M4的介绍基本上结束了,还有一个看门狗和一个位带操作,这个我是打算鸽了,笔者最近正在准备一个板子,因为这个系列主要使用的寄存器来编程控制,而且用的是M4系列的;其实在实际使用过程中M3系列的还是占比比较大的,所以下一个系列可能使用标准库,围绕这个板子进行一个介绍,然后插入一点FreeRTOS或者是用STM32CubeMX配置,用HAL库来进行。当然,前提是这个板子能够正常调通。而且最近立创那边好像也开了一个GD32的小车项目,这个大家有兴趣的也可以去试试水。
在这里插入图片描述
欢迎大家提供意见和建议哟,感谢大家的支持和点赞。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌入式学习笔记——IIC通信 的相关文章

  • linux生成可执行文件的命令

    linux生成带调试的可执行文件命令行 xff1a g span class token operator 43 43 span span class token operator span g main span class token
  • git rebase origin/develop

    1 进行git rebase origin develop之前需要进行 lt git add gt lt git commit gt 操作先将修改给提交到暂存区 2 执行git rebase origin develop时候有冲突的话需要自
  • linux---文件描述符和重定向

    文件描述符 进程就是通过struct file结构体来描述打开的文件 xff0c 使用struct file fd array 来存储我们的文件 那什么是文件描述符呢 xff1f 什么是文件描述符 xff1a 文件描述符就是struct f
  • git合并多个commit

    git合并多个commit
  • 深度学习资料

    深度学习资料
  • cmake总结

    cmake 用CMakeList txt产生makefile xff0c make 使用makefile编译可执行程序
  • kuangbin连通图专题,Network of Schools (POJ - 1236,tarjan算法求缩点+缩点的入度与出度的运用)

    kuangbin 题意是有N个学校 每个学校可能向几个学校进行数据传输 xff08 单向的 xff09 问 至少需要把一个文件给几个学校可以使给的N个学校都收到文件 再问在加几个通信线路可以使各个学校之间都能直接或间接的传递文件 一个强连通
  • endnote 文献保留前三个作者

    1 问题描述 xff1a endnote使用GBT7714文献格式 xff0c 显示文献的全部作者 2 想要达到的效果 xff1a 最多显示三个作者 3 解决方法 xff1a 还不知道怎么弄 xff0c 看看以后再来补充 xff0c 心情烦
  • RTK_LIB 源码、可执行文件、rtkget、观测文件、星历文件(精密星历、广播星历)、精密钟差文件介绍

    1 RTK LIB开源程序下载 xff1a 点开rtklib链接 xff1a 下载最新版本的可执行文件和程序源码 2 GNSS数据处理需要的文件 2 1 伪距定位 xff1a spp 观测数据 xff08 0 xff09 导航星历 广播星历
  • RTKLIB ppp rtk_post

    1 实时ppp xff1a IGS MGEX数据处理中心的播发的实时轨道钟差产品 xff0c 结合广播星历 xff0c 实现实时定位 2 事后的 xff08 近似实时 xff09 xff1a 下载精密星历 钟差产品 xff0c 结合其他的精
  • 4.使用静态库、动态库,常见问题解决

    使用动态库的流程 xff08 ORBSLAM3实例 xff09 xff1a 在调用动态库或静态库的 cpp文件添加库的头文件 xff08 可以包含路径 xff0c 也可以在cmakelist文件加头文件搜索路径 xff09 span cla
  • vscode查看代码更新历史

    开源代码推出新版本后 xff0c 如何查看代码更改信息 1 首先打开vscode xff0c 点击左侧的插件管理器 xff0c 进入插件面板 xff0c 搜索Git Graph并安装 2 点击下图图标 xff0c 即可进入Git Graph
  • git更新代码

    一 git一般有很多分支 xff0c 我们clone到本地的时候一般都是master分支 xff0c 那么如何切换到其他分支呢 xff1f 主要命令如下 xff1a 1 查看本地分支文件信息 xff0c 确保更新时不产生冲突 span cl
  • linux---硬链接和软链接

    文件系统 磁盘上文件读写存储与查找系统 xff08 管理 xff09 就是文件系统 xff0c 在每一个分区都会存在自己的文件系统 在这里我们有swap交换分区和文件分区 xff0c 我们这里只介绍文件分区 在文件分区都会有上图中的分块管理
  • char类型数组

    字符数组 xff08 一维 二维 xff09 字符数组是数组元素为char类型的一种数组 凡是适合数组的定义和赋值 xff0c 也都适合于字符数组 由于C语言没有提供字符串类型 xff0c 字符串一般用一维字符数组来存放 xff0c 而二维
  • ubuntu18.04 安装腾讯会议

    腾讯会议现在以及上线了Linux版本 xff0c 可以直接在腾讯会议官网下载linux 版本 xff0c 在官网点击免费下载 xff0c 可以直接下载Linux版本 腾讯会议下载链接 选择Linux版本 xff0c x86 64版本 xff
  • 2.树莓派系统备份

    树莓派使用SD卡来装载系统 xff0c 如果SD卡丢失或者损坏 xff0c 那么树莓派上的数据都会丢失 xff0c 所以一定要备份好SD卡 这篇文章可以帮你备份你的树莓派系统 主要内容为备份SD卡 xff0c 制作树莓派系统镜像以及在需要的
  • ic_gvins编译及环境配置问题解决

    RTK VIO松组合 对惯导精度要求较高 1 环境配置和编译 安装依赖项 span class token comment gcc 8 span span class token function sudo span span class
  • EVO画图设置

    一 绘图设置 1 更改背景色和网格 span class token comment 白色网格 span evo config span class token builtin class name set span plot seabor
  • GINS_OB环境配置

    1 程序简介 武大开源GNSS INS松组合IMU预积分有考虑地球自传和不考虑两种形式可以灵活设置GNSS中断时间IMU可以和里程计进行融合 2 环境配置 span class token comment gcc 8 g 43 43 8 s

随机推荐

  • OB_GINS程序框架

    1 程序运行 span class token builtin class name cd span OB GINS span class token comment 编译好的可执行文件 xff1a bin ob gins xff0c 参数
  • KEIL、MDK中关于__LINE__宏 printf 的显示不正确的问题

    span class token operator gt span define span class token function DEBUG span span class token punctuation span log span
  • VINS-回环检测与重定位

    参考博客 pose graph分析1 pose graph分析2 pose graph分析3
  • 源码安装naviagtion,但是出现[move_base-2] process has died 运行错误的解决办法

    今天开始记录ros遇到的问题 安装navigation可以使用两种方法 第一种 xff1a sudo apt get install ros kinetic navigation 这种安装方法最简单 xff0c 新手或者不需要动naviag
  • linux---静态库和动态库的制作和使用

    静态链接和动态链接 静态链接 xff1a 生成可执行代码 xff0c 链接静态库 xff08 与代码位置有关的链接方式 xff09 xff0c 需要将代码拷贝到我们的源代码中才能运行 动态链接 xff1a 生成可执行代码 xff0c 链接动
  • 加一

    加一 描述 给定一个由整数组成的非空数组所表示的非负整数 xff0c 在该数的基础上加一 最高位数字存放在数组的首位 xff0c 数组中每个元素只存储单个数字 你可以假设除了整数 0 之外 xff0c 这个整数不会以零开头 示例 1 输入
  • STM32bootloader原理解释

    STM32bootloader原理解释 一 STM32的常规启动流程 STM32的内部flash地址起始于0x8000000 xff0c 一般情况下 xff0c 程序文件就从此地址开始写入 此外STM32是基于Cortex M3内核的微控制
  • 模糊PID基本原理及matlab仿真实现(新手!新手!新手!)

    有关模糊pid的相关知识就把自己从刚接触到仿真出结果看到的大部分资料总结一下 xff0c 以及一些自己的ps 以下未说明的都为转载内容 1 转自 https blog csdn net weixin 36340979 article det
  • VMware+ubuntu+win10笔记本实现笔记本连接WIFI且ubuntu既可以上网又能连接开发板

    背景 最近在学习imx6ull开发板的时候 xff0c 发现开发板通过网线连接笔记本电脑却无法ping通ubuntu xff0c 于是捣鼓了很久终于可以了 xff0c 却又发现ubuntu不能上网了 xff0c 经过一番查找资料和尝试 xf
  • 在windows上用vscode打造比vc++6.0好用的C/C++ IDE,适用编程小白

    准备 xff1a 1 安装MinGW xff0c 添加gcc gdb等编译调试工具bin目录 头文件Include目录 库lib的路径到系统环境变量 xff0c 安装LLVM 添 加Clang编译器所在bin目录到系统环境变量 具体操作百度
  • C语言数据结构——线性表的链式存储结构

    文章目录 线性表的链式存储结构1 基本概念2 设计与实现3 优点和缺点 线性表的链式存储结构 1 基本概念 链式存储定义 xff1a 为了表示每个数据元素与其直接后继元素之间的逻辑关系 xff0c 每个元素除了存储本身的信息之外 xff0c
  • 智能车浅谈——硬件篇

    目录 初识小车硬件系统1 电源系统线性电源开关电源 2 人机交互系统3 MCU最小系统4 传感器系统摄像头电感编码器 5 驱动系统 机械结构 17届完赛代码智能车系列文章汇总 前言 xff1a 作为一名老三本玩家 xff0c 笔者深知一些同
  • 智能车浅谈——图像篇

    文章目录 前言认识图像基本含义图像类型数字图像彩色图像灰度图像黑白图像 小结 图像处理图像压缩二值化固定阈值法大津法 图像降噪 xff08 腐蚀 xff09 寻边线 总结17届完赛代码17届完赛代码智能车系列文章汇总 前言 前面已经记录了智
  • 智能车浅谈——手把手让车跑起来(电磁篇)

    文章目录 前言材料准备备赛组车模硬件 练习组车模硬件方案 整车原理赛道信息获取及转向原理工字电感运放模块转向原理元素判断 电机及舵机控制原理 代码实现效果欣赏总结17届完赛代码智能车系列文章汇总 前言 电磁寻迹小车 之前智能车系列已经做了一
  • 手把手教你OneNET数据可视化

    文章目录 前言OneNET实现数据可视化效果一览发布项目 xff08 5 17更新 xff09 总结 前言 之前介绍了Hi3861使用MQTT协议接入OneNET实现数据的上传以及命令的下发 xff0c 本文主要是介绍一下如何使用OneNE
  • linux---进程间通信(ipc)之管道

    进程间通信方式 管道共享内存消息队列信号量本地套接字等等都能作为我们进程间通信的方法 操作系统提供进程间通信方式的原因 因为对于我们进程来说 xff0c 每一个进程都是相互独立的 xff0c 具有独立性 xff0c 如果我们需要两个不同的进
  • 嵌入式学习笔记——STM32的USART收发字符串及串口中断

    USART收发字符串及串口中断 前言字符串的收发发送一个字符串接收字符串需求 利用串口实现printf 中断中断是什么串口的接收中断以及空闲中断实现代码实现效果 总结M4系列目录 前言 上一篇中 xff0c 介绍了串口收发相关的寄存器 xf
  • 嵌入式学习笔记——PWM与输入捕获(下)

    输入捕获 前言输入捕获的概述框图输入通道部分比较捕获寄存器与事件生成 寄存器编程思路 实际需求配置流程打开对应的时钟配置GPIO为复用模式定时器的时基部分配置定时器输入通道部分配置定时器中断配置 代码 xff1a 运行效果 xff1a 需求
  • 嵌入式学习笔记——SPI通信的应用

    SPI通信的应用 前言屏幕分类1 3OLED概述驱动芯片框图原理图通信时序显示的方式页地址 列地址初始化指令 程序设计初始化代码初始化写数据与写命令清屏函数 初始化代码字符显示函数 总结M4系列目录 前言 上一篇中介绍了STM32的SPI通
  • 嵌入式学习笔记——IIC通信

    IIC通信 前言IIC概述通信特征物理拓扑结构IIC通信的流程IIC的特点 xff1a STM32的IIC通信GPIO模拟IICIIC的时序组成 xff08 主机对从机写入数据 xff09 1 起始信号2 器件地址与读写位3 从机应答信号5