EEPROM、MCU6050和OLED显示屏外设都是通过IIC协议【半双工】进行通信。

除此之外,另一个广泛地使用在系统内多个集成电路间的通讯协议:SPI。

目录

一、IIC物理层:

二、IIC协议层

1.IIC的读写过程

1-主机写数据到从机:

2-主机由从机中读数据:

3-通讯复合格式

2.通讯的起始和停止信号

3.数据有效性

4.地址及数据方向

5.响应

三、程序

1.IIC协议底层程序

1-配置IIC宏定义

2-初始化IIC用到的GPIO口

3-IIC底层通信的基本程序

2.配置上层程序(EEPROM为例)

1-EEPROM检测函数

2-写字节程序:

3-读字节程序:

4-读多个字节程序:

5-写多个字节程序:

四、问题汇总

1.如何读取、存储16个字节的数?

2.为什么传入的数据都是地址

一、IIC物理层:

MCU就是STM32。IIC协议就是一个支持多设备的总线,“总线”指多个设备(传感器)共用的信号线,由主机发起通信。一个IIC总线只使用两条总线线路,一条双向串行数据线(SDA),一条串行时钟线 (SCL)。数据线即用来表示数据,时钟线用于数据收发同步。

每个连接到总线的设备都有一个独立的地址,用7位的二进制数表示,主机可以利用这个地址进行不同设备之间的访问。

总线通过上拉电阻接到电源(在STM32里面是连接到3.3V)。当IIC设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。(在数字电路里面,3.3V是逻辑1,0V是逻辑0,高阻态相当于断路)。

设备表达逻辑0或1的方法:如果所有的设备都空闲,都在输出高阻态,那么整条总线都可以通过上拉电阻拉到3.3V,也就是逻辑1;如果只要有一个设备没有空闲,那么通过这个设备总线就会连接到GND,这根总线就会拉成0V,变成逻辑0.所以:IIC里面,逻辑0的优先级是高于逻辑1的。这就是仲裁机制。多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。

相同的输出模式在GPIO口的应用:GPIO可以通过开漏输出模式输出高阻态,此I/O口的电压就由外界的上拉电阻拉高决定。如果我们想通过I/O口输出一个5V的电压,就可以将其设置成开漏输出模式,外接5V的上拉电阻,就可以输出5V电压。

二、IIC协议层

IIC的协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节。

1.IIC的读写过程

1-主机写数据到从机:

S:主机发送起始信号

SLAVE_ADDRESS: 从机地址

A/A非:应答(ACK)或非应答(NACK)信号

应答位:返回0,应答成功;返回1,应答失败。

主机发送起始信号之后,开始对地址进行点名,收到从机应答信号之后,开始传输数据。传输数据的过程是一个字节一个字节传输的,主机传完一个字节之后,就要等待从机去应答。如果从机返回了一个非应答信号,就说明从机接收的数据已经够多了,主机就会暂停传输,产生结束信号“P”。

2-主机由从机中读数据:

此过程与前面类似。

3-通讯复合格式

IIC的读和写复合在一起进行

大体过程与前面相同。

注意:我们确定读取/写入数据的从机是EEPROM而不是OLED,是取决于SLAVE_ADDRESS的。EEPROM总共能存储256个字节,那如何确定读取/写入数据是EEPROM的哪个字节?

第一次发送起始信号,确定是EEPROM的地址之后,先写数据,得到应答之后,发送一个数据,这个数据就是EEPROM的字节。然后再次发送开始信号,换成读数据,等待应答并且返回该字节内的数据。

2.通讯的起始和停止信号

当SCL线是高电平时,SDA线从高电平向低电平切换,这个情况表示通讯的起始。当SCL是高电平时SDA线由低电平向高电平切换,表示通讯的停止。

这两个信号都是由主机产生。

3.数据有效性

IIC使用SDA信号线来传输数据,使用SCL信号线进行数据同步。 SDA数据线在SCL的每个时钟周期传输一位数据(8位数据一个字节)。

