STM32-(20):I2C通信(实验:读写EEPROM)

上一篇:STM32-(19):I2C通信(理论基础)下一篇:STM32-(21):NVIC中断

硬件电路连接

底板上的 I2C 接口
在这里插入图片描述
在这里插入图片描述
A0、A1是用来确定器件的地址的。

排针上的引脚图:
在这里插入图片描述
核心板上的引脚图:
在这里插入图片描述

通过I2C总线实现对EEPROM的读写操作的准备工作:
1、掌握芯片(目标对象)特性,才能对其正确的读和写。
2、掌握 I2C 通信,读写过程需要用到。
3、Cortex的一些操作,编程方法。

实验内容:通过I2C总线实现对EEPROM的读写操作

main.c

#include"stm32f10x_lib.h"
#include"IIC.h"

/*------------函数的声明---------------*/
void Delay_MS(u16 dly);
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);

/**********************************TEST*******************************/
int main(void)
{
	#ifdef	DEBUG
		debug();
	#endif
	u8 Tab[]="hello";
	u8 ReadTab[5];
	RCC_Configuration();
	I2C_Configuration();
	NVIC_Configuration(); //中断配置
	GPIO_Configuration();
	GPIO_SetBits(GPIOA, GPIO_Pin_3);	
	
	//这里将 Tab的5个值写入 EEPROMZ中去,然后从EEPROM中读取出来存入ReadTab 中去,
	//然后比较Tab 和 EEPROM ,若内容一致,则说明读写都成功。
	while(1)		
	{
//		 I2C_PageWrite(&Tab[0],0xA0,5);
		 I2C_BufferWrite(&Tab[0],0xA0,5);
		 Delay_MS(20);
		I2C_BufferRead(&ReadTab[0],0xA0,5);	
		Delay_MS(20);		
	}
}


/*******************************************************************************
* Function Name  : Delay_Ms
* Description    : delay 1 ms.
* Input          : dly (ms)
* Output         : None
* Return         : None
*******************************************************************************/
void Delay_MS(u16 dly)
{
	u16 i,j;
	for(i=0;i<dly;i++)
		for(j=1000;j>0;j--);
}

/*******************************************************************************
* Function Name  : RCC_Configuration
* Description    : Configures the different system clocks.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void RCC_Configuration(void)
{
	//----------使用外部RC晶振-----------
	RCC_DeInit();			//初始化为缺省值
	RCC_HSEConfig(RCC_HSE_ON);	//使能外部的高速时钟 
	while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);	//等待外部高速时钟使能就绪
	
	FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);	//Enable Prefetch Buffer
	FLASH_SetLatency(FLASH_Latency_2);		//Flash 2 wait state
	
	RCC_HCLKConfig(RCC_SYSCLK_Div1);		//HCLK = SYSCLK
	RCC_PCLK2Config(RCC_HCLK_Div1);			//PCLK2 =  HCLK
	RCC_PCLK1Config(RCC_HCLK_Div2);			//PCLK1 = HCLK/2
	RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);	//PLLCLK = 8MHZ * 9 =72MHZ
	RCC_PLLCmd(ENABLE);			//Enable PLLCLK

	while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);	//Wait till PLLCLK is ready
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);	//Select PLL as system clock
	while(RCC_GetSYSCLKSource()!=0x08);		//Wait till PLL is used as system clock source
	
	//---------打开相应外设时钟--------------------
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	//使能APB2外设的GPIOA的时钟		 
}

/*******************************************************************************
* Function Name  : GPIO_Configuration
* Description    : 初始化GPIO外设
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void GPIO_Configuration(void)
{
	GPIO_InitTypeDef	GPIO_InitStructure;		//声明一个结构体变量
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; 	//选择PA.3
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	 //管脚频率为50MHZ
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	 //输出模式为推挽输出
	GPIO_Init(GPIOA,&GPIO_InitStructure);				 //初始化GPIOA寄存器		
} 

/*******************************************************************************
* Function Name  : NVIC_Configuration
* Description    : Configures the nested vectored interrupt controller.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void NVIC_Configuration(void)
{   
//	NVIC_InitTypeDef NVIC_InitStructure;

#ifdef  VECT_TAB_RAM  
  	/* Set the Vector Table base location at 0x20000000 */ 
  	NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 
#else  /* VECT_TAB_FLASH  */
  	/* Set the Vector Table base location at 0x08000000 */ 
  	NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
#endif

}

IIC.c

/*******************************************************************
本实验使用CAT24WC16:
	CAT24WC16是CATALSYT公司生产的串行电可擦除的可编程存储器。其内部共有128页,每一页
为16字节,每一个字节8位。CAT24WC16以一个字节为一个存储单元,共有2K个存储单元。因此任一
存储单位地址为11位(A0~A11),地址范围为0x00~0x7FF(2K地址范围)。
*******************************************************************/
#include"stm32f10x_lib.h"
#include"IIC.h"

