I2C_EEPROM

一、编程要点

1、I2C相关GPIO以及外设使能

2、初始化I2C结构体(模式、地址、速率等参数)

3、编写I2C读写函数

4、对EEPROM进行读写

二、结构体&库函数

1、I2C初始化结构 ( I2C_InitTypeDef 

typedef struct
{
  uint32_t I2C_ClockSpeed;          /*!< I2C通讯速率 不高于400 000 */

  uint16_t I2C_Mode;                /*!< 模式 I2C and  */

  uint16_t I2C_DutyCycle;           /*!<设置占空比 2   16/9 */

  uint16_t I2C_OwnAddress1;         /*!< 设置STM32自身地址  在总线上唯一即可*/

  uint16_t I2C_Ack;                 /*!<产生应答信号 */

  uint16_t I2C_AcknowledgedAddress; /*!< 7位地址模式 */

}I2C_InitTypeDef;

2、起始 停止 信号产生函数

I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState)
I2C_GenerateSTART(EEPROM_I2C,ENABLE);
@brief 产生起始信号
@param1:使能或使能

I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState)
I2C_GenerateSTOP(EEPROM_I2C,ENABLE);	
@brief 产生停止信号
@param1:使能或使能

3、标志位检查函数

I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
@brief 检查I2C相应标志位
@param1:i2c端口号 
@param2:要检查的相应标志位(EV5  EV6 等)
4、广播设备地址函数
I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction)
I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);
@brief 广播要通讯的设备地址(7位)
@param1:i2c端口号 
@param2:设备地址
@param2:读写方向

5、发送 读取数据函数

I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data)
I2C_SendData (EEPROM_I2C,data);
@brief 向数据缓存寄存器发送数据
@param1:i2c端口号 
@param2:要发送的数据(8位)

uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx)
data = I2C_ReceiveData(EEPROM_I2C);
@brief 从数据缓存寄存器读取数据
@param1:i2c端口号 
@retval:读取到的数据

6、产生应答信号

I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState)
@brief 产生应答或不产生应答信号
@param1:i2c端口号 
@retval:使能或失能  (应答  非应答)

7、判断EEPROM内部时序完成函数

void EE_Await(void)
{
	do
	{
		I2C_GenerateSTART(I2C1,ENABLE);		//发送起始信号
		while((I2C_GetFlagStatus(I2C1, I2C_FLAG_SB))==RESET);	//检测EV5时间并清除标志

		
		I2C_Send7bitAddress(I2C1,0XA0,I2C_Direction_Transmitter);//广播要发送的设备地址
	}
	while((I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR))==RESET);          //检测EV6时间并清除标志
	I2C_GenerateSTOP(I2C1,ENABLE);					 //产生结束信号
}

三、I2C通讯时序

发送数据时序:
S ->      ->  EEPROM地址 ->        ->  Addr  ->        ->  data  ->      ->   data n  ->    data(p) ->      ->p
    EV5                    EV6                 EV8                  EV8                 EV8           EV8_2
读数据时序:
S ->      ->  EEPROM地址 ->        ->  Addr  ->        ->
    EV5                    EV6                 EV8
S ->      ->  EEPROM地址(读方向)  ->               (判断是否最后一个方向)                ->read()->p
    EV5                               EV6(读方向)       (是则使能应答)  EV7(有新数据到来)     

四、程序源码

1、eeprom.c文件

#include "eeprom.h"


void I2C_EE_config(void)	
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	I2C_InitTypeDef I2C_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);	//打开GPIO时钟
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;						//选择SCL线
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;	      //开漏输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;			//输出速率
	GPIO_Init(GPIOB,&GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;						//选择SDA线
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;	      //开漏输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;			//输出速率
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
	I2C_InitStructure.I2C_ClockSpeed = 400000;
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_OwnAddress1 = 0x5f;
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_Init(I2C1, &I2C_InitStructure);

	I2C_Cmd(I2C1,ENABLE);

}

void I2C_WriteByte(uint8_t Addr,uint8_t *pBuffer,uint8_t num)
{
	//uint32_t i=0x1000;	
	//延时等待时间
	I2C_GenerateSTART(I2C1,ENABLE);						//发送起始信号
	
	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)== ERROR);		//检测EV5时间并清除标志
	
	I2C_Send7bitAddress(I2C1,0XA0,I2C_Direction_Transmitter);			//广播要发送的设备地址
	

	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)== ERROR);//检测EV6时间并清除标志


	I2C_SendData(I2C1,Addr);							//发送写入设备内存地址

	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)== ERROR);	//检测EV8时间并清除标志

	
	while(num)
	{
		num--;
		I2C_SendData(I2C1,*pBuffer);					//发送写入数据
		while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)== ERROR);	//检测EV8时间并清除标志

		pBuffer++;
	
	}
	
	

	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)== ERROR);		//检测EV8-2时间并清除标志

	I2C_GenerateSTOP(I2C1,ENABLE);						//产生结束信号
	
	
}


void I2C_ReadByte(u8 Addr,uint8_t *data,uint8_t num)
{	
	
	I2C_GenerateSTART(I2C1,ENABLE);						//发送起始信号
	
	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)== ERROR);	//检测EV5时间并清除标志
	
	I2C_Send7bitAddress(I2C1,0XA0,I2C_Direction_Transmitter);		//广播要发送的设备地址
	

	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)== ERROR);//检测EV6时间并清除标志


	I2C_SendData(I2C1,Addr);							//发送写入设备内存地址

	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)== ERROR);	//检测EV8时间并清除标志


	I2C_GenerateSTART(I2C1,ENABLE);						//第二次发送起始信号
	
	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)== ERROR);		//检测EV5时间并清除标志
	
	I2C_Send7bitAddress(I2C1,0XA0,I2C_Direction_Receiver);				//广播要发送的设备地址
	

	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)== ERROR);    //检测EV6时间并清除标志
	
	while(num)
	{
		if(num==1)I2C_AcknowledgeConfig(I2C1,DISABLE);
		
		while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_RECEIVED ) == ERROR); //检测到EV7事件 表示有新的数据到来

		*data=I2C_ReceiveData(I2C1);
		
		data++;
		num--;
	}

	
	//数据传输完成
	I2C_GenerateSTOP(EEPROM_I2C,ENABLE);	
	
	//重新配置ACK使能,以便下次通讯
	I2C_AcknowledgeConfig (EEPROM_I2C,ENABLE);
}

void EE_Await(void)
{
	do
	{
		I2C_GenerateSTART(I2C1,ENABLE);						//发送起始信号
		while((I2C_GetFlagStatus(I2C1, I2C_FLAG_SB))==RESET);			//检测EV5时间并清除标志

		
		I2C_Send7bitAddress(I2C1,0XA0,I2C_Direction_Transmitter);		//广播要发送的设备地址
	}
	while((I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR))==RESET); //检测EV6时间并清除标志
	I2C_GenerateSTOP(I2C1,ENABLE);				 //产生结束信号
}

2、eeprom.h 文件

#ifndef __EEPROM_H
#define __EEPROM_H

#include "stm32f10x.h"

#define EEPROM_I2C    I2C1

void I2C_EE_config(void);
void I2C_WriteByte(uint8_t Buffer,uint8_t Addr);
void I2C_ReadByte(u8 Addr,uint8_t *data,uint8_t num);
void EE_Await(void);

#endif		//__EEPROM_H
3、main.c 文件
#include "stm32f10x.h"   
#include "bsp_led.h"
#include "usart.h"
#include "eeprom.h"

#define GPIOB_ODR_Addr      (GPIOB_BASE+0X0C)
#define PBout(n)   *(unsigned int *)((GPIOB_ODR_Addr & 0xF0000000)+0x02000000+((GPIOB_ODR_Addr&0x00FFFFFF)<<5)+(n<<2))

uint8_t ReadData[10]={0};
uint8_t writeData[8]={0,1,2,3,4,5,6,7};

int main(void)
{	
    u8 i;
    LED_GPIO_Config();
    PBout(0)=1;
    USART_config();
    I2C_EE_config();    

    I2C_WriteByte(8,writeData,8);	//数据  地址  数量

    EE_Await();
    I2C_ReadByte(8,ReadData,8);	//地址  数据数量

    for(i=0;i<8;i++)                //循环通过串口发送读取到的数据
    {
        printf("%2d",ReadData[i]);
        PBout(0)=0;
    }
  while(1);
}



 


猜你喜欢

转载自blog.csdn.net/qq_41985317/article/details/80656172
今日推荐