SCL为高电平的时候SDA表示的数据有效,即此时的SDA为高电平时表示数据“1”,为低电平时表示数据“0”。当SCL为低电平时,SDA的数据无效,一般在这个时候SDA进行电平切换,为下一次表示数据做好准备。

4.地址及数据方向

IIC总线上的每个设备都有自己的独立地址,主机发起通讯时,通过SDA信号线发送设备地址(SLAVE_ADDRESS)来查找从机。设备地址可以是7位或10位。紧跟设备地址的一个数据位R/W用来表示数据传输方向,数据方向位为“1”时表示主机由从机读数据,该位为“0”时表示主机向从机写数据。

例如:EEPROM的地址确定:由A0、A1、A2引脚的值确定,比如A0接地,A1接3.3V.但在MINI板子上这三个引脚都接地(都是0,高4位是1010,是确定值,则地址位固定为1010 000x,x就是读/写模式位)【8位设备读地址:0XA1,写地址:0XA0】

5.响应

I2C的数据和地址传输都带响应。响应包括“应答(ACK)”和“非应答(NACK)”两种信号。每传输一个字节,都要带一个响应位。

传输时主机产生时钟,在第9个时钟时,数据发送端会释放SDA的控制权,由数据接收端控制SDA,若SDA为高电平,表示非应答信号(NACK),低电平表示应答信号(ACK)。【主机和从机都有可能成为发送端或者接收端】

三、程序

1.IIC协议底层程序

1-配置IIC宏定义

IIC协议的初始化GPIO端口函数,和一些产生起始信号、终止信号、应答信号,读取、写入字节等。该协议适用于全部IIC协议的模块,是较底层的函数,只需要修改相应的引脚、端口、时钟即可。

#define IIC_SCL_GPIO_CLK         RCC_APB2Periph_GPIOA//时钟
#define IIC_SCL_GPIO_PORT        GPIOA               //端口
#define IIC_SCL_GPIO_PIN         GPIO_Pin_2//pin 引脚#define IIC_SDA_GPIO_CLK         RCC_APB2Periph_GPIOA//时钟
#define IIC_SDA_GPIO_PORT        GPIOA               //端口
#define IIC_SDA_GPIO_PIN         GPIO_Pin_3//pin//控制引脚电平
#define EEPROM_IIC_SDA_1()           GPIO_SetBits(IIC_SDA_GPIO_PORT,IIC_SDA_GPIO_PIN)//SDA 数据线 输出高电平
#define EEPROM_IIC_SDA_0()           GPIO_ResetBits(IIC_SDA_GPIO_PORT,IIC_SDA_GPIO_PIN)#define EEPROM_IIC_SCL_1()            GPIO_SetBits(IIC_SCL_GPIO_PORT,IIC_SCL_GPIO_PIN)//SCL 时钟线 输出高电平
#define EEPROM_IIC_SCL_0()       GPIO_ResetBits(IIC_SCL_GPIO_PORT,IIC_SCL_GPIO_PIN)//读取引脚电平
#define EEPROM_IIC_SDA_READ()  GPIO_ReadInputDataBit(IIC_SDA_GPIO_PORT,IIC_SDA_GPIO_PIN)//读取指定的输入端口引脚

2-初始化IIC用到的GPIO口

新建一个IIC通信的文件夹。IIC协议所用到的GPIO端口的初始化。EEPROM用到两个引脚:SDA和SCL其输出模式:开漏输出模式。

void IIC_GPIO_Config(void)//初始化相关的GPIO IIC-EEPROM
{GPIO_InitTypeDef GPIO_InitStruct;/*第一步:打开外设的时钟(RCC寄存器控制)*/RCC_APB2PeriphClockCmd(IIC_SCL_GPIO_CLK|IIC_SDA_GPIO_CLK,ENABLE);/*第二步:配置外设初始化结构体*/GPIO_InitStruct.GPIO_Pin = IIC_SCL_GPIO_PIN;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;//开漏输出GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;/*第三步:调用外设初始化函数,把配置好的结构体成员写到寄存器里面*/GPIO_Init(IIC_SCL_GPIO_PORT,&GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin = IIC_SDA_GPIO_PIN;GPIO_Init(IIC_SDA_GPIO_PORT,&GPIO_InitStruct);
}

