打印

STM32F4硬件IIC实现对AT24C02的操作

[复制链接]
11949|20
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本程序利用STM32F4的硬件IIC实现对AT24C02的任何操作!!
Bsp.c主要对板载外设进行初始化!
/**
  ******************************************************************************
  * @file    bsp.c
  * @author  wangfei
  * @date    13-April-2012
  * @e-mail  wfmjj@hotmail.com
  * @brief   Initialize peripherals.
  *****************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include "bsp.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
  * @brief   This function handles NMI exception.
  * @param  None
  * @retval None
  */
void Bsp_Init(void)
{
Bsp_GPIO_Config();
Bsp_IIC_Config();
Bsp_USART3_Config();

}
/**
  * @brief   This function config gpio.
  * @param  None
  * @retval None
  */
void Bsp_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;  //定义结构体

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);   //打开外设GPIOE的时钟--LED
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);     //turn on gpioc clock
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);   //打开GPIOB口的时钟I2C_CLK--PB6

//LED端口配置
GPIO_InitStructure.GPIO_Pin=(GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);  //led口配置
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOE, &GPIO_InitStructure);
//USART3端口配置
GPIO_PinAFConfig(GPIOC,GPIO_PinSource10,GPIO_AF_USART3);  //Connect USART3 pins to AF7
  GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_USART3);

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10 | GPIO_Pin_11;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
//IIC端口设置 IIC_CLK和IIC_SDA引脚均要设置为复用开漏不带上拉输出
GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_I2C1);  //开启PB6的复用功能连接至I2C1
GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1);

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6 | GPIO_Pin_7;   //选择PB6和PB7引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;           //开启PB6和PB7的复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;    //PB6和PB7设置为开漏输出
GPIO_InitStructure.GPIO_PuPd =GPIO_PuPd_NOPULL;   //PB6和PB7口不带上拉电阻
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/**
  * @brief   This function config iic.
  * @param  None
  * @retval None
  */
void Bsp_IIC_Config(void)
{
  I2C_InitTypeDef I2C_InitStructure;   

RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);   //打开IIC外设时钟
  
I2C_DeInit(I2C1); //将外设IIC的各个寄存器恢复到复位以后的值

I2C_InitStructure.I2C_ClockSpeed=100000;  //标准模式 时钟频率为100KHZ
I2C_InitStructure.I2C_Mode=I2C_Mode_I2C;   //选中I2C模式
I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1=0X00;      //当I2C出于从模式时,自身的地址
I2C_InitStructure.I2C_Ack=I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C1, &I2C_InitStructure);

I2C_AcknowledgeConfig(I2C1,ENABLE);   //在接收到一个字节后返回一个应答ACK
I2C_Cmd(I2C1,ENABLE);  //开启外设IIC模块
}
/**
  * @brief   This function config usart3.
  * @param  None
  * @retval None
  */
void Bsp_USART3_Config(void)
{
USART_InitTypeDef USART_InitStructure;
  
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //turn on usart3 clock
  
  USART_InitStructure.USART_BaudRate =115200 ;         //波特率设置
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USART3, &USART_InitStructure);
  
  //USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
  USART_Cmd(USART3,ENABLE);
  USART_ClearFlag(USART3, USART_FLAG_TC);   //清除发送完成标志位
}
AT24C02.C文件主要对AT24C02的操作
/**
  ******************************************************************************
  * @file    at24c02.c
  * @author  wangfei
  * @date    13-April-2012
  * @e-mail  wfmjj@hotmail.com
  * @brief  write or read eeprom
  *****************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include "at24c02.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
  * @brief   This function write one byte to at24c02.
  * @param  None
  * @retval None
  */
void IIC_Write_AT24C02_OneByte(uint8_t addr,uint8_t data)
{
uint16_t flag;
//判断BUSY是否为1,BUSY=1总线处于忙状态
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));  //如果BUSY=1则等待一直等到BUSY=0

//主机产生起始条件
I2C_GenerateSTART(I2C1,ENABLE);  

//判断SB是否为1,SB=1起始条件已经发送 即判断EV5
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);  //当产生了起始条件,设备就进入了主模式

