STM32 第19讲 IIC(协议简介/读取驱动AT24C02/实验)

这篇具有很好参考价值的文章主要介绍了STM32 第19讲 IIC(协议简介/读取驱动AT24C02/实验)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

IIC总线协议介绍

IIC: Inter Integrated Circuit,集成电路总线,是一种同步 串行 半双工通信协议

IIC总线结构图

at24c02 驱动,单片机学习笔记,单片机,网络,嵌入式硬件
①总线由数据线 SDA 和时钟线 SCL 构成的串行总线,数据线用来传输数据,时钟线用来同步数据收发。
②总线上每一个器件都有一个唯一的地址识别,所以我们只需要知道器件的地址,根据时序就可以实现微控制器与器件之间的通信。
③数据线 SDA 和时钟线 SCL 都是双向线路,都通过一个电流源或上拉电阻连接到正的电压,所以当总线空闲的时候,这两条线路都是高电平
④总线上数据的传输速率在标准模式下可达 100kbit/s 在快速模式下可达 400kbit/s,在高速模式下可达 3.4Mbit/s。
⑤总线支持设备连接。在使用 IIC 通信总线时,可以有多个具备 IIC 通信能力的设备挂载在上面,同时支持多个主机和多个从机,连接到总线的接口数量只由总线电容 400pF 的限制决定。

IIC协议

at24c02 驱动,单片机学习笔记,单片机,网络,嵌入式硬件

可以归纳为

  1. 三个信号:起始信号、停止信号、应答信号
  • ①起始信号:当 SCL 为高电平期间,SDA 由高到低的跳变。起始信号是一种电平跳变时序信号,而不是一个电平信号。该信号由主机发出,在起始信号产生后,总线就处于被占用状态,准备数据传输。

  • ②停止信号:当 SCL 为高电平期间,SDA 由低到高的跳变。停止信号也是一种电平跳变时序信号,而不是一个电平信号。该信号由主机发出,在停止信号发出后,总线就处于空闲状态。

  • ③应答信号:发送器每发送一个字节,就在时钟脉冲 9 期间释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK 简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有功。

  1. 两个注意:数据有效性、数据传输
  • ④数据有效性:IIC 总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。数据在 SCL 的上升沿到来之前就需准备好。并在下降沿到来之前必须稳定。

  • ⑤数据传输:在 I2C 总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在 SCL 串行时钟的配合下,在 SDA 上逐位地串行传送每一位数据。数据位的传输是边沿触发

  1. 一个状态:空闲状态
  • ⑥空闲状态:IIC 总线的 SDA 和 SCL 两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。

IIC读写通讯过程

at24c02 驱动,单片机学习笔记,单片机,网络,嵌入式硬件

  • step1:主机首先在 IIC 总线上发送起始信号,那么这时总线上的从机都会等待接收由主机发出的数据。
  • step2:主机接着发送从机地址+0(写操作)组成的 8bit 数据,所有从机接收到该 8bit 数据后,自行检验是否是自己的设备的地址,假如是自己的设备地址,那么从机就会发出应答信号
  • step3:主机在总线上接收到有应答信号后,才能继续向从机发送数据。IIC 总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号。
    at24c02 驱动,单片机学习笔记,单片机,网络,嵌入式硬件
  • step1:主机发出起始信号,接着发送从机地址+1(读操作)组成的 8bit 数据
  • step2:从机接收到数据验证是否是自身的地址。 那么在验证是自己的设备地址后,从机就会发出应答信号,并向主机返回 8bit 数据,发送完之后从机就会等待主机的应答信号
  • step3:假如主机一直返回应答信号,那么从机可以一直发送数据,也就是图中的(n byte + 应答信号)情况,直到主机发出非应答信号,从机才会停止发送数据。

24C02 简介

