【STM32自学笔记-I2C】

一、I2C通信简介

        IIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接
微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。
在 CPU 与被控 IC 之间、 IC 与 IC 之间进行双向传送, 高速 IIC 总线一般可达 400kbps 以上。

二、I2C物理层

有如下特点:
(1) 它是一个支持设备的总线。“总线”指多个设备共用的信号线。在一个 I2C 通讯总线中,可连
接多个 I2C 通讯设备,支持多个通讯主机及多个通讯从机。
(2) 一个 I2C 总线只使用两条总线线路,一条双向串行数据线 (SDA) ,一条串行时钟线 (SCL)。数
据线即用来表示数据,时钟线用于数据收发同步。
(3) 每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访
问。
(4) 总线通过上拉电阻接到电源。当 I2C 设备空闲时,会输出高阻态,而当所有设备都空闲,都
输出高阻态时,由上拉电阻把总线拉成高电平。
(5) 多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。
(6) 具有三种传输模式:标准模式传输速率为 100kbit/s ,快速模式为 400kbit/s ,高速模式下可达
3.4Mbit/s,但目前大多 I2C 设备尚不支持高速模式。
(7) 连接到相同总线的 IC 数量受到总线的最大电容 400pF 限制。

三、I2C协议层

 I2C协议组成

I2C协议层主要由信号起始信号,停止信号、发送一个字节、接收一个字节、发送应答位、接收应答位组成。

产生起始信号:

         SCL高电平期间,SDA从高电平切换到低电平

产生停止信号:

        SCL高电平期间,SDA从低电平切换到高电平

发送一个字节:

        发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节

接收一个字节:

        接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA

产生应答信号:

发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答

接收应答信号:

        主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA

I2C读写时序类型

指定地址写

