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

您所在的位置:网站首页 存储器读写实验报告怎么写出来 STM32 第19讲 IIC(协议简介/读取驱动AT24C02/实验)

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

2024-07-17 07:54| 来源: 网络整理| 查看: 265

文章目录 IIC总线协议介绍IIC总线结构图IIC协议IIC读写通讯过程 24C02 简介24C02读写时序图写时序图读时序 实验实现功能实验原理流程图代码IIC底层驱动代码24C02驱动代码main.c

IIC总线协议介绍

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

IIC总线结构图

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

IIC协议

在这里插入图片描述

可以归纳为

三个信号:起始信号、停止信号、应答信号

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

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

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

两个注意:数据有效性、数据传输

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

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

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

在这里插入图片描述

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

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

WP引脚:写保护引脚,高电平时只读,接地时允许读写。24C02设备地址:可编程部分+不可编程部分 可编程部分由A0,A1,A2决定,最后一位设置数据传输方向,即0–>写操作,1–>读操作,其具体格式为: 在这里插入图片描述 24C02读写时序图 写时序图

在这里插入图片描述

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

上面的写操作只能单字节写入到24C02,效率低下,24C02具有页写时序如图所示。 在这里插入图片描述 在页写时序中,只需要告诉 24C02 第一个内存地址 1,后面数据会按照顺序写入到内存地址 2,内存地址 3等。

读时序

在这里插入图片描述 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 口。 在这里插入图片描述

流程图

在这里插入图片描述

代码 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(); }

在这里插入图片描述 ⑤发送函数 将需要发送的数据作为形参,形参大小位1字节,在IIC中一个时钟信号发送1bit,故该函数需要循环8次,模拟8个时钟信号。 在这里插入图片描述

void iic_send_byte(uint8_t data) { uint8_t t; for (t = 0; t > 7); /* 高位先发送 */ iic_delay(); IIC_SCL(1); iic_delay(); IIC_SCL(0); data 8)> 8); /* 发送高字节地址 */ } else { iic_send_byte(0xA0 + ((addr >> 8) > 8); /* 发送高字节地址 */ } else { iic_send_byte(0xA0 + ((addr >> 8)


【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3