24C02 是一个 2K bit 的串行 EEPROM 存储器,内部含有 256 个字节。在 24C02 里面还有一个 8 字节的页写缓冲器。该设备的通信方式 IIC,通过其 SCL 和 SDA 与其他设备通信。
单片机内部的ROM只能在程序下载时进行擦除和改写,程序运行时本身是不能改写的,单片机内部的RAM中的数据程序运行时可以修改,但掉电丢失,所以需要用到数据存在系统中且掉电不丢失时需要用到EEPROM。
at24c02 驱动,单片机学习笔记,单片机,网络,嵌入式硬件

  • WP引脚:写保护引脚,高电平时只读,接地时允许读写。
  • 24C02设备地址:可编程部分+不可编程部分
    可编程部分由A0,A1,A2决定,最后一位设置数据传输方向,即0–>写操作,1–>读操作,其具体格式为:
    at24c02 驱动,单片机学习笔记,单片机,网络,嵌入式硬件

24C02读写时序图

写时序图

at24c02 驱动,单片机学习笔记,单片机,网络,嵌入式硬件

  • step1:主机在IIC总线发送第1个字节的数据为设备地址0xA0,用于寻找总线上的24C02
  • step2:在获得应答信号后,主机继续发送第2个字节的数据,为24C02的内存地址
  • step3:在获得应答信号后,主机发送第3个字节的数据,为写入在第二字节内存地址处的数据。

上面的写操作只能单字节写入到24C02,效率低下,24C02具有页写时序如图所示。
at24c02 驱动,单片机学习笔记,单片机,网络,嵌入式硬件
在页写时序中,只需要告诉 24C02 第一个内存地址 1,后面数据会按照顺序写入到内存地址 2,内存地址 3等。

读时序

at24c02 驱动,单片机学习笔记,单片机,网络,嵌入式硬件
24C02 读取数据的过程是一个复合的时序,其中包含写时序和读时序

  • step1:起始信号后,主机向24C02发送设备地址0xA0,获取从机应答信号后,接着发送需要读取内存地址
  • step2:起始信号产生后主机发送24C02设备地址0xA1,获取从机应答信号后,接着从机返回刚刚写入内存地址中的数据。如果主机获得数据后返回的是应答信号,那么会一直获取从机返回的数据,当主机返回非应答信号时,从机结束传输

实验

实现功能

每按下 KEY1,MCU 通过 IIC 总线向 24C02 写入数据,通过按下 KEY0 来控制 24C02 读取数据。同时在 LCD 上面显示相关信息。LED0 闪烁用于提示程序正在运行。

实验原理

24C02 的 SCL 和 SDA 分别连接在 STM32 的 PB8 和 PB9 上。本实验通过软件模拟 IIC 信号建立起与 24C02 的通信,进行数据发送与接收,使用按键 KEY0 和 KEY1 去触发,LCD 屏幕进行显示。
用软件模拟 IIC,最大的好处就是方便移植,同一个代码兼容所有 MCU,任何一个单片机只要有 IO 口,就可以很快的移植过去,而且不需要特定的 IO 口。
at24c02 驱动,单片机学习笔记,单片机,网络,嵌入式硬件

流程图

at24c02 驱动,单片机学习笔记,单片机,网络,嵌入式硬件

代码

IIC底层驱动代码

  • myiic.h
#ifndef __MYIIC_H
#define __MYIIC_H

#include "./SYSTEM/sys/sys.h"


/******************************************************************************************/
/* 引脚 定义 */

#define IIC_SCL_GPIO_PORT               GPIOB
#define IIC_SCL_GPIO_PIN                GPIO_PIN_8
#define IIC_SCL_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 */

#define IIC_SDA_GPIO_PORT               GPIOB
#define IIC_SDA_GPIO_PIN                GPIO_PIN_9
#define IIC_SDA_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 */

/******************************************************************************************/

/* IO操作 */
#define IIC_SCL(x)        do{ x ? \
                              HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_RESET); \
                          }while(0)       /* SCL */

#define IIC_SDA(x)        do{ x ? \
                              HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_RESET); \
                          }while(0)       /* SDA */

#define IIC_READ_SDA     HAL_GPIO_ReadPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) /* 读取SDA */