//发送eepROM的地址0XA0
I2C_Send7bitAddress(I2C1,0XA0,I2C_Direction_Transmitter); //软件读取SR1寄存器后,写数据寄存器的操作将清除SB位
//判断ADDR是否为1,ADDR=1地址发送结束 即判断EV6
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
  flag=I2C1->SR2; //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位
//发送AT24C02的内部地址:即数据要写入的地址
I2C_SendData(I2C1,addr);

//判断TXE是否为1,TXE=1移位寄存器不为空,数据寄存器为空 即判断EV8
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING)==ERROR);

//发送数据到要写入的地址
I2C_SendData(I2C1,data);    //对数据寄存器的写操作将清除TXE位

//判断TXE和BTF是否为1,TXE=1,BTF=1请求设置停止位 即判断EV8_2
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED)==ERROR);

//关闭通讯,产生停止条件
I2C_GenerateSTOP(I2C1,ENABLE); //产生停止条件时,硬件自动清除TXE和BTF位
}
/**
  * @brief   This function waite for eeprom standby state.
  * @param   none
* @retval  None
  */
/*AT24C02在接收完数据后,启动内部周期写入数据的时间内不会对主机的请求做出应答的特性,因此此
  函数循环发送起始信号,若检测到AT24C02的应答,则说明AT24C02已完成上一步的数据写入,进入稳定状态
  可以进行下一次的操作,因此这个函数在数据写入完成后必须调用此函数,判断AT24C02是否进入稳定状态*/
void IIC_Waite_AT24C02_Standby(void)
{
  uint16_t SR1_Flag;
I2C1->SR1&=0X0000;  //清除I2C1_SR1寄存器
do
{
  I2C_GenerateSTART(I2C1,ENABLE);  //产生起始条件
  
  SR1_Flag=I2C1->SR1;  //软件读取SR1寄存器后,写数据寄存器的操作将清除SB位
  
  I2C_Send7bitAddress(I2C1,0XA0,I2C_Direction_Transmitter); //发送7位AT24C02的地址
}while((I2C1->SR1&0X0002)==0X00);  //当ADDR=1时,跳出此循环表明AT24C02写入数据已完成

  I2C_ClearFlag(I2C1,I2C_FLAG_AF);  //清除应答失败位

  I2C_GenerateSTOP(I2C1,ENABLE);   //发送停止信号
}
/*
* 函数名:IIC_AT24C02_PageWrite
* 描述  :在EEPROM的一个写循环中可以写多个字节,但一次写入的字节数
*         不能超过EEPROM页的大小。AT24C02每页有8个字节。
* 输入  :-pBuffer 缓冲区指针
*         -WriteAddr 接收数据的EEPROM的地址
*         -NumByte 要写入EEPROM的字节数
* 输出  :无
* 返回  :无
* 调用  :外部调用
*/
void IIC_AT24C02_PageWrite(uint8_t *pBuffer,uint8_t WriteAddr,uint8_t NumByte)
{
uint16_t state;
//判断BUSY是否为1,BUSY=1总线处于忙状态
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));  //如果BUSY=1则等待一直等到BUSY=0

//主机产生起始条件
I2C_GenerateSTART(I2C1,ENABLE);  

//判断SB是否为1,SB=1起始条件已经发送 即判断EV5
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);  //当产生了起始条件,设备就进入了主模式

//发送eepROM的地址0XA0
I2C_Send7bitAddress(I2C1,0XA0,I2C_Direction_Transmitter); //软件读取SR1寄存器后,写数据寄存器的操作将清除SB位
//判断ADDR是否为1,ADDR=1地址发送结束 即判断EV6
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
  state=I2C1->SR2; //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位

//发送AT24C02的内部地址:即数据要写入的地址
I2C_SendData(I2C1,WriteAddr);

//判断TXE是否为1,TXE=1移位寄存器不为空,数据寄存器为空 即判断EV8
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING)==ERROR);

for(;NumByte>0;NumByte--)
{
  //发送数据到要写入的地址
   I2C_SendData(I2C1,*pBuffer);    //对数据寄存器的写操作将清除TXE位
  
  //缓冲区指针加1指向下一个要写入的数据
  pBuffer++;
  
  //判断TXE和BTF是否为1,TXE=1,BTF=1请求设置停止位 即判断EV8_2
   while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED)==ERROR);
}

