STM32-I2C驱动-AT24C02-EEPROM

SOC:STM32F103RCT6    PB10作为SCL和AT24C02相连,PB11作为SDL和AT24C02相连。
软件平台:STM官方库V3.5.0
开发工具:Keil

AT24C022C访问代码(轮询)
I2C这里使用轮询方法,不是中断,请留意。

首先,给出I2C控制器的初始化代码,和读写代码,一共三个函数,对应三个功能
注意:这里是使用I2C控制器2。
 

1. uint16_t I2C_OwnAddress1 :芯片的地址0XA0   在芯片手册中能查到

2.EEPROM需要注意下面参数:I2C_PageSize ATMEL芯片中,2K以下为8byte一页,4K以上16字节为一页,其他厂家有不同

3.配置,这里全部用4.7K电阻上拉,所以GPIO模式为:GPIO_Mode_AF_OD,这样,AT24C02的初始化配置完成

4.结构体初始化完成以后,用CMD命令打开I2C模块

 

从设备地址

在进行I2C通信时,主机发送启动信号后,再发送寻址信号。器件的地址有7位和10位,以7为地址寻址为例,寻址信号由一个字节构成,高7位为地址位,最低位为方向位,用来表示主机与从器件的数据传输方向,方向位0代表主机接下来对从器件进行写操作,

方向位为1,表明主机接下来对器件进行读操作。  

AT24C02的高4位是固定的,为1010b,低3位则由A0/A1/A2信号线的电平决定。按照我们此处的连接, A0/A1/A2 均为 0,所以 EEPROM 的 7 位设备地址是: 1010 000b ,即 0x50。由于 I2C 通讯时常常是地址跟读写方向连在一起构成一个 8 位数,且当R/W 位为 0 时,表示写方向,所以加上 7 位地址,其值为“ 0xA0”,常称该值为 I2C 设备的“写地址”;当 R/W 位为 1 时,表示读方向,加上 7 位地址,其值为“ 0xA1”,常称该值为“读地址”。

A0/A1/A2输入脚用于多个器件级联时设置器件地址,当这些脚悬空时默认值为0。当使用AT24C02 时最大可级联8个器件。如果只有一个AT24C02被总线寻址,这三个地址输入脚(A0、A1、A2 )可悬空(接地也可以)或连接到Vss,如果只有一个AT24C01被总线寻址这三个地址输入脚(A0、A1、A2 )必须连接到Vss。

I2C协议:①空闲状态 I2C总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。

此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。②开始信号 起始信号:当SCL为高期间,SDA由高到低的跳变;停止信号:当SCL为高期间,SDA由低到高的跳变;注:起始/停止信号是一种电平跳变时序信号,而不是一个电平信号。④应答信号 发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。  对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。⑤数据的有效性 I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。 即:数据在SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。⑥数据传输在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发。

24C02的读/写操作:

写入过程:发送器件地址(0XA0)发送要写入24C02的内存地址发送要写入的数据发送器件地址的格式

高四位1010是24Cxx系列的固定器件地址,接下来是A2、A1、A0是根据器件连接来决定,我们的原理图都接地所以是000。R/W为是选择读还是写,1的时候是读,0的时候是写。所以写的地址为0xA0。

读出过程:发送写入的器件地址(0XA0)发送要读的24C02的内存地址发送读出的器件地址(0XA1)读取数据当读取的时候,地址的最后一位R/W为是选择读,也就是该位为1。所以读取的地址为0xA1。

#include "stm32f10x.h"
#include "stm32f10x_i2c.h"
#include <stdio.h>
 
/* i2c 写一个字节*/
void I2C2_WriteByte(uint8_t DeviceAddress, uint8_t MemoryAddress, uint8_t Data)
{
    while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY));       //等待I2C空闲 
 
    //start
    I2C_GenerateSTART(I2C2, ENABLE);
    while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS ); 
    
    //device address
    I2C_Send7bitAddress(I2C2, DeviceAddress, I2C_Direction_Transmitter); //写模式
    while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS );     
    //printf("address over\r\n") ; 
 
    //memory address
    I2C_SendData(I2C2, MemoryAddress);
    while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS ); 
            
    //data
    I2C_SendData(I2C2, Data);
    while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS );     
 
    //stop
    I2C_GenerateSTOP(I2C2, ENABLE); 
}
 