/* IIC所有操作函数 */
void iic_init(void);            /* 初始化IIC的IO口 */
void iic_start(void);           /* 发送IIC开始信号 */
void iic_stop(void);            /* 发送IIC停止信号 */
void iic_ack(void);             /* IIC发送ACK信号 */
void iic_nack(void);            /* IIC不发送ACK信号 */
uint8_t iic_wait_ack(void);     /* IIC等待ACK信号 */
void iic_send_byte(uint8_t txd);/* IIC发送一个字节 */
uint8_t iic_read_byte(unsigned char ack);/* IIC读取一个字节 */

#endif
  • myiic.c
    ①初始化IIC
    SDA开漏模式,不用规定IO方向,也可以读取外部信号的高低电平。
void iic_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;

    IIC_SCL_GPIO_CLK_ENABLE();  /* SCL引脚时钟使能 */
    IIC_SDA_GPIO_CLK_ENABLE();  /* SDA引脚时钟使能 */

    gpio_init_struct.Pin = IIC_SCL_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;        /* 推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 快速 */
    HAL_GPIO_Init(IIC_SCL_GPIO_PORT, &gpio_init_struct);/* SCL */

    gpio_init_struct.Pin = IIC_SDA_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD;        /* 开漏输出 */
    HAL_GPIO_Init(IIC_SDA_GPIO_PORT, &gpio_init_struct);/* SDA */
    /* SDA引脚模式设置,开漏输出,上拉, 这样就不用再设置IO方向了, 开漏输出的时候(=1), 也可以读取外部信号的高低电平 */

    iic_stop();     /* 停止总线上所有设备 */
}

②IIC延时函数用于控制IIC读写速度

static void iic_delay(void)
{
    delay_us(2);    /* 2us的延时, 读写速度在250Khz以内 */
}

③起始信号

void iic_start(void)
{
    IIC_SDA(1);
    IIC_SCL(1);
    iic_delay();
    IIC_SDA(0);     /* START信号: 当SCL为高时, SDA从高变成低, 表示起始信号 */
    iic_delay();
    IIC_SCL(0);     /* 钳住I2C总线,准备发送或接收数据 */
    iic_delay();
}

④停止信号

void iic_stop(void)
{
    IIC_SDA(0);     /* STOP信号: 当SCL为高时, SDA从低变成高, 表示停止信号 */
    iic_delay();
    IIC_SCL(1);
    iic_delay();
    IIC_SDA(1);     /* 发送I2C总线结束信号 */
    iic_delay();
}

at24c02 驱动,单片机学习笔记,单片机,网络,嵌入式硬件
⑤发送函数
将需要发送的数据作为形参,形参大小位1字节,在IIC中一个时钟信号发送1bit,故该函数需要循环8次,模拟8个时钟信号。
at24c02 驱动,单片机学习笔记,单片机,网络,嵌入式硬件

void iic_send_byte(uint8_t data)
{
    uint8_t t;
    
    for (t = 0; t < 8; t++)
    {
        IIC_SDA((data & 0x80) >> 7);    /* 高位先发送 */
        iic_delay();
        IIC_SCL(1);
        iic_delay();
        IIC_SCL(0);
        data <<= 1;     /* 左移1位,用于下一次发送 */
    }
    IIC_SDA(1);         /* 发送完成, 主机释放SDA线 */
}

⑥IIC读取函数
首先需要一个变量 receive 存放接收到的数据,在每一次循环开始前都需要对 receive 进行左移 1 位操作,那么 receive 的 bit0 位每一次赋值前都是空的,用来存放最新接收到的数据位,然后在 SCL 线进行高低电平切换时输出 IIC 时钟,在 SCL 高电平期间加入延时,确保有足够的时间能让数据发送并进行处理,使用宏定义 IIC_READ_SDA 就可以判断读取到的高低电平,假如 SDA 为高电平,那么 receive++即在 bit0 置 1,否则不做处理即保持原来的0 状态。当 SCL 线拉低后,需要加入延时,便于从机切换 SDA 线输出数据。在 8 次循环结束后,我们就获得了 8bit 数据,把它作为返回值返回,然而按照时序图,作为主机就需要发送应答或者非应答信号,去回复从机。