//关闭通讯,产生停止条件
I2C_GenerateSTOP(I2C1,ENABLE); //产生停止条件时,硬件自动清除TXE和BTF位
}
/**
  * @brief   This function read one byte from slect address.
  * @param   none
* @retval  None
  */
/*选择性读取允许主器件对AT24C02寄存器的任意字节读操作,具体步骤如下:
1--主器件发送起始信号,从器件地址,和他想读取的字节数据的地址执行一个伪写操作
2--AT24C02应答之后,主器件从新发送起始信号和从器件地址,此时R/W位置1。
3--AT24C02响应并发送应答信号,然后输出一个所要求的8位字节数据。
4--主器件不发送应答信号,但产生一个停止信号。*/
uint8_t IIC_Read_AT24C02_OneByte(uint8_t address)
{
  uint16_t temp,flag;
//判断BUSY是否为1,BUSY=1总线处于忙状态
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));  //如果BUSY=1则等待一直等到BUSY=0

//主机产生起始条件
I2C_GenerateSTART(I2C1,ENABLE);  

//判断SB是否为1,SB=1起始条件已经发送 即判断EV5
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);  //当产生了起始条件,设备就进入了主模式

//发送eepROM的地址0XA0
I2C_Send7bitAddress(I2C1,0XA0,I2C_Direction_Transmitter); //软件读取SR1寄存器后,写数据寄存器的操作将清除SB位
//判断ADDR是否为1,ADDR=1地址发送结束 即判断EV6
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
  flag=I2C1->SR2; //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位
//发送想要读取字节的地址
I2C_SendData(I2C1,address);
//判断TXE是否为1,TXE=1移位寄存器不为空,数据寄存器为空 即判断EV8
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING)==ERROR);

//主机重新发送起始信号
I2C_GenerateSTART(I2C1,ENABLE);  

//判断SB是否为1,SB=1起始条件已经发送 即判断EV5
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);  //当产生了起始条件,设备就进入了主模式
//主机重新发送AT24C02的地址,这是R/W位置1
  I2C_Send7bitAddress(I2C1,0XA0,I2C_Direction_Receiver);

//判断ADDR是否为1,ADDR=1地址发送结束 即判断EV6
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)==ERROR);
  flag=I2C1->SR2; //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位
I2C_AcknowledgeConfig(I2C1,DISABLE);
I2C_GenerateSTOP(I2C1,ENABLE);
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED)==ERROR);

temp=I2C_ReceiveData(I2C1);

I2C_AcknowledgeConfig(I2C1, ENABLE); //打开应答信号使其回到初始状态
return temp;
}
/*
* 函数名:IIC_AT24C02_PageRead
* 描述  :从EEPROM里面读取一块数据。
* 输入  :-pBuffer 存放从EEPROM读取的数据的缓冲区指针。
*         -ReadAddr 接收数据的EEPROM的地址。
*         -NumByte 要从EEPROM读取的字节数。
* 输出  :无
* 返回  :无
* 调用  :外部调用
*/
void IIC_AT24C02_PageRead(uint8_t *pBuffer,uint8_t ReadAddr,uint8_t NumByte)
{
uint16_t  flag1,flag2;

//判断BUSY是否为1,BUSY=1总线处于忙状态
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));  //如果BUSY=1则等待一直等到BUSY=0

//主机产生起始条件
I2C_GenerateSTART(I2C1,ENABLE);  

//判断SB是否为1,SB=1起始条件已经发送 即判断EV5
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);  //当产生了起始条件,设备就进入了主模式
//发送eepROM的地址0XA0
I2C_Send7bitAddress(I2C1,0XA0,I2C_Direction_Transmitter); //软件读取SR1寄存器后,写数据寄存器的操作将清除SB位
//判断ADDR是否为1,ADDR=1地址发送结束 即判断EV6
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
  flag1=I2C1->SR2; //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位

//发送想要读取字节的地址
I2C_SendData(I2C1,ReadAddr);
//判断TXE是否为1,TXE=1移位寄存器不为空,数据寄存器为空 即判断EV8
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING)==ERROR);

//主机重新发送起始信号
I2C_GenerateSTART(I2C1,ENABLE);  

