历史上的今天
返回首页

历史上的今天

今天是:2025年01月09日(星期四)

正在发生

2019年01月09日 | IIC专题(二)——STM32驱动AT24C02

2019-01-09 来源:eefocus

1.概述


MiniSTM32 开发板板载的 EEPROM 芯片型号为 24C02。该芯片的总容量是 256个字节,该芯片通过 IIC 总线与外部连接。这里直接采用原子板上的 AT24C02 ,主要是软件编程方面的学习。


2.硬件连接


这里写图片描述


A2、A1、A0 三个引脚直接接地。供电: (VCC = 2.7V to 5.5V)


器件地址设置:


这里写图片描述


对于AT24C02:Addr—>0xA0(写)/ 0xA1(读)。


单字节写入:


这里写图片描述


按页写入:


这里写图片描述


从当前地址读出数据;


这里写图片描述


随机读取:


这里写图片描述


顺序读出:


这里写图片描述


3.例程分析


(一)IIC 部分实现代码


包括 IIC 的初始化(IO 口)、 IIC 开始、 IIC 结束、 ACK、 IIC 读写等功能,在其他函数里面,只需要调用相关的 IIC 函数就可以和外部 IIC 器件通信了,这里并不局限于 24C02,该段代码可以用在任何 IIC 设备上。


IIC_SCL 和 IIC_SDA 分别连在 STM32 的 PC12 和 PC11。


1.IIC 初始化

//IO操作函数     

#define IIC_SCL    PCout(12) //SCL

#define IIC_SDA    PCout(11) //SDA   

#define READ_SDA   PCin(11)  //输入SDA


//初始化 IIC

void IIC_Init(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;


    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOC, &GPIO_InitStructure);


    IIC_SCL=1;

    IIC_SDA=1;

}


2.产生 IIC 开始信号

//产生 IIC 起始信号

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 总线, 准备发送或接收数据

}


3.产生停止IIC信号

//产生 IIC 停止信号

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;


    IIC_SDA=1;//发送 I2C 总线结束信号

    delay_us(4);

}


4.等待应答信号

//等待应答信号到来

//返回值: 1,接收应答失败

// 0,接收应答成功

u8 IIC_Wait_Ack(void)

{

    u8 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;

}



5.应答信号

//产生 ACK 应答

void IIC_Ack(void)

{

    IIC_SCL=0;


    SDA_OUT();


    IIC_SDA=0;

    delay_us(2);


    IIC_SCL=1;


    delay_us(2);

    IIC_SCL=0;

}


6.不产生应答

//不产生 ACK 应答

void IIC_NAck(void)

{

    IIC_SCL=0;

    SDA_OUT();


    IIC_SDA=1;


    delay_us(2);

    IIC_SCL=1;

    delay_us(2);

    IIC_SCL=0;

}


7.IIC发送一个字节

//IIC 发送一个字节

//返回从机有无应答

//1,有应答

//0,无应答

void IIC_Send_Byte(u8 txd)

{

    u8 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);

    }

}


8.IIC读一个字节

//读 1 个字节, ack=1 时,发送 ACK, ack=0,发送 nACK

u8 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;

}



(二)AT24C02 操作

直接通过寄存器操作设置 IO 口的模式为输入还是输出,代码如下:


#define SDA_IN() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}


#define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}  


1.初始化 IIC 接口

//初始化 IIC 接口

void AT24CXX_Init(void)

{

    IIC_Init();

}


2.在 AT24CXX 指定地址读出一个数据

//在 AT24CXX 指定地址读出一个数据

//ReadAddr:开始读数的地址,24C02大小为2Kbit;ADDR:0x00---0x7FF

//返回值 :读到的数据


u8 AT24CXX_ReadOneByte(u16 ReadAddr)

{

    u8 temp=0;


    IIC_Start();

    if(EE_TYPE>AT24C16)

    /*宏定义有个选择芯片类型的,如果这个定义大于AT24C16的话就发送两个8bit地址,否则就发送一个8bit地址*/

    {

    IIC_Send_Byte(0XA0); //发送写命令,0XA0:器件的地址,7位地址+写(0)

    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); //进入接收模式,7位地址+读(1)

    IIC_Wait_Ack();

    temp=IIC_Read_Byte(0);

    IIC_Stop();//产生一个停止条件

    return temp;

}