#define EEPROM_ADDRESS	0xA0
#define	I2C2_SLAVE_ADDRESS7	0xA0 
#define I2C_Speed	200000
#define I2C_PageSize	16

void I2C_Configuration(void)
{
	GPIO_InitTypeDef	GPIO_InitStructure;
	I2C_InitTypeDef 	I2C_InitStructure;

	//1、开时钟 GPIOB,I2C2
  	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
  	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);

	//2、PB10  PB11	复用开漏输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_Init(GPIOB,&GPIO_InitStructure);

	//3、I2C 配置
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;	//设置I2C为I2C模式
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;	//I2C快速模式
	I2C_InitStructure.I2C_OwnAddress1 = I2C2_SLAVE_ADDRESS7;
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;	//使能应答
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;

	//4、使能I2C模块
	I2C_Cmd(I2C2,ENABLE);
	I2C_Init(I2C2,&I2C_InitStructure);

}

void I2C2_Init(void)
{
 	I2C_Configuration();	
}
//字节写
void I2C_ByteWrite(u8 *pBuffer,u8 WriteAddr)
{	
	I2C_WaitEepromStandbyState();						    
	/* [1]Send Start Condition  发送起始信号*/
	I2C_GenerateSTART(I2C2,ENABLE);

	/* [2]Test On EV5 and clear it  起始信号已发送并清除该事件 */
	while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT));

	/* [3]Send EEPROM address for write  发送器件地址*/
 	I2C_Send7bitAddress(I2C2,EEPROM_ADDRESS,I2C_Direction_Transmitter);

	/* [4]Test on Ev6 and clear it 地址发送结束 */
	while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

	
	/* [5]Send EEPROM's internal address to  write 发送器件内部写入地址 */
	I2C_SendData(I2C2,WriteAddr);

	/* [6]Test on EV8 _1 and clear it 移位寄存器空 */
	while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));


	/* [7]Send the byte to be writeen 发送数据*/
	I2C_SendData(I2C2,*pBuffer);

	/* [8]Test on EV8 and clear it 发送缓冲区空*/
	while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));


	/* [9]Send STOP condition 发送停止信号 */
	I2C_GenerateSTOP(I2C2,ENABLE);
}
//页写	
void I2C_PageWrite(u8 *pBuffer,u8 WriteAddr,u8 NumByteToWrite)
{
	I2C_WaitEepromStandbyState();
	/*[1]Send START condition 发送起始条件*/
	I2C_GenerateSTART(I2C2,ENABLE);

	/*[2]Test on EV5 and clear it 起始信号发送是否成功*/
	while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT));

	/*[3]Send EEPROM address for write 发送器件地址*/
	//EEPROM_ADDRESS 表示 EEPROM器件的地址
	I2C_Send7bitAddress(I2C2,EEPROM_ADDRESS,I2C_Direction_Transmitter); 

	/*[4]Test on EV6 and clear it  发送器件地址是否成功*/
	while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

	/*[5]Send EEPROM'S internal address to write to 发送数据的写入首地址*/
	//WriteAddr 表示EEPROM器件内部的读写地址(器件内部的存储地址)
	I2C_SendData(I2C2,WriteAddr);
		
	/*[6]Test on EV8 and clear it  发送内部地址是否成功*/
	while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
	/*[7]Send data to Written 发送数据*/
				while(NumByteToWrite--)
				{
				 	/*Send the current byte 发送当前一个字节*/
					 	I2C_SendData(I2C2,*pBuffer);
				 	/* Point to the next byte to be written 地址++*/
						pBuffer++;
				 	/*Test on EV8 and clear it 发送缓冲区是否为空*/
					while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
				 }
	/*[8]Send STOP condition 发送停止信号*/ (发送完成之后发送停止信号)
	I2C_GenerateSTOP(I2C2,ENABLE);
}

