STM32F103 EEPROM_24C02实验

实验目的

本实验向大家介绍如何使用STM32的IIC硬件接口,实现和24C02之间的双向通信,通过本实验的学习,我们将对IIC通信的过程会有一个详细的了解。

实验简介

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

使用IIC总线通信时,只需要2根通信线,一条双向串行数据线(SDA),一条串行时钟线(SCL)。每个IIC设备都有一个独立的地址,主机可以利用这个地址进行不同设备间的访问。当多主机使用总线时,IIC有一个仲裁机制,会决定由那个主机使用总线。

IIC总线协定如下:

  1. 只有在总线空闲时才允许启动数据发送。
  2. 在数据传送过程中,当时钟线为高电平时,数据线必须保持稳定状态,不允许有跳变。时钟线为高电平时,数据线的任何电平变化将被看作总线的起始或停止信号。

IIC在数据通信过程中共有3种信号,分别是起始信号,停止信号和应答信号。

**起始信号:**时钟线(SCL)保持高电平期间,数据线(SDA)电平从高到低跳变作为I2C总线的起始信号。

**停止信号:**时钟线(SCL)保持高电平期间,数据线(SDA)电平从低到高的跳变作为I2C总线的停止信号

**应答信号:**接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,则判断为受控单元出现故障。
STM32F103 EEPROM_24C02实验_第1张图片
器件简介
本实验所用IIC器件为非易失性存储器EEPROM——AT24C02,容量为256字节,可擦写100万次,掉电数据不会丢失,通常被用来保存一些用户数据。这个系列芯片容量可以达到1Mbit,即128K字节,如AT24C1024.
AT24C02的管脚配置如下,关于这个芯片详细介绍请参看数据手册:
STM32F103 EEPROM_24C02实验_第2张图片

电路设计

星光STM32F103开发板采用的EEPROM芯片为AT24C02,容量为256字节,这里我们把A0-A2均接地,也就是将AT24C02的地址设为0,写程序时要注意这点,连接到STM32的I2C2,对应管脚PB10,PB11,电路如图所示
STM32F103 EEPROM_24C02实验_第3张图片

代码

main.c

#include "MyIncludes.h"
u16 sys_cnt = 0;
void systick_isr(void)
{
	if(sys_cnt < 1000)
	{
		sys_cnt++;
	}
	else
	{
		sys_cnt = 0;
		HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_4|GPIO_PIN_5);
	}
}

u8 Wr_Buf[100];
//写缓冲器
u8 Rd_Buf[100];
//读缓冲器
int main()
{
	 u16 i;
	 System_Init();
	 LED_Init();
	 SysTick_Init(systick_isr);
	 USART1_Init(115200,NULL,NULL);
	 printf("EEPROM ReadWrite Test\n");
	 while(EEPROM_Init()!=EEPROM_OK)
	 {
		 printf("EEPROM Init ERROM\n");
	 }
	 //当EEPROM初始化未完成
	 //输出EEPROM Init ERROM
	 for(i=0; i<100; i++)
	 {
		 Wr_Buf[i] = i+1;
	 }
	 
	 EEPROM_Write(Wr_Buf,0,100);
	 EEPROM_Read(Rd_Buf,0,100);
	 
	 if(strncmp((char *)Wr_Buf,(char *)Rd_Buf,100) == 0)
	 {
		 printf("EEPROM TEST OK\n");
	 }
	 else
	 {
		 printf("EEPROM TEST ERROR");
	 }
	 
	 while(1)
	 {
		 
	 }
}

24cxx.h

#ifndef __24CXX_H_
#define __24CXX_H_

#include "stm32f1xx.h"
#include "stm32_types.h"
#include "stm32f1xx_hal.h"

#define EEPROM_MAX_TRIALS  ((uint32_t)3000)
//函数的最大试用次数(貌似未用到)
#define EEPROM_OK ((uint8_t)0)
//状态:成功
#define EEPROM_FAIL   ((uint8_t)1)
#define EEPROM_TIMEOUT  ((uint8_t)2)

#define EEPROM_I2C_ADDRESS ((uint16_t)0xA0)
//EEPROM地址 0xA0
#define AT24C01  127
#define AT24C02  255
#define AT24C04  511
#define AT24C08  1023
#define AT24C16  2047
#define AT24C32  4095
#define AT24C64  8191
#define AT24C128 16383
#define AT24C256 32767

uint8_t EEPROM_Init(void);
//EEPROM初始化

uint32_t EEPROM_Read(uint8_t* pBuffer,uint16_t ReadAddr,uint16_t NumToRead);
//指定位置读出指定个数的数据(数据数组首地址,开
//始读出的地址,要读出数据的个数);

uint32_t EEPROM_Write(uint8_t* pBuffer,uint16_t WriteAddr,uint16_t NumToWrite);
//在指定位置写入指定个数的数据,(数据数组首地址
//开始写入地址,要写入数据个数)

void EEPROM_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);
//在指定地址写入长度为Len的数据(开始写入的地址
//,数据数组首地址,要写入数据的长度)

uint32_t EEPROM_ReadLenByte(u16 ReadAddr,u8 Len);
//在指定地址读出长度为Len的数据(开始读出的地址
//要读的长度)

#endif


24cxx.c

#include "24cxx.h"
#include "iic.h"

I2C_HandleTypeDef hI2cEEpromHandler;

void EEPROM_IO_Init(void)
//EEPROM的I2c接口初始化
{
  I2C2_Init(&hI2cEEpromHandler);
}



HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress,uint16_t MemAddress,uint8_t* pBuffer,uint32_t BufferSize)
//向EEPROM写入数据(器件地址,器件寄存器地址,代写入数据,写入长度)
{
      return (I2C2_WriteMultiple(&hI2cEEpromHandler,DevAddress,MemAddress,I2C_MEMADD_SIZE_8BIT,pBuffer,BufferSize));
      //I2C写操作(I2chandler,器件地址,器件寄存器地址
      //一次发送数据大小,待写入的数据,写入长度)
}



HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress,uint16_t MemAddress,uint8_t* pBuffer,uint32_t BufferSize)
//从EEPROM读取数据(器件地址,器件寄存器地址,待
//读取数据,待读取长度)
{
    return (I2C2_ReadMultiple(&hI2cEEpromHandler,DevAddress,MemAddress,I2C_MEMADD_SIZE_8BIT,pBuffer,BufferSize));
    //I2C读操作(i2c handler,器件地址,器件寄存
    //器地址,一次发送数据大小8位,待写入数据,长度)
}


HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress,uint32_t Trials)
//检查EEPROM是否准备就绪通信(器件地址,检测最大次数)
{
      return(I2C2_IsDeviceReady(&hI2cEEpromHandler,DevAddress,Trials));
      //判断器件是否就绪(I2C Hanler,器件地址
      //检测最大次数)
}

__IO uint16_t EEPROMAddress = 0;
//EEPROMAddress 地址声明
uint8_t EEPROM_Init(void)
{
	EEPROM_IO_Init();
	//初始化I2C总线
	EEPROMAddress = EEPROM_I2C_ADDRESS;
	//EEPROMAddress = 0xA0
	if(EEPROM_IO_IsDeviceReady(EEPROMAddress,EEPROM_MAX_TRIALS) != HAL_OK)
	//检查EEPROM是否准备就绪通信
	{
		return EEPROM_FAIL;
		//返回失败
	}
	
	return EEPROM_OK;
	//返回成功
}




uint32_t EEPROM_WaitEepromStandbyState(void)
//等待EEPROM就绪
{
   if(EEPROM_IO_IsDeviceReady(EEPROMAddress,EEPROM_MAX_TRIALS) != HAL_OK)
   //检查EEPROM是否准备就绪(器件地址,检测最大次数)
	 {
      return EEPROM_TIMEOUT;
	 }
   return EEPROM_OK;
}



//实验未用到
uint8_t EEPROM_ReadOneByte(uint16_t ReadAddr)
//在AT24C02中读出指定个个数数据
{
   uint8_t ReadVal = 0;
   
   if(EEPROM_IO_ReadData(EEPROMAddress,ReadAddr,&ReadVal,1) != HAL_OK)
   //从EEPROM中读取数据(器件地址,开始读取地址,待写入的数据,写入长度)
   {
        ReadVal = 0xFF;
   }

   return ReadVal;

}




uint32_t EEPROM_Read(uint8_t* pBuffer,uint16_t ReadAddr,uint16_t NumToRead)
//EEPROM读数据  缓冲区首地址,要读的地址,要读的个数
{
    uint32_t buffersize = NumToRead;
    
    if(EEPROM_IO_ReadData(EEPROMAddress,ReadAddr,pBuffer,buffersize) != HAL_OK)
    //从EEPROM读取数据(器件地址,器件寄存器地
    //址,待读取数据,待读入长度)
		{
		  return EEPROM_FAIL;
		
		}

   return EEPROM_OK;
}




uint32_t EEPROM_WriteOneByte(uint16_t WriteAddr,uint8_t DataToWrite)
//向EEPROM写入一字节数据
//(写入的地址,待写入的数据)
{
   uint32_t status = EEPROM_OK;
   
   if(EEPROM_IO_WriteData(EEPROMAddress,WriteAddr,&DataToWrite,1) != HAL_OK)
   //向EEPROM写入数据(器件地址,器件寄存器地址,
   //代写入数据,写入长度)
	 {
      status = EEPROM_FAIL;
	 }
   
   if(EEPROM_WaitEepromStandbyState() != EEPROM_OK)
   //等待EEPROM就绪
   {
      return EEPROM_FAIL;
	 }

    return status;
 }




uint32_t EEPROM_Write(uint8_t *pBuffer,uint16_t WriteAddr,uint16_t NumToWrite)
//在EEPROM里面的指定地址开始写入指定个数的数据
//(数据数组首地址,开始写入的地址,要写入数据的个数)
{
	uint32_t status = EEPROM_OK;
	
	while(NumToWrite--)
	{
		status = EEPROM_WriteOneByte(WriteAddr,*pBuffer);
		//向EEPROM写入一字节数据
	  if(status != EEPROM_OK)
	  {
		 return status;
	  }
	  WriteAddr++;
	  //要写入地址自加
  	  pBuffer++;
  	  //缓冲地址自加
	}
	return EEPROM_OK;
}


//实验未用到
void EEPROM_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
//向EEPROM里面的指定地址开始写入长度为Len的数据
{
	 u8 t;
	for(t=0;t<Len;t++)
	{
		EEPROM_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
		//每次写入一个(开始地址,待写入的数据)
	}
}


uint32_t EEPROM_ReadLenByte(u16 ReadAddr, u8 Len)
//读取指定长度为Len的数据。
{
	u8 t;
	u32 temp=0;
	for(t=0;t<Len;t++)
	{
		temp <<= 8;
		temp += EEPROM_ReadOneByte(ReadAddr+Len-t-1);
		//读取指定个数数据(地址)
	}
	return temp;
}

实验现象

你可能感兴趣的:(星光STM32)