赞
踩
IIC(Inter-Integrated Circuit)总线是一种由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。
在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。
PS: 这里要注意IIC是为了与低速设备通信而发明的,所以IIC的传输速率比不上SPI
IIC的物理层
IIC一共有只有两个总线: 一条是双向的数据线SDA,一条是串行时钟线SCL,所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。I2C总线上的每一个设备都对应一个唯一的地址。
关于IIC的讲解,已经单独整理了一篇文章:
《IIC原理超详细讲解---值得一看-CSDN博客》。
如果对IIC还不是太了解的朋友请移步到这篇文章中
IIC起始信号和终止信号:
起始信号:SCL保持高电平,SDA由高电平变为低电平后,延时(>4.7us),SCL变为低电平。
停止信号:SCL保持高电平。SDA由低电平变为高电平。
数据有效性
IIC信号在数据传输过程中,当SCL=1高电平时,数据线SDA必须保持稳定状态,不允许有电平跳变,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
SCL=1时 数据线SDA的任何电平变换会看做是总线的起始信号或者停止信号。
也就是在IIC传输数据的过程中,SCL时钟线会频繁的转换电平,以保证数据的传输
应答信号
每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据,
应答信号:主机SCL拉高,读取从机SDA的电平,为低电平表示产生应答
应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;
应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
每发送一个字节(8个bit)在一个字节传输的8个时钟后的第九个时钟期间,接收器接收数据后必须回一个ACK应答信号给发送器,这样才能进行数据传输。
应答出现在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,1表示非应答,
AT24C02是一个2K位串行CMOS,内部含有256个字节,此芯片具有I2C通讯接口,芯片内保存的数据在掉电的情况下不丢失(EEPROM),常用于存放比较重要的数据。本实验使用的是SOP-8封装的AT24C02芯片,其引脚说明见下图
AT24C02芯片的器件地址为7位,高4位固定为1010,低3位有上表中的A0/A1/A2引脚的电平决定,还有一位(最低位R/W)用来选择读写方向。本实验中A0/A1/A2引脚接在GND上了,因此器件地址为1010000;加上最低位的读写方向位后,写器件地址为10100000(0xA0),读器件地址为10100001(0xA1)
下图为AT24C02的总线时序图和时间参数
LED2指示灯用来提示系统运行状态,s1按键用来控制24C02的数据写入,S2按键用来控制24C02的数据读取,数据的写入与读取信息通过串口1打印出来
上面的函数看起来多,但是只是发送和接收的方式改变了,函数的参数和本质功能并没有改变
比方说IIC发送函数 还是发送函数,只不过有普通发送,DMA传输,中断 的几种发送模式
这里我们仅介绍下普通发送,其他的只是改下函数名即可
IIC写函数(单个字节写入)
HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
功能:IIC写一个字节数据
参数:
举例:
HAL_I2C_Master_Transmit(&hi2c1,0xA0,(uint8_t*)TxData,2,1000) ;//发送两个字节数据
IIC读函数(单个字节读取)
HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
功能:IIC读一个字节数据
参数:
举例:
HAL_I2C_Master_Receive(&hi2c1,0xA1,(uint8_t*)TxData,2,1000) ;//读取两个字节数据
IIC写数据函数(多字节写入)
-
- HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
- /* 第1个参数为I2C操作句柄
- 第2个参数为从机设备地址
- 第3个参数为从机寄存器地址
- 第4个参数为从机寄存器地址长度
- 第5个参数为发送的数据的起始地址
- 第6个参数为传输数据的大小
- 第7个参数为操作超时时间 */
功能: IIC写多个数据 该函数适用于IIC外设里面还有子地址寄存器的设备,比方说E2PROM,除了设备地址,每个存储字节都有其对应的地址
参数:
写入数据的字节类型 8位还是16位
I2C_MEMADD_SIZE_8BIT
I2C_MEMADD_SIZE_16BIT
在stm32f1xx_hal_i2c.h中有定义
使用HAL_I2C_Mem_Write等于先使用HAL_I2C_Master_Transmit传输第一个寄存器地址,再用HAL_I2C_Master_Transmit传输写入第一个寄存器的数据。可以传输多个数据
在传输过程,寄存器地址和源数据地址是会自加的。
至于读函数也是如此,因此用HAL_I2C_Mem_Write和HAL_I2C_Mem_Read,来写读指定设备的指定寄存器数据是十分方便的,让设计过程省了好多步骤。
举例:
8位:
- HAL_I2C_Mem_Write(&hi2c2, ADDR, i, I2C_MEMADD_SIZE_8BIT,&(I2C_Buffer_Write[i]),8, 1000);
-
- HAL_I2C_Mem_Read(&hi2c2, ADDR, i, I2C_MEMADD_SIZE_8BIT,&(I2C_Buffer_Write[i]),8, 1000);
16位:
- HAL_I2C_Mem_Write(&hi2c2, ADDR, i, I2C_MEMADD_SIZE_16BIT,&(I2C_Buffer_Write[i]),8, 1000);
-
- HAL_I2C_Mem_Read(&hi2c2, ADDR, i, I2C_MEMADD_SIZE_16BIT,&(I2C_Buffer_Write[i]),8, 1000);
- #ifndef __24cxx_h__
- #define __24cxx_h__
-
-
- #include "usart.h"
-
- //AT24C02 写地址和读地址
- #define ADDR_24CXX_WRITE 0XA0
- #define ADDR_24CXX_READ 0XA1
-
-
- void AT24CXX_Init(void);
- uint8_t AT24CXX_Check(void);
-
- #endif
- #include "24cxx.h"
- #include "i2c.h"
-
-
-
- void AT24CXX_Init(void){
-
- MX_I2C2_Init(); //IIC初始化
-
- while(AT24CXX_Check()){ //检测AT24C02
- printf1("AT24C02 Checked Failed!\r\n");
- HAL_Delay(500);
- }
- printf1("AT24C02 Checked Sucessed!\r\n");
- }
-
- //该函数仅做AT24C02的检测,检测AT24C02是否正常使用。
- uint8_t AT24CXX_Check(void){
- uint8_t temp;
-
- HAL_I2C_Mem_Read(&hi2c2,ADDR_24CXX_READ,255,I2C_MEMADD_SIZE_8BIT,&temp,1,0xff);
- if(temp==0x36)
- return 0;
- else{
- uint8_t data = 0x36;
- HAL_I2C_Mem_Write(&hi2c2,ADDR_24CXX_WRITE,255,I2C_MEMADD_SIZE_8BIT,&data,1,0xff);
- HAL_I2C_Mem_Read(&hi2c2,ADDR_24CXX_READ,255,I2C_MEMADD_SIZE_8BIT,&temp,1,0xff);
- if(temp==0x36)
- return 0;
- }
- return 1;
- }