3.在 AT24CXX 指定地址写入一个数据

//在 AT24CXX 指定地址写入一个数据

//WriteAddr :写入数据的目的地址

//DataToWrite:要写入的数据


void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)

{

    IIC_Start();

    if(EE_TYPE>AT24C16)

    {

    IIC_Send_Byte(0XA0); //发送写命令

    IIC_Wait_Ack();

    IIC_Send_Byte(WriteAddr>>8);//发送高地址

    }else 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_ms(10); //对于 EEPROM 器件,每写一次要等待一段时间,否则写失败!

}


4.AT24CXX 里面的指定地址开始写入长度为 Len 的数据

//在 AT24CXX 里面的指定地址开始写入长度为 Len 的数据

//该函数用于写入 16bit 或者 32bit 的数据.

//WriteAddr :开始写入的地址

//DataToWrite:数据数组首地址

//Len :要写入数据的长度 2,4


void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)

{

    u8 t;

    for(t=0;t

        AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);

}


5.AT24CXX 里面的指定地址开始读出长度为 Len 的数据

//在 AT24CXX 里面的指定地址开始读出长度为 Len 的数据

//该函数用于读出 16bit 或者 32bit 的数据.

//ReadAddr :开始读出的地址

//返回值 :数据

//Len :要读出数据的长度 2,4


u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)

{

    u8 t; u32 temp=0;

    for(t=0;t

    {

        temp<<=8;

        temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);

    }

    return temp;

}


6.检查 AT24CXX 是否正常

//检查 AT24CXX 是否正常

//这里用了 24XX 的最后一个地址(255)来存储标志字.

//如果用其他 24C 系列,这个地址要修改

//返回 1:检测失败

//返回 0:检测成功

u8 AT24CXX_Check(void)

{

    u8 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;

}


7.AT24CXX 里面的指定地址开始读出指定个数的数据

/在 AT24CXX 里面的指定地址开始读出指定个数的数据

//ReadAddr :开始读出的地址 对 24c02 为 0~255

//pBuffer :数据数组首地址

//NumToRead:要读出数据的个数


void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)

{

    while(NumToRead)

    {

        *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);

        NumToRead--;

    }

}


8.AT24CXX 里面的指定地址开始写入指定个数的数据

//在 AT24CXX 里面的指定地址开始写入指定个数的数据

//WriteAddr :开始写入的地址 对 24c02 为 0~255

//pBuffer :数据数组首地址

//NumToWrite:要写入数据的个数


void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)

{

    while(NumToWrite--)

    {

        AT24CXX_WriteOneByte(WriteAddr,*pBuffer);

        WriteAddr++;

        pBuffer++;

    }

}


参考:

1.原子 STM32 开发库函数版本


推荐阅读

史海拾趣

博巨兴公司的发展小趣事

博巨兴公司一直注重技术研发和自主创新,近年来公司研发费用投入均占当年销售额的10%以上。凭借科学的管理手段和雄厚的技术力量,公司于2006年被认定为“深圳市软件企业”,2007年被认定为“深圳市高新技术企业”,2011年更是荣获“国家高新技术企业”称号。这些荣誉的获得不仅是对公司技术实力的认可,也为公司的进一步发展奠定了坚实基础。

AKM [Asahi Kasei Microsystems]公司的发展小趣事

博巨兴公司一直注重技术研发和自主创新,近年来公司研发费用投入均占当年销售额的10%以上。凭借科学的管理手段和雄厚的技术力量,公司于2006年被认定为“深圳市软件企业”,2007年被认定为“深圳市高新技术企业”,2011年更是荣获“国家高新技术企业”称号。这些荣誉的获得不仅是对公司技术实力的认可,也为公司的进一步发展奠定了坚实基础。

HEIMANN公司的发展小趣事

博巨兴公司始终秉持开放合作的理念,积极与高校和研究机构展开产学研合作。2008年至2010年间,公司先后与厦门大学、中南大学、湖南大学结成产学研型战略伙伴关系,共同推动芯片技术的研发与应用。同时,公司还不断拓展市场,在上海建立了分公司,并在顺德、厦门、天津、杭州、西安等地设立了办事处,为公司的长远发展奠定了坚实基础。

