STM32硬件I2C测试EEPROM读写功能

STM32硬件I2C测试读写EEPROM

  • 一、测试环境
  • 二、程序测试
  • 1.主程序实现
  • 2.I2C1驱动
  • 3.使用逻分抓I2C数据
  • 4.测试结果
  • 三、gitee路径

  • 一、测试环境

    使用正点原子STM32F103,精英V2开发板上 I2C1(B6,B7)测试eeprom 读写数据,网上都说stm32硬件I2C有问题,不提倡使用硬件I2C。

    二、程序测试

    1.主程序实现

    main.c代码如下:

    #include "led.h"
    #include "delay.h"
    #include "key.h"
    #include "sys.h"
    #include "lcd.h"
    #include "usart.h"
    #include "i2c.h"
    
    
    uint8_t I2C_EE_Test(void);
    
    int main(void)
    {
    	delay_init();	    	 //延时函数初始化	  
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
    	uart_init(115200);	 	//串口初始化为115200
    	LED_Init();		  		//初始化与LED连接的硬件接口
    	I2C1_Init();
    
    	printf("stm32 i2c master test:\r\n");
    
    	I2C_EE_Test();
    
    	while(1)
    	{
    		LED0=!LED0;//提示系统正在运行	
    		delay_ms(300);	   
    	}
    }
    
    uint8_t I2C_EE_Test(void)
    {	
    	uint8_t ReadData[256]={0};
    	uint8_t WriteDdta[256]={0};
    	uint16_t i;
    
    	//初始化写入数组
    	for(i = 0; i < 256; i++)
    	{
    		WriteDdta[i]=i; 
    	}
    
    	//向EEPROM从地址为0开始写入256个字节的数据 
    	I2C_EE_BufferWrite(WriteDdta, 0, 256);
    	//等待EEPROM写入数据完成 
    	EEPROM_WaitForWriteEnd();	 
    	//向EEPROM从地址为0开始读出256个字节的数据
    	EEPROM_Read(ReadData, 0, 256);
    
    	for (i=0; i<256; i++)
    	{	
    		if(ReadData[i] != WriteDdta[i])
    		{
    			EEPROM_ERROR("0x%02X ", ReadData[i]);
    			EEPROM_ERROR("错误:I2C EEPROM写入与读出的数据不一致\n\r");
    			return 0;
    		}
    		
    		printf("0x%02X ", ReadData[i]);
    		if(i%16 == 15)    
    			printf("\n\r");   
    	}
    	
    	EEPROM_INFO("I2C(AT24C02)读写测试成功\n\r");
    	return 1;
    }
    
    void Delay(__IO uint32_t nCount)	 //简单的延时函数
    {
    	for(; nCount != 0; nCount--);
    }
    
    
    
    
    

    2.I2C1驱动

    i2c.c代码如下:

    #include "i2c.h"
    
    //设置等待时间
    static __IO uint32_t  I2CTimeout = I2CT_LONG_TIMEOUT;   
    
    //等待超时,打印错误信息
    static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode);
    
    void I2C1_Init(void)
    {
    	GPIO_InitTypeDef    GPIO_InitStuctrue;
    	I2C_InitTypeDef     I2C_InitStuctrue;
    
    	//开启GPIO外设时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    	//开启IIC外设时钟
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    
    	//SCL引脚-复用开漏输出
    	GPIO_InitStuctrue.GPIO_Mode = GPIO_Mode_AF_OD;
    	GPIO_InitStuctrue.GPIO_Pin = GPIO_Pin_6;
    	GPIO_InitStuctrue.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOB, &GPIO_InitStuctrue);
    
    	//SDA引脚-复用开漏输出
    	GPIO_InitStuctrue.GPIO_Mode = GPIO_Mode_AF_OD;
    	GPIO_InitStuctrue.GPIO_Pin = GPIO_Pin_7;
    	GPIO_InitStuctrue.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOB, &GPIO_InitStuctrue);
    
    	//IIC结构体成员配置
    	I2C_InitStuctrue.I2C_Ack = I2C_Ack_Enable;
    	I2C_InitStuctrue.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    	I2C_InitStuctrue.I2C_ClockSpeed = EEPROM_I2C_BAUDRATE;
    	I2C_InitStuctrue.I2C_DutyCycle = I2C_DutyCycle_2;
    	I2C_InitStuctrue.I2C_Mode = I2C_Mode_I2C;
    	I2C_InitStuctrue.I2C_OwnAddress1 = STM32_I2C_OWN_ADDR;
    	I2C_Init(I2C1, &I2C_InitStuctrue);
    	I2C_Cmd(I2C1, ENABLE);
    
    }
    
    //向EEPROM写入一个字节
    void  EEPROM_Byte_Write(uint8_t addr,uint8_t data)
    {
    	//发送起始信号
    	I2C_GenerateSTART(EEPROM_I2C,ENABLE);
    	//检测EV5事件
    	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);
    	//发送设备写地址
    	I2C_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter);
    	//检测EV6事件
    	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
    	//发送要操作设备内部的地址
    	I2C_SendData(EEPROM_I2C,addr);
    	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR);
      	I2C_SendData(EEPROM_I2C,data);
    	//检测EV8_2事件
    	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR);
    	//发送停止信号
    	I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
    	
    }
    
    //向EEPROM写入多个字节
    uint32_t  EEPROM_Page_Write(uint8_t addr,uint8_t *data,uint16_t Num_ByteToWrite)
    {
    	
    	 I2CTimeout = I2CT_LONG_TIMEOUT;
    	//判断IIC总线是否忙碌
    	while(I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY))   
    	{
    		if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
    	} 
    	//重新赋值
    	I2CTimeout = I2CT_FLAG_TIMEOUT;
    	//发送起始信号
    	I2C_GenerateSTART(EEPROM_I2C,ENABLE);
    	//检测EV5事件
    	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR)
    	{
    		 if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);
    	} 
    	I2CTimeout = I2CT_FLAG_TIMEOUT;
    	//发送设备写地址
    	I2C_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter);
    	//检测EV6事件
    	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR)
    	{
    		 if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
    	} 
    
    	I2CTimeout = I2CT_FLAG_TIMEOUT;
    	//发送要操作设备内部的地址
    	I2C_SendData(EEPROM_I2C,addr);
    	//检测EV8事件
    	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
    	{
    		 if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(4);
    	} 
    
    	while(Num_ByteToWrite)
    	{
    		I2C_SendData(EEPROM_I2C,*data);
    		I2CTimeout = I2CT_FLAG_TIMEOUT;
    		while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
    		{
    				if((I2CTimeout--) == 0) return   I2C_TIMEOUT_UserCallback(5);
    		} 
    		 Num_ByteToWrite--;
    		 data++;
    	}
    
    	I2CTimeout = I2CT_FLAG_TIMEOUT;
    	//检测EV8_2事件
    	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR)
    	{
    		if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(6);
    	} 
    	//发送停止信号
    	I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
    	 return 1;
    }
    
    //向EEPROM读取多个字节
    uint32_t EEPROM_Read(uint8_t *data,uint8_t addr,uint16_t Num_ByteToRead)
    {
    	 I2CTimeout = I2CT_LONG_TIMEOUT;
    	//判断IIC总线是否忙碌
    	while(I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY))   
    	{
    		if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
    	} 
    	
    	I2CTimeout = I2CT_FLAG_TIMEOUT;
    	//发送起始信号
    	I2C_GenerateSTART(EEPROM_I2C,ENABLE);
    	//检测EV5事件
    	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT )==ERROR)
    	{
    		if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(7);
    	} 
    	
    	I2CTimeout = I2CT_FLAG_TIMEOUT;
    	//发送设备写地址
    	I2C_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter);
    	//检测EV6事件等待从机应答
    	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED )==ERROR)
    	{
    		if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(8);
    	}
      
    	I2CTimeout = I2CT_FLAG_TIMEOUT;
    	//发送要操作设备内部存储器的地址
    	I2C_SendData(EEPROM_I2C,addr);
    	//检测EV8事件
    	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
    	{
    		if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(9);
    	}
    	I2CTimeout = I2CT_FLAG_TIMEOUT;
    	//发送起始信号
    	I2C_GenerateSTART(EEPROM_I2C,ENABLE);
    	//检测EV5事件
    	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT )==ERROR)
    	{
    		if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);
    	}
    	I2CTimeout = I2CT_FLAG_TIMEOUT;	 
    	//发送设备读地址
    	I2C_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Receiver);
    	//检测EV6事件
    	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED )==ERROR)
    	{
    		if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);
    	}
    	 
    	while(Num_ByteToRead--)
    	{
    		//是否是最后一个字节,若是则发送非应答信号
    	if( Num_ByteToRead==0)
    	{
    		//发送非应答信号
    		I2C_AcknowledgeConfig(EEPROM_I2C,DISABLE);
    		//发送停止信号
    		I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
    	}
    	 
    	I2CTimeout = I2CT_FLAG_TIMEOUT;	 
    	//检测EV7事件
       	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_RECEIVED )==ERROR)
    	{
    		if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);
    	}
    	 
    	*data=I2C_ReceiveData(EEPROM_I2C);
    	data++; 
    	 
    	}
    	
    	//重新开启应答信号
    	I2C_AcknowledgeConfig(EEPROM_I2C,ENABLE);
      	return 1;
    }
    void I2C_EE_BufferWrite(uint8_t* pBuffer,uint8_t WriteAddr, uint16_t NumByteToWrite)
    {
      u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;
      //I2C_PageSize=8
      Addr = WriteAddr % I2C_PageSize;
      count = I2C_PageSize - Addr;
      NumOfPage =  NumByteToWrite / I2C_PageSize;
      NumOfSingle = NumByteToWrite % I2C_PageSize;
     
      /* 写入数据的地址对齐,对齐数为8 */
      if(Addr == 0) 
      {
        /* 如果写入的数据个数小于8 */
        if(NumOfPage == 0) 
        {
          EEPROM_Page_Write(WriteAddr, pBuffer, NumOfSingle);
          EEPROM_WaitForWriteEnd();
        }
        /* 如果写入的数据个数大于8 */
        else  
        {
    			//按页写入
          while(NumOfPage--)
          {
            EEPROM_Page_Write(WriteAddr, pBuffer, I2C_PageSize); 
        	  EEPROM_WaitForWriteEnd();
            WriteAddr +=  I2C_PageSize;
            pBuffer += I2C_PageSize;
          }
          //不足一页(8个)单独写入
          if(NumOfSingle!=0)
          {
            EEPROM_Page_Write(WriteAddr, pBuffer, NumOfSingle);
            EEPROM_WaitForWriteEnd();
          }
        }
      }
      /*写的数据的地址不对齐*/
      else 
      {
          NumByteToWrite -= count;
          NumOfPage =  NumByteToWrite / I2C_PageSize;
          NumOfSingle = NumByteToWrite % I2C_PageSize;	
          
          if(count != 0)
          {  
            EEPROM_Page_Write(WriteAddr, pBuffer, count);
            EEPROM_WaitForWriteEnd();
            WriteAddr += count;
            pBuffer += count;
          } 
          
          while(NumOfPage--)
          {
            EEPROM_Page_Write(WriteAddr, pBuffer, I2C_PageSize);
            EEPROM_WaitForWriteEnd();
            WriteAddr +=  I2C_PageSize;
            pBuffer += I2C_PageSize;  
          }
          if(NumOfSingle != 0)
          {
            EEPROM_Page_Write(WriteAddr, pBuffer, NumOfSingle); 
            EEPROM_WaitForWriteEnd();
          }
        } 
    }
    
    uint32_t EEPROM_WaitForWriteEnd(void)
    {
    	I2CTimeout = I2CT_FLAG_TIMEOUT;	
    	
    	do
    	{
    		I2CTimeout = I2CT_FLAG_TIMEOUT;
    		//发送起始信号
    		I2C_GenerateSTART(EEPROM_I2C,ENABLE);
    		//检测EV5事件
    		while( I2C_GetFlagStatus(EEPROM_I2C,I2C_FLAG_SB )==RESET)
    		{
    					if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);
    			}
    		I2CTimeout = I2CT_FLAG_TIMEOUT;	
    		//发送设备写地址
    		I2C_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter);
    		
    	}while( (I2C_GetFlagStatus(EEPROM_I2C,I2C_FLAG_ADDR )==RESET) && (I2CTimeout--) );
    	
    	//发送停止信号
    	I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
    	return 1;
    }
    
    
    
    static  uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode)
    {
      /* Block communication and all processes */
      EEPROM_ERROR("I2C 等待超时!errorCode = %d",errorCode);
      
      return 0;
    }
    
    

    i2c.h代码如下:

    #ifndef __I2C_H
    #define __I2C_H
    #include <stdio.h>
    #include "sys.h"
    
    //IIC1
    #define  EEPROM_I2C                       I2C1
    #define  EEPROM_I2C_BAUDRATE              400000
    
    //STM32自身地址1 与从机设备地址不相同即可(7位地址)
    #define   STM32_I2C_OWN_ADDR             0x6f
    //EEPROM设备地址
    #define   EEPROM_I2C_Address             0XA0
    #define   I2C_PageSize                     8
    
    //等待次数
    #define I2CT_FLAG_TIMEOUT         ((uint32_t)0x1000)
    #define I2CT_LONG_TIMEOUT         ((uint32_t)(10 * I2CT_FLAG_TIMEOUT))
    
    /*信息输出*/
    #define EEPROM_DEBUG_ON                    0
    #define EEPROM_INFO(fmt,arg...)           printf("<<-EEPROM-INFO->> "fmt"\n",##arg)
    #define EEPROM_ERROR(fmt,arg...)          printf("<<-EEPROM-ERROR->> "fmt"\n",##arg)
    #define EEPROM_DEBUG(fmt,arg...)          do{\
                                              if(EEPROM_DEBUG_ON)\
                                              printf("<<-EEPROM-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
                                              }while(0)
    
    void I2C1_Init(void);
    void EEPROM_Byte_Write(uint8_t addr,uint8_t data);	
    uint32_t  EEPROM_WaitForWriteEnd(void);	
    uint32_t  EEPROM_Page_Write(uint8_t addr,uint8_t *data,uint16_t Num_ByteToWrite);																					
    uint32_t  EEPROM_Read(uint8_t *data,uint8_t addr,uint16_t Num_ByteToRead);
    void I2C_EE_BufferWrite(uint8_t* pBuffer,uint8_t WriteAddr, uint16_t NumByteToWrite);
    
    #endif
    

    3.使用逻分抓I2C数据

    4.测试结果

    三、gitee路径

    https://gitee.com/sugang2022/stm32f103zet6.git
    

    作者:sugang1990

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32硬件I2C测试EEPROM读写功能

    发表回复