STM32F103通过IIC总线读取EEPROM

发布者:和谐的24号最新更新时间:2022-01-27 来源: eefocus关键字:STM32F103  IIC总线  读取EEPROM 手机看文章 扫描二维码
随时随地手机看文章

IIC总线是常用的串行总线,它只需要简单的两根线就可以实现数据的高速传输,同时还可以实现多机通信功能。


在单片机中用的比较多的就是通过IIC总线操作EEPROM芯片。比较常用的EEPROM芯片就是24Cxx系列的芯片,主要用来存储系统运行过程中的关键数据。

image.png

要操作这个芯片的话,必须按照一定的时序去读写。这个时序通常被称为通信协议。24Cxx系列芯片通信协议如下。


I2 C 总线协议


I 2 C 总线协议定义如下:


只有在总线空闲时才允许启动数据传送

在数据传送过程中 当时钟线为高电平时 数据线必须保持稳定状态 不允许有跳变 时钟线为高电平时 数据线的任何电平变化将被看作总线的起始或停止信号。

image.png

起始信号


时钟线保持高电平期间 数据线电平从高到低的跳变作为 I 2 C 总线的起始信号


停止信号


时钟线保持高电平期间 数据线电平从低到高的跳变作为 I 2 C 总线的停止信号

image.png

image.png

image.png

image.png

这里就使用最简单的几个通信时序起始、停止、读、写和应答时序。


为了IIC协议的通用性,将这几个协议封装为一个c文件,这样以后每个使用IIC协议的器件都能调用这个文件。


//IIC产生起始信号

void IIC_Start(void)

{

    //START:when CLK is high,DATA change form high to low

    SDA_OUT();

    IIC_SDA = 1;

    IIC_SCL = 1;

    delay_us(4);

    IIC_SDA = 0;

    delay_us(4);

    IIC_SCL = 0;

}

//产生停止信号

void IIC_Stop(void)

{

    //STOP:when CLK is high DATA change form low to high

    SDA_OUT();

    IIC_SCL = 0;

    IIC_SDA = 0;

    delay_us(4);

    IIC_SCL = 1;

    IIC_SDA = 1;

    delay_us(4);

}

//等待应答信号

//返回值: 1 应答失败

//        0 应答成功

u8 IIC_Wait_Ack(void)

{

    u8 errTime = 0;

    SDA_IN();

    IIC_SDA = 1;

    delay_us(1);

    IIC_SCL = 1;

    delay_us(1);

    while(READ_SDA)

    {

        errTime++;

        if(errTime > 250)

        {

            IIC_Stop();

            return 1;

        }

    }

    IIC_SCL = 0;

    return 0;

}

//产生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;

}

//不产生应答

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发送一个字节

void IIC_Send_Byte(u8 txd)

{

    u8 t;

    SDA_OUT();

    IIC_SCL = 0;

    for(t = 0; t < 8; t++)

    {

        if((txd & 0x80) >> 7)

            IIC_SDA = 1;

        else

            IIC_SDA = 0;

        txd <<= 1;

        delay_us(2);

        IIC_SCL = 1;

        delay_us(2);

        IIC_SCL = 0;

        delay_us(2);

    }

}

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

u8 IIC_Read_Byte(unsigned char ack)

{

    unsigned char i, receive = 0;

    SDA_IN();

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

    else

        IIC_Ack();

    return receive;

}


这里将最常用的几个信号封装为函数,当操作24Cxx芯片的时候,直接调用这几个函数。


#include "24Cxx.h"

#include "delay.h"


void AT24Cxx_Init(void)

{

    IIC_Init();

}

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

//ReadAddr:开始读数的地址

//返回值  :读到的数据

u8 AT24Cxx_ReadOneByte(u16 ReadAddr)

{

    u8 temp = 0;

    IIC_Start();

    if(EE_TYPE > AT24C16)

    {

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

        IIC_Wait_Ack();

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

        IIC_Wait_Ack();

    }

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

}

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

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