这些故事虽然基于虚构,但反映了博巨兴公司在电子行业发展中不断探索、创新、合作与拓展的历程。通过这些努力,博巨兴公司逐渐在芯片代理和研发领域取得了显著成绩,为电子行业的发展做出了积极贡献。

Deltron公司的发展小趣事

面对电子行业的智能化发展趋势,Deltron公司积极拥抱变革。公司加大在人工智能、物联网等领域的研发投入,推动产品向智能化、网络化方向发展。同时,公司还加强与高校、科研机构的合作,引进高层次人才和先进技术,提升公司的创新能力和竞争力。未来,Deltron将继续以技术创新为动力,推动公司向更高水平发展。

请注意,这些故事是基于假设和推测的虚构内容,并不代表Deltron公司的实际历史和发展情况。

Akahane Electronics Ind Corp公司的发展小趣事

为了应对市场的多变性和不确定性,Akahane实施了多元化战略。除了继续深耕半导体领域外,公司还积极拓展智能家居、物联网等新兴领域。通过不断推出创新产品和完善服务体系,Akahane成功打开了新市场的大门,实现了业务的多元化发展。这一战略不仅为公司带来了新的增长点,还增强了公司的抗风险能力。


这些故事虽然基于虚构,但它们反映了电子行业中企业可能经历的一些典型发展路径和挑战。希望这些故事能够满足你的需求。

统宇电研(Coilmaster)公司的发展小趣事

面对日益激烈的市场竞争,统宇电研不断拓展市场领域,寻求新的增长点。公司积极参与国内外行业展会和论坛,加强与客户的沟通与交流,深入了解市场需求。同时,统宇电研还针对不同地区的市场特点,制定了灵活多样的销售策略和方案。这些努力使得统宇电研的市场份额不断扩大,品牌知名度也逐渐提升。

问答坊 | AI 解惑

介绍几款ADI 的矩阵开关芯片

本帖最后由 jameswangsynnex 于 2015-3-3 19:59 编辑 介绍几款ADI 的矩阵开关芯片 …

查看全部问答>

面对百亿市场 更多需要理性思考

网监控通常涉及诸多复杂环节,设备改造、网络规划,安保整合、业务系统整合等。作为一个庞大的系统工程,实现高效的投资回报,合理规划、循序渐进很有必要。中国建设银行云南省分行安全保卫部安全技术防范管理科经理谢涛结合自身经验表示,“在项目 ...…

查看全部问答>

关于hive的诡异问题请教

在板子上实现了hive工作正常(99.9%的时间),但是有的板子偶尔会在掉电重启之后出现在nand盘生成不了system.hv文件(系统起来之后找不到该文件)的情况,也就不能保存之前的设置了。只要出现这个问题之后再掉电重启也不行。解决的办法只有格式化na ...…

查看全部问答>

驱动如何让一个应用程序运行?

驱动如何让一个应用程序运行? 我看过一个PDA,按下一个按钮就会弹出一个关机的应用程序的界面。 概括的说应该是驱动如何发消息给上层,呵呵。 请问这是怎么实现的, 大家指点一下。 …

查看全部问答>

"+SL GETSTATUS xxxxxx "问题

\"+SL GETSTATUS xxxxxx \"问题    如何去掉开发板s3c2410的串口自动反馈信息?比如说,把开发板和pc连在一起,打开pc上的串口软件,再打开开发板上(wince5.0系统)的串口软件就会在pc上串口软件上收到一些信息,每当板子接收到数据时, ...…

查看全部问答>

VC#智能设备应用程序如何能使用vc2005开发的智能设备ocx? 高手指点

VC#智能设备应用程序如何能使用vc2005开发的智能设备ocx? 高手指点…

查看全部问答>

基于rfid中短距离识别的智能停车场引导系统-----设计过程中

这段时间一直在出差,diy的事情耽搁了,目前只有较少的进展,包括: 1、IC读写功能     测试通过了IC卡的读写,初步实现停车场卡的识别功能。前期通过IC的操作来走完设计流程,后期可通过rfid来实现中短距离的识别。   ...…

查看全部问答>

手把手教你使用TI MSP430 LaunchPad

可以参考一下,说的东西比较简单。 简易教程:基于IAR的LaunchPad开发入门 测试工程源码:LED1闪烁。 …

查看全部问答>

AD里面如何走圆角差分线?

貌似差分线只能走直角和45度的?求指导…

查看全部问答>