I2C—读写EEPROM学习笔记之代码详解-bytewrite/ramdomread

bsp_i2c.h

#ifndef __BSP_I2C_H
#define	__BSP_I2C_H


#include "stm32f10x.h"

//EEPROM 设备地址(8位)
#define EEPROM_ADDR   0xA0

/** 
* IIC EERPOM的引脚定义
*
*/
#define STM32_I2C_OWN_ADDR            0x5f 

	
// IIC
#define  EEPROM_I2C                   I2C1                   //I2C1
#define  EEPROM_I2C_CLK               RCC_APB1Periph_I2C1    //I2C时钟
#define  EEPROM_I2C_APBxClkCmd        RCC_APB1PeriphClockCmd //使能I2C时钟
#define  EEPROM_I2C_BAUDRATE          400000                 //波特率

//IIC GPIO 引脚宏定义
#define  EEPROM_I2C_SCL_GPIO_CLK      (RCC_APB2Periph_GPIOB) //GPIO时钟
#define  EEPROM_I2C_SDA_GPIO_CLK			(RCC_APB2Periph_GPIOB) //GPIO时钟

#define  EEPROM_I2C_GPIO_APBxClkCmd   RCC_APB2PeriphClockCmd //使能GPIO时钟
    
#define  EEPROM_I2C_SCL_GPIO_PORT     GPIOB  
#define  EEPROM_I2C_SCL_GPIO_PIN      GPIO_Pin_6

#define  EEPROM_I2C_SDA_GPIO_PORT     GPIOB
#define  EEPROM_I2C_SDA_GPIO_PIN      GPIO_Pin_7


void I2C_EE_Config(void);
void EEPROM_Byte_Write(uint8_t addr,uint8_t data);
void EEPROM_Read(uint8_t addr,uint8_t *data,uint8_t numByteToRead);
void EEPROM_Page_Write(uint8_t addr,uint8_t *data,uint8_t numByteToWrite);
void EEPROM_WaitForWriteEnd(void);


#endif /* __BSP_I2C_H */

bsp_i2c.c

#include "bsp_i2c.h"

 /**
  * @brief  IIC EEPROM  配置,工作参数配置
  * @param  无
  * @retval 无
  */
void I2C_EE_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	I2C_InitTypeDef  I2C_InitStructure; 

	// 打开IIC GPIO的时钟 SCL|SDA
	EEPROM_I2C_GPIO_APBxClkCmd(EEPROM_I2C_SCL_GPIO_CLK|EEPROM_I2C_SDA_GPIO_CLK, ENABLE);
	
	// 打开IIC 外设的时钟
	EEPROM_I2C_APBxClkCmd(EEPROM_I2C_CLK, ENABLE);

	// 将IIC SCL的GPIO配置为开漏复用模式
	GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SCL_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(EEPROM_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
	
  //这里只需要将不一样的内容赋值就可以了,结构体内内容不变
	
  // 将I2C SDA的GPIO配置为开漏复用模式
	GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SDA_GPIO_PIN;
	GPIO_Init(EEPROM_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
	
	// 配置I2C的工作参数
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable  ;                             //使能应答
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit ;//使用7位地址模式
	I2C_InitStructure.I2C_ClockSpeed = EEPROM_I2C_BAUDRATE;                   //配置SCL时钟频率(波特率)
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2 ;                       // 16:9/2:1
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C ;                               //I2C模式
	I2C_InitStructure.I2C_OwnAddress1 = STM32_I2C_OWN_ADDR;                   //这是STM32 IIC自身设备地址,只要是总线上唯一即可
	
	I2C_Init(EEPROM_I2C,&I2C_InitStructure);                                  //结构体成员赋值进去
	
	// 使能I2C
	I2C_Cmd (EEPROM_I2C, ENABLE);	    
}


//向EEPROM写入一个字节

void EEPROM_Byte_Write(uint8_t addr,uint8_t data)
{
	//产生起始信号
	I2C_GenerateSTART(EEPROM_I2C,ENABLE);
	//SB=1,起始信号发送成功
	while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	
	//EV5事件被检测到,发送设备地址
	I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);
	
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) == ERROR);

	//EV6事件被检测到,发送要操作的存储单元地址
	I2C_SendData (EEPROM_I2C,addr);
	
	while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING ) == ERROR);

  //EV8事件被检测到,发送要存储的数据
	I2C_SendData (EEPROM_I2C,data);
	
	while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED ) == ERROR);
	
	//EV8_2事件被检测到,数据传输完成
	I2C_GenerateSTOP(EEPROM_I2C,ENABLE);	

}



//向EEPROM写入多个字节(页写入),每次写入不能超过8个字节

void EEPROM_Page_Write(uint8_t addr,uint8_t *data,uint8_t numByteToWrite)
{
	//产生起始信号
	I2C_GenerateSTART(EEPROM_I2C,ENABLE);
	
	while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	
	//EV5事件被检测到,发送设备地址,选择方向transmitter
	I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);
	
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) == ERROR);

	//EV6事件被检测到,发送要操作的存储单元地址
	I2C_SendData (EEPROM_I2C,addr);
	
	while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING ) == ERROR);

	
	while(numByteToWrite)
	{
		//EV8事件被检测到,发送要存储的数据
		I2C_SendData (EEPROM_I2C,*data);
		
		while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED ) == ERROR);
		
		data++;
		numByteToWrite--;
			
	}
	//数据传输完成
	I2C_GenerateSTOP(EEPROM_I2C,ENABLE);	

}