//判断SB是否为1,SB=1起始条件已经发送 即判断EV5
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);  //当产生了起始条件,设备就进入了主模式
//主机重新发送AT24C02的地址,这是R/W位置1
  I2C_Send7bitAddress(I2C1,0XA0,I2C_Direction_Receiver);
//判断ADDR是否为1,ADDR=1地址发送结束 即判断EV6
while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)==ERROR);
  flag2=I2C1->SR2; //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位

//接收AT24C02发送的数据
  while(NumByte)
{
  if(NumByte==1)   //等于1时数据已经发送完成
  {
   //主机不再发送响应信号
   I2C_AcknowledgeConfig(I2C1,DISABLE);
  //主机产生停止信号
      I2C_GenerateSTOP(I2C1,ENABLE);
  }
  //检查RXNE是否为1,即判断EV7
  if(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED)==SUCCESS)
  {
   /* Read a byte from the EEPROM */
    *pBuffer = I2C_ReceiveData(I2C1);  //软件读取数据寄存器的值,讲清除RXNE位
   
   /* Point to the next location where the byte read will be saved */
       pBuffer++;
   
    /* Decrement the read bytes counter */
       NumByte--;   
  }
}
I2C_AcknowledgeConfig(I2C1, ENABLE); //打开应答信号使其回到初始状态
}
/*
* 函数名:IIC_AT24C02_BufferWrite
* 描述  :将缓冲区中的数据写到I2C EEPROM中
* 输入  :-pBuffer 缓冲区指针
*         -WriteAddr 接收数据的EEPROM的地址
*         -NumByteToWrite 要写入EEPROM的字节数
* 输出  :无
* 返回  :无
*/
void IIC_AT24C02_BufferWrite(uint8_t *pBuffer,uint8_t WriteAddr,uint8_t NumByteToWrite )
{
uint8_t NumofPage=0;    //要写入的数据块按页操作所需的次数(AT24C02页写,可一次写入8个字节数据)
uint8_t NumofSignal=0;  //要写入的数据块按页写操作完成后剩余的字节数
uint8_t addr=0;         //要写入数据块的首地址是否为8的倍数
uint8_t count=0;        //

addr=WriteAddr%I2C_PageSize; //判断要写入的数据块首地址是否为8的倍数,addr=0则为8的整数倍
//如果要写入的数据的起始地址不是8的倍数,则addr不为0.算出与8的差值。
//写入数据的起始地址+这个差值=下一个为8的倍数的地址
  
count=8-addr;

NumofPage=NumByteToWrite/I2C_PageSize; //计算写入的数据块按页写需要进行页操作的次数
NumofSignal=NumByteToWrite%I2C_PageSize; //页操作剩余的字节数

/* 如果要写入数据块的首地址为8的倍数,即addr=0只需操作几次页写函数即可 */
if(addr==0)   //首先判断起始地址是否为8的整数倍,在判断要写的数据长度是否大于8个字节
{
  //如果写入的数据块长度小于8个字节
  if(NumofPage==0)
  {
   IIC_AT24C02_PageWrite(pBuffer,WriteAddr,NumofSignal);
   IIC_Waite_AT24C02_Standby();
  }
  else    //要写入的数据块长度大于8个字节,即按页操作
  {
   while(NumofPage--)
   {
    IIC_AT24C02_PageWrite(pBuffer,WriteAddr,8);  //进行页操作一次可以连续写入8个字节数据
    IIC_Waite_AT24C02_Standby();
    WriteAddr+=8;       //写入数据的地址加8
    pBuffer+=8;         //将要写入的数据的指针加8
   }
   if(NumofSignal!=0)  //按页操作完成之后的数据不够8个字节的
   {
    IIC_AT24C02_PageWrite(pBuffer,WriteAddr,NumofSignal);  //将剩余的字节数写入到对应的地址中
    IIC_Waite_AT24C02_Standby();
   }
  }
}
else   //如果写入数据的起始地址不为8的倍数,即addr!=0.
{
  //如果写入的数据块长度小于8个字节
  if(NumofPage==0)
  {
   IIC_AT24C02_PageWrite(pBuffer,WriteAddr,NumofSignal);
   IIC_Waite_AT24C02_Standby();
  }
  else    //要写入的数据块长度大于8个字节,即按页操作
  {
   //首先要先写入count个数据,即算出写完counter个字节数据后NumByteToWrite的新值
   
   NumByteToWrite-=count;
   NumofPage=NumByteToWrite/I2C_PageSize; //计算写入的数据块按页写需要进行页操作的次数
     NumofSignal=NumByteToWrite%I2C_PageSize; //页操作剩余的字节数
   
   if(count!=0)
   {
    IIC_AT24C02_PageWrite(pBuffer,WriteAddr,count);
     IIC_Waite_AT24C02_Standby();
    WriteAddr+=count;
    pBuffer+=count;
   }
   while(NumofPage--)
   {
    IIC_AT24C02_PageWrite(pBuffer,WriteAddr,8);  //进行页操作一次可以连续写入8个字节数据
    IIC_Waite_AT24C02_Standby();
    WriteAddr+=8;       //写入数据的地址加8
    pBuffer+=8;         //将要写入的数据的指针加8
   }
   if(NumofSignal!=0)  //按页操作完成之后的数据不够8个字节的
   {
    IIC_AT24C02_PageWrite(pBuffer,WriteAddr,NumofSignal);  //将剩余的字节数写入到对应的地址中
    IIC_Waite_AT24C02_Standby();
   }
  }
}
}
沙发
wfmartin28|  楼主 | 2013-1-31 16:02 | 只看该作者
app.c主要对at24c02的读与写
/**
  ******************************************************************************
  * @file    app.c
  * @author  wangfei
  * @date    13-April-2012
  * @e-mail  wfmjj@hotmail.com
  * @brief   Initialize peripherals.
  *****************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include "app.h"
#include "bsp.h"
#include "at24c02.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint8_t PageWrite[8]={1,2,3,4,5,6,7,8};
uint8_t PageRead[8];
uint8_t SequenceWrite[15]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
uint8_t SequenceRead[15];
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
  * @brief   This function handles NMI exception.
  * @param  None
  * @retval None
  */
