STM32H743-ARM例程17-I2C
本文介绍了基于银杏科技GT7000开发板和iToolXE仿真器的I2C通信实验平台。文章详细阐述了I2C总线协议的特点、时序和工作原理,包括起始位、停止位、应答信号、数据位等关键时序说明,并给出了读写操作的具体流程。同时介绍了EEPROM存储器的基本特性和工作原理,说明其作为非易失性存储器的优势。实验平台采用STM32CubeH7固件库和MDK开发环境,通过I2C接口实现对EEPROM的读写操作。
实验平台
硬件:银杏科技GT7000双核心开发板-ARM-STM32H743XIH6,银杏科技iToolXE仿真器
软件:最新版本STM32CubeH7固件库,STM32CubeMX v6.10.0,开发板环境MDK v5.35,串口工具putty
网盘资料包:链接: https://pan.baidu.com/s/1Y3nwaY4SMxfoUsdqPm2R3w?pwd=inba 提取码: inba
I2C
I2C介绍
IIC 通讯协议(Inter-Integrated Circuit)是由Phiilps公司开发的,IIC是一种串行、半双工总线,主要用于近距离、低速的芯片之间的通信。有两根信号线,一根为SCL(时钟线),一根为SDA(数据线) 。 IIC是一种多主机总线,连接在IIC总线上的器件分为主机和从机,主机有权发起和结束一次通信,而从机只能被呼叫;当总线上有多个主机同时启用总线时,IIC也具备冲突检测和仲裁的功能来防止错误产生;每个连接到IIC总线上的器件都有唯一的地址(7bit),并且每个器件都可以作为主机和从机;IIC总线在通信时总线上发送数据的为发送器,接受数据的为接受器。
IIC特点:
①总线由数据线SDA和时钟线SCL构成的串行总线,数据线用来传输数据,时钟线用来同步数据收发。
②总线上每一个器件都有一个唯一的地址识别,所以我们只需要知道器件的地址,根据时序就可以实现微控制器与器件之间的通信。
③数据线SDA和时钟线SCL都是双向线路,都通过一个电流源或上拉电阻连接到正的电压,所以当总线空闲的时候,这两条线路都是高电平。
④总线上数据的传输速率在标准模式下可达100kbit/s 在快速模式下可达400kbit/s在高速模式下可达3.4Mbit/s。
⑤总线支持设备连接。在使用IIC通信总线时,可以有多个具备IIC通信能力的设备挂载在上面,同时支持多个主机和多个从机,连接到总线的接口数量只由总线电容400pF的限制决定。IIC总线挂载多个器件的示意图,如下图所示:
IIC时序

1.起始位
当主设备决定开始通讯时,需要发送开始信号,并且执行以下过程:
- 将SDA线由高电平切换成低电平;
- 将SCL线由高电平切换成低电平;
在主设备发送开始条件信号之后,所有从机即使处于睡眠模式也将变为活动状态,并等待接收地址位。
2.停止位
当主设备决定结束通讯时,需要发送结束信号,需要执行以下动作:
- 先将SDA线从低电压电平切换到高电压电平;
- 再将SCL线从高电平拉到低电平;
该信号由主设备发出,在停止信号发出后,总线就会处于空闲状态。
3.应答信号
IIC最大的一个特点就是有完善的应答机制,从机接收到主机的数据时,会回复一个应答信号来通知主机表示“我收到了”。
应答信号: 出现在1个字节传输完成之后,即第9个SCL时钟周期内,此时主机需要释放SDA总线,把总线控制权交给从机,由于上拉电阻的作用,此时总线为高电平,如果从机正确的收到了主机发来的数据,会把SDA拉低,表示应答响应。如果接收器是主机,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主机接收器发送一个停止信号。

4.数据位
IIC数据总线传输要保证在SCL为高电平时,SDA数据稳定,所以SDA上数据变化只能在SCL为低电平时。
一次传输的数据总共有8位,由发送方设置,它需要将数据位传输到接收方。发送之后会紧跟一个ACK / NACK位,如果接收器成功接收到数据,则从机发送ACK。否则,从机发送NACK。
数据可以重复发送多个,直到接收到停止位为止。
5.停止位
当主设备决定结束通讯时,需要发送结束信号,需要执行以下动作:
- 先将SDA线从低电压电平切换到高电压电平;
- 再将SCL线从高电平拉到低电平;