/* i2c 读一个字节*/
uint8_t I2C2_ReadByte(uint8_t DeviceAddress, uint8_t MemoryAddress)
{
    uint8_t    Data;
    
    while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY));       //等待I2C空闲  

    //start
    I2C_GenerateSTART(I2C2, ENABLE);
    while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS ); //ev5 
 
    //device address
    I2C_Send7bitAddress(I2C2, DeviceAddress, I2C_Direction_Transmitter);  //写模式
    while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS );     //ev6 
     
    //memory address
    I2C_SendData(I2C2,  MemoryAddress);
    while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS ) ; 
                                                                          
    //start
    I2C_GenerateSTART(I2C2, ENABLE);
    while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS ) ;     
 
    //device address
    I2C_Send7bitAddress(I2C2, DeviceAddress, I2C_Direction_Receiver); //读模式
    while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS ) ;
    
    /* 按照manual的图273,先读取数据,关闭ACK应答,最后发出STOP*/       
    while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS );   /* 等待读取事件,再读取数据 */
       Data = I2C_ReceiveData(I2C2); 
        I2C_AcknowledgeConfig(I2C2, DISABLE); //关闭应答和停止条件产生  
    printf("received\r\n");

    //stop
    I2C_GenerateSTOP(I2C2, ENABLE); 

    I2C_AcknowledgeConfig(I2C2, ENABLE); 
    return Data;
}


接着给出相应的AT24C02访问代码

#include "stm32f10x.h"
#include "stm32f10x_i2c.h"
#include "i2c.h"
#include "delay.h"
#include <stdio.h>
 
I2C2_ReadByte(0xA0, ReadAddr); /* 从AT24CXX的指定地址开始读出一个字节 */
I2C2_WriteByte(0xA0, WriteAddr, Data); /* 向AT24CXX的指定地址开始写入一个字节 */
 
void AT24CXX_test(void)
{
    uint8_t i;
    I2C_InitTypeDef I2C_InitStructure; 
    GPIO_InitTypeDef GPIO_InitStruct; 
 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);     
    
    GPIO_InitStruct.GPIO_Pin =  GPIO_Pin_10 | GPIO_Pin_11;        
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;        
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOB, &GPIO_InitStruct); 

    I2C_InitStructure.I2C_ClockSpeed     =  200000;       //200kHZ
    I2C_InitStructure.I2C_Mode             =  I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle     =  I2C_DutyCycle_2;    //根据datasheet,Tlow/Thigh = 2
    I2C_InitStructure.I2C_OwnAddress1     =  0xA0;         
    I2C_InitStructure.I2C_Ack              =  I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_Init(I2C2, &I2C_InitStructure);
    I2C_Cmd(I2C2, ENABLE);
    
/*    
    NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn   ;                //I2C事件中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;    //抢占优先级1 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;            //子优先级2 
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;               //使能中断通道
    NVIC_Init(&NVIC_InitStructure);     //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    //I2C_ITConfig(I2C2, I2C_IT_EVT, ENABLE); //打开事件中断
 */

    for(i = 0; i < 10; i++){    
        I2C2_WriteByte(0xA0, i, 100 + i);
        /* NOTE: 根据datasheet,两次字节写之间必须延迟5ms,也就是stop和start之间的间隔时间*/
        delay_ms(6);  
    }
    printf("Write completed \r\n");
 
    for(i = 0; i < 10; i++){    
        printf("%d ", I2C2_ReadByte(0xA0, i));
        delay_ms(6);
    }
    printf("\r\n");
}

注意:两次访问间隔必须大于5ms,这是datasheet规定的。
如果不加延时,第二次写入时候,写入设备地址后,无法接受到ACK,程序陷入死循环。
 

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值