uint8_t iic_read_byte(uint8_t ack)
{
    uint8_t i, receive = 0;

    for (i = 0; i < 8; i++ )    /* 接收1个字节数据 */
    {
        receive <<= 1;  /* 高位先输出,所以先收到的数据位要左移 */
        IIC_SCL(1);
        iic_delay();

        if (IIC_READ_SDA)
        {
            receive++;
        }
        
        IIC_SCL(0);
        iic_delay();
    }

    if (!ack)
    {
        iic_nack();     /* 发送nACK */
    }
    else
    {
        iic_ack();      /* 发送ACK */
    }

    return receive;
}

⑦等待从机应答信号
该函数主要用在写时序中,当启动起始信号,发送完8bit 数据到从机时,我们就需要等待以及处理接收从机发送过来的响应信号或者非响应信号,一般就是在 iic_send_byte 函数后面调用。
在这个等待读取的过程中加入了超时判断,假如超过这个时间没有接收到数据,那么主机直接发出停止信号,跳出循环,返回等于 1的变量。在正常等待到应答信号后,主机会把 SCL 时钟线拉低并延时,返回是否接收到应答信号。

uint8_t iic_wait_ack(void)
{
    uint8_t waittime = 0;
    uint8_t rack = 0;

    IIC_SDA(1);     /* 主机释放SDA线(此时外部器件可以拉低SDA线) */
    iic_delay();
    IIC_SCL(1);     /* SCL=1, 此时从机可以返回ACK */
    iic_delay();

    while (IIC_READ_SDA)    /* 等待应答 */
    {
        waittime++;

        if (waittime > 250)
        {
            iic_stop();
            rack = 1;
            break;
        }
    }

    IIC_SCL(0);     /* SCL=0, 结束ACK检查 */
    iic_delay();
    return rack;
}

⑧产生ACK应答

void iic_ack(void)
{
    IIC_SDA(0);     /* SCL 0 -> 1 时 SDA = 0,表示应答 */
    iic_delay();
    IIC_SCL(1);     /* 产生一个时钟 */
    iic_delay();
    IIC_SCL(0);
    iic_delay();
    IIC_SDA(1);     /* 主机释放SDA线 */
    iic_delay();
}

⑨不产生ACK应答

void iic_nack(void)
{
    IIC_SDA(1);     /* SCL 0 -> 1  时 SDA = 1,表示不应答 */
    iic_delay();
    IIC_SCL(1);     /* 产生一个时钟 */
    iic_delay();
    IIC_SCL(0);
    iic_delay();
}

24C02驱动代码

  • 24cxx.h
#ifndef __24CXX_H
#define __24CXX_H

#include "./SYSTEM/sys/sys.h"


#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

/* 开发板使用的是24c02,所以定义EE_TYPE为AT24C02 */

#define EE_TYPE     AT24C02

void at24cxx_init(void);        /* 初始化IIC */
uint8_t at24cxx_check(void);    /* 检查器件 */
uint8_t at24cxx_read_one_byte(uint16_t addr);                       /* 指定地址读取一个字节 */
void at24cxx_write_one_byte(uint16_t addr,uint8_t data);            /* 指定地址写入一个字节 */
void at24cxx_write(uint16_t addr, uint8_t *pbuf, uint16_t datalen); /* 从指定地址开始写入指定长度的数据 */
void at24cxx_read(uint16_t addr, uint8_t *pbuf, uint16_t datalen);  /* 从指定地址开始读出指定长度的数据 */

#endif
  • 24cxx.c
    ①指定地址写入一个数据
    主机发送的设备地址和内存地址共同确定了要写入的地方, iic_send_byte(0XA0+((addr>>8)<<1))和 iic_send_byte(addr % 256)确定写入位置,由于它内存大小一共 2048 字节,所以只需要定义 11 个寻址地址线,2048 = 2^11。主机下发读写命令的时候带了 3 位,后面再跟 1 个字节(8 位)的地址,正好 11 位,就不需要再发后续的地址字节了。