int main(void)
{
  uint8_t I2C_Data,i,m;
  uint8_t *p,*q,*r,*s;
  uint8_t ReadSum=0,WriteSum=0;
  p=PageWrite;
  q=PageRead;
  r=SequenceWrite;
  s=SequenceRead;
   GPIO_ResetBits(GPIOE,(GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3));  //可以通过观察LED的状态判断写入和读取的数值相等不
  Bsp_Init();
//单字节的读与写
  IIC_Write_AT24C02_OneByte(200,0x78);
  IIC_Waite_AT24C02_Standby();
  I2C_Data=IIC_Read_AT24C02_OneByte(200);
  if(I2C_Data==0x78)
  {
   GPIO_SetBits(GPIOE,(GPIO_Pin_0));
  }
//页写和连续读取
  IIC_AT24C02_PageWrite(p,2,8);
  IIC_Waite_AT24C02_Standby();
  IIC_AT24C02_PageRead(q,2,8);
  if(PageRead[1]==2)
  {
   GPIO_SetBits(GPIOE,(GPIO_Pin_1));
  }
//连续写与读
  IIC_AT24C02_BufferWrite(r,15,15);
  IIC_Waite_AT24C02_Standby();
  IIC_AT24C02_PageRead(s,15,15);
  WriteSum=SequenceWrite_Checksum();
  ReadSum=SequenceRead_Checksum();
  if(WriteSum==ReadSum)
  {
    GPIO_SetBits(GPIOE,(GPIO_Pin_2));
  }
while(1)
{
   USART_SendData(USART3,I2C_Data);
     while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
     Delay(10000000);
   for(i=0;i<8;i++)
   {
    USART_SendData(USART3,PageRead);
      while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
   }
   Delay(10000000);
   for(m=0;m<15;m++)
   {
   USART_SendData(USART3,SequenceRead[m]);
      while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
   }
   Delay(10000000);
}
}
/**
  * @brief  Delay Function.
  * @param  nCount:specifies the Delay time length.
  * @retval None
  */