注意事项:
AT24C02的IIC每次写之后要延时一段时间才能继续写 每次写之后要delay 5ms左右 不管硬件IIC采用何种形式(DMA,IT),都要确保两次写入的间隔大于5ms;
读写函数最后一个超时调整为1000以上 因为我们一次写8个字节,延时要久一点
AT24C02页写入只支持8个byte,所以需要分32次写入。这不是HAL库的bug,而是AT24C02的限制,其他的EEPROM可以支持更多byte的写入。
AT24C02的2Kbit分为32页,每页8个字节。而EEPROM也可以按页写入,本例使用了按页写入的方式,分32次写入。注意每次写入完毕需要延时5ms,是AT24C02芯片的要求;读取数据没有页的限制,可以一次全部读取256个字节
- /* USER CODE BEGIN PV */
- #define ADDR_24CXX_WRITE 0XA0
- #define ADDR_24CXX_READ 0XA1
- uint8_t WriteBuf[256];
- uint8_t ReadBuf[256];
- uint16_t i,j;
- /* USER CODE END PV */
- void SystemClock_Config(void);
- int main(void){
-
- ///***省略***///
- /* USER CODE BEGIN 2 */
- AT24CXX_Init();//检测AT24C02是否存在
- printf1("\r\n*********STM32CubeMX I2C AT24C02 Example*********\r\n");
- for(i = 0;i < 256; i++){ //初始化写数据缓冲区
- WriteBuf[i] = i;
- }
- /* USER CODE END 2 */
- while (1){
- char key=KEY_Scan(0);
- if(key == 1){
- for(j = 0;j < 32;j++){ //按页写入EEPROM,分32次写入,因为24c02每次只能写8个数据。
- //通过hi2c2(IIC2)往从机(ADDR_24CXX_WRITE)的8位(I2C_MEMADD_SIZE_8BIT)寄存器(8*j)中写入WriteBuf+8*j的8个数据,超时0xff
- if(HAL_I2C_Mem_Write(&hi2c2,ADDR_24CXX_WRITE,8*j,I2C_MEMADD_SIZE_8BIT,WriteBuf+8*j,8,0xFF) == HAL_OK){
- printf1("\r\nEEPROM 24C02 Write Test OK!\r\n");
- HAL_Delay(5);//每次写入需间隔5ms
- }
- else{
- printf1("\r\nEEPROM 24C02 Write Test False!\r\n");
- HAL_Delay(5);
- }
- }
- }
-
- if(key == 2){ //EEPROM读取没有页限制,可以一次读取256个字节
- //通过hi2c2(IIC2)往从机(ADDR_24CXX_READ)的8位(I2C_MEMADD_SIZE_8BIT)寄存器(0)中读出256个数据并存放在ReadBuf中,超时0xff
- HAL_I2C_Mem_Read(&hi2c2,ADDR_24CXX_READ,0,I2C_MEMADD_SIZE_8BIT,ReadBuf,256,0xFF);
- for(i=0;i<256;i++){
- printf1("0x%02X ",ReadBuf[i]);
- }
-
- if(memcmp(WriteBuf,ReadBuf,256) == 0){ //通过内存比较,判断读取和写入的数据是否相同
- printf1("\r\nEEPROM 24C02 Read Test OK!\r\n");
- }
- else{
- printf1("\r\nEEPROM 24C02 Read Test False!\r\n");
- }
- }
-
- HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);
- HAL_Delay(500);
- }
- }

编译无误下载到开发板后,可以看到LED2指示灯不断闪烁,当按下S1按键后数据写入到24C02芯片内,当按下S2按键后读取24C02芯片的值,同时串口打印出相应信息
【STM32】HAL库 STM32CubeMX教程十二---IIC(读取AT24C02 )_hal iic-CSDN博客
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。