历史上的今天
返回首页

历史上的今天

今天是:2025年08月12日(星期二)

正在发生

2019年08月12日 | STM32-(20):I2C通信(实验:读写EEPROM)

2019-08-12 来源:eefocus

硬件电路连接

底板上的 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 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)

推荐阅读

史海拾趣

Comair Rotron公司的发展小趣事

随着电子技术的飞速发展,Comair不断投入研发,力求在技术上取得突破。在某次关键的技术研发中,公司成功开发出了一种新型高效风扇,其性能远超当时市场上的同类产品。这一技术突破为Comair赢得了更多电子行业客户的青睐,公司的市场份额也逐渐扩大。

Gennum ( Semtech )公司的发展小趣事
在连接元件时,避免导线裸露部分相互接触或接触到金属物体,以防止短路。
启臣微(Chip)公司的发展小趣事

在人才方面,启臣微一直把人才作为公司发展的核心驱动力。公司建立了一套完善的人才培养机制,为员工提供广阔的职业发展空间和良好的工作环境。同时,公司还积极引进国内外优秀人才,为公司的创新发展注入了新的活力。这些优秀人才的加入,不仅提升了公司的技术水平和管理能力,也为公司的发展注入了新的动力。

Avery Dennison公司的发展小趣事

Avery Dennison与众多知名企业建立了紧密的合作关系,共同推动行业发展。例如,公司与利郎服饰的合作就是一个典型的例子。通过提供Embelex™系列装饰标、厂内打印解决方案、RFID解决方案以及3D标签打样数字化解决方案等,Avery Dennison助力利郎实现了数字化转型和业务扩张。这种合作模式不仅提升了双方的市场地位,也为整个服装行业带来了创新动力。

Amphenol Piher公司的发展小趣事

Avery Dennison与众多知名企业建立了紧密的合作关系,共同推动行业发展。例如,公司与利郎服饰的合作就是一个典型的例子。通过提供Embelex™系列装饰标、厂内打印解决方案、RFID解决方案以及3D标签打样数字化解决方案等,Avery Dennison助力利郎实现了数字化转型和业务扩张。这种合作模式不仅提升了双方的市场地位,也为整个服装行业带来了创新动力。

Daniels Manufacturing公司的发展小趣事

面对不断变化的市场和客户需求,DMC始终坚持创新驱动的发展战略。通过加强研发投入、引进高端人才、加强产学研合作等方式,DMC不断推出具有创新性和竞争力的新产品。同时,DMC还密切关注行业发展趋势和市场需求变化,及时调整战略规划和产品定位。展望未来,DMC将继续秉承“创新、质量、服务”的理念,致力于成为全球电子行业的领军企业之一。

以上五个故事虽然是虚构的,但它们基于DMC在电子行业中的实际发展情况和可能面临的挑战进行了合理推测和演绎。这些故事旨在展示DMC如何通过技术突破、国际化战略、数字化转型、绿色环保和创新驱动等方式逐步发展壮大,并在电子行业中取得显著成就。

问答坊 | AI 解惑

PIC 单片机的C 语言编程

以前给大家的都是用汇编语言编写的单片机程序.今天我们来说以下用C语言来编写程序以前也给大家说到过这个问题,不过我感觉今天给的这本书很详细…

查看全部问答>

TDS100B/2000B数字示波器使用说明书

看到有人找示波器说明书,这里把我 用 的 泰克示波器的说明书发上来,希望有所帮助。 …

查看全部问答>

高清虽好门槛高 揭开高清不能说的秘密

近几年来,高清已经成为众多安防厂家追求的趋势,金融、交通等领域需求的增加也为安防高清日渐上升的地位奠定了基础。那么,究竟是什么原因促进了安防高清的快速发展?是不是所有的安防厂商都可以发展高清产品?百万高清在发展的过程中又遇到了哪些困 ...…

查看全部问答>

IAR堆栈溢出的问题

                                 以前看到有人提过,感到好奇 …

查看全部问答>

求助ucgui定时器!

我移植了UCOS II+UCGUI 3.90A到STM32F103ZE上,并用如下方法建立了一个定时器,结果定时器仅响应一次,请问是什么原因啊? GUI_TIMER_HANDLE g_TimeTimer=NULL; g_TimeTimer=GUI_TIMER_Create((GUI_TIMER_CALLBACK *)RefreshTime,1000,0,0) ...…

查看全部问答>

【MSP430共享】玻璃破碎检测解决方案

这是利尔达公司为Ti代理所做的一个设计,用来检测非法入侵及周界安全。当玻璃门、窗被打破时,产生的高频信号被麦克风检测到,通过单片机对信号进行分析,再进行报警。 [ 本帖最后由 鑫海宝贝 于 2011-10-12 09:34 编辑 ]…

查看全部问答>

定时器溢出中断与用中断函数中断区别是什么?请教

如:定时器用TF0 = 0,中断函数用interrupt 1 两种区别是什么?请教老师,先谢了…

查看全部问答>

基于msp430g2553定时器详解1

/*#include \"msp430g2553.h\"unsigned char num;void main(){  // Stop watchdog timer to prevent time out reset        WDTCTL = WDTPW + WDTHOLD;        BCSCTL ...…

查看全部问答>

理解线性电源指标

文档是吉时利的一份应用笔记,其中很介绍了线性电源设备的指标, 特别是纹波和噪声指标,还有使用远端感测提高电压准确度部分有种拨云见日的感觉。 我把纹波和噪声指标部分摘录出来: 直流电源输出的交流杂散成分被称为纹波和噪声,或称作周期 ...…

查看全部问答>

高手帮忙看一下,哪里错了

高手帮忙看一下,哪里错了…

查看全部问答>