void at24cxx_write_one_byte(uint16_t addr, uint8_t data)
{
    /* 原理说明见:at24cxx_read_one_byte函数, 本函数完全类似 */
    iic_start();    /* 发送起始信号 */

    if (EE_TYPE > AT24C16)      /* 24C16以上的型号, 分2个字节发送地址 */
    {
        iic_send_byte(0xA0);    /* 发送写命令, IIC规定最低位是0, 表示写入 */
        iic_wait_ack();         /* 每次发送完一个字节,都要等待ACK */
        iic_send_byte(addr >> 8);   /* 发送高字节地址 */
    }
    else
    {
        iic_send_byte(0xA0 + ((addr >> 8) << 1));   /* 发送器件 0xA0 + 高位a8/a9/a10地址,写数据 */
    }
    
    iic_wait_ack();             /* 每次发送完一个字节,都要等待ACK */
    iic_send_byte(addr % 256);  /* 发送低位地址 */
    iic_wait_ack();             /* 等待ACK, 此时地址发送完成了 */
    
    /* 因为写数据的时候,不需要进入接收模式了,所以这里不用重新发送起始信号了 */
    iic_send_byte(data);        /* 发送1字节 */
    iic_wait_ack();             /* 等待ACK */
    iic_stop();                 /* 产生一个停止条件 */
    delay_ms(10);               /* 注意: EEPROM 写入比较慢,必须等到10ms后再写下一个字节 */
}

uint8_t at24cxx_read_one_byte(uint16_t addr)
{
    uint8_t temp = 0;
    iic_start();    /* 发送起始信号 */

    /* 根据不同的24CXX型号, 发送高位地址
     * 1, 24C16以上的型号, 分2个字节发送地址
     * 2, 24C16及以下的型号, 分1个低字节地址 + 占用器件地址的bit1~bit3位 用于表示高位地址, 最多11位地址
     *    对于24C01/02, 其器件地址格式(8bit)为: 1  0  1  0  A2  A1  A0  R/W
     *    对于24C04,    其器件地址格式(8bit)为: 1  0  1  0  A2  A1  a8  R/W
     *    对于24C08,    其器件地址格式(8bit)为: 1  0  1  0  A2  a9  a8  R/W
     *    对于24C16,    其器件地址格式(8bit)为: 1  0  1  0  a10 a9  a8  R/W
     *    R/W      : 读/写控制位 0,表示写; 1,表示读;
     *    A0/A1/A2 : 对应器件的1,2,3引脚(只有24C01/02/04/8有这些脚)
     *    a8/a9/a10: 对应存储整列的高位地址, 11bit地址最多可以表示2048个位置, 可以寻址24C16及以内的型号
     */    
    if (EE_TYPE > AT24C16)      /* 24C16以上的型号, 分2个字节发送地址 */
    {
        iic_send_byte(0xA0);    /* 发送写命令, IIC规定最低位是0, 表示写入 */
        iic_wait_ack();         /* 每次发送完一个字节,都要等待ACK */
        iic_send_byte(addr >> 8);   /* 发送高字节地址 */
    }
    else 
    {
        iic_send_byte(0xA0 + ((addr >> 8) << 1));   /* 发送器件 0xA0 + 高位a8/a9/a10地址,写数据 */
    }
    
    iic_wait_ack();             /* 每次发送完一个字节,都要等待ACK */
    iic_send_byte(addr % 256);  /* 发送低位地址 */
    iic_wait_ack();             /* 等待ACK, 此时地址发送完成了 */
    
    iic_start();                /* 重新发送起始信号 */ 
    iic_send_byte(0xA1);        /* 进入接收模式, IIC规定最低位是1, 表示读取 */
    iic_wait_ack();             /* 每次发送完一个字节,都要等待ACK */
    temp = iic_read_byte(0);    /* 接收一个字节数据 */
    iic_stop();                 /* 产生一个停止条件 */
    return temp;
}

③检查AT24CXX是否正常
这里利用的是 EEPROM 芯片掉电不丢失的特性,在第一次写入了某个值之后,再去读一下是否写入成功,这种方式去检测芯片是否正常工作。文章来源地址https://www.toymoban.com/news/detail-779311.html