对于指定设备(Slave Address),在指定地址下(Reg Address),写入指定数据(Data

        首先主机产生I2C起始信号,然后通过SDA发送7位从机地址和1位的写数据.等待从机产生应答信号。从机应答后,继续发送8位从机的寄存器地址,等待从机产生应答信号。从机应答后,在发送要写入寄存器的值,从机发送应答后。就可以产生起始信号。

当前地址读

对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data

        首先主机产生I2C起始信号,然后主机控制SDA发送7位从机地址和1位的读数据.然后主机把发送SDA的控制权交给从机。主机对从机发送应答后,从机接收应答后,由从机发送对应寄存器的值。然后主机接收数据,主机在发送非应答信号后。从机接收后不再发送数据,并把SDA控制权交给主机,然后由主机产生停止信号。

指定地址读

对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据

        首先主机产生I2C起始信号,然后SDA发送7位从机地址和1位的写数据.等待从机产生应答信号。从机应答后,继续发送8位从机的寄存器地址,等待从机产生应答信号。从机应答后,然后主机在产生2次起始信号,主机使用SDA发送7位从机地址和1位读数据。等待从机产生应答信号。然后主机把发送SDA的控制权交给从机。主机对从机发送应答后,从机接收应答后,由从机发送对应寄存器的值。然后主机接收数据,主机在发送非应答信号后。从机接收后不再发送数据,并把SDA控制权交给主机,然后由主机产生停止信号。

四、I2C外设简介

        STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担。STM32 的 I2C 外设可用作通讯的主机及从机,支持 100Kbit/s 和 400Kbit/s 的速率,支持 7 位、 10位设备地址,支持 DMA 数据传输,并具有数据校验功能。它的 I2C 外设还支持 SMBus2.0 协议,SMBus 协议与 I2C 类似,主要应用于笔记本电脑的电池管理中

五、I2C系统架构

第一部分:通信引脚

SDA和SCL都是I2C通信的引脚,其中的 SMBA 线用于 SMBUS 的警告信号, I2C 通讯没有使用。

第二部分:时钟控制逻辑

SCL 线的时钟信号,由 I2C 接口根据时钟控制寄存器 (CCR) 控制,控制的参数主要为时钟频率。
配置 I2C 的 CCR 寄存器可修改通讯速率相关的参数:
可选择 I2C 通讯的“标准/快速”模式,这两个模式分别 I2C 对应 100/400Kbit/s 的通讯速率。
1、在快速模式下可选择 SCL 时钟的占空比,可选 Tlow/Thigh=2 或 Tlow/Thigh=16/9 模式,我
们知道 I2C 协议在 SCL 高电平时对 SDA 信号采样, SCL 低电平时 SDA 准备下一个数据,
修改 SCL 的高低电平比会影响数据采样,但其实这两个模式的比例差别并不大,若不是要
求非常严格,这里随便选就可以了。
2、 CCR 寄存器中还有一个 12 位的配置因子 CCR,它与 I2C 外设的输入时钟源共同作用,产生
SCL 时钟, STM32 的 I2C 外设都挂载在 APB1 总线上,使用 APB1 的时钟源 PCLK1, SCL
信号线的输出时钟公式如下:

标准模式:
Thigh=CCR*TPCKL1 Tlow = CCR*TPCLK1
快速模式中 Tlow/Thigh=2 时:
Thigh = CCR*TPCKL1 Tlow = 2*CCR*TPCKL1
快速模式中 Tlow/Thigh=16/9 时:
Thigh = 9*CCR*TPCKL1 Tlow = 16*CCR*TPCKL1
例如,我们的 PCLK1=36MHz,想要配置 400Kbit/s 的速率,计算方式如下:
PCLK 时钟周期: TPCLK1 = 1/36000000
目标 SCL 时钟周期: TSCL = 1/400000
SCL 时钟周期内的高电平时间: THIGH = TSCL/3
SCL 时钟周期内的低电平时间: TLOW = 2*TSCL/3
计算 CCR 的值: CCR = THIGH/TPCLK1 = 30
计算结果得出 CCR 为 30,向该寄存器位写入此值则可以控制 IIC 的通讯速率为 400KHz,其实即
使配置出来的 SCL 时钟不完全等于标准的 400KHz, IIC 通讯的正确性也不会受到影响,因为所
有数据通讯都是由 SCL 协调的,只要它的时钟频率不远高于标准即可。
 

第三部分:数据控制逻辑

I2C 的 SDA 信号主要连接到数据移位寄存器上,数据移位寄存器的数据来源及目标是数据寄存
器 (DR)、地址寄存器 (OAR)、 PEC 寄存器以及 SDA 数据线。当向外发送数据的时候,数据移位
寄存器以“数据寄存器”为数据源,把数据一位一位地通过 SDA 信号线发送出去;当从外部接收
数据的时候,数据移位寄存器把 SDA 信号线采样到的数据一位一位地存储到“数据寄存器”中。
若使能了数据校验,接收到的数据会经过 PCE 计算器运算,运算结果存储在“PEC 寄存器”中。
当 STM32 的 I2C 工作在从机模式的时候,接收到设备地址信号时,数据移位寄存器会把接收到
的地址与 STM32 的自身的“I2C 地址寄存器”的值作比较,以便响应主机的寻址。 STM32 的自
身 I2C 地址可通过修改“自身地址寄存器”修改,支持同时使用两个 I2C 设备地址,两个地址分
别存储在 OAR1 和 OAR2 中。

第四部分:整体控制逻辑

整体控制逻辑负责协调整个 I2C 外设,控制逻辑的工作模式根据我们配置的“控制寄存器
(CR1/CR2)”的参数而改变。在外设工作时,控制逻辑会根据外设的工作状态修改“状态寄存
器 (SR1 和 SR2)”,我们只要读取这些寄存器相关的寄存器位,就可以了解 I2C 的工作状态。除
此之外,控制逻辑还根据要求,负责控制产生 I2C 中断信号、 DMA 请求及各种 I2C 的通讯信号
(起始、停止、响应信号等)

六、AT24C02简介

        AT24C02是一个2K Bit的串行EEPROM存储器(掉电不丢失),内部含有256个字节。在24C02里面有一个8字节的页写缓冲器。A0-A2引脚为芯片地址,用于多器件工作模式;SDA、SCL分别为IIC通信的数据线和时钟线;WP为写保护引脚,当该引脚接 GND 时,允许正常的读/写操作。当该引脚接 VCC 时,芯片启动写保护功能;AT24C02的高4位是固定的,为1010b,低3位则由A0/A1/A2信号线的电平决定。在使用I2C对AT24C02进行读写操作时,需要加入5MS延时确保读取数据不出错。

七、硬件I2C读写AT24C02

主发送器流程

EV5事件:表示起始信号已经发送;

EV6事件:地址已经发送

EV8事件:发送数据寄存器为空

EV8_2事件:通讯结束

主接收器流程

EV5事件:表示起始信号已经发送;

EV6事件:地址已经发送

EV7事件:接收数据寄存器非空

EV7_2事件:通讯结束

在发送和接收过程中,有的事件不只是标志了我们上面提到的状态位,还可能同时标志主机状态
之类的状态位,而且读了之后还需要清除标志位,比较复杂。我们可使用 STM32 标准库函数来
直接检测这些事件的复合标志,降低编程难度

代码部分

硬件I2C头文件
#ifndef __I2C_EE_H
#define __I2C_EE_H
//RCC
#define     RCC_I2C_CLK    RCC_APB1Periph_I2C1
#define     RCC_GPIO_CLK   RCC_APB2Periph_GPIOB
//GPIO 
#define     IC2_GPIO_X     GPIOB
#define     I2C_SCL_PIN    GPIO_Pin_6
#define     I2C_SDA_PIN    GPIO_Pin_7
//I2C
#define     I2CX           I2C1
#define     I2C_7_AddR     0x35 
#define     I2C_SPEND      400000

#define     EEPROM_Write_Addr    0xA0 
#define     EEPROM_Read_Addr     0xA1 

void I2C_EE_Init(void);

void I2C_EE_ByteWrite(uint8_t Addr,uint8_t Date);

void I2C_EE_Read(uint8_t Addr,uint8_t* date,uint8_t lenght);

void wait(void);

void I2C_EE_8ByteWrite(uint8_t Addr,uint8_t *Date,uint8_t lenght);


#endif
硬件I2C源文件
#include "stm32f10x.h"                 
#include "i2c_ee.h"  

void I2C_EE_Init(void)
{
   //RCC
   RCC_APB1PeriphClockCmd(RCC_I2C_CLK,ENABLE);
   RCC_APB2PeriphClockCmd(RCC_GPIO_CLK,ENABLE);
   //GPIO
   GPIO_InitTypeDef GPIO_InitStructure;
   GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_OD;//选择工作模式为开漏输出模式
   GPIO_InitStructure.GPIO_Pin=I2C_SCL_PIN;//SCL引脚
   GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//配置工作频率
   GPIO_Init(IC2_GPIO_X,&GPIO_InitStructure);//初始化结构体
   
   GPIO_InitStructure.GPIO_Pin=I2C_SDA_PIN;//SDA引脚
   GPIO_Init(IC2_GPIO_X,&GPIO_InitStructure);
   
   //I2C
   I2C_InitTypeDef I2C_InitStructure;
   
   I2C_InitStructure.I2C_OwnAddress1=I2C_7_AddR;//STM32的I2C地址
   I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit; //确认地址位数
   I2C_InitStructure.I2C_ClockSpeed=I2C_SPEND;//I2C时钟频率
   I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2;//快速模式占空比
   I2C_InitStructure.I2C_Ack=I2C_Ack_Enable;//是否启用应答信号
   I2C_InitStructure.I2C_Mode=I2C_Mode_I2C;//指定I2C模式
   I2C_Init(I2CX,&I2C_InitStructure);
   
   I2C_Cmd(I2CX,ENABLE);//启动I2C
   
}
//发送一个字节
void I2C_EE_ByteWrite(uint8_t Addr,uint8_t Date)
{
   //产生I2C起始信号
   I2C_GenerateSTART(I2CX,ENABLE);
   
   //检测EV5事件(起始信号是否发送结束)
   while(I2C_CheckEvent(I2CX,I2C_EVENT_MASTER_MODE_SELECT )==ERROR);
   
   //发送7位从机地址和读写方向
   I2C_Send7bitAddress(I2CX,EEPROM_Write_Addr,I2C_Direction_Transmitter);

   //检测EV6事件(地址是否发送出去)
   while(I2C_CheckEvent(I2CX,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
  
   //发送寄存器地址
   I2C_SendData(I2CX,Addr);
   
    //检测EV8事件(TX数据寄存器是否为空)
   while(I2C_CheckEvent(I2CX,I2C_EVENT_MASTER_BYTE_TRANSMITTING)==ERROR);

   //在对应的寄存器中写入值
   I2C_SendData(I2CX,Date);
    //检测EV8_2事件(字节发送结束)
   while(I2C_CheckEvent(I2CX,I2C_EVENT_MASTER_BYTE_TRANSMITTED)==ERROR);

   //产生结束信号
   I2C_GenerateSTOP(I2CX,ENABLE);
}
//接收多个字节
void I2C_EE_Read(uint8_t Addr,uint8_t* date,uint8_t lenght)
{
   //产生I2C起始信号
   I2C_GenerateSTART(I2CX,ENABLE);
   
   //检测EV5事件(起始信号是否发送结束)
   while(I2C_CheckEvent(I2CX,I2C_EVENT_MASTER_MODE_SELECT )==ERROR);
   
   //发送7位从机地址和读写方向
   I2C_Send7bitAddress(I2CX,EEPROM_Write_Addr,I2C_Direction_Transmitter);

   //检测EV6事件(地址是否发送出去)
   while(I2C_CheckEvent(I2CX,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
  
   //发送寄存器地址
   I2C_SendData(I2CX,Addr);
   
    //检测EV8事件(TX数据寄存器是否为空)
   while(I2C_CheckEvent(I2CX,I2C_EVENT_MASTER_BYTE_TRANSMITTING)==ERROR);

   //***第2次起始信号***
   
     //产生I2C起始信号
   I2C_GenerateSTART(I2CX,ENABLE);
   //检测EV5事件(起始信号是否发送结束)
   while(I2C_CheckEvent(I2CX,I2C_EVENT_MASTER_MODE_SELECT )==ERROR);
   //发送7位从机地址和读写方向
   I2C_Send7bitAddress(I2CX,EEPROM_Read_Addr,I2C_Direction_Receiver);
    //检测EV6事件(地址是否发送出去)
   while(I2C_CheckEvent(I2CX,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)==ERROR);


   while(lenght)
   {
         //如果当长度只有1个就产生非应答信号
        if(lenght==1)
        {
         I2C_AcknowledgeConfig(I2CX,DISABLE);
        }
     
       //检测EV7事件(RX数据寄存器是否为空)
       while(I2C_CheckEvent(I2CX,I2C_EVENT_MASTER_BYTE_RECEIVED)==ERROR);
       //接收寄存器的数据
       *date=I2C_ReceiveData(I2CX);
        date++;//地址要递增
        lenght--;//不断循环读取寄存器的数据
   }
 
    //产生结束信号
   I2C_GenerateSTOP(I2CX,ENABLE);
   //默认开启应答信号
   I2C_AcknowledgeConfig(I2CX,ENABLE);
}
//等待函数
void wait(void)
{
   do
   {
      //产生I2C起始信号
      I2C_GenerateSTART(I2CX,ENABLE);
      
      //检测EV5事件(起始信号是否发送结束)
      while(I2C_GetFlagStatus(I2CX,I2C_FLAG_SB)==RESET);
      
      //发送7位从机地址和读写方向
      I2C_Send7bitAddress(I2CX,EEPROM_Write_Addr,I2C_Direction_Transmitter);

      
   } //检测EV6事件(地址是否发送出去)
   while(I2C_GetFlagStatus(I2CX,I2C_FLAG_ADDR)==RESET);
   
     //产生结束信号
   I2C_GenerateSTOP(I2CX,ENABLE);
}

//发送多字节数据
void I2C_EE_8ByteWrite(uint8_t Addr,uint8_t *Date,uint8_t lenght)
{
   //产生I2C起始信号
   I2C_GenerateSTART(I2CX,ENABLE);
   
   //检测EV5事件(起始信号是否发送结束)
   while(I2C_CheckEvent(I2CX,I2C_EVENT_MASTER_MODE_SELECT )==ERROR);
   
   //发送7位从机地址和读写方向
   I2C_Send7bitAddress(I2CX,EEPROM_Write_Addr,I2C_Direction_Transmitter);

   //检测EV6事件(地址是否发送出去)
   while(I2C_CheckEvent(I2CX,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
   
  //发送寄存器地址
   I2C_SendData(I2CX,Addr);
   
   //检测EV8事件(TX数据寄存器是否为空)
   while(I2C_CheckEvent(I2CX,I2C_EVENT_MASTER_BYTE_TRANSMITTING)==ERROR);

   
   while(lenght)
   {
      //发送寄存器值
     I2C_SendData(I2CX,*Date);
      //检测EV8_2事件(字节发送结束)
   while(I2C_CheckEvent(I2CX,I2C_EVENT_MASTER_BYTE_TRANSMITTED)==ERROR);
     Date++;   
     lenght--;      
   }
   
   //产生结束信号
   I2C_GenerateSTOP(I2CX,ENABLE);
}
mian函数
#include "stm32f10x.h"                  // Device header
#include "led.h"   
#include "serial.h"  
#include "i2c_ee.h" 

uint8_t RxDate[10];
uint8_t TxDate[8]={1,2,3,4,5,6,7,8};

int main(void)
{
    uint8_t i;
    I2C_EE_Init();
    Serial_Init();
    printf("STM32战舰板IIC通信测试\r\n");
	
   

   I2C_EE_8ByteWrite(0,TxDate,8);
   wait();
      I2C_EE_ByteWrite(8,11);
    wait();
	 I2C_EE_ByteWrite(9,22);
    wait();
	I2C_EE_Read(0,RxDate,10);
  	  for(i=0;i<10;i++)
   {
   printf(" %d ",RxDate[i]);
   }

   while(1)
	{
     
	}
}

八、软件I2C读写AT24C02

软件I2C头文件
#ifndef __IIC_H
#define __IIC_H

#define  RCC_GPIO_IIC_CLK         RCC_APB2Periph_GPIOB
#define  GPIO_X                   GPIOB
#define  IIC_SCL_PIN              GPIO_Pin_6
#define  IIC_SDA_PIN              GPIO_Pin_7

void SoftwareIIC_Init(void);


void IIC_Start(void);


void IIC_Stop(void);

void IIC_SendByte(uint8_t byte);


uint8_t IIC_ReceiveByte(void);


void IIC_SendACK(uint8_t ack);

uint8_t IIC_ReceiveACK(void);

#endif
软件I2C源文件
#include "stm32f10x.h"                 
#include "IIC.h" 
#include "delay.h" 

void SCL_W(uint8_t BitVal)//SCL时钟线写入
{
  GPIO_WriteBit(GPIO_X,IIC_SCL_PIN, (BitAction) BitVal);
   Delay_us(10);
}

void SDA_W(uint8_t BitVal)//SDA数据线写入
{
  GPIO_WriteBit(GPIO_X,IIC_SDA_PIN, (BitAction) BitVal);
   Delay_us(10);
}

uint8_t SDA_R(void)//读取SDA
{
   uint8_t num;
   num=GPIO_ReadInputDataBit(GPIO_X,IIC_SDA_PIN);
   Delay_us(10);
   return num;   
}

void SoftwareIIC_Init(void)//初始化模拟IC2的GPIO
{
   RCC_APB2PeriphClockCmd(RCC_GPIO_IIC_CLK,ENABLE);
   
   GPIO_InitTypeDef GPIO_InitStructure;
   GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;//选择工作模式为开漏输出模式
   GPIO_InitStructure.GPIO_Pin=IIC_SCL_PIN | IIC_SDA_PIN;//选择对应的引脚
   GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//配置工作频率
   GPIO_Init(GPIO_X,&GPIO_InitStructure);//初始化结构体
   
   GPIO_SetBits(GPIO_X,IIC_SCL_PIN | IIC_SDA_PIN); 
}
//产生I2C的起始信号
void IIC_Start(void)
{
  SDA_W(1);
  SCL_W(1);
  SDA_W(0);
  SCL_W(0); 
}
//产生I2C的停止信号
void IIC_Stop(void)
{
  SDA_W(0);
  SCL_W(1);
  SDA_W(1); 
}
//发送一个字节的数据
void IIC_SendByte(uint8_t byte)
{
   uint8_t i;
   for(i=0;i<8;i++)
   {
    SDA_W(byte &(0x80>>i));//从高位依次发送数据
    SCL_W(1);//释放SCL。从机读取数据
    SCL_W(0);//进入下一个时序
   }
}
//接收一个字节的数据
uint8_t IIC_ReceiveByte(void)
{
   uint8_t i,byte=0x00;
   SDA_W(1);//主机把控制权转交给从机
   for(i=0;i<8;i++)
   {
     SCL_W(1); //主机读取数据
      if(SDA_R()==1){byte |= (0x80>>i);}//从高位接收数据
     SCL_W(0); //进入下一个时序
   }
   return byte;
}
//发送ACK应答信号
void IIC_SendACK(uint8_t ack)
{
  SDA_W(ack);//主机发送应答
  SCL_W(1);//从机接收应答
  SCL_W(0);//进入下一个时序
}
//接收ACK应答信号
uint8_t IIC_ReceiveACK(void)
{
   uint8_t ack;
   SDA_W(1);//从机获得SDA控制权
   SCL_W(1);//主机读取数据
   ack=SDA_R();
   SCL_W(0);//进入下一个时序
   return ack;
}
读写AT24C02头文件
#ifndef __AT24C02_H
#define __AT24C02_H

void AT24C02_Init(void);


void Write_AT24C02(uint8_t Addr,uint8_t date);


uint8_t Read_AT24C02(uint8_t Addr);



void Write8byte_AT24C02(uint8_t Addr,uint8_t* date,uint8_t lenght);


void Read8Byte_AT24C02(uint8_t Addr,uint8_t *date,uint8_t lenght);

#endif
读写AT24C02源文件
#include "stm32f10x.h"                  
#include "iic.h"  
#include "delay.h"

#define  EEPROM   0xA0


void AT24C02_Init(void)
{
  SoftwareIIC_Init();
}

void Write_AT24C02(uint8_t Addr,uint8_t date)
{
  IIC_Start();//产生起始信号
  IIC_SendByte(EEPROM);//指定地址写
  IIC_ReceiveACK();   //接收应答信号
  IIC_SendByte(Addr); //发送从机的寄存器地址
  IIC_ReceiveACK();   //接收应答信号
  IIC_SendByte(date); //在对应的寄存器写入数据
  IIC_ReceiveACK();   //接收应答信号
  IIC_Stop();         //产生停止信号
}

uint8_t Read_AT24C02(uint8_t Addr)
{
   uint8_t date;
  IIC_Start();           //产生起始信号
  IIC_SendByte(EEPROM);//产生起始信号
  IIC_ReceiveACK();   //接收应答信号
  IIC_SendByte(Addr); //发送从机的寄存器地址
  IIC_ReceiveACK();   //接收应答信号
     
  IIC_Start();               //产生2次起始信号
  IIC_SendByte(EEPROM | 0x01);//指定地址读
  IIC_ReceiveACK();         //接收应答信号
   
  date=IIC_ReceiveByte();
  IIC_SendACK(1);       //产生非应答信号
  IIC_Stop();          //产生停止信号
   return date;
   
}

void Write8byte_AT24C02(uint8_t Addr,uint8_t* date,uint8_t lenght)
{
    while(lenght)
    {
     Write_AT24C02(Addr,*date);
     Addr++;
     lenght--;
    }       
}


void Read8Byte_AT24C02(uint8_t Addr,uint8_t *date,uint8_t lenght)
{
  while(lenght--)
  {
  *date++=Read_AT24C02(Addr);
  }
}
main函数
#include "stm32f10x.h"                  // Device header 
#include "serial.h"  
#include "AT24C02.h" 
#include "delay.h" 

uint8_t TxDate[8]={11,22,33,44,55,66,77,88};
uint8_t RxDate[8];

int main(void)
{
   uint8_t date=0;
   uint8_t i=0;
   AT24C02_Init();
   Serial_Init();
   printf("STM32战舰板串口通信测试\r\n");
    
   Write_AT24C02(0,123);
   Delay_ms(5);
   date=Read_AT24C02(0);
   Delay_ms(5);
   printf("读取的AT24C02第0个寄存器的值为:%d",date);
    
     for(i=0;i<8;i++)
   {
   Write8byte_AT24C02(i,TxDate+i,8);
    Delay_ms(5);
   }

     for(i=0;i<8;i++)
   {
    Read8Byte_AT24C02(i,RxDate+i,8);
    
    Delay_ms(5);
   }
   
   for(i=0;i<8;i++)
   {
    printf("读取的AT24C02第i个寄存器的值为:%d\r\n",RxDate[i]);
   }
   
    while(1)
	{
     
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值