【N32L40X】学习笔记13-软件IIC读写EEPROM AT24C02

AT24C02

  1. 8个字节每页,累计32个页

  2. 通讯频率MAX = 400K

  3. AT24C02大小 2K

在这里插入图片描述

  1. 芯片地址

在这里插入图片描述
对于at24c02 A2A1A0 这三个引脚没有使用
【N32L40X】学习笔记13-软件IIC读写EEPROM AT24C02_第1张图片

【N32L40X】学习笔记13-软件IIC读写EEPROM AT24C02_第2张图片

  1. 写时序在这里插入图片描述

由于设备在写周期中不会产生ACK恢复,因此这可用于确定周期何时完成(此特性可用于最大限度地提高总线吞吐量)。一旦从主服务器发出了写命令的停止条件,设备就会启动内部定时的写周期,然后就可以立即启动ACK轮询。这涉及到主服务器发送一个开始条件,然后是一个写命令的控制字节(R/W =0)。如果设备仍忙于写入周期,则不会返回ACK。如果循环完成,设备将返回ACK,然后主命令可以继续下一个读或写命令。该操作的流程图见图5-1。

【N32L40X】学习笔记13-软件IIC读写EEPROM AT24C02_第3张图片

  1. 读时序
    在这里插入图片描述
    在这里插入图片描述

at24c2.h

#ifndef _24CXX_H
#define _24CXX_H
#include 


#define AT24C01		127
#define AT24C02		255
#define AT24C04		511
#define AT24C08		1023
#define AT24C16		2047
#define AT24C32		4095
#define AT24C64	  8191
#define AT24C128	16383
#define AT24C256	32767

//定义EE_TYPE为AT24C16
#define EE_TYPE AT24C16

uint8_t AT24CXX_ReadOneByte(uint16_t ReadAddr);							//指定地址读取一个字节
void AT24CXX_WriteOneByte(uint16_t WriteAddr,uint8_t DataToWrite);		//指定地址写入一个字节

void AT24CXX_WriteLenByte(uint16_t WriteAddr,uint32_t DataToWrite,uint8_t Len);//指定地址开始写入指定长度的数据
uint32_t AT24CXX_ReadLenByte(uint16_t ReadAddr,uint8_t Len);					//指定地址开始读取指定长度数据

void AT24CXX_Write(uint16_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite);	//从指定地址开始写入指定长度的数据
void AT24CXX_Read(uint16_t ReadAddr,uint8_t *pBuffer,uint16_t NumToRead);   	//从指定地址开始读出指定长度的数据
void AT24CXX_Erasure(uint16_t NumToWrite);  /*从地址0开始将指定个数的地址清0*/
uint8_t AT24CXX_Check(void);  //检查器件
void AT24CXX_Init(void); //初始化IIC

#endif


at24c2.c

#include "at24c02.h"
#include "n32l40x.h"
//#include "delay.h"
//#include "debug.h"
//IO方向设置
//#define SDA_OUT {GPIOC->MODER |= 0x00040000;}  // 设置SDA为输出方向,对于双向I/O需切换为输出
//#define SDA_IN  {GPIOC->MODER &= 0xFFF3FFFF;}  // 设置SDA为输入方向,对于双向I/O需切换为输入
IO操作
//#define IIC_SCL   PAout(8) //SCL
//#define IIC_SDA   PCout(9) //SDA
//#define READ_SDA  PCin(9)  //输入SDA

#define  SDA_OUT do{\
	 GPIO_InitType GPIO_InitStructure;\
    GPIO_InitStruct(&GPIO_InitStructure);\
    GPIO_InitStructure.Pin            = GPIO_PIN_11;\
    GPIO_InitStructure.GPIO_Mode      = GPIO_Mode_Out_PP;\
    GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);}while(0);

#define  SDA_IN do{\
	 GPIO_InitType GPIO_InitStructure;\
    GPIO_InitStruct(&GPIO_InitStructure);\
    GPIO_InitStructure.Pin            = GPIO_PIN_11;\
    GPIO_InitStructure.GPIO_Mode      = GPIO_Mode_Input;\
    GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);}while(0);
//产生IIC起始信号
#define 	READ_SDA 	GPIO_ReadInputDataBit(GPIOB,GPIO_PIN_11)
#define 	IIC_SDA(x) 	GPIO_WriteBit(GPIOB,GPIO_PIN_11,x)
#define 	IIC_SCL(x) 	GPIO_WriteBit(GPIOB,GPIO_PIN_10,x)



static void IIC_Init(void);
static void IIC_Start(void);
static void IIC_Stop(void);
static uint8_t IIC_Wait_Ack(void);
static void IIC_Ack(void);
static void IIC_NAck(void);
static void IIC_Send_Byte(uint8_t txd);
static uint8_t IIC_Read_Byte(unsigned char ack);

void delay_us(int x)
{
    for(int i=0; i<x*60; i++);
}