3-IIC底层通信的基本程序

配置通讯的起始信号和终止信号,原理图见“通讯的起始和停止信号”。注意的是,要在电平升高/降低之前加一点延时,保持一段时间,因为硬件需要一些反应时间。延时函数使用原装的。

void IIC_Start(void)//产生起始信号
{EEPROM_IIC_SDA_1();EEPROM_IIC_SCL_1();i2c_Delay();//需要在这个状态下加一点延时,保持一段时间EEPROM_IIC_SDA_0();i2c_Delay();//产生起始信号EEPROM_IIC_SCL_0();i2c_Delay();
}void IIC_Stop(void)//产生停止信号
{EEPROM_IIC_SDA_0();EEPROM_IIC_SCL_1();i2c_Delay();EEPROM_IIC_SDA_1();i2c_Delay();//产生停止信号EEPROM_IIC_SCL_0();i2c_Delay();
}

配置产生应答和非应答信号程序(接收端),原理图见“响应”。在应答程序内:配置完之后SDA拉成高电平,释放控制权,供其他设备使用。接着配置等待等待应答信号,无应答返回1;应答返回0。原理图见上图黄色部分。将SDA和SCL的电平都拉高,给个延时之后判断SDA返回的是高低电平,高电平返回无应答;低电平返回应答;最后再把SCL置0.

void IIC_Ask(void)//产生应答信号
{EEPROM_IIC_SDA_0();EEPROM_IIC_SCL_1();i2c_Delay();EEPROM_IIC_SCL_0();//SCL产生时钟i2c_Delay();//产生应答信号EEPROM_IIC_SDA_1();//SDA 拉成高电平,释放控制权,供其他设备使用i2c_Delay();
}void IIC_NAsk(void)//产生非应答信号
{EEPROM_IIC_SDA_1();EEPROM_IIC_SCL_1();i2c_Delay();EEPROM_IIC_SCL_0();//SCL产生时钟i2c_Delay();//产生非应答信号
}uint8_t IIC_Wait_Ask()//等待应答信号 无应答:1 应答:0
{uint8_t reply;EEPROM_IIC_SDA_1();//释放控制权EEPROM_IIC_SCL_1();i2c_Delay();if(EEPROM_IIC_SDA_READ() == 1){reply = 1;}else {reply = 0;}EEPROM_IIC_SCL_0();i2c_Delay();return reply;
}

配置写入一个字节的函数,通过for循环将数据一位一位传输过去,0X80:1000 0000,让要写入的数据一位一位的与0X80相与,直到整个数据都与其相与完毕。写入1的话返回1,写入0的话返回0。传输完之后,释放SDA控制权。