6.空闲状态
IIC总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。
7.读写操作流程
写操作
- Master发起START
- Master发送I2C addr(7bit)和w操作0(1bit),等待ACK
- Slave发送ACK
- Master发送reg addr(8bit),等待ACK
- Slave发送ACK
- Master发送data(8bit),即要写入寄存器中的数据,等待ACK
- Slave发送ACK
- 第6步和第7步可以重复多次,即顺序写多个寄存器
- Master发起STOP
读操作
- Master发送I2C addr(7bit)和w操作1(1bit),等待ACK
- Slave发送ACK
- Master发送reg addr(8bit),等待ACK
- Slave发送ACK
- Master发起START
- Master发送I2C addr(7bit)和r操作1(1bit),等待ACK
- Slave发送ACK
- Slave发送data(8bit),即寄存器里的值
- Master发送ACK
- 第8步和第9步可以重复多次,即顺序读多个寄存器
EEPROM简介
EEPROM (Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器。是一种掉电后数据不丢失的存储芯片。 EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。
由于EPROM操作的不便,后来出的主板上BIOSROM芯片大部分都采用EEPROM。EEPROM的擦除不需要借助于其它设备,它是以电子信号来修改其内容的,而且是以Byte为最小修改单位,不必将资料全部洗掉才能写入,彻底摆脱了EPROMEraser和编程器的束缚。
EEPROM在写入数据时,仍要利用一定的编程电压,此时,只需用厂商提供的专用刷新程序就可以轻而易举地改写内容,所以,它属于双电压芯片。借助于EEPROM芯片的双电压特性,可以使BIOS具有良好的防毒功能,在升级时,把跳线开关打至“on”的位置,即给芯片加上相应的编程电压,就可以方便地升级;平时使用时,则把跳线开关打至“off”的位置,防止CIH类的病毒对BIOS芯片的非法修改。所以,至今仍有不少主板采用EEPROM作为BIOS芯片并作为自己主板的一大特色。
传统的单片机存贮结构,一般要由ROM、RAM组成。随着存贮器技术的发展.市场上推出电可擦除可编程只读存贮器,即EEPROM器件。该类器件基于FLOTOX(floatin~gatetunneling~Oxide)结构.根据Fowler—Nordheim效应来完成数据的擦除或写入。因而具备联机可读、可写的特性,以及掉电之后的非易失性。EEPROM存贮器件的出现,为单片机存贮体的选择提供了新的设计方案。
原理图:
STM32CubeMX生成工程
我们参考前面章节STM32H743-结合CubeMX新建HAL库MDK工程,打开CubeMX软件,重复步骤不再展示,我们来看配置I2C部分如下图所示:
实验代码
1. 主函数
int main(void)
{
MPU_Config();
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART6_UART_Init();
uint8_t writeData[] = {0x11, 0x22, 0x33};
uint8_t readData[3];
uart6.printf("\033[1;32;40m");
// 写入测试
if(EEPROM_WritePage(0x0000, writeData, sizeof(writeData)) == HAL_OK)
{
uart6.printf("Write Success!\r\n");
uart6.printf("write data:0x%02x 0x%02x 0x%02x\r\n\r\n",writeData[0],writeData[1],writeData[2]);
HAL_Delay(10);
// 读取验证
if(EEPROM_ReadByte(0x0000, &readData[0]) == HAL_OK)
{
uart6.printf("Read Success!\r\n");
uart6.printf("Read Data readData[0]: 0x%02X\r\n", readData[0]);
}
}
else
{
uart6.printf("Write Failed!\r\n");
}
while (1)
{
}
}
2. EEPROM读写函数
// 写入单字节(需处理页边界)
HAL_StatusTypeDef EEPROM_WriteByte(uint16_t memAddr, uint8_t data)
{
HAL_StatusTypeDef status;
status = HAL_I2C_Mem_Write(&hi2c1, EEPROM_ADDR_WRITE, memAddr, I2C_MEMADD_SIZE_16BIT, &data, 1, 1000);
HAL_Delay(5); // 必须延时等待EEPROM内部写入完成
return status;
}
// 读取单字节
HAL_StatusTypeDef EEPROM_ReadByte(uint16_t memAddr, uint8_t *data)
{
return HAL_I2C_Mem_Read(&hi2c1, EEPROM_ADDR_READ, memAddr, I2C_MEMADD_SIZE_16BIT, data, 1, 1000);
}
// 写入多字节(自动分页)
HAL_StatusTypeDef EEPROM_WritePage(uint16_t memAddr, uint8_t *data, uint16_t size)
{
while (size > 0)
{
uint16_t bytesToWrite = (memAddr % PAGE_SIZE == 0) ? PAGE_SIZE : PAGE_SIZE - (memAddr % PAGE_SIZE);
bytesToWrite = (bytesToWrite > size) ? size : bytesToWrite;
HAL_StatusTypeDef status = HAL_I2C_Mem_Write(&hi2c1, EEPROM_ADDR_WRITE, memAddr, I2C_MEMADD_SIZE_16BIT, data,bytesToWrite, 1000);
if (status != HAL_OK) return status;
HAL_Delay(5);
memAddr += bytesToWrite;
data += bytesToWrite;
size -= bytesToWrite;
}
return HAL_OK;
}
实验现象
EEPROM读写测试成功,则在终端显示出相应的写入数据和读出数据。
更多推荐



所有评论(0)