//初始化IIC接口
void AT24CXX_Init(void)
{
#if HW_WARE_24CXX >0
    printf("%s %s %d\r\n",__FILE__,__FUNCTION__,__LINE__);
#endif

    IIC_Init();//IIC初始化
}
//在AT24CXX指定地址读出一个数据
//ReadAddr:开始读数的地址
//返回值  :读到的数据
uint8_t AT24CXX_ReadOneByte(uint16_t ReadAddr)
{
#if HW_WARE_24CXX >1
    printf("%s %s %d\r\n",__FILE__,__FUNCTION__,__LINE__);
#endif

    uint8_t temp=0;
    IIC_Start();
    if(EE_TYPE>AT24C16)
    {
        IIC_Send_Byte(0XA0);	   //发送写命令
        IIC_Wait_Ack();
        IIC_Send_Byte(ReadAddr>>8);//发送高地址
    } else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据
    IIC_Wait_Ack();
    IIC_Send_Byte(ReadAddr%256);   //发送低地址
    IIC_Wait_Ack();
    IIC_Start();
    IIC_Send_Byte(0XA1);           //进入接收模式
    IIC_Wait_Ack();
    temp=IIC_Read_Byte(0);
    IIC_Stop();//产生一个停止条件
    return temp;
}
//在AT24CXX指定地址写入一个数据
//WriteAddr  :写入数据的目的地址
//DataToWrite:要写入的数据
void AT24CXX_WriteOneByte(uint16_t WriteAddr,uint8_t DataToWrite)
{
    int page=0;
#if HW_WARE_24CXX >1
    printf("%s %s %d\r\n",__FILE__,__FUNCTION__,__LINE__);
#endif

    IIC_Start();
    if(EE_TYPE>AT24C16)
    {
        IIC_Send_Byte(0XA0);	    //发送写命令10100000
        IIC_Wait_Ack();
        IIC_Send_Byte(WriteAddr>>8);//发送高地址
    } else
    {
        page = WriteAddr/256;
#if HW_WARE_24CXX >0
        printf("%s %s %d page = %02xH\r\n",__FILE__,__FUNCTION__,__LINE__,page);
#endif

        IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据
    }
    IIC_Wait_Ack();
    IIC_Send_Byte(WriteAddr%256);   //发送低地址
    IIC_Wait_Ack();
    IIC_Send_Byte(DataToWrite);     //发送字节
    IIC_Wait_Ack();
    IIC_Stop();//产生一个停止条件
    delay_us(100);
}
//在AT24CXX里面的指定地址开始写入长度为Len的数据
//该函数用于写入16bit或者32bit的数据.
//WriteAddr  :开始写入的地址
//DataToWrite:数据数组首地址
//Len        :要写入数据的长度2,4
void AT24CXX_WriteLenByte(uint16_t WriteAddr,uint32_t DataToWrite,uint8_t Len)
{
#if HW_WARE_24CXX >0
    printf("%s %s %d\r\n",__FILE__,__FUNCTION__,__LINE__);
#endif

    uint8_t t;
    for(t=0; t<Len; t++)
    {
        AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
    }
}

//在AT24CXX里面的指定地址开始读出长度为Len的数据
//该函数用于读出16bit或者32bit的数据.
//ReadAddr   :开始读出的地址
//返回值     :数据
//Len        :要读出数据的长度2,4
uint32_t AT24CXX_ReadLenByte(uint16_t ReadAddr,uint8_t Len)
{
#if HW_WARE_24CXX >0
    printf("%s %s %d\r\n",__FILE__,__FUNCTION__,__LINE__);
#endif

    uint8_t t;
    uint32_t temp=0;
    for(t=0; t<Len; t++)
    {
        temp<<=8;
        temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);
    }
    return temp;
}
//检查AT24CXX是否正常
//这里用了24XX的最后一个地址(255)来存储标志字.
//如果用其他24C系列,这个地址要修改
//返回1:检测失败
//返回0:检测成功
uint8_t AT24CXX_Check(void)
{
#if HW_WARE_24CXX > 0
    printf("%s %s %d\r\n",__FILE__,__FUNCTION__,__LINE__);
#endif

    uint8_t temp;
    temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX
    if(temp==0X55)return 0;
    else//排除第一次初始化的情况
    {
        AT24CXX_WriteOneByte(255,0X55);
        temp=AT24CXX_ReadOneByte(255);
        if(temp==0X55)return 0;
    }
    return 1;
}

//在AT24CXX里面的指定地址开始读出指定个数的数据
//ReadAddr :开始读出的地址 对24c02为0~255
//pBuffer  :数据数组首地址
//NumToRead:要读出数据的个数
void AT24CXX_Read(uint16_t ReadAddr,uint8_t *pBuffer,uint16_t NumToRead)
{
#if HW_WARE_24CXX >0
    printf("%s %s %d\r\n",__FILE__,__FUNCTION__,__LINE__);
#endif

    while(NumToRead)
    {
        *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
        NumToRead--;
    }
}
//在AT24CXX里面的指定地址开始写入指定个数的数据
//WriteAddr :开始写入的地址 对24c02为0~255
//pBuffer   :数据数组首地址
//NumToWrite:要写入数据的个数
void AT24CXX_Write(uint16_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite)
{
#if HW_WARE_24CXX >1
    printf("%s %s %d\r\n",__FILE__,__FUNCTION__,__LINE__);
#endif

    while(NumToWrite--)
    {
        AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
        WriteAddr++;
        pBuffer++;
    }
}