//写数据:参数1:即将被写入的源数据;参数2:写入的目的地址;参数3:写入数据的大小;
 void I2C_BufferWrite(u8 *pBuffer,u8 WriteAddr,u16 NumByteToWrite)
 {
 	u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;

  	Addr = WriteAddr % I2C_PageSize;	//得到页地址 I2C_PageSize = 16,
  	count = I2C_PageSize - Addr;
  	NumOfPage =  NumByteToWrite / I2C_PageSize;
  	NumOfSingle = NumByteToWrite % I2C_PageSize;

	I2C_WaitEepromStandbyState();	//等待EEPROM处于空闲状态
 
  /* If WriteAddr is I2C_PageSize aligned  */
  if(Addr == 0) 
  {
    /* If NumByteToWrite < I2C_PageSize */
    if(NumOfPage == 0) 
    {
      I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle);
      I2C_WaitEepromStandbyState();
    }
    /* If NumByteToWrite > I2C_PageSize */
    else  
    {
      while(NumOfPage--)
      {
        I2C_PageWrite(pBuffer, WriteAddr, I2C_PageSize); 
    	I2C_WaitEepromStandbyState();
        WriteAddr +=  I2C_PageSize;
        pBuffer += I2C_PageSize;
      }

      if(NumOfSingle!=0)
      {
        I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle);
        I2C_WaitEepromStandbyState();
      }
    }
  }
  /* If WriteAddr is not I2C_PageSize aligned  */
  else 
  {
    /* If NumByteToWrite < I2C_PageSize */
    if(NumOfPage== 0) 
    {
      I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle);
      I2C_WaitEepromStandbyState();
    }
    /* If NumByteToWrite > I2C_PageSize */
    else
    {
      NumByteToWrite -= count;
      NumOfPage =  NumByteToWrite / I2C_PageSize;
      NumOfSingle = NumByteToWrite % I2C_PageSize;	
      
      if(count != 0)
      {  
        I2C_PageWrite(pBuffer, WriteAddr, count);
        I2C_WaitEepromStandbyState();
        WriteAddr += count;
        pBuffer += count;
      } 
      
      while(NumOfPage--)
      {
        I2C_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
        I2C_WaitEepromStandbyState();
        WriteAddr +=  I2C_PageSize;
        pBuffer += I2C_PageSize;  
      }
      if(NumOfSingle != 0)
      {
        I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle); 
        I2C_WaitEepromStandbyState();
      }
    }
  }  	
 }

void I2C_WaitEepromStandbyState(void)
{
	vu16 SR1_Tmp = 0;

  do
  {
    /* Send START condition */
    I2C_GenerateSTART(I2C2, ENABLE);
    /* Read I2C1 SR1 register */
    SR1_Tmp = I2C_ReadRegister(I2C2, I2C_Register_SR1);
    /* Send EEPROM address for write */
    I2C_Send7bitAddress(I2C2, EEPROM_ADDRESS, I2C_Direction_Transmitter);
  }while(!(I2C_ReadRegister(I2C2, I2C_Register_SR1) & 0x0002));	
  //当 EEPROM 处于非空闲状态,则一直等待,这里需要注意 I2C_Register_SR1 的寄存器 的第1位
  //为0时表示地址发送没有结束,则While的判断为真,则会一直等待。
  
  /* Clear AF flag */
  I2C_ClearFlag(I2C2, I2C_FLAG_AF);		//清除应答错误标志位
}
//读数据:参数1:读完数据存放的位置;参数2:从哪里读取数据;参数3:读取数据的大小;
void I2C_BufferRead(u8 *pBuffer,u8 ReadAddr,u16 NumByteToRead)
{
	I2C_WaitEepromStandbyState();
	/*Send START Condition 发送起始信号*/
	I2C_GenerateSTART(I2C2,ENABLE);

	/*Test on EV5 and clear it 检测起始信号是否发送成功*/
	while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT));

	/* In the case of a singel data transfer disable ACK before readint the data*/
	if(NumByteToRead==1)
	{
		I2C_AcknowledgeConfig(I2C2,DISABLE);//如果NumByteToRead则不需1字节一应答
	}
	/*Send EEPROM ADDRESS for write */
	I2C_Send7bitAddress(I2C2,EEPROM_ADDRESS,I2C_Direction_Transmitter);

	/* Test on EV6 and clear it*/
	while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

	/* Enable I2C*/
	I2C_Cmd(I2C2,ENABLE);

	/* Send EEPROM'S internal address to write to*/
	I2C_SendData(I2C2,ReadAddr);

	/*Test on EV8 and clear it*/
	while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));

	//在这之前都是告诉 EEPROM ,即将要从EERROM的某个位置读取数据
	/*Send START condition again*/
	I2C_GenerateSTART(I2C2,ENABLE);

	/*Test on EV5 and clear it*/
	while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT));

	/*Send EEPROM address for read*/
	I2C_Send7bitAddress(I2C2,EEPROM_ADDRESS,I2C_Direction_Receiver);

	/*Test on EV6 and clear it*/
	while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

    /*Read Data*/
	while(NumByteToRead)
	{
		/*Test on EV7 and clear it*/
		if(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED))
		{
			if(NumByteToRead == 2)				
			{
				/*Disable Acknowledgement*/
				I2C_AcknowledgeConfig(I2C2,DISABLE); 	//一般在最后一个字节关闭应答
			}
			if(NumByteToRead == 1) 
			{
				/*Send STOP condition */  	//最后一位要关闭应答,发送停止信号
				I2C_GenerateSTOP(I2C2,ENABLE);
			}
			/*Read a byte from the EEPROM*/
			*pBuffer = I2C_ReceiveData(I2C2);
			/*Point to the next location where the byte read will be saved*/
			pBuffer++;
			/*Decrement the read bytes counter*/
			NumByteToRead--;
		}
	}
	/*Enable Acknowledgement to be ready for anotherreception*/
   I2C_AcknowledgeConfig(I2C2,ENABLE);		//允许再次应答				
}
上一篇:STM32-(19):I2C通信(理论基础)下一篇:STM32-(21):NVIC中断
  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值