在之前的标准库中,STM32的硬件IIC非常复杂,更重要的是它并不稳定,所以都不推荐使用。但是在我们的HAL库中,对硬件IIC做了全新的优化,使得之前软件IIC几百行代码,在HAL库中,只需要寥寥几行就可以完成 那么这篇文章将带你去感受下它的优异之处。
本文将详细地讲解I2C协议,并基于I2C
来读写EEPROM模块以达到练习的目的
通过本篇博客您将学到:
- I2C的基本原理
- STM32CubeMX创建I2C例程
- I2C函数库(HAL)
- AT24C256芯片原理及读写方法
I2C简介
IIC(Inter-Integrated Circuit)总线是一种由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信。
I2C特性
- 半双工
- 没有严格的波特率要求
- 小数据量场合使用
- 传输距离短、传输速率不如SPI
- 任何时刻只能有一个主机,但任何设备都可成为主机
- 只需要两条总线——SDA与SCL
IIC一共有只有两个总线: 一条是双向的数据线SDA,一条是串行时钟线SCL
所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。I2C总线上的每一个设备都对应一个唯一的地址。
I2C起始信号与终止信号(代码段为软件I2C)
1、起始信号:SCL为高电平时,SDA由高->低
void I2C_Start()
{
SDA=1; //确保SDA为高电平
HAL_Delay(1);
SCL=1; //确保SCL为高电平
HAL_Delay(1);
SDA=0; //SCL为高时拉低SDA线
HAL_Delay(1);
SCL=0; //钳住I2C总线,准备数据的发送与接收
}
2、终止信号:SCL为高电平时,SDA由低->高
void I2C_Stop()
{
SCL=0;
SDA=0;
HAL_Delay(1);
SCL=1; //确保SCL为高电平
HAL_Delay(1);
SDA=1; //SCL为高时拉高SDA
}
I2C应答信号与非应答信号 (代码段为软件I2C)
每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据。
- 应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;
- 应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
1、应答信号‘0’:SCL高时SDA低
void I2C_Ack() //产生应答信号
{
SCL=0;
SDA=0;
HAL_Delay(1);
SCL=1; //确保SCL为高时SDA为低
HAL_Delay(1);
SCL=0;
}
2、非应答信号‘1’:SCL高时SDA高
void I2C_NAck() //不产生应答信号
{
SCL=0;
SDA=1;
HAL_Delay(1);
SCL=1; //SCL高时SDA高
HAL_Delay(1);
SCL=0;
}
I2C数据有效性
I2C信号在进行数据传输时, 当SCL=1高电平时,数据线SDA必须保持稳定状态,不允许有电平跳变,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
SCL=1时 数据线SDA的任何电平变换会看做是总线的起始信号或者停止信号。也就是在IIC传输数据的过程中,SCL时钟线会频繁的转换电平,以保证数据的传输
接着我们介绍一下基于AT24C256的I2C通信
AT24C256芯片手册如下:
描述:
AT24C256是提供131072/262144位串行电可擦除可编程只读存储器(EEPROM),该设备最多允许4个设备共享一条公共的双线总线。
特征:
- 低电压和标准电压操作-2.7V(Vcc=2.7V至5.5V)(一般选择3.3V)
- 双线串行接口
- 施密特触发器,用于噪声抑制的滤波输入
- 双向数据传输协议
- 400kHz兼容性
- 硬件和软件的写保护引脚
- 64字节页写入模式(允许部分页写入)
- 自定时写入周期
- 高可靠性(数据保留:40年)
- A0,A1,A2:硬件地址引脚
- WP:写保护引脚,接高电平只读,接地允许读和写
芯片的寻址:
AT24C设备地址为如下,前四位固定为1010,A2~A0为由管脚电平。AT24CXX EEPROM Board模块中默认为接地。所以A2~A0默认为000,最后一位表示读写操作。所以AT24Cxx的读地址为0xA1,写地址为0xA0。
也就是说如果是\写24C02的时候,从器件地址为10100000(0xA0);读24C02的时候,从器件地址为10100001(0xA1)。
注意:
- 在写数据的过程中,每成功写入一个字节,E2PROM存储空间的地址就会自动加1,当加到0xFF后,再写一个字节,地址就会溢出又变成0x00。
- 当我们在写多个字节时,写入一个字节之后,再写入下一个字节之前,必须延时5ms才可以
STM32CubeMX创建I2C例程(作者使用的是STM32f4ccu6)
1、设置RCC时钟
2、配置I2C
- Master features 主模式特性
- I2C Speed Mode: IIC模式设置 快速模式和标准模式。实际上也就是速率的选择。I2C Clock Speed:I2C传输速率,默认为100KHz
- Slave features 从模式特性
- Clock No Stretch Mode: 时钟没有扩展模式
- IIC时钟拉伸(Clock stretching) - -clock stretching通过将SCL线拉低来暂停一个传输.直到释放SCL线为高电平,传输才继续进行.clock stretching是可选的,实际上大多数从设备不包括SCL驱动,所以它们不能stretch时钟.
- Primary Address Length selection: 从设备地址长度 设置从设备的地址是7bit还是10bit 大部分为7bit
- Dual Address Acknowledged: 双地址确认
- Primary slave address: 从设备初始地址
3、配置串口
这里配置串口是为了读EEPROM并打印出来。
4、时钟树配置
5、项目文件配置
- 设置项目名称
- 设置项目路径(不能包含中文)
- 选择IDE(作者用的是keil5)
- 复制所用的.c和.h文件
- 不同功能生成独立的.c和.h文件
6、 生成代码
7、配置下载工具
8、重写printf函数
重写printf函数能更方便与上位机通信 ,方法参考printf重写
I2C函数库(HAL)
在I2C.c文件中可以看到I2C初始化函数。在stm32f1xx_hal_i2c.h头文件中可以看到I2C的操作函数。分别对应轮询,中断和DMA三种控制方式
这里我们简单介绍一下等下用到的函数
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)
功能: IIC写多个数据 该函数适用于IIC外设里面还有子地址寄存器的设备,比方说E2PROM,除了设备地址,每个存储字节都有其对应的地址
- I2C_HandleTypeDef *hi2c i2c句柄,例如上文配置的&hi2c1,实际上是一个结构体
- uint16_t DevAddress 从机设备地址,对AT24Cxx来说,0xA0代表写数据,0xA1代表读数据
- uint16_t MemAddress 从机寄存器地址,每写入一个字节的数据,地址自动+1
- uint16_t MemAddSize 从机寄存器地址长度,8bit和16bit可选
- uint8_t *pData 发送数据的起始地址
- uint16_t Size 传输数据的大小
- uint32_t Timeout 传输超时时间
读写AT24C256
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define AT24C256_Write 0xA0
#define AT24C256_Read 0xA1
#define BufferSize 64
/* USER CODE END PD */
宏定义,增加了程序的可读性
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint8_t w[BufferSize],r[BufferSize];
uint16_t i,j;
/* USER CODE END PV */
定义接收与发送数组
/* USER CODE BEGIN 2 */
for(i=0;i<64;i++)
{
w[i]=i;
}
printf("I2C Example Test\n");
//for( j=0;j<16;j++)
//{
if(HAL_I2C_Mem_Write(&hi2c1,AT24C256_Write,0,I2C_MEMADD_SIZE_16BIT,w,64,10000)==HAL_OK)
{
printf("EEPROM AT24C256 Write Test OK\n");
HAL_Delay(100);
}
else
{
printf("EEPROM AT24C256 Write Test False");
HAL_Delay(50);
}
//}
HAL_Delay(100);
HAL_I2C_Mem_Read(&hi2c1,AT24C256_Read,0,I2C_MEMADD_SIZE_16BIT,r,BufferSize,10000);
for(i=0;i<64;i++)
{
HAL_Delay(10);
printf("0x%02X ",r[i]);
}
/* USER CODE END 2 */
64字节一次性写入
或
/* USER CODE BEGIN 2 */
for(i=0;i<64;i++)
{
w[i]=i;
}
printf("I2C Example Test\n");
for( j=0;j<16;j++)
{
if(HAL_I2C_Mem_Write(&hi2c1,AT24C256_Write,0+16*j,I2C_MEMADD_SIZE_16BIT,w+16*j,16,10000)==HAL_OK)
{
printf("EEPROM AT24C256 Write Test OK\n");
HAL_Delay(100);
}
else
{
printf("EEPROM AT24C256 Write Test False");
HAL_Delay(50);
}
}
HAL_Delay(100);
HAL_I2C_Mem_Read(&hi2c1,AT24C256_Read,0,I2C_MEMADD_SIZE_16BIT,r,BufferSize,10000);
for(i=0;i<64;i++)
{
HAL_Delay(10);
printf("0x%02X ",r[i]);
}
/* USER CODE END 2 */
分批次写入
单片机烧录,运行
注意:确保写入时地址不会溢出,否则可能像当时的菜鸡博主一样搞半天(如下)
文章来源:https://www.toymoban.com/news/detail-779969.html
文章来源地址https://www.toymoban.com/news/detail-779969.html
到了这里,关于【STM32CubeMX+HAL库】I2C详解+读写EEPROM的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!