//在AT24CXX里面的指定地址开始写入指定个数的数据
//WriteAddr :开始写入的地址 对24c02为0~255
//pBuffer   :数据数组首地址
//NumToWrite:要写入数据的个数
void AT24CXX_Erasure(uint16_t NumToWrite)
{
#if HW_WARE_24CXX >0
    printf("%s %s %d\r\n",__FILE__,__FUNCTION__,__LINE__);
#endif

    uint16_t  WriteAddr=0;
    while(NumToWrite--)
    {
        AT24CXX_WriteOneByte(WriteAddr,0);
        WriteAddr++;
    }
}


/*软件模拟IIC*/
//IIC初始化
static void IIC_Init(void)
{
#if HW_WARE_24CXX >0
    printf("%s %s %d\r\n",__FILE__,__FUNCTION__,__LINE__);
#endif


    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB,ENABLE);
    GPIO_InitType GPIO_InitStructure;

    /* Initialize GPIO_InitStructure */
    GPIO_InitStruct(&GPIO_InitStructure);

    /* Configure USARTx Tx as alternate function push-pull */
    GPIO_InitStructure.Pin            = GPIO_PIN_10;
    GPIO_InitStructure.GPIO_Mode      = GPIO_Mode_Out_PP;
    GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
    GPIO_InitStructure.Pin            = GPIO_PIN_11;
    GPIO_InitStructure.GPIO_Mode      = GPIO_Mode_Out_PP;
    GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);

    GPIO_WriteBit(GPIOB,GPIO_PIN_10,Bit_SET);
    GPIO_WriteBit(GPIOB,GPIO_PIN_11,Bit_SET);

}

static void IIC_Start(void)
{
    SDA_OUT;     //sda线输出
    IIC_SDA(1);
    IIC_SCL(1);
    delay_us(4);
    IIC_SDA(0);//START:when CLK is high,DATA change form high to low
    delay_us(4);
    IIC_SCL(0);//钳住I2C总线,准备发送或接收数据
}

//产生IIC停止信号
static void IIC_Stop(void)
{
    SDA_OUT;//sda线输出
    IIC_SCL(0);
    IIC_SDA(0);//STOP:when CLK is high DATA change form low to high
    delay_us(4);
    IIC_SCL(1);
    delay_us(4);
    IIC_SDA(1);//发送I2C总线结束信号
}

//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
static uint8_t IIC_Wait_Ack(void)
{
    uint8_t ucErrTime=0;
    SDA_IN;      //SDA设置为输入
    IIC_SDA(1);
    delay_us(1);
    IIC_SCL(1);
    delay_us(1);
    while(READ_SDA)
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
            IIC_Stop();
            return 1;
        }
    }
    IIC_SCL(0);//时钟输出0
    return 0;
}

//产生ACK应答
static void IIC_Ack(void)
{
    IIC_SCL(0);
    SDA_OUT;
    IIC_SDA(0);
    delay_us(2);
    IIC_SCL(1);
    delay_us(2);
    IIC_SCL(0);
}
//不产生ACK应答
static void IIC_NAck(void)
{
    IIC_SCL(0);
    SDA_OUT;
    IIC_SDA(1);
    delay_us(2);
    IIC_SCL(1);
    delay_us(2);
    IIC_SCL(0);
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
static void IIC_Send_Byte(uint8_t txd)
{
    uint8_t t;
    SDA_OUT;
    IIC_SCL(0);//拉低时钟开始数据传输
    for(t=0; t<8; t++)
    {
        IIC_SDA((txd&0x80)>>7);
        txd<<=1;
        delay_us(2);   //对TEA5767这三个延时都是必须的
        IIC_SCL(1);
        delay_us(2);
        IIC_SCL(0);
        delay_us(2);
    }
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
static uint8_t IIC_Read_Byte(unsigned char ack)
{
    unsigned char i,receive=0;
    SDA_IN;//SDA设置为输入
    for(i=0; i<8; i++ )
    {
        IIC_SCL(0);
        delay_us(2);
        IIC_SCL(1);
        receive<<=1;
        if(READ_SDA)receive++;
        delay_us(1);
    }
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK
    return receive;
}


测试代码

    AT24CXX_Init();
    if(!AT24CXX_Check())
    {
        printf("AT24CXX_Check ok\r\n");
    }
    else
    {
        printf("AT24CXX_Check fail\r\n");
    }

    uint8_t buff[100];

    uint8_t buff1[100];
    for(int i=0; i<100; i++)
    {
        buff[i]=i;
    }

    AT24CXX_Write(0,buff,100);
    AT24CXX_Read(0,buff1,100);
    for(int i=0; i<100; i++)
    {
        printf("%02d ",buff1[i]);
    }
    printf("\r\n");

你可能感兴趣的:(N32L40X,N32,IIC,at24c02,eeprom)