{
    uint8_t temp;
    uint16_t addr = EE_TYPE;

    temp = at24cxx_read_one_byte(addr);     /* 避免每次开机都写AT24CXX */
    if (temp == 0x55)   /* 读取数据正常 */
    {
        return 0;
    }
    else    /* 排除第一次初始化的情况 */
    {
        at24cxx_write_one_byte(addr, 0x55); /* 先写入数据 */
        temp = at24cxx_read_one_byte(255);  /* 再读取数据 */

        if (temp == 0x55)return 0;
    }

    return 1;
}

main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./USMART/usmart.h"
#include "./BSP/KEY/key.h"
#include "./BSP/24CXX/24cxx.h"


/* 要写入到24c02的字符串数组 */
const uint8_t g_text_buf[] = {"STM32 IIC TEST"};

#define TEXT_SIZE   sizeof(g_text_buf)          /* TEXT字符串长度 */

int main(void)
{
    uint8_t key;
    uint16_t i = 0;
    uint8_t datatemp[TEXT_SIZE];

    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(336, 8, 2, 7);         /* 设置时钟,168Mhz */
    delay_init(168);                            /* 延时初始化 */
    usart_init(115200);                         /* 串口初始化为115200 */
    usmart_dev.init(84);                        /* 初始化USMART */
    led_init();                                 /* 初始化LED */
    lcd_init();                                 /* 初始化LCD */
    key_init();                                 /* 初始化按键 */
    at24cxx_init();                             /* 初始化24CXX */

    lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
    lcd_show_string(30, 70, 200, 16, 16, "IIC TEST", RED);
    lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    lcd_show_string(30, 110, 200, 16, 16, "KEY1:Write  KEY0:Read", RED);    /* 显示提示信息 */

    while (at24cxx_check()) /* 检测不到24c02 */
    {
        lcd_show_string(30, 130, 200, 16, 16, "24C02 Check Failed!", RED);
        delay_ms(500);
        lcd_show_string(30, 130, 200, 16, 16, "Please Check!      ", RED);
        delay_ms(500);
        LED0_TOGGLE();      /* 红灯闪烁 */
    }

    lcd_show_string(30, 130, 200, 16, 16, "24C02 Ready!", RED);

    while (1)
    {
        key = key_scan(0);

        if (key == KEY1_PRES)   /* KEY1按下,写入24C02 */
        {
            lcd_fill(0, 150, 239, 319, WHITE);  /* 清除半屏 */
            lcd_show_string(30, 150, 200, 16, 16, "Start Write 24C02....", BLUE);
            at24cxx_write(0, (uint8_t *)g_text_buf, TEXT_SIZE);
            lcd_show_string(30, 150, 200, 16, 16, "24C02 Write Finished!", BLUE);   /* 提示传送完成 */
        }

        if (key == KEY0_PRES)   /* KEY0按下,读取字符串并显示 */
        {
            lcd_show_string(30, 150, 200, 16, 16, "Start Read 24C02.... ", BLUE);
            at24cxx_read(0, datatemp, TEXT_SIZE);
            lcd_show_string(30, 150, 200, 16, 16, "The Data Readed Is:  ", BLUE);   /* 提示传送完成 */
            lcd_show_string(30, 170, 200, 16, 16, (char *)datatemp, BLUE);          /* 显示读到的字符串 */
        }

        i++;

        if (i == 20)
        {
            LED0_TOGGLE();  /* 红灯闪烁 */
            i = 0;
        }

        delay_ms(10);
    }
}