//WriteAddr  :开始写入的地址

//DataToWrite:数据数组首地址

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

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

{

    u8 t;

    for(t = 0; t < Len; t++)

    {

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

    }

}

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

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

//ReadAddr   :开始读出的地址

//返回值     :数据

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

u32 AT24Cxx_ReadLenByte(u16 ReadAddr, u8 Len)

{

    u8 t;

    u32 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:检测成功

u8 AT24Cxx_Check(void)

{

    u8 temp;

    temp = AT24Cxx_ReadOneByte(255);

    if(temp == 0x55)

        return 0;

    else

    {

        AT24Cxx_WriteOneByte(1023, 0x55);

        temp = AT24Cxx_ReadOneByte(255);

        if(temp == 0x55)

            return 0;

    }

    return 1;

}


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

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

//pBuffer  :数据数组首地址

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

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

{

    while(NumToRead)

    {

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

        NumToRead--;

    }

}

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

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

//pBuffer   :数据数组首地址

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

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

{

    while(NumToWrite--)

    {

        AT24Cxx_WriteOneByte(WriteAddr, *pBuffer);

        WriteAddr++;

        pBuffer++;

    }

}


这里就是对具体的芯片操作函数,在主函数中通过这几个函数就可读写EEPROM存储芯片的内容了。


int main(void)

{


    u8 key;

    u16 i = 0, j = 0;

    u8 datatemp[SIZE];


    delay_init();

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    uart_init(115200);

    LED_Init();

    KEY_Init();

   

    AT24Cxx_Init();


    printf("IIC test!!!rn");

    while(AT24Cxx_Check())

    {

        printf("The chip is not detected, please check whether the hardware connection is normal!!!rn");

        delay_ms(300);

        LED1 = !LED1;

    }


    while(1)

    {


        key = KEY_Sacn(0);

        if(key == WKUP_PRES)

        {

            printf("rnStart Write 24C02....rn");

            AT24Cxx_Write(0, (u8 *)TEXT_Buffer, SIZE);

            printf("24C02 Write Finished!rn");

        }

        else if(key == KEY1_PRES)

        {

            printf("rnStart Read 24C02....rn");

            AT24Cxx_Read(0, datatemp, SIZE);

            printf("The Data Readed Is:  ");

            for(j = 0; j < SIZE; j++)

            {

                printf("%c", datatemp[j]);

            }

        }


        i++;

        if(i == 20)

        {

            i = 0;

            LED0 = !LED0;

        }

        delay_ms(5);

    }

}


这里通过按键来测试存储芯片,一个按键按下后向芯片内写入数据,另一个按键按下后从芯片中读取刚才写入的内容。

关键字:STM32F103  IIC总线  读取EEPROM 引用地址:STM32F103通过IIC总线读取EEPROM

上一篇:STM32F103定时器输入捕获功能
下一篇:STM32F103外部中断实现

推荐阅读最新更新时间:2024-11-13 10:40

stm32f103 flash模拟eeprom
STM32F103是意法半导体(STMicroelectronics)推出的一款32位单片机系列,该系列芯片具有高性能和丰富的外设接口,广泛应用于工业控制、消费电子、汽车电子等领域。其中,STM32F103的Flash存储器可以模拟EEPROM的功能,在本文中我们将详细介绍如何使用STM32F103的Flash存储器来实现EEPROM。 概述 EEPROM(Electrically Erasable Programmable Read-Only Memory)是一种可擦写的非易失性存储器,可以在不使用外部电压的情况下对其进行擦除和编程。它不同于Flash存储器的主要特点是可以对单个字节进行随机读写操作。而STM32F103的Fl
[单片机]
STM32F103_TIM3输出PWM波实现全彩呼吸灯
一、LED灯 1. 必须是全彩RGB_LED灯 2. 通过不同的红绿蓝三色LED混合出256种颜色,同电脑画图里的调色RGB888,每个灯各用8位控制其亮度,其中全灭表示黑色。 二、 1. LED亮度等级表 /* LED亮度等级 PWM表,指数曲线 ,此表使用工程目录下的python脚本index_wave.py生成*/ const uint16_t indexWave = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 12
[单片机]
stm32f103c8t6最小系统AD工程,封装
7*7厘米大小,稳压用的LM1117s,已经打印焊接过了,可以用。两边的是焊盘不能焊排针。因为是新手画的板子比较大。反正能用,LED灯的焊盘稍微有点问题,焊盘距离有点大,但也能焊上。其他封装都没什么问题。当初画的时候找封装找了好久,在这里发一下,看到的直接用就好了。
[单片机]
<font color='red'>stm32f103</font>c8t6最小系统AD工程,封装
精英STM32F103开发板试用体验:+OLED屏显示功能的实现
鉴于STM32F103开发板没有配置显示屏,因此要显示一些信息除了借助串行通讯,就必须为其添加相应的显示器件了。在初步掌握GPIO口的基础上,最好是以OLED屏为显示器件。 OLED屏有多种类型,按色彩分有单色屏、双色屏及彩色屏;按接口方式分有并口屏、SPI接口屏及IIC接口屏。这里所选用的IIC接口的双色OLED屏,该显示屏在工作时只需占用2个GPIO口,所以该器件很有特色,图1是其显示效果。 图1OLED屏显示效果 在STM32F103开发板所配的光盘中,也有OLED屏显示例程但它是并口屏,并与OV7670摄像头共用同一接口,其接口的原理图如图2所示。 图2接口原理图 在IIC接口的使用方式中,我们只用到PC0和
[单片机]
精英<font color='red'>STM32F103</font>开发板试用体验:+OLED屏显示功能的实现
STM32F103串口1和串口2不同波特率之间交换数据问题
前几天写一个东西,要用到STM32F103的串口1和串口2以不同的波特率交换数据,也就是说串口1波特率为9600,串口2波特率为115200,串口1可以把接收到的数据通过串口2发送出去,串口2也可以把接收到的数据通过串口1发送出去。低波特率向高波特率发送数据没问题,高波特率向低波特率发送数据会丢数据,原因是低波特率的串口还没发送完数据高波特率的串口就又发数据过来了,处理不过来。在同事的在帮助下,写出一个先进先出环形队列(FIFO)程序。接收数据用中断,发送数据用在主函数中查询发送完成标志位。希望对大家有点帮助,可能程序不完美,但程序可以用。定义一个fifo.h部件和一个fifo.c文件。其他的都在主函数中调用。 #ifndef
[单片机]
51单片机 EEPROM 24c02 读取存储多字节
先将数据存进去,然后再读出来显示在数码管上。 除了代码里定义的连线外还要把p0连接到8位数码管的8针上。 1 /*-- 2 名称:IIC协议 EEPROM24c02 3 内容:此程序用于检测EEPROM性能,测试方法如下:写入24c02一些数据,然后在内存中清除这些数据, 4 掉电后主内存将失去这些信息,然后从24c02中调入这些数据。看是否与写入的相同。 5 函数是采用软件延时的方法产生SCL脉冲,固对高晶振频率要作 一定的修改....(本例是1us机器 6 周期,即晶振频率要小于12MHZ) 7 */ 8 #include reg52.h //头文件的包含 9 #include intrins.
[单片机]
使用STM32CubeMX,生成STM32F103ZE SPI3 HAL 工程
1,选择芯片型号为STM32F103ZET6,开始工程,引脚配置如下: 主要是RCC,SPI3,和SYS三个模块 2,时钟配置,可按下图进行: 3,SPI3配置,如下图,配完这一步其它可以不管,直接生成工程。 4,生成工程,打开工程 手动输入红框中内容。 运行:成功输出波形。
[单片机]
使用STM32CubeMX,生成<font color='red'>STM32F103</font>ZE SPI3 HAL 工程
stm32f103zet6定时器详解及应用
  1、stm32f103zet6芯片及引脚图        2、stm32f103xx器件功能与配置      3、stm32f103zet6 定时器   大容量的STM32F103XX增强型系列产品包含最多2个高级控制定时器、4个普通定时器和2个基本定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。   下表比较了高级控制定时器、普通定时器和基本定时器的功能:   定时器功能比较      1)计数器三种计数模式   向上计数模式:从0开始,计到arr预设值,产生溢出事件,返回重新计时   向下计数模式:从arr预设值开始,计到0,产生溢出事件,返回重新计时   中央对齐模式:从0开始向上计数,计到arr产生溢出事件,然后