void Delay(__IO uint32_t nCount)
{
  while(nCount--)
  {
  }
}
//计算SequenceWrite[]的校验和
uint8_t SequenceWrite_Checksum(void)
{
uint8_t Write_Checksum=0;
uint8_t j;
for(j=0;j<15;j++)
{
  Write_Checksum+=SequenceWrite[j];
}
return Write_Checksum;
}
//计算SequenceRead[]的校验和
uint8_t SequenceRead_Checksum(void)
{
uint8_t Read_Checksum=0;
uint8_t j;
for(j=0;j<15;j++)
{
  Read_Checksum+=SequenceRead[j];
}
return Read_Checksum;
}
  

使用特权

评论回复
板凳
wfmartin28|  楼主 | 2013-1-31 16:05 | 只看该作者
用串口接收到的数据

未命名1.JPG (36.42 KB )

未命名1.JPG

使用特权

评论回复
地板
outstanding| | 2013-8-16 16:17 | 只看该作者

使用特权

评论回复
5
njchenmin| | 2013-8-17 07:54 | 只看该作者
可以参考一下

使用特权

评论回复
6
keasen| | 2013-8-18 21:14 | 只看该作者
做一个mark

使用特权

评论回复
7
天罡星lmy| | 2014-1-8 15:25 | 只看该作者
mark

使用特权

评论回复
8
ADaiPlay| | 2014-3-2 10:57 | 只看该作者
感谢楼主,参考楼主代码,稍加修改就可以读写AT23C64了,官方的DMA的代码库咱实在是用不来

使用特权

评论回复
9
outstanding| | 2014-3-2 11:34 | 只看该作者
再  MARK

使用特权

评论回复
10
潜力变实力| | 2014-3-17 19:40 | 只看该作者
收藏一下

使用特权

评论回复
11
wangzhihai1986| | 2014-3-17 20:54 | 只看该作者
用表笔触碰SDA,SCL引脚,有影响不?

使用特权

评论回复
12
wfmartin28|  楼主 | 2014-3-18 14:03 | 只看该作者
wangzhihai1986 发表于 2014-3-17 20:54
用表笔触碰SDA,SCL引脚,有影响不?

用表笔随便再AT24C02的那两个引脚上捣鼓都没事!

使用特权

评论回复
13
香水城| | 2014-3-18 14:56 | 只看该作者
好多while()的死等,至少要加个超时吧

使用特权

评论回复
14
圣骑士by| | 2014-3-19 17:02 | 只看该作者
mark

使用特权

评论回复
15
jazu| | 2014-5-7 07:06 | 只看该作者

使用stm32L151 + AT24C02测试了下楼主的代码

1. pageRead()和pageWrite() 存在问题,会丢字节
2. EV5 event / EV6 event 也是 ADDR 没有被设置为1
     检测在单步调试的时候不能通过,直接设置断点可以跳过去,这个有点疑惑

使用特权

评论回复
16
拿起书本| | 2014-5-7 08:53 | 只看该作者
不知道楼主为什么要这样搞,难道是为了增加程序的可移植性?

使用特权

评论回复
17
无为之益| | 2014-7-17 10:27 | 只看该作者
楼主,地址是10位的I2C怎么修改呢?谢谢

使用特权

评论回复
18
无为之益| | 2014-7-17 10:46 | 只看该作者
本帖最后由 无为之益 于 2014-7-17 17:29 编辑

楼主,请教一下:
我设置
I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_10bit;
后,
对I2C_SendData(I2C1,WriteAddr);  //其中WriteAddr为uint16_t
需要不需要改成
AddrH = WriteAddr >> 8;
AddrL = WriteAddr & 0x00ff;
I2C_SendData(I2C1,AddrH);  
I2C_SendData(I2C1,AddrL);  
主要是这里用的是I2C模块功能,ACK应答是自动完成,所以不知道怎么改,希望能得到你的指点,谢谢

我试了下,我这样改是正确的。不过楼主的页写有问题,必须要从第一个字节开始写?我加了个页尾判断,很好用。

无论如何,要谢谢楼主

使用特权

评论回复
19
cool_coder| | 2014-7-17 15:05 | 只看该作者
不错,有参考价值。

使用特权

评论回复
20
qiye123| | 2015-5-27 11:05 | 只看该作者
楼主问下at24c64和这个有什么区别啊我试了半天时钟单字节写不进去

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

19

主题

144

帖子

0

粉丝