void IIC_Write_byte(uint8_t data)//写入一个字节
{uint8_t i;for(i=0;i<8;i++){if(data & 0x80)//0X80:1000 0000 让要写入的数据一位一位的与 0X80 相与{              //下面的 data <<= 1;直到整个数据都与其相与完毕。EEPROM_IIC_SDA_1();//相与:写入1的话返回1,写入0的话返回0}else {EEPROM_IIC_SDA_0();}i2c_Delay();EEPROM_IIC_SCL_1();i2c_Delay();EEPROM_IIC_SCL_0();//SCL产生时钟i2c_Delay();if(i == 7){EEPROM_IIC_SDA_1();//释放控制权}data <<= 1;}
}

配置读取一个字节的函数,用temp暂存读取的数据,通过for循环全部读取。

uint8_t  IIC_Read_byte()//读取一个字节
{uint8_t i,temp=0;for(i=0;i<8;i++){temp <<= 1;EEPROM_IIC_SCL_1();i2c_Delay();if(EEPROM_IIC_SDA_READ() == 1){temp += 1;}//如果读取的数为1,就加进去;如果是0,就不操作EEPROM_IIC_SCL_0();//SCL产生时钟i2c_Delay();}return temp;
}

官方给的延时程序

static void i2c_Delay(void)//官方给的延时程序
{uint8_t i;/* 下面的时间是通过逻辑分析仪测试得到的。工作条件:CPU主频72MHz ,MDK编译环境,1级优化循环次数为10时,SCL频率 = 205KHz 循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us 循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us */for (i = 0; i < 10; i++);
}

2.配置上层程序(EEPROM为例)

建立一个新的文件夹,存放上层的设备程序。

1-EEPROM检测函数

首先是EEPROM的检测函数,检测其是否存在。注意:如果是读模式下,还要我们自己给EEPROM返回一个非应答信号才能停止。

//返回值为1:连接失败;返回值为0:连接正常
uint8_t EEPROM_check_device(uint8_t addr)//检测EEPROM是否存在
{uint8_t result;IIC_Start();//发送起始信号IIC_Write_byte(addr);//发送 EEPROM 设备地址/*这个与写入一个字节的程序一样,因为 EEPROM 自己知道发送完起始信号之后,下一个写入的就是设备地址*/if(IIC_Wait_Ask())//检测响应信号{result = 1; }//表示EEPROM不存在,无应答else{result = 0;}       //表示EEPROM存在IIC_NAsk();//如果是读模式下,还要我们自己给EEPROM返回一个非应答信号才能停止IIC_Stop();return result;
}

写完后在主函数内进行判断,把EEPROM的设备地址传输过去,看能否检测得到,检测的结果通过串口返回回来。

2-写字节程序:

如果检测的没有问题,就往EEPROM里面写入一个字节。先发送起始信号,发送EEPROM(写)的设备地址;检查响应信号,如果EEPROM应答,发送要写入的EEPROM的存储单元格地址(这个是根据具体的设备确定,有的设备不需要发送存储单元格地址,只要发送设备地址就可以写数据,但EEPROM要写);

WORD ADDRESS:往EEPROM里面的哪个存储空间写入字节。

DATA:写入的内容

再次检测响应信号,应答之后向EEPROM写入数据。写完之后再次检测响应信号,如果没有检测到响应信号(包括前面),就让他们停止并且返回0【goto 语句】。

由于EEPROM是有内部时序的,我们有时候需要连续调用写函数向EEPROM存储数据,所以我们要等待EEPROM内部时序完成之后再进行操作,所以我们写一个等待函数,放在起始信号之前和终止信号之后。这样就可以完成连续调用。

//返回值为1:等待超时;返回值为0:正常
uint8_t EEPROM_wait(void)//等待EEPROM内部时序完成
{uint16_t cycle = 0;while(EEPROM_check_device(EEPROM_ADDR | EEPROM_WRITE_DIR))//EEPROM无应答{cycle++;if(cycle>=10000) return 1;//等待超时}return 0;//完成等待
}//返回值为1:写入正常;返回值为0:写入错误
uint8_t EEPROM_write_byte(uint8_t w_addr,uint8_t data)//往EEPROM里面写入一个字节
{            //w_addr:EEPROM 内存储单元格的地址(0-256),data:写入的数据if(EEPROM_wait() == 1) goto xiangying_w_fail;//超时IIC_Start();//发送起始信号IIC_Write_byte(EEPROM_ADDR | EEPROM_WRITE_DIR);//发送 EEPROM 设备地址/*这个与写入一个字节的程序一样,因为 EEPROM 自己知道发送完起始信号之后,下一个写入的就是设备地址*/if(IIC_Wait_Ask())//检测响应信号goto xiangying_w_fail;//表示EEPROM不存在,无应答else {IIC_Write_byte(w_addr);//发送要写入的 EEPROM的存储单元格地址if(IIC_Wait_Ask())//检测响应信号goto xiangying_w_fail;else IIC_Write_byte(data);//向 EEPROM写入数据if(IIC_Wait_Ask())//检测响应信号goto xiangying_w_fail;else {}}IIC_Stop();if(EEPROM_wait() == 1) goto xiangying_w_fail;//超时return 1;xiangying_w_fail:IIC_Stop();return 0;
}

在写完写字节函数之后,可以在主函数内部加以判断,通过串口返回存储是否正确。

3-读字节程序:

注意的是,第一次发送的设备地址仍然是写模式下的地址;然后检测响应信号,发送要读出的EEPROM的存储单元格地址;再检测响应信号,发送第二次起始信号和第二次设备地址:读方向;再次检测响应信号,读出数据。

等待函数,只放在起始信号之前即可。

//返回值为1:读取正常;返回值为0:读取错误
uint8_t EEPROM_read_byte(uint8_t r_addr,uint8_t *data)//从EEPROM里面读取一个字节
{/*r_addr:读EEPROM 哪个内存储单元格的地址(0-256),*data:读取到的数据存储到指针里面data是数值,*data是地址C语言要把一个函数内的数据传输给外面的变量,必须通过指针进行值传递    */if(EEPROM_wait() == 1) goto xiangying_r_fail;//超时IIC_Start(); //发送第一次起始信号IIC_Write_byte(EEPROM_ADDR | EEPROM_WRITE_DIR);//发送第一次设备地址:写方向if(IIC_Wait_Ask())//检测响应信号goto xiangying_r_fail;//表示EEPROM不存在,无应答else {IIC_Write_byte(r_addr);//发送要读出的 EEPROM的存储单元格地址if(IIC_Wait_Ask())//检测响应信号goto xiangying_r_fail;else {IIC_Start(); //发送第二次起始信号IIC_Write_byte(EEPROM_ADDR | EEPROM_READ_DIR);//发送第二次设备地址:读方向if(IIC_Wait_Ask())//检测响应信号goto xiangying_r_fail;else {*data = IIC_Read_byte();             }}  }IIC_NAsk();IIC_Stop(); return 1;xiangying_r_fail:IIC_NAsk();IIC_Stop();return 0;
}

4-读多个字节程序:

每读一个字节之后,发送一个应答信号;发送完之后,发送一个非应答信号即可。

//返回值为1:读取正常;返回值为0:读取错误
uint8_t EEPROM_read_bytes(uint8_t r_addr,uint8_t *data,uint16_t size)//从EEPROM里面读取n个字节
{/*r_addr:读EEPROM 哪个内存储单元格的地址(0-256),*data:读取到的数据存储到指针里面size:要读取多少个字节data是数值,*data是地址C语言要把一个函数内的数据传输给外面的变量,必须通过指针进行值传递    */if(EEPROM_wait() == 1) goto xiangying_r_fail;//超时IIC_Start(); //发送第一次起始信号IIC_Write_byte(EEPROM_ADDR | EEPROM_WRITE_DIR);//发送第一次设备地址:写方向if(IIC_Wait_Ask())//检测响应信号goto xiangying_r_fail;//表示EEPROM不存在,无应答else {IIC_Write_byte(r_addr);//发送要读出的 EEPROM的存储单元格地址if(IIC_Wait_Ask())//检测响应信号goto xiangying_r_fail;else {IIC_Start(); //发送第二次起始信号IIC_Write_byte(EEPROM_ADDR | EEPROM_READ_DIR);//发送第二次设备地址:读方向if(IIC_Wait_Ask())//检测响应信号goto xiangying_r_fail;else {uint16_t i;for(i=0;i<size;i++){*data = IIC_Read_byte();        if(i == size - 1) IIC_NAsk();//数据接收够了 else IIC_Ask();data++;//指针指向下一个数据}}}  }IIC_Stop();    return 1;xiangying_r_fail:IIC_NAsk();IIC_Stop();return 0;
}

5-写多个字节程序:

一次性最多写入8个字节,每8个字节为1页,我们可以分页写入

三个形参:w_addr:EEPROM 内存储单元格的地址(0-256);

data:写入的数据;         size:要写入多少个字节

用for循环,采用地址对齐的方法,每8个字节(0-7)一页,在每一页的开头发送起始信号。在发送起始信号之前:每写完一页的结束,先发送一次stop信号,结束前面的写入操作,如果是第一次写入也不影响,因为后面有等待EEPROM内部时序完成的程序。

在第一页或者每写完8个字节都要走一遍发送终止、起始信号发送EEPROM设备地址,发送要写入的EEPROM的存储单元格地址。

全部输入完成之后,再发送总的停止信号,等待EEPROM内部时序完成。

//返回值为1:写入正常;返回值为0:写入错误
uint8_t EEPROM_write_bytes(uint8_t w_addr,uint8_t *data,uint16_t size)//往EEPROM里面写入一个字节
{/*w_addr:EEPROM 内存储单元格的地址(0-256),data:写入的数据size:要写入多少个字节*/uint16_t i;for(i=0;i<size;i++){if(i == 0 || w_addr%8 == 0)//第一次或者每八次,i是从0-7的//采用地址对齐的方法,每8个字节(0-7)一页,在每一页的开头发送起始信号{/*每写完一页的结束,先发送一次stop信号,结束前面的写入操作如果是第一次写入也不影响,因为后面有等待EEPROM内部时序完成的程序*/IIC_Stop();if(EEPROM_wait() == 1) goto xiangying_w_fail;//超时IIC_Start();//发送起始信号IIC_Write_byte(EEPROM_ADDR | EEPROM_WRITE_DIR);//发送 EEPROM 设备地址/*这个与写入一个字节的程序一样,因为 EEPROM 自己知道发送完起始信号之后,下一个写入的就是设备地址*/if(IIC_Wait_Ask())//检测响应信号goto xiangying_w_fail;//表示EEPROM不存在,无应答else {IIC_Write_byte(w_addr);//发送要写入的 EEPROM的存储单元格地址if(IIC_Wait_Ask())//检测响应信号goto xiangying_w_fail;}}//在第一页或者每写完8个字节都要走一遍上面的程序IIC_Write_byte(*data);//向 EEPROM写入数据,一个字节一个字节的输入if(IIC_Wait_Ask())//检测响应信号goto xiangying_w_fail;data++;w_addr++;}/*全部输入完成之后*/IIC_Stop();if(EEPROM_wait() == 1) goto xiangying_w_fail;//超时 作用:等待EEPROM完成内部时序return 1;xiangying_w_fail:IIC_Stop();return 0;
}

注意:写入和读出数据传递的形参都是地址(原因后面介绍)

四、问题汇总

1.如何读取、存储16个字节的数?

把数据的指针写入进去,要占两个存储空间(一个存储空间能存8个字节),所以在传递指针的时候,我们要强制转换为8位的指针。读出数据的时候用数组的方式,将两位分开读。

写入:ABCD,输出结果:

r_temp0 = cd,r_temp1 = ab;

输出顺序与输入顺序相反原因:16进制的数一般左边为高位,右边为低位。STM32是小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。AB是高位,在temp1中。

然后我们再将其合并输出,将其转换为16位指针输出

printf("temp = %x",*(uint16_t *)r_temp);

2.为什么传入的数据都是地址

用指针把要写入的数据进行强制转换,一个字节一个字节地去读取数据的原始值(内部操作),然后通过write函数写进去。

读回来的时候也一样,先把原始值从EEPROM中读出来:

使用指针的方式把原始值强制转换为想要的数据类型

STM32 IIC协议 读写EEPROM相关推荐

  1. Verilog实现IIC协议读写EEPROM

    在FPGA设计中,IIC协议是一个十分常见的协议,因为几乎所有的EEPROM都是用这个协议进行读写的,此外,一些特殊场合,也会用到此协议.这里我首先给出IIC协议的中文标准文档的下载链接(不要积分), ...

  2. 通信协议之IIC协议(eeprom)_通俗易懂篇!

    1.IIC(Inter-Integrated Circuit),是IICBus简称,是一种串行通信总线. 2.IIC协议:遵循主机master和从机slave的主从关系机制,区别于SPI通信协议,II ...

  3. iic获取salve设备地址_Linux下使用IIC总线读写EEPROM(读写i2c从设备通用程序)

    Linux 下使用IIC总线 读写 EEPROM by 韩大卫 @吉林师范大学 handawei@jusontech.com 转载请务必表明出处 ******************* ******* ...

  4. IIC协议驱动EEPROM的Verilog实现与竞争冒险与下降沿触发、多重驱动

    文章目录 一.前言 二.软硬件平台 软件平台 硬件平台 三.IIC与EEPROM IIC简介 1. 写操作大致步骤 2. 读操作大致步骤 3. IIC总线有以下几种状态 1. 空闲状态 2. 起始信号 ...

  5. stm32 IIC 协议控制PCA9685舵机驱动板

    这篇教程与网上的大部分教程都不相同,着重讲述如何使用编程PCA9685,而不是着重讲述原理,最后你还是一头雾水.这是一篇教你如何如何输出固定舵机角度,如何移植程序,从PCA9685的原理到如何移植的教 ...

  6. mini2440----keil for AMR之IIC读写EEPROM(AT24C08)

    mini2440----keil for AMR之IIC读写EEPROM(AT24C08) 一:EEPROM芯片介绍 在这里分析AT24C02A/AT24C04A/AT24C08A,对于其他不同型号的 ...

  7. STM32模拟I2C时序读写EEPROM精简版

    平台:STM32ZET6(核心板)+ST-LINK/V2+SD卡+USB串口线+外部EEPROM(不需要上拉电阻) 工程介绍:主要文件在USER组中,bsp_i2c_ee.c,bsp_i2c_ee.h ...

  8. 基于I2C协议的EEPROM驱动控制(笔记整理)

    一.目标 要求:设计一个使用I2C通讯协议的EEPROM读写控制器.使用写按键向EEPROM中写入1~10共10字节数据:使用读按键读出之前写入的数据并显示在数码管上. 分析:①首先按键控制读写操作按 ...

  9. STM32学习之I2C协议(读写EEPROM)

    关于STM32学习分享 第七章 I2C协议(读写EEPROM) 文章目录 关于STM32学习分享 前言 二.代码 1.i2c.c 2.i2c.h 3.main.c 总结 前言 开始!开始!单片机的I2 ...

最新文章

  1. spark学习13(spark RDD)
  2. linux下安装sz/rz命令
  3. iptables加载顺序问题及优化方法
  4. Andorid应用去google广告
  5. 光流 | 金字塔迭代(Iterative Pyramidal)LK光流算法(Matlab源代码)
  6. JS判断 浏览器 是否禁用Cookie
  7. h.264 rtp打包
  8. java学习(87):Interage包装类进制转换
  9. c语言程序设计课件数组,数组(C语言程序设计)课件
  10. java的循环控制结构有哪些_java中的控制结构(if,循环)详解
  11. 使用AfxGetMainWnd函数的一个心得
  12. PIL-读取与保存图片
  13. 广州恒义计算机科技,【长文】SONY MAP-S1解码一体机恒义科技HY-05台式耳放听感测评...
  14. 微信无法绑定手机号的解决方案
  15. 新加坡国立大学计算机系访学,【访学归来】白卫岗:在新加坡国立大学探讨线性水声网络容量...
  16. 软件工程(C编码实践篇)学习总结
  17. 电脑c语言找不到,电脑安装过的应用程序找不到了怎么办
  18. 小说《小城恋情》第三十三章
  19. 什么是云手机?云手机的原理是什么?
  20. create remote oracle odbc data source on win10

热门文章

  1. 无人帆船模拟及实船实验步骤
  2. JS上传文件(base64字符串和二进制文件流)
  3. 【100%通过率】华为OD机试真题 C 实现【单词倒序】【2022.11 Q4 新题】
  4. 基于图像和激光的多模态点云融合与视觉定位
  5. 利用ClaudiaIDE插件在VS中插入图片
  6. 【物理应用】基于傅里叶伽辽金谱法二维纳维-斯托克斯附matlab代码
  7. Win10 安装loadrunner提示计算机上缺少vc2005_sp1_with_atl_fix_redist解决方法
  8. PHP实现以数组var_dump,array_combine等函数的方法功能举例
  9. cs实现上线linux主机与CrossC2的配置
  10. java将多个文件写入到一个文件流中再有规律的取出_编写java程序,往一个txt文件里写入学生的基本信息,然后再读出这些信息并打印出来,最后把该文件拷贝到指...