韩国吃秀在哪个网站做直播,什么事网站开发,百度排名优化工具,中国外协加工网免费文章目录 1. IIC总线协议1. IIC简介2. IIC时序1. 数据有效性2. 起始信号和终止信号3. 数据格式4. 应答和非应答信号5. 时钟同步6. 写数据和读数据 2. AT24C023. AT24C02读写时序4. AT24C02配置步骤5. 代码部分1. IIC基本信号2. AT24C02驱动代码3. 实验结果分析 1. IIC总线协议 … 文章目录 1. IIC总线协议1. IIC简介2. IIC时序1. 数据有效性2. 起始信号和终止信号3. 数据格式4. 应答和非应答信号5. 时钟同步6. 写数据和读数据 2. AT24C023. AT24C02读写时序4. AT24C02配置步骤5. 代码部分1. IIC基本信号2. AT24C02驱动代码3. 实验结果分析 1. IIC总线协议
1. IIC简介 简介 IIC(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线用于连接微控制器以及其外围设备。它是由数据线SDA和时钟线SCL构成的串行总线可发送和接收数据在CPU与被控IC之间、IC与IC之间进行双向传送。 特点 总线由数据线 SDA 和时钟线 SCL 构成的串行总线数据线用来传输数据时钟线用来同步数据收发总线上每一个器件都有一个唯一的地址识别所以我们只需要知道器件的地址根据时序就可以实现微控制器与器件之间的通信数据线 SDA 和时钟线 SCL 都是双向线路都通过一个电流源或上拉电阻连接到正的电压所以当总线空闲的时候这两条线路都是高电平总线上数据的传输速率在标准模式下可达 100kbit/s 在快速模式下可达 400kbit/s 在高速模式下可达 3.4Mbit/s总线支持设备连接。在使用 IIC 通信总线时可以有多个具备 IIC 通信能力的设备挂载在上面同时支持多个主机和多个从机连接到总线的接口数量只由总线电容 400pF 的限制决定。 总线挂载器件示意图 IIC通信的优缺点 优点 (Advantages)缺点 (Disadvantages)简化的连线仅需两根线SDA 和 SCL速度较慢最高速率为 3.4 Mbps多主多从架构支持多个主设备和从设备协议复杂性处理起始位、停止位、应答信号等灵活的速度选择支持多种速度模式功耗较高使用开漏驱动方式需上拉电阻芯片地址分配每个从设备有唯一地址有限的从设备数量地址有数量限制内置握手和校验机制提高通信可靠性信号完整性问题高速模式下可能影响通信 硬件IIC与软件IIC对比 IIC用法速度稳定性管脚硬件IIC比较复杂快较稳定需使用特定管脚软件IIC操作过程比较清晰较慢稳定任意管脚比较灵活
2. IIC时序
1. 数据有效性
SDA 线上的数据在时钟的高电平期间必须保持稳定。只有当 SCL 线上的时钟信号为低电平时数据线的高电平或低电平状态才会改变。每传输一个数据位都会产生一个时钟脉冲。
2. 起始信号和终止信号 3. 数据格式 SDA线上的每个字节长度必须为8位每次可以传输的字节数不受限制。每个字节后面必须有一个确认位。数据传输时首先传输最高有效位。如果从设备在执行其他功能例如处理内部中断之前无法接收或传输另一个完整的数据字节则可以将时钟线SCL保持在低位以强制主设备进入等待状态。当从设备准备好接收另一个数据字节并释放时钟线SCL时数据传输将继续。
4. 应答和非应答信号
每个字节后都会应答。应答位允许从机向主机发出应答信号表示已成功接收该字节并且可以发送另一个字节。主机生成所有时钟脉冲包括应答的第九个时钟脉冲。
检测应答信号
应答信号定义如下主机在应答时钟脉冲期间释放 SDA 线以便从机可以将 SDA 线拉低并且在此时钟脉冲的高电平期间保持稳定的低电平。还必须考虑设置和保持时间。
非应答信号定义如下当 SDA 在第九个时钟脉冲期间保持高电平时这被定义为未确认信号。然后主机可以生成 STOP 条件以中止传输或生成重复的 START 条件以开始新的传输。
有五种情况会导致生成 NACK
总线上没有传输地址的从机因此没有设备可以做出确认信号从机无法接收或发送因为它正在执行某些实时功能并且尚未准备好开始与主设备通信在传输过程中从机收到其无法理解的数据或命令在传输期间从机无法再接收任何数据字节主机必须向从机发送传输结束信号。
5. 时钟同步
两个主设备可以同时在空闲总线上开始传输并且必须有一种方法来决定由哪个主设备控制总线并完成传输。这是通过时钟同步和仲裁来实现的。在单主系统中不需要时钟同步和仲裁。
6. 写数据和读数据
写操作
主机首先在IIC总线上发送起始信号此时总线上的从机都会等待接收由主机发送的数据。主机接下来发送从机地址0(写操作)组成的8位数据所有从机接收该8位数据后自行检验是否是自己的设备地址如果是就会发出应答信号。主机在总线上接收到应答信号后才能继续向从机发送数据。
读操作
主机向从机读取数据的操作主机发出起始信号接着发送从机地址1(读操作)组成的8位数据从机接收到数据验证是否是自身的地址。验证成功后从机会发出应答信号 并向主机返回8位数据发送完之后主机就会等待主机的应答信号。如果主机一直返回应答信号那么从机可以一直发送数据直到主机发出非应答信号从机才会停止发送信号。
发送1字节数据
读取1字节数据
2. AT24C02 引脚定义
WP写保护引脚接高电平只读接低电平读和写默认接低电平。
A0/1/2可编程地址部分由8位组成最后一位是读写操作0是读操作1是写操作。
写操作地址0xA0 读操作地址0xA1.
3. AT24C02读写时序
写字节时序
主机在 IIC 总线发送第 1 个字节的数据为 24C02的设备地址 0xA0用于寻找总线上找到 24C02在获得 24C02 的应答信号之后继续发送第2 个字节数据该字节数据是 24C02 的内存地址再等到 24C02 的应答信号主机继续发送第 3 字节数据这里的数据即是写入在第 2 字节内存地址的数据。主机完成写操作后可以发出停止信号终止数据传输。
连续写时序
在单字节写时序时每次写入数据时都需要先写入设备的内存地址才能实现在页写时序 中只需要告诉24C02 第一个内存地址 1后面数据会按照顺序写入到内存地址 2内存地址 3等大大节省了通信时间提高了时效性。因为 24C02 每次只能 8bit 数据所以它的页大小也就是 1 字节。
读字节时序
24C02读取数据的过程是一个复合的时序其中包含写时序和读时序。先看第一个通信过程这里是写时序起始信号产生后主机发送24C02设备地址0xA0,获取从机应答信号后接着发送需要读取的内存地址在读时序中起始信号产生后主机发送24C02设备地址0xA1,获取从机应答信号后接着从机返回刚刚在写时序中内存地址的数据以字节为单位传输在总线上假如主机获取数据后返回的是应答信号那么从机会一直传输数据当主机发出的是非应答信号并以停止信号发出为结束从机就会结束传输。
4. AT24C02配置步骤 使能SCL和SDA对应时钟 __HAL_RCC_GPIOB_CLK_ENABLE()设置GPIO工作模式 HAL_GPIO_Init()编写基本信号 void iic_init(void);
static void iic_delay(void);
void iic_start(void);
void iic_stop(void);
uint8_t iic_wait_ack(void);
void iic_ack(void);
void iic_nack(void);
void iic_send_byte(uint8_t data);
uint8_t iic_read_byte(uint8_t ack);编写读和写函数 void at24c02_write_one_byte(uint8_t addr, uint8_t data);
uint8_t at24c02_read_one_byte(uint8_t addr);5. 代码部分
1. IIC基本信号 软件模拟IIC使用的引脚 #define IIC_SCL(x) do{ x ? \HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET) : \HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET); \}while(0) /* SCL */#define IIC_SDA(x) do{ x ? \HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET) : \AL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET); \}while(0) /* SDA */#define IIC_READ_SDA HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) /* 读取SDA */延时函数 static void iic_delay(void)
{delay_us(2);
}在iic_delay函数中使用2微秒延迟对于确保I²C通信的正确时序和信号稳定性至关重要。这种延迟有助于满足I²C的标准和快速模式的时序要求适应微控制器的速度并确保在总线的电气特性下信号转换的稳定性。选择的延迟时间平衡了及时通信和信号转换稳定性的需求。 起始信号 void iic_start(void)
{IIC_SDA(1); // 确保SDA线为高电平IIC_SCL(1); // 确保SCL线为高电平iic_delay(); // 短暂延迟IIC_SDA(0); // 将SDA线拉低生成起始条件iic_delay(); // 短暂延迟IIC_SCL(0); // 将SCL线拉低准备进行数据传输iic_delay(); // 短暂延迟
}确保总线空闲状态 IIC_SDA(1);将SDA线设置为高电平。IIC_SCL(1);将SCL线设置为高电平。在I²C协议中空闲状态是SDA和SCL都为高电平。 生成起始信号 IIC_SDA(0);将SDA线从高电平拉低在SCL高电平期间这是I²C的起始条件。这个信号告诉所有从设备主设备即将开始通信。 准备数据传输 IIC_SCL(0);将SCL线拉低表示开始数据传输。 终止信号 void iic_stop(void)
{IIC_SDA(0); // 确保SDA线为低电平iic_delay(); // 短暂延迟IIC_SCL(1); // 将SCL线拉高iic_delay(); // 短暂延迟IIC_SDA(1); // 将SDA线拉高生成停止条件iic_delay(); // 短暂延迟
}准备停止信号 IIC_SDA(0);将SDA线设置为低电平。 生成停止信号 IIC_SCL(1);将SCL线拉高准备生成停止条件。IIC_SDA(1);将SDA线从低电平拉高在SCL高电平期间这是I²C的停止条件Stop Condition。这个信号通知所有从设备主设备已经结束通信释放总线。 等待应答信号 uint8_t iic_wait_ack(void)
{IIC_SDA(1); // 主机释放SDA线将SDA线设置为高电平准备接收从机的ACK信号iic_delay(); // 短暂延迟等待信号稳定IIC_SCL(1); // 主机拉高SCL线准备读取SDA线的状态iic_delay(); // 短暂延迟等待信号稳定if(IIC_READ_SDA) // 在SCL高电平时读取SDA线的状态{iic_stop(); // 如果SDA线为高电平表示从机未发送ACK信号执行停止条件return 1; // 返回1表示未接收到ACK信号}IIC_SCL(0); // 主机拉低SCL线iic_delay(); // 短暂延迟return 0; // 返回0表示成功接收到ACK信号
}释放SDA线 IIC_SDA(1);主机将SDA线设置为高电平准备接收从机的ACK信号。 短暂延迟 iic_delay();等待一段时间以确保信号稳定。 拉高SCL线 IIC_SCL(1);主机拉高SCL线使数据稳定在SDA线上并准备读取SDA线的状态。 读取SDA线的状态 if(IIC_READ_SDA)在SCL高电平时读取SDA线的状态。如果SDA线为高电平表示从机未发送ACK信号从机没有将SDA线拉低。 停止条件 iic_stop();如果未接收到ACK信号SDA线为高电平主机生成停止条件终止通信。 返回值 return 1;返回1表示未接收到ACK信号。return 0;返回0表示成功接收到ACK信号。 拉低SCL线 IIC_SCL(0);主机拉低SCL线准备进行下一步操作。 延迟 iic_delay();再次短暂延迟以确保信号稳定。 应答信号 void iic_ack(void)
{IIC_SCL(0); // 确保SCL线为低电平iic_delay();IIC_SDA(0); // 数据线为低电平表示应答信号iic_delay();IIC_SCL(1); // 拉高SCL线发送应答信号iic_delay();
}IIC_SCL(0) 这一步确保时钟线SCL为低电平表示准备发送应答信号。 IIC_SDA(0) 将数据线SDA拉低表示发送应答信号ACK。ACK信号表示接收设备成功接收到数据并准备接收下一个字节。 IIC_SCL(1) 拉高SCL线完成应答信号的发送。接收设备在此时刻确认它已准备好接收数据。 非应答信号 void iic_nack(void)
{IIC_SCL(0);iic_delay();IIC_SDA(1); //数据线为高电平表示非应答iic_delay();IIC_SCL(1);iic_delay();
}IIC_SCL(0) 这一步确保时钟线SCL为低电平表示准备发送非应答信号。 IIC_SDA(1) 将数据线SDA拉高表示发送非应答信号NACK。NACK信号表示接收设备未能成功接收到数据或发送设备需要停止传输。 IIC_SCL(1) 拉高SCL线完成非应答信号的发送。发送设备在此时刻了解接收设备未能成功接收数据或接收设备不再准备接收更多数据。 发送一个字节数据 void iic_send_byte(uint8_t data)
{for(uint8_t t 0; t 8; t){IIC_SDA((data 0x80) 7);iic_delay();IIC_SCL(1);iic_delay();IIC_SCL(0);data 1;}IIC_SDA(1); //发送完成主机释放SDA线
}循环发送每一位数据 for(uint8_t t 0; t 8; t)
{IIC_SDA((data 0x80) 7); // 设置数据线的值iic_delay(); // 延时IIC_SCL(1); // 设置时钟线为高电平iic_delay(); // 延时IIC_SCL(0); // 设置时钟线为低电平data 1; // 左移一位准备发送下一位数据
}for 循环从 t 0 开始一直执行到 t 8每次循环 t 自增。IIC_SDA((data 0x80) 7);设置数据线SDA的值为 data 的最高位第7位data 0x80 是用来获取 data 的最高位 7 是右移操作将最高位移到最低位然后通过 IIC_SDA 函数设置数据线的值。iic_delay();延时一段时间为了等待数据稳定或者设备处理数据。IIC_SCL(1);设置时钟线SCL为高电平。iic_delay();再次延时一段时间。IIC_SCL(0);将时钟线SCL设置为低电平。data 1;将数据左移一位这样下一次循环时处理的是数据的下一位次高位。 这样循环执行完毕后就完成了对一个字节数据的逐位发送。 释放数据线 IIC_SDA(1); //发送完成主机释放SDA线将数据线SDA设置为高电平表示数据发送完成后释放数据线让其他设备可以使用这条数据线。 读取一个字节数据 uint8_t iic_read_byte(uint8_t ack)
{uint8_t receive 0;for(uint8_t t 0; t 8; t){receive 1;IIC_SCL(1);iic_delay();if(IIC_READ_SDA) receive;IIC_SCL(0);iic_delay();}if(!ack) iic_nack();else iic_ack();return receive;
}初始化接收变量和循环接收每一位数据 uint8_t receive 0;for(uint8_t t 0; t 8; t)
{receive 1;IIC_SCL(1);iic_delay();if(IIC_READ_SDA) receive;IIC_SCL(0);iic_delay();
}receive 是用来存储接收到的数据的变量初始值为0。for 循环从 t 0 开始一直执行到 t 8每次循环 t 自增。receive 1;将接收变量 receive 左移一位为下一位数据的接收做准备。IIC_SCL(1);设置时钟线SCL为高电平表示准备接收数据。iic_delay();延时一段时间以确保数据稳定。if(IIC_READ_SDA) receive;检查数据线SDA的状态如果为高电平1则将 receive 的最低位第0位设置为1。IIC_SCL(0);将时钟线SCL设置为低电平完成一个时钟周期的接收。 这样循环执行完毕后receive 变量中存储了从设备发送过来的8位数据。 发送应答或不应答信号 if(!ack) iic_nack();
else iic_ack();根据函数参数 ack 的值来决定发送应答ACK或不应答NACK信号。如果 ack 为0调用 iic_nack() 函数发送不应答信号。如果 ack 不为0即非0调用 iic_ack() 函数发送应答信号。 返回接收到的数据 return receive;将接收到的完整字节数据返回给调用该函数的地方。 总结 函数功能void iic_init(void)IIC初始化函数static void iic_delay(void)IIC延时函数void iic_start(void)起始信号void iic_stop(void)终止信号uint8_t iic_wait_ack(void)等待应答信号void iic_ack(void)应答信号void iic_nack(void)非应答信号void iic_send_byte(uint8_t data)发送一个字节数据uint8_t iic_read_byte(uint8_t ack)读取1个字节数据
2. AT24C02驱动代码 写字节函数 void at24c02_write_one_byte(uint8_t addr, uint8_t data)
{//1.发送起始信号iic_start();//2.发送通信地址iic_send_byte(0xA0);//3.等待应答信号iic_wait_ack();//4.发送内存地址iic_send_byte(addr);//5.等待应答信号iic_wait_ack();//6.发送数据iic_send_byte(data);//7.等待应答信号iic_wait_ack();//8.发送停止信号iic_stop();//等待EEPROM写入完成delay_ms(10);
}读字节函数 uint8_t at24c02_read_one_byte(uint8_t addr)
{uint8_t rec 0;//1.发送起始信号iic_start();//2.发送通信地址iic_send_byte(0xA0);//3.等待应答信号iic_wait_ack();//4.发送内存地址iic_send_byte(addr);//5.等待应答信号iic_wait_ack();//6.发送起始信号iic_start();//7.发送读操作地址iic_send_byte(0xA1);//8.等待应答信号iic_wait_ack();//9.等待接收数据rec iic_read_byte(0);//10.发送非应答获取该地址//11.发送停止信号iic_stop();//等待EEPROM写入完成delay_ms(10);return rec;
}3. 实验结果分析 以上是写时序的实验结果三个字节分别是设备地址、内存地址、数据内容。黄色线条为时钟线SCL绿色线条为数据线SDA从图中可以清晰的看到起始信号、终止信号、应答信号、以及发送的数据。 声明资料来源战舰STM32F103ZET6开发板资源包 Cortex-M3权威指南(中文).pdfSTM32F10xxx参考手册_V10中文版.pdfSTM32F103 战舰开发指南V1.3.pdfSTM32F103ZET6中文版.pdf战舰V4 硬件参考手册_V1.0.pdf