文章目录
- I2C简介
- I2C传输过程
- I2C仲裁
- IST8310磁力计
- Cube配置
- 相关函数
- HAL_I2C_Mem_Read函数
- HAL_I2C_Mem_Write函数
- IST8310的初始化
- 程序流程
- 代码编写
I2C简介
-
2C是一种半双工双向二线制的同步串行总线。
-
I2C只有两根信号线,一根数据线SDC,一根时钟线SCL。
-
一般情况下,数据线SDA和时钟线SCL都是处于上拉电阻状态(因为在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平)。
-
当IIC总线的数据线SDA和时钟线SCL两条信号线同时处于高电平时,规定为总线的空闲状态。
-
I2C允许挂载多个主设备(支持多主控),但总线时钟只能由一个主设备产生。
-
对于并联在一条总线上的每个IC都有唯一的地址。
-
在硬件上有I2C,也可以使用软件的方式进行模拟(由于硬件I2C比较复杂且不稳定,所以我们一般使用软件的方式进行模拟)
-
I2C通信的信号:
- S:开始信号,当SCL处于高电平时,SDC从高电平拉低至低电平,代表数据传输的开始
- P:结束信号,当SCL处于高电平时,SDC从低电平拉高至高电平,代表数据传输的结束
- 数据信号:数据信号每次传输8位数据,每一位数据都在一个时钟周期内传递(当SCL处于高电平时,SDC数据线上的电平需要稳定;当SCL处于低电平时,SDC数据线上的电平才能够改变)
- ACK/NACK:应答信号(每个应答由主机产生),是主机发送的8bit数据,从机对主机发送低电平,表示已经接收数据(应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。)
- 发送ACK的条件:接收器在第9个时钟脉冲之前的低电平期间将数据线SDA拉低,并且确保在该时钟的高电平期间为稳定的低电平。
I2C传输过程
I2C在进行数据传输时,当时钟信号为高电平期间,SDA上的数据必须保持稳定;只有时钟信号为低电平期间,SDA上的高低电平状态才能改变(数据在时钟线SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定)。
在I2C传送的每一位数据都有一个时钟脉冲与之相对应(在SCL串行时钟的配合下,在SDC上逐位地传送,每一位数据,数据位的传输是边沿触发)
- I2C总线上每个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址,主从设备之间就通过这个地址来确定与哪个器件进行通信
- 主设备在传输有效数据之前要先指定从设备的地址大多数设备的地址是7位的,协议规定给7位地址再添加一个表示数据传输方向的最低位(0表示主设备向从设备写数据,1表示主设备向从设备读数据)
主设备向从设备写数据:
- 淡蓝色部分表示数据由主机向从机传送,粉红色部分则表示数据由从机向主机传送。(写用0来表示,为高电平;读用1来表示,为低电平)
主设备从从设备中读数据:
I2C仲裁
- 在多主的通信系统中,总线上有多个节点,它们都有自己的寻址地址,可以作为从节点被别的节点访问,同时它们都可以作为主节点向其它的节点发送控制字节和传送数据。
- 但是如果有两个或两个以上的节点都向总线上发送启动信号并开始传送数据,这样就形成了冲突。
- 要解决这种冲突,就要进行仲裁的判决,这就是I2C总线上的仲裁。
IST8310磁力计
磁力计是一种测量地球磁场强度的传感器,又名电子罗盘,可用于计算机器人的朝向。
IST8310是一款由ISentek公司推出的3轴磁场传感器,支持快速I2C通信,可达400kHz,14位磁场数据,测量范围可达1600uT(x,y-axis)和2500uT(z-axis),最高200Hz输出频率。
使用IST8310磁力计可以检测地磁场强度,用于计算磁场角度。
IST8310的GPIO管脚各个功能及对应的MCU管脚如下表所示:
管脚 | 功能 | MCU管脚 |
---|---|---|
SCL | I2C的时钟线 | PA8 |
SDC | I2C的数据线 | PC9 |
RSTN | IST8310的RESET,低电平重启IST8310 | PG6 |
DRDY | IST8310的数据准备(data ready) | PG3 |
Cube配置
PG3配置外部中断,下降沿触发
PG6配置成GPIO的输出模式,上拉模式
I2C3配置成快速模式,通信频率设置为400k,I2C地址配置成7位
对应引脚为PA8和PC9
这样就完成了Cube配置。
相关函数
HAL_I2C_Mem_Read函数
格式:
HAL_StatusTypeDef 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)
函数名 | HAL_I2C_Mem_Read |
---|---|
作用 | 从I2C设备的寄存器读取数据 |
返回值 | HAL状态 |
参数1:hi2c | I2C句柄 |
参数2:DevAddress | I2C从机地址 |
参数3:MemAddress | 寄存器地址 |
参数4:MemAddSize | 寄存器地址增加大小 I2C_MEMADD_SIZE_8BIT:增加八位 I2C_MEMADD_SIZE_16BIT:增加十六位 |
参数5:pData | 数据指针 |
参数6:Size | 数据长度 |
参数7:Timeout | 超时时间 |
HAL_I2C_Mem_Write函数
格式:
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef*hi2c, uint16_t DevAddress, uint16_tMemAddress, uint16_t MemAddSize, uint8_t*pData, uint16_t Size, uint32_t Timeout)
函数名 | HAL_I2C_Mem_Write |
---|---|
作用 | 往I2C设备的寄存器写入数据 |
返回值 | HAL状态 |
参数1:hi2c | I2C句柄 |
参数2:DevAddress | I2C从机地址 |
参数3:MemAddress | 寄存器地址 |
参数4:MemAddSize | 寄存器地址增加大小 I2C_MEMADD_SIZE_8BIT:增加八位 I2C_MEMADD_SIZE_16BIT:增加十六位 |
参数5:pData | 数据指针 |
参数6:Size | 数据长度 |
参数7:Timeout | 超时时间 |
IST8310的初始化
步骤 | 语句 | 功能 |
---|---|---|
1. 初始化GPIO和通信 | ist8310_GPIO_init(); ist8310_com_init(); | 初始化管脚和I2C通信接口,保证正常通信。 |
2. 重启设备 | ist8310_RST_L(); ist8310_delay_ms(sleepTime); ist8310_RST_H(); ist8310_delay_ms(sleepTime); | 通过IST8310重启管脚进行重启。 |
3. 验证设备ID | 通过读取WHO_AM_I寄存器判断 | 判断IST8310通信是否正常 |
4. 配置IST8310的四个寄存器 | 0x0B:中断寄存器,配置成开启中断,中断时为低电平; 0x41:采样次数寄存器,配置成x,y,z均是2次采样 0x42:需要配置成0xC0; 0x0A:配置成200Hz输出频率 |
程序流程
程序开始先进行HAL库自带的初始化,包括时钟,GPIO,I2C3的初始化;之后完成配置IST8310,IST8310的DRDY引脚会产生200Hz的周期信号;当DRDY下降沿,会引起单片机的下降沿外部中断;在外部中断回调函数中,调用ist8310的读取函数,便可以读取磁场数据。
代码编写
首先调用官方封装好的I2C读写函数,以及初始化函数,读取磁场数据函数
/* USER CODE BEGIN Includes */
#include "ist8310driver_middleware.h" //官方提供I2C 读写函数的文件
#include "ist8310driver.h" //官方提供初始化函数,读取磁场数据函数
/* USER CODE END Includes */
然后进行GPIO初始化,I2C3初始化,IST8310初始化
/* Initialize all configured peripherals */
MX_GPIO_Init(); //GPIO初始化
MX_I2C3_Init(); //I2C3初始化
/* USER CODE BEGIN 2 */
ist8310_init(); //IST8310初始化
/* USER CODE END 2 */
当IST8310的DRDY引脚产生200Hz的周期信号时,使DRDY处于下降沿,会引起单片机的下降沿外部中断;
然后在这个外部中断回调函数中调用IST8310的读取函数
/* USER CODE BEGIN 1 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) //中断回调函数
{
if (GPIO_Pin==IST8310_DRDY_Pin) //判断是否为PG3的外部中断
{
ist8310_read_mag(mag); //读取磁场数据
}
}
/* USER CODE END 1 */