//从EEPROM读取数据

void EEPROM_Read(uint8_t addr,uint8_t *data,uint8_t numByteToRead)
{
	//产生起始信号
	I2C_GenerateSTART(EEPROM_I2C,ENABLE);
	
	while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	
	//EV5事件被检测到,发送设备地址
	I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);
	
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) == ERROR);

	//EV6事件被检测到,发送要操作的存储单元地址
	I2C_SendData (EEPROM_I2C,addr);
	
	while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING ) == ERROR);

	//EV8事件被检测到
	//第二次起始信号
	//产生起始信号
	I2C_GenerateSTART(EEPROM_I2C,ENABLE);
	
	while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	
	//EV5事件被检测到,发送设备地址,选择方向receiver
	I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Receiver);
	
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) == ERROR);

  //EV6事件被检测到
	while(numByteToRead)
	{
		if(numByteToRead == 1)
		{		
			//如果为最后一个字节
			I2C_AcknowledgeConfig (EEPROM_I2C,DISABLE);//产生notack信号
		}		
		
	
		while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_RECEIVED ) == ERROR);

		//EV7事件被检测到,即数据寄存器有新的有效数据	
		*data = I2C_ReceiveData(EEPROM_I2C);
		
		data++;
		
		numByteToRead--;
		
	}
	
	
	//数据传输完成
	I2C_GenerateSTOP(EEPROM_I2C,ENABLE);	
	
	//重新配置ACK使能,以便下次通讯
	I2C_AcknowledgeConfig (EEPROM_I2C,ENABLE);

}


//等待EEPROM内部时序完成
//ACKNOWLEDGE POLLING写完数据之后直接读取导致卡死
//原因是EEPROM正在把数据写入自己的存储单元,无法响应
//经过断点调试,发现卡死出现在发送完7位地址之后
//所以检测要检测到发送地址,并且EEPROM给出响应这一步
//所以要一直发送起始信号和地址,检测EEPROM是否处理完了
//相当于一直问EEPROM“您好了吗”

void EEPROM_WaitForWriteEnd(void)
{
	
	do
	{
		//产生起始信号
		I2C_GenerateSTART(EEPROM_I2C,ENABLE);
		
		//这里不能用I2C_CheckEvent这个函数
		//会有谜之错误,可能是检查过多标志位
		//这里用I2C_GetFlagStatus代替
		while(I2C_GetFlagStatus (EEPROM_I2C,I2C_FLAG_SB) == RESET);
		
		//EV5事件被检测到,发送设备地址
		I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);
	}  
	while(I2C_GetFlagStatus (EEPROM_I2C,I2C_FLAG_ADDR) == RESET );
	//EV6事件被检测到,EEPROM内部时序完成传输完成
	
	I2C_GenerateSTOP(EEPROM_I2C,ENABLE);	//结束
}

main.c

#include "stm32f10x.h"
#include "bsp_usart.h"
#include "./i2c/bsp_i2c.h"

//1.初始化IIC相关的GPIO
//2.配置IIC外设的工作模式
//3.编写IIC写入EEPROM的Byte write函数
//4.编写IIC读取EEPROM的RANDOM Read函数
//5.使用read函数及write函数进行读写校验

//6.编写page write 及seq read函数并校验(升级)


uint8_t readData[10]={0};
uint8_t writeData[8]={4,5,6,7,8,9,10,11};

int main(void)
{	
	
	uint8_t i=0;
  /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
  USART_Config();
	
	/* 发送一个字符串 */
	printf("this is a IIC test\n");
	
	//初始化IIC
	I2C_EE_Config();

	//写入一个字节
	EEPROM_Byte_Write(11,55);
	
	//等待写入操作完成
	EEPROM_WaitForWriteEnd();
	
	//写入一个字节
	EEPROM_Byte_Write(12,52);
	
	//等待写入操作完成
	EEPROM_WaitForWriteEnd();
	
	//页写入要求,首地址必须是8的倍数 
	//??什么傻子操作,脑壳疼
	//addr%8 == 0 ,即为地址对齐
	EEPROM_Page_Write(16,writeData,8);
	
	//等待写入操作完成
	EEPROM_WaitForWriteEnd();
	
	//读取数据
	EEPROM_Read(16,readData,8);
	
	
	for(i=0;i<8;i++)
	{	
		printf("%d ",readData[i]);	
	}
	printf("111111111111111111");
	
  while(1)
	{	
		
	}	
}
/*********************************************END OF FILE**********************/

大致学完了I2C发送接收流程,很繁琐,但也很有用,再巩固巩固,争取把OLED模块,超声模块啥的都玩起来。

猜你喜欢

转载自blog.csdn.net/weixin_37676403/article/details/93200567