到了这里,关于STM32 第19讲 IIC(协议简介/读取驱动AT24C02/实验)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32速成笔记—EEPROM(AT24C02)

    🎀 文章作者:二土电子 🌸 关注文末公众号获取其他资料和工程文件! 🐸 期待大家一起学习交流! AT24C01/02/04/08/16…是一个1K/2K/4K/8K/16K位电可擦除PROM,内部含有128/256/512/1024/2048个8位字节,AT24C01有一个8字节页写缓冲器,AT24C02/04/08/16有一个16字节页写缓冲器。电压可允许低

    2024年02月11日
    浏览(63)
  • STM32MX配置EEPROM(AT24C02)------保姆级教程

    ———————————————————————————————————— ⏩ 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大三学生。 ⏩最近在开发一个STM32H723ZGT6的板子,使用STM32CUBEMX做了很多驱动,包括ADC、UART、RS485、EEPROM(IIC)、FLASH(SPI)等等。

    2024年02月16日
    浏览(54)
  • STM32-I2C通信在AT24C02的应用

    AT24C02是一种失去电源供给后依旧能保持数据的储存器,常用来储存一些配置信息,在系统重新上电之后也可以加载。它的容量是2k bit的EEPROM存储器,采用I2C通信方式。 AT24C02支持两种写操作:字节写操作和页写操作。本实验中我们采用的是字节写操作,就是一个地址一个数据

    2024年02月09日
    浏览(52)
  • STM32基于HAL工程硬件I2C读写AT24C02/04/08数据

    ✨申明:本文章仅发表在CSDN网站,任何其他网站,未注明来源,见此内容均为盗链和爬取,请多多尊重和支持原创! 🍁对于文中所提供的相关资源链接将作不定期更换。 相关篇针对AT24C32及以上容量《STM32基于STM32-HAL工程硬件I2C读取AT24Cxx数据》 🎯本工程使用STM32F103VE+AT24C02实

    2023年04月11日
    浏览(55)
  • STM32读取EEPROM存储芯片AT24C512故障然后排坑记录

    有一个项目用到STM32F091芯片去读取 AT24C512C-SSHD  EEPROM 芯片,我直接移植了之前项目的IIC库,结果程序运行后,读不出EEPROM里面的数据。 本文主要介绍一个基于STM32F091芯片和AT24C512C-SSHD EEPROM芯片的项目,该项目旨在读取EEPROM芯片中的数据。我直接移植了之前项目的库,但是遇

    2024年02月01日
    浏览(52)
  • STM32使用IIC协议驱动0.96寸OLED屏

    IIC是常用的协议之一,它通过不同的地址来区分设备,并且端口需要是开漏模式,并且需要接上拉电阻  要使用IIC驱动OLED,首先要配置IIC 然后编写写入函数 ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT) 为判断事件的函数 有以下多种事件 OLED初始化 上图分别为 (起始位

    2024年02月03日
    浏览(41)
  • 蓝桥杯嵌入式(G4系列)HAL:IIC通信之AT24C02与MCP4017

    目录 前言: IIC协议简介: 1、起始信号和停止信号: 2、应答信号: 3、读写字节: AT24C02: 字节写操作: 页写操作: 读操作: MCP4017: 写操作: 读操作:         本篇文章主要介绍IIC通信协议,同时给大家介绍一下蓝桥杯嵌入式的模块的AT24C02和MCP4017,此外本篇博客会采

    2023年04月09日
    浏览(92)
  • MSP432自主开发笔记5:IIC通信移植与驱动AT24Cxx存储芯片

    今日学习移植MSP432的IIC总线协议,并用此驱动AT24C02芯片实现写入以及读取的功能,然后实现打印开机复位次数的效果。 文章贴出测试工程,测试截图,测试代码~  其实是实在看不懂MSP432有关于FLASH存储操作相关的英文手册与例程,没法实现掉电保护数据等功能,才想到用A

    2024年02月15日
    浏览(43)
  • 【IMX6ULL驱动开发学习】10.Linux I2C驱动实战:AT24C02驱动设计流程

    前情回顾:【IMX6ULL驱动开发学习】09.Linux之I2C框架简介和驱动程序模板_阿龙还在写代码的博客-CSDN博客 目录 一、修改设备树(设备树用来指定引脚资源) 二、编写驱动 2.1 i2c_drv_read 2.2 i2c_drv_write 2.3 完整驱动程序 三、上机测试 放在哪个I2C控制器下面 AT24C02的I2C设备地址(查

    2024年02月11日
    浏览(52)
  • stm32-iic 时序驱动

    数据发送

    2024年02月12日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包