[单片机]
<font color='red'>stm32f103</font>zet6定时器详解及应用

推荐帖子

关于linux自定制,请教-:新手上路
新手中的新手!望大家慷慨相助或是提供帮助信息、教程之类的:)想要自定制一个剪裁过的linux系统,现在手里有一套DellOptilex745n系列电脑赠送的redhat安装盘,请问是否能够靠它剪裁出自己希望的小规模系统。目标硬件平台为PC104,CPU:AMD嵌入式,主频500M,内存256M,CF卡容量1G,显示屏为标准的VGA接口LCD。要求:剪裁出的系统具有网络、串口、键盘、显示驱动功能,开发工具Qt3.2,其开发的软件能够在目标机稳定运行,程序主要做显示、键盘参数录入
huangluling Linux与安卓
RISC-V处理器设计系列课程——CPU基础知识
主要为大家介绍一下CPU相关的基础知识,从CPU发展的角度来看RISC-V的诞生缘由RISC-V处理器设计系列课程——CPU基础知识
火辣西米秀 国产芯片交流
关于OPA847的自激
上面是制成的PCB电路板,反馈电阻接的是滑动变阻器,焊好之后上电测试就发现自激了,没有输入信号的时候就有了输出,大概660MHz,检查了电路板发现也没什么问题。不知道问题出在哪里,哪位老师能帮我看看?关于OPA847的自激@maychang@gmchen这类高带宽高增益运放,本来就是很难使用的,必须严格按照说明书中所指示的注意事项使用。不像LM358之类,电路板无论怎么布局大致上都稳定工作。把电原理图贴出来,请教gmchen老师吧。我在这方面经验不多。没看到原理图,就看到的实
Alexline 模拟电子
用ST的JOYSTICK例程改的程序,端点3无**常发送数据
UserToPMABufferCopy(Key_Buffer,GetEPTxAddr(ENDP1),9);//*enableendpointfortransmissionSetEPTxCount(ENDP1,9);SetEPTxValid(ENDP1);用端点1能正常发送数据,但把上述ENDP1改成ENDP3,发送了9个随机数。设置如下:/*txbufferbaseaddress*/#defineENDP1_TXADDR(0x100)#d
wang1jin stm32/stm8
点阵屏的任意级联原理
利用75HC595串行移动功能和存功能,支持理论上任意长度级联,不知道正确否?欢迎大家指正点阵屏的任意级联原理条件是没有寄生电感和电容过长时可以中间加245做驱动楼上兄弟都做过LED显示屏的吧近期打算做过LED显示控制器,希望大家多多帮组
eeleader 工控电子
MF RC500
MFRC500是应用于13.56MHz非接触式通信中高集成读卡IC系列中的一员。该读卡IC系列利用了先进的调制和解调概念,完全集成了在13.56MHz下所有类型的被动非接触式通信方式和协议。MFRC500支持ISO14443A所有的层。内部的发送器部分不需要增加有源电路就能够直接驱动近操作距离的天线(可达100mm)。接收器部分提供一个坚固而有效的解调和解码电路,用于ISO14443A兼容的应答器信号。数字部分处理ISO14443A帧和错误检测(奇偶&CRC)。此外,它还支持快速CR
rain RF/无线
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved