本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本文围绕STM32微控制器与ADS1110高精度ADC芯片之间的I2C通信展开,介绍了如何通过STM32配置I2C外设实现对ADS1110的模拟驱动。内容涵盖GPIO配置、I2C协议解析、寄存器设置、数据读取及错误处理等关键步骤,旨在帮助开发者构建高效可靠的嵌入式信号采集系统。配套的驱动代码可直接用于项目实践,提升开发效率。
ADS1110   stm32 I2C模拟驱动

1. STM32与ADS1110高精度ADC采集系统概述

在嵌入式系统中,ADC(模数转换器)是实现模拟信号数字化处理的关键组件。随着工业控制、传感器网络与智能设备对测量精度要求的不断提升,高精度ADC的应用变得尤为重要。ADS1110是一款内置PGA(可编程增益放大器)的12位ADC芯片,具备I2C数字接口,适用于与STM32系列微控制器进行高效通信。STM32凭借其强大的处理能力和丰富的外设资源,成为本系统的核心控制器。本文将围绕STM32与ADS1110构建的高精度ADC采集系统展开,详细介绍其硬件配置、驱动开发与数据采集优化策略,旨在为工业测量、环境监测和智能传感器网络提供可靠的技术实现方案。

2. STM32 I2C总线通信基础

2.1 I2C总线协议的基本原理

2.1.1 I2C的物理层结构

I2C(Inter-Integrated Circuit)总线是一种广泛应用于嵌入式系统中的双线串行通信协议。它由Philips公司(现NXP)于1980年代提出,专为在单个电路板上的集成电路之间进行短距离通信而设计。其物理层由两根信号线组成:

  • SCL(Serial Clock) :串行时钟线,由主设备生成,用于同步数据传输。
  • SDA(Serial Data) :串行数据线,用于传输数据位。

这两根线均为开漏输出结构,通常需要外部上拉电阻连接到电源,以确保高电平状态的稳定。这种设计允许多个设备共享同一总线,无需复杂的总线仲裁机制。

信号线 类型 功能描述
SCL 输出 时钟信号,由主设备驱动
SDA 输入/输出 数据信号,主从设备均可读写

2.1.2 主从设备通信机制

I2C通信采用主从结构,总线上的设备分为 主设备 (Master)和 从设备 (Slave)。主设备负责发起通信、生成时钟信号(SCL),并决定数据的传输方向(读或写)。

每个从设备都有一个 唯一的7位或10位地址 ,主设备通过发送该地址来选择与哪个从设备通信。一次完整的I2C通信通常包括以下步骤:

  1. 起始信号(START) :主设备将SDA从高拉低,同时SCL保持高电平,表示通信开始。
  2. 地址帧(Address) :主设备发送7位从设备地址 + 1位读写标志(R/W)。
  3. 数据帧(Data) :主设备和从设备之间交换数据,每次传输8位数据。
  4. 应答信号(ACK/NACK) :每传输完一个字节后,接收方必须发送一个应答位(ACK = 0 表示接收成功,NACK = 1 表示接收失败)。
  5. 停止信号(STOP) :主设备将SDA从低拉高,同时SCL保持高电平,表示通信结束。

2.1.3 数据传输的同步机制

I2C协议采用 同步串行通信 方式,所有数据传输都由SCL时钟信号控制。数据在SCL上升沿被采样,下降沿期间允许SDA状态改变。因此,SDA的变化必须发生在SCL为低电平时,否则可能被误认为是起始或停止信号。

下面是一个典型的I2C通信时序图(使用Mermaid格式):

sequenceDiagram
    participant Master
    participant Slave
    Master->>Slave: START
    Master->>Slave: 7位地址 + R/W
    Slave-->>Master: ACK
    Master->>Slave: Data Byte 1
    Slave-->>Master: ACK
    Master->>Slave: Data Byte 2
    Slave-->>Master: NACK
    Master->>Slave: STOP

在这个流程中,主设备发送了两个数据字节,第二个字节接收方返回NACK,表明不再接收更多数据。

2.2 STM32中的I2C外设功能

2.2.1 支持的I2C模式(标准/快速/高速)

STM32系列MCU的I2C外设支持多种通信速率模式,满足不同应用场景的需求:

模式 通信速率 说明
标准模式(Standard Mode) 最高100 kbps 基础模式,广泛兼容
快速模式(Fast Mode) 最高400 kbps 提高通信速度
高速模式(Fast Mode Plus) 最高1 Mbps 需要外部上拉,部分引脚支持

在STM32CubeMX配置中,可以设置I2C接口的工作模式。例如,对于I2C1:

hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000;  // 快速模式
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;

代码逻辑分析:

  • ClockSpeed :设置为400000即400kHz,为快速模式。
  • DutyCycle :决定SCL的占空比,I2C_DUTYCYCLE_2表示低电平时间是高电平的2倍。
  • AddressingMode :设置为7位地址模式。
  • DualAddressMode :是否启用双地址识别,这里关闭。
  • GeneralCallMode :是否响应通用地址,关闭。
  • NoStretchMode :是否禁用时钟拉伸,关闭。

2.2.2 I2C寄存器结构与功能

STM32的I2C模块通过多个寄存器控制通信流程。关键寄存器包括:

寄存器名 功能描述
CR1 控制寄存器1,控制使能、ACK、SMBus等
CR2 控制寄存器2,设置时钟频率、起始/停止信号等
OAR1/OAR2 从设备地址寄存器
DR 数据寄存器,用于读写数据
SR1/SR2 状态寄存器,指示通信状态(如ACK失败、总线忙等)

例如,在发送数据时,流程如下:

// 启动I2C传输
HAL_I2C_Master_Transmit(&hi2c1, DevAddress, pData, Size, Timeout);

底层操作:

  1. 设置CR2寄存器中的从设备地址和传输长度。
  2. 触发起始信号(START)。
  3. 依次将pData中的每个字节写入DR寄存器。
  4. 检查SR1寄存器中的TXE(发送寄存器空)标志。
  5. 收到ACK后继续发送下一个字节。
  6. 所有字节发送完成后,发送STOP信号。

2.2.3 中断与DMA机制支持

STM32的I2C模块支持中断和DMA机制,以提高通信效率并减少CPU占用。

  • 中断方式 :适用于小数据量通信,便于实时响应。
  • DMA方式 :适用于大数据量传输,自动搬运数据,减少CPU干预。

例如,使用DMA接收数据的配置如下:

// 启用DMA接收
HAL_I2C_Master_Receive_DMA(&hi2c1, DevAddress, rxBuffer, bufferSize);

DMA流程分析:

  1. 主设备发送从设备地址 + 写标志。
  2. 从设备发送ACK。
  3. 开始接收数据,DMA控制器自动将DR寄存器的数据搬运到内存缓冲区rxBuffer。
  4. 数据接收完成后触发DMA中断。
  5. 在DMA中断处理函数中调用HAL_I2C_MemRxCpltCallback()回调函数。

2.3 I2C通信在嵌入式开发中的典型应用

2.3.1 传感器数据采集

I2C常用于连接各种传感器,如温度传感器(LM75)、加速度计(MPU6050)、ADC芯片(ADS1110)等。以ADS1110为例,读取ADC转换结果的流程如下:

uint8_t reg = 0x00; // CONVERSION寄存器地址
uint8_t data[2];

// 发送寄存器地址
HAL_I2C_Master_Transmit(&hi2c1, ADS1110_ADDRESS, &reg, 1, HAL_MAX_DELAY);
// 读取2字节数据
HAL_I2C_Master_Receive(&hi2c1, ADS1110_ADDRESS, data, 2, HAL_MAX_DELAY);

// 组合为12位结果
uint16_t adcValue = (data[0] << 8) | data[1];

逐行分析:

  • reg = 0x00 :指定要读取CONVERSION寄存器。
  • HAL_I2C_Master_Transmit(...) :发送寄存器地址。
  • HAL_I2C_Master_Receive(...) :读取寄存器内容。
  • adcValue :将两个字节组合为16位数据,实际有效位为12位。

2.3.2 多设备通信拓扑

I2C支持多主/多从结构,允许一个主设备控制多个从设备。典型的拓扑结构如下:

graph TD
    A[STM32主设备] -->|SCL| B(I2C总线)
    A -->|SDA| B
    B --> C(ADS1110)
    B --> D(MPU6050)
    B --> E(EEPROM)

关键点:

  • 每个从设备有独立地址。
  • 所有设备共享SCL和SDA信号线。
  • 需要合理配置上拉电阻,防止信号衰减。

2.3.3 通信速率与稳定性考量

在设计I2C通信系统时,需考虑以下因素以确保稳定性和可靠性:

因素 影响 优化建议
上拉电阻 影响上升时间 通常使用4.7kΩ~10kΩ
时钟频率 影响通信速度 根据从设备最大支持频率设置
总线长度 影响信号完整性 不宜过长,建议<30cm
噪声干扰 可能导致通信错误 使用屏蔽线或降低频率
时钟拉伸 从设备延缓主设备 需在代码中处理

例如,STM32中可以通过设置 I2C_TIMINGR 寄存器来优化时序:

hi2c1.Instance->TIMINGR = 0x20404786; // 自定义时序参数

该寄存器控制SCL的高/低电平时间、上升沿/下降沿斜率等,适合复杂环境下定制通信时序。

总结:

本章深入讲解了I2C总线协议的基本原理、STM32中I2C外设的硬件结构与配置方法,以及I2C在嵌入式系统中的典型应用。通过代码示例、流程图与表格的结合,帮助读者全面掌握STM32与I2C通信的实现机制与优化策略,为后续ADS1110的集成与高精度ADC采集打下坚实基础。

3. ADS1110 ADC芯片功能特性

ADS1110是一款专为高精度模拟信号采集设计的12位ADC芯片,广泛应用于嵌入式系统中对传感器信号的采集与处理。其内置的PGA(可编程增益放大器)、多种工作模式、以及标准I2C接口,使其在与STM32等微控制器进行通信时具有高度灵活性与易用性。本章将深入探讨ADS1110的核心功能特性、工作模式配置、以及其与I2C总线的连接方式。

3.1 ADS1110芯片概述

ADS1110是一款高精度、低功耗的12位ADC芯片,适用于对电压信号进行高精度测量的场景,如温度传感器、压力传感器、电池电压监测等应用。

3.1.1 高精度12位ADC性能

ADS1110的分辨率高达12位,意味着它可以将输入电压范围划分为4096个等级。以2.048V参考电压为例,其最小分辨电压为:

\text{LSB} = \frac{V_{ref}}{2^{12}} = \frac{2.048}{4096} = 0.5mV

这使得ADS1110在测量微弱信号时具有较高的精度,适用于工业控制、医疗仪器等对精度要求较高的场景。

3.1.2 内置PGA与输入通道配置

ADS1110集成了一个可编程增益放大器(PGA),增益可设置为1、2、4、8或更高的值,使得它可以处理不同幅度的输入信号。例如,当PGA设置为8倍增益时,输入电压范围可缩小为±256mV,从而提高了小信号的测量精度。

该芯片支持差分输入,提供两个可选的差分输入通道(A0-A1 或 A0-GND),允许用户根据应用需求选择合适的输入模式。

PGA增益 输入范围(V) 分辨率(LSB)
1 ±2.048 1mV
2 ±1.024 0.5mV
4 ±512mV 0.25mV
8 ±256mV 0.125mV

3.1.3 工作电压与封装形式

ADS1110的工作电压范围为2.7V至5.5V,适应多种供电环境。其采用小型SOT23-6封装,适合在空间受限的嵌入式设备中使用。

3.2 ADS1110的工作模式与配置

ADS1110提供了多种工作模式,包括单次转换模式、连续转换模式、比较器模式等,满足不同应用场景下的数据采集需求。

3.2.1 单次转换与连续转换模式

  • 单次转换模式 :适用于需要按需采集数据的场景。每次采集前需向配置寄存器写入启动位,采集完成后进入低功耗状态。
  • 连续转换模式 :适用于实时监控应用,芯片会持续进行ADC转换,输出最新数据。

切换模式可通过修改配置寄存器(CONFIG)中的 MODE 位实现。例如,设置 MODE=0 为连续模式, MODE=1 为单次模式。

3.2.2 数据输出率与精度调整

ADS1110支持不同的数据输出速率(Data Rate),从8SPS(每秒采样数)到3300SPS不等。数据速率越高,采样速度越快,但噪声抑制能力下降。用户可以根据系统对精度和速度的需求进行权衡设置。

数据速率(SPS) 等效噪声带宽(Hz)
8 6.5
16 13
32 27
240 190
3300 2600

3.2.3 比较器模式与阈值检测

ADS1110还支持比较器模式,用户可以设置一个阈值电压,当输入电压超过该阈值时,芯片将触发中断信号。该功能非常适合用于过压检测、电池低电量提醒等应用场景。

设置比较器模式需要配置 CONFIG 寄存器中的 COMP_MODE COMP_POL 位,并通过 HI_THRESH LO_THRESH 寄存器设置上下限阈值。

3.3 ADS1110与I2C接口的连接方式

ADS1110通过标准I2C总线与主控制器(如STM32)通信,其通信接口包括SCL(时钟线)和SDA(数据线)。

3.3.1 SCL/SDA引脚功能说明

  • SCL :I2C时钟线,由主设备控制,用于同步数据传输。
  • SDA :I2C数据线,双向传输数据,支持开漏输出。

在硬件设计中,SCL和SDA引脚通常需要外接上拉电阻(通常为4.7kΩ),以确保信号的完整性。ADS1110支持I2C总线的400kHz标准速率,也兼容100kHz的低速模式。

3.3.2 地址选择与多设备共用I2C总线

ADS1110的I2C地址由 ADDR 引脚决定,该引脚可以接GND、VDD、SDA或SCL,从而实现四种不同的地址配置:

ADDR引脚连接 I2C地址(7位)
GND 0x48
VDD 0x49
SDA 0x4A
SCL 0x4B

这种设计允许在同一I2C总线上挂载多个ADS1110芯片,适用于多通道ADC采集系统。

3.3.3 上拉电阻与信号完整性设计

为了确保I2C通信的稳定性,必须在SCL和SDA线上添加上拉电阻。上拉电阻的值取决于总线电容和通信速率。通常使用4.7kΩ的上拉电阻即可满足大多数应用需求。

此外,建议在PCB布局时将ADS1110靠近主控芯片,并使用短而直的走线以减少寄生电感和电容对信号完整性的影响。

graph TD
    A[STM32] -->|SCL| B[ADS1110]
    A -->|SDA| B
    A -->|ADDR| B
    A -->|VDD| B
    A -->|GND| B
    A -->|INT| B

如上图所示,典型的ADS1110与STM32之间的连接包括SCL、SDA、电源、地以及可选的中断引脚(INT),用于触发比较器事件。

本章从ADS1110的硬件特性、工作模式配置到I2C接口设计进行了详细分析。ADS1110凭借其高精度、低功耗、多通道支持以及灵活的I2C通信能力,成为嵌入式系统中理想的ADC采集解决方案。下一章将介绍如何在STM32平台上进行I2C总线的初始化与配置,为ADS1110的通信做好准备。

4. STM32 I2C驱动的硬件配置与初始化

在嵌入式系统开发中,I2C总线是一种常用的串行通信接口,尤其适用于连接低速外设如传感器、EEPROM、ADC等模块。STM32系列微控制器集成了I2C硬件外设,支持标准模式(100kHz)、快速模式(400kHz)甚至高速模式(3.4MHz),为开发者提供了高效、稳定的通信方式。本章将深入探讨STM32中I2C通信的硬件配置与初始化流程,涵盖GPIO引脚配置、外设初始化参数设置以及HAL/LL库的驱动实现。

4.1 STM32 GPIO引脚配置(SCL/SDA)

在使用STM32的I2C功能之前,必须对SCL(串行时钟线)和SDA(串行数据线)引脚进行正确的配置。这一步是I2C通信成功的基础。

4.1.1 推挽输出与开漏模式选择

I2C总线在物理层上采用开漏输出结构,因为多个设备可以共享同一总线,因此必须使用外部上拉电阻。在STM32中,SCL和SDA引脚应配置为 复用开漏输出模式 (GPIO_MODE_OUTPUT_OD)。

GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;  // 假设使用I2C1的SCL和SDA
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;          // 复用开漏模式
GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;      // 设置复用功能为I2C1
GPIO_InitStruct.Pull = GPIO_NOPULL;              // 不使用内部上下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
逻辑分析与参数说明:
  • GPIO_MODE_AF_OD :表示该引脚用于复用功能,并以开漏方式输出。
  • GPIO_AF4_I2C1 :指定引脚的复用功能为I2C1。
  • GPIO_NOPULL :I2C总线需外部上拉电阻,因此不使用内部上下拉。
  • GPIO_SPEED_FREQ_VERY_HIGH :虽然I2C是低速通信,但引脚速度应设置为高速以保证时序准确。

4.1.2 引脚复用功能配置

STM32的每个GPIO引脚可以配置为多种复用功能。使用I2C时,必须将引脚映射到对应的I2C外设功能上。

示例:使用I2C1的SCL/SDA引脚
引脚名称 默认复用功能
PB6 I2C1_SCL
PB7 I2C1_SDA

若使用重映射引脚,例如I2C1的SDA映射到PB9、SCL映射到PB8,则需启用重映射功能。

4.1.3 上拉电阻与信号完整性设计

由于I2C使用开漏输出,SCL和SDA信号线必须通过上拉电阻接到VCC。典型值为4.7kΩ或10kΩ,取决于总线速率和电容负载。

表:不同速率下推荐的上拉电阻值
通信速率 推荐上拉电阻
标准模式(100kHz) 4.7kΩ
快速模式(400kHz) 2.2kΩ
高速模式(3.4MHz) 1kΩ

设计注意事项:

  • 总线上的电容不能超过400pF;
  • 若连接多个设备,需注意电容叠加;
  • 使用低ESR电容滤波电源,确保VCC稳定。

4.2 STM32 I2C外设初始化流程

在完成GPIO配置后,接下来是I2C外设本身的初始化。这包括时钟源选择、波特率设置以及中断和DMA的配置。

4.2.1 I2C时钟源配置

STM32的I2C外设支持多种时钟源,通常使用系统时钟(SYSCLK)作为输入。在初始化结构体中需指定时钟源。

hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;        // 100kHz
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddress = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
逻辑分析与参数说明:
  • ClockSpeed :设置I2C通信速率;
  • DutyCycle :决定SCL高电平时间,标准模式通常使用 I2C_DUTYCYCLE_2
  • AddressingMode :选择7位或10位地址模式;
  • OwnAddress1 :主设备无需设置,设为0;
  • GeneralCallMode :是否启用广播地址;
  • NoStretchMode :是否禁用时钟拉伸。

4.2.2 波特率与时序参数设置

I2C的波特率计算依赖于系统时钟和时钟预分频器。公式如下:

ClockSpeed = F_SCL = F_PCLK / (CCR * (1 + DUTY))

其中:

  • F_PCLK:I2C外设的时钟源频率;
  • CCR:时钟控制寄存器;
  • DUTY:占空比(2或16/9)。

例如:若F_PCLK=80MHz,希望F_SCL=100kHz,可设置CCR=400。

4.2.3 中断与DMA通道配置

为了提高I2C通信效率,可以启用中断或DMA方式。

使用中断方式初始化:
HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
使用DMA方式初始化:
hdma_i2c1_tx.Instance = DMA1_Stream6;
hdma_i2c1_tx.Init.Channel = DMA_CHANNEL_1;
hdma_i2c1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_i2c1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2c1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_i2c1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_i2c1_tx.Init.Mode = DMA_NORMAL;
hdma_i2c1_tx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_i2c1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
逻辑分析:
  • DMA_DIRECTION :内存到外设传输,适用于发送数据;
  • MemInc = DMA_MINC_ENABLE :内存地址递增;
  • PeriphDataAlignment :按字节对齐;
  • DMA_PRIORITY_HIGH :确保I2C传输优先级较高;
  • FIFOMode :关闭FIFO,适用于简单传输。

4.3 STM32 HAL/LL库中I2C驱动实现

STM32提供了HAL库和LL库两种方式操作I2C。HAL库封装度高,适合快速开发;LL库更贴近寄存器,适合性能优化。

4.3.1 HAL库中的I2C初始化函数

使用HAL库时,通常调用 HAL_I2C_Init() 函数完成初始化。

if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
    Error_Handler();
}

HAL库内部会调用 I2C_Init() 函数,设置寄存器CR1、CR2、CCR、TRISE等,完成I2C外设配置。

4.3.2 LL库的底层寄存器操作

使用LL库可以直接操作寄存器,提高执行效率。

LL_I2C_InitTypeDef I2C_InitStruct = {0};

I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
I2C_InitStruct.ClockSpeed = 100000;
I2C_InitStruct.DutyCycle = LL_I2C_DUTYCYCLE_2;
I2C_InitStruct.OwnAddress1 = 0;
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;

LL_I2C_Init(I2C1, &I2C_InitStruct);
LL_I2C_Enable(I2C1);
逻辑分析:
  • PeripheralMode :设置为I2C模式;
  • ClockSpeed :波特率;
  • TypeAcknowledge :是否启用应答;
  • OwnAddrSize :7位地址格式;
  • LL_I2C_Enable() :启用I2C外设。

4.3.3 数据发送与接收函数实现

HAL库提供了如下发送与接收函数:

// 发送数据
HAL_I2C_Master_Transmit(&hi2c1, dev_addr, tx_data, size, HAL_MAX_DELAY);

// 接收数据
HAL_I2C_Master_Receive(&hi2c1, dev_addr, rx_data, size, HAL_MAX_DELAY);

LL库中需手动控制状态机:

LL_I2C_GenerateStartCondition(I2C1);
while (!LL_I2C_IsActiveFlag_SB(I2C1));

LL_I2C_TransmitData8(I2C1, dev_addr << 1);
while (!LL_I2C_IsActiveFlag_ADDR(I2C1));
LL_I2C_ClearFlag_ADDR(I2C1);

for (int i = 0; i < size; i++) {
    LL_I2C_TransmitData8(I2C1, tx_data[i]);
    while (!LL_I2C_IsActiveFlag_TXE(I2C1));
}
LL_I2C_GenerateStopCondition(I2C1);
状态机流程图(mermaid):
graph TD
    A[Start Condition] --> B[发送设备地址]
    B --> C{地址应答?}
    C -->|Yes| D[发送数据]
    D --> E[等待发送完成]
    E --> F[Stop Condition]
    C -->|No| G[错误处理]

本章从GPIO引脚配置入手,逐步介绍了STM32 I2C外设的初始化流程,并对比了HAL库与LL库的实现方式。下一章将继续深入I2C协议本身,分析其通信流程与错误处理机制。

5. I2C通信协议详解与实现

在嵌入式系统中,I2C(Inter-Integrated Circuit)协议因其结构简洁、通信稳定、支持多主多从架构等优点,被广泛应用于芯片间的短距离通信。STM32系列微控制器集成了I2C硬件接口,同时也支持通过GPIO模拟实现I2C通信。本章将深入剖析I2C协议的基本流程,探讨STM32模拟I2C通信的实现方法,并介绍常见的错误检测与恢复机制。

5.1 I2C通信协议基本流程

I2C总线是一种同步串行通信接口,由Philips(现NXP)开发。其核心特点包括双线制(SCL为时钟线,SDA为数据线)、支持多主设备和多从设备、数据传输速率可调(标准模式100kbps、快速模式400kbps、高速模式3.4Mbps)。

5.1.1 起始信号与停止信号

I2C通信的起始(START)和停止(STOP)信号由主设备发起,用于标识一次通信的开始与结束。

  • 起始信号(START) :SCL为高电平时,SDA由高变低。
  • 停止信号(STOP) :SCL为高电平时,SDA由低变高。

这些信号是I2C通信的基础,确保从设备能够识别主设备的通信请求。

5.1.2 地址帧与数据帧格式

每次I2C通信开始后,主设备会发送一个地址帧,用于选择目标从设备。地址帧为8位,其中前7位为从设备地址,最后1位为读写标志(0表示写,1表示读)。

随后是数据帧的传输,每个数据帧为8位,高位(MSB)先传。每发送一个字节后,接收方需要发送一个应答信号(ACK),表示接收成功。

字段 长度 说明
设备地址 7位 从设备的唯一标识
R/W位 1位 0表示写,1表示读
数据字节 8位 每次传输的数据
ACK/NACK 1位 应答/非应答信号

5.1.3 应答机制与数据有效性

在每个字节传输后,接收设备需返回一个ACK或NACK信号:

  • ACK(应答) :SDA在第9个时钟周期为低电平。
  • NACK(非应答) :SDA在第9个时钟周期为高电平。

这为通信的可靠性和错误检测提供了基础。主设备在接收到NACK时,通常表示从设备未准备好或地址无效。

5.2 STM32模拟I2C通信实现

虽然STM32具有硬件I2C模块,但在某些应用场景中(如硬件模块被占用或调试需求),开发者可能需要使用GPIO模拟I2C通信。这种方式虽然效率略低,但具有高度灵活性。

5.2.1 模拟I2C的时序控制方法

模拟I2C的核心是通过控制GPIO引脚模拟SCL和SDA信号的时序。主要步骤包括:

  1. 起始信号生成 :SCL高电平时,SDA下降沿。
  2. 地址/数据发送 :逐位发送数据,高位先传。
  3. 应答信号检测 :等待从设备发送ACK/NACK。
  4. 停止信号生成 :SCL高电平时,SDA上升沿。

以下是一个简单的模拟I2C起始信号函数示例:

void I2C_Start(void) {
    SDA_HIGH();  // 初始化SDA为高
    SCL_HIGH();  // SCL拉高
    Delay_us(1); // 延时以满足建立时间
    SDA_LOW();   // SDA下降沿表示起始信号
    Delay_us(1);
    SCL_LOW();   // SCL拉低准备发送数据
}

逻辑分析
- SDA_HIGH() SCL_HIGH() 设置GPIO为高电平。
- Delay_us(1) 用于满足I2C时序要求(建立时间和保持时间)。
- SDA_LOW() 产生起始信号。
- 最后将SCL拉低,进入数据发送阶段。

5.2.2 模拟I2C的GPIO操作函数

除了起始信号外,还需要实现以下基本操作函数:

void I2C_WriteByte(uint8_t data) {
    for (int i = 0; i < 8; i++) {
        if (data & 0x80) {
            SDA_HIGH(); // 发送高位
        } else {
            SDA_LOW();
        }
        SCL_HIGH();     // 拉高SCL
        Delay_us(1);
        SCL_LOW();      // 拉低SCL
        data <<= 1;     // 左移准备发送下一位
    }
    // 等待ACK
    SDA_HIGH();         // 释放SDA,准备读取ACK
    SCL_HIGH();
    Delay_us(1);
    if (SDA_READ()) {
        // NACK
    }
    SCL_LOW();
}

参数说明
- data :要发送的8位数据。
- SDA_READ() :读取SDA引脚电平,判断是否收到ACK。
- 该函数逐位发送数据,并在最后检测应答信号。

5.2.3 模拟I2C的通信速率调整

模拟I2C的通信速率受限于GPIO操作速度和延时函数。可以通过调整 Delay_us() 的时间来控制SCL频率,从而调节通信速率。

例如,若希望实现100kHz的速率,则每个SCL周期为10μs。通过控制SCL高/低电平时间,可以实现不同速率的通信。

通信速率 周期时间 高/低时间(各)
100kHz 10μs 5μs
400kHz 2.5μs 1.25μs

优化建议
- 使用硬件定时器实现更精确的延时。
- 若系统资源允许,考虑使用硬件I2C模块。

5.3 I2C通信错误检测与处理

I2C通信中可能出现多种错误类型,如仲裁丢失、总线繁忙、应答失败、通信超时等。良好的错误处理机制是系统稳定性的关键。

5.3.1 常见错误类型与判断方法

错误类型 原因 检测方法
应答失败(NACK) 从设备不存在或未准备好 在发送完地址/数据后未收到ACK
总线繁忙 其他主设备正在通信 检测SCL或SDA是否被占用
仲裁丢失 多主竞争导致主设备失去控制权 硬件I2C中断标志位判断
通信超时 未在规定时间内收到应答或响应 设置超时计数器

5.3.2 错误恢复机制设计

当检测到错误时,应采取相应的恢复措施,例如:

  • 重发机制 :在NACK后重新发送起始信号和地址。
  • 总线复位 :若总线被锁死,可通过拉高SCL多次并释放SDA来恢复。
  • 中断处理 :在硬件I2C中,利用中断机制快速响应错误。

以下是一个I2C总线复位的示例函数:

void I2C_BusReset(void) {
    SCL_HIGH();
    SDA_HIGH();
    Delay_us(5);
    for (int i = 0; i < 9; i++) {
        SCL_LOW();
        Delay_us(1);
        SCL_HIGH();
        Delay_us(1);
    }
    I2C_Start();  // 重新发起起始信号
}

逻辑分析
- 拉高SCL和SDA,确保总线空闲。
- 连续发送9个SCL脉冲,强制从设备释放SDA。
- 最后发送起始信号,重新初始化通信。

5.3.3 通信超时与重试机制

为了避免通信卡死,应设置通信超时和重试机制。例如:

#define I2C_TIMEOUT 1000

uint8_t I2C_Write(uint8_t address, uint8_t* data, uint16_t length) {
    uint32_t timeout = I2C_TIMEOUT;
    I2C_Start();
    I2C_WriteByte(address);  // 写地址
    if (!WaitForAck()) {     // 等待ACK
        return I2C_ERROR_NACK;
    }
    for (int i = 0; i < length; i++) {
        I2C_WriteByte(data[i]);
        if (!WaitForAck()) {
            return I2C_ERROR_NACK;
        }
    }
    I2C_Stop();
    return I2C_OK;
}

参数说明
- address :从设备地址。
- data :要发送的数据缓冲区。
- length :数据长度。
- WaitForAck() :等待应答信号,返回是否收到ACK。

优化建议
- 可引入重试机制,例如失败后重试3次。
- 在RTOS环境中,使用超时任务或事件标志组进行控制。

5.4 小结与拓展

本章详细解析了I2C通信协议的核心流程,包括起始/停止信号、地址/数据帧格式、应答机制等。并深入探讨了如何在STM32上通过GPIO模拟实现I2C通信,提供了完整的代码示例及参数说明。最后,介绍了常见的I2C通信错误类型、判断方法以及恢复机制,确保系统通信的可靠性。

在后续章节中,我们将基于本章内容,结合ADS1110的I2C接口,进一步探讨其寄存器配置与ADC数据采集流程,实现完整的高精度ADC采集系统。

6. ADS1110寄存器配置与ADC转换控制

ADS1110是一款高精度、12位分辨率的I2C接口模数转换器(ADC),广泛用于高精度传感器数据采集系统中。要充分发挥其性能,必须深入了解其寄存器结构和配置方法。本章将深入解析ADS1110的寄存器配置流程,包括配置寄存器(CONFIG)、转换结果寄存器(CONVERSION)的功能与使用方法,并详细说明如何通过STM32控制ADS1110进行单次与连续ADC转换操作。

6.1 ADS1110寄存器结构与功能

ADS1110的寄存器结构相对简洁,主要包含两个寄存器: 配置寄存器(CONFIG) 转换结果寄存器(CONVERSION)

6.1.1 寄存器地址映射

ADS1110的寄存器地址映射如下:

寄存器地址 寄存器名称 功能描述
0x00 CONFIG 控制ADC工作模式、通道选择等配置
0x01 CONVERSION 存储最近一次转换的结果

ADS1110的I2C地址为固定的 0x48 (7位地址),可以通过ADDR引脚配置多个设备共用I2C总线。

6.1.2 配置寄存器(CONFIG)详解

配置寄存器(CONFIG)为16位寄存器,其结构如下(MSB到LSB):

位号 字段名称 描述
15 OS 单次转换启动位(1: 启动单次转换)
14-12 MUX 输入通道选择(000-101:通道0~5,110:温度传感器,111:GND)
11-9 PGA 增益设置(001: 1x, 010: 2x, 011: 4x, 100: 8x, 101: 16x)
8 MODE 工作模式(0: 连续模式,1: 单次模式)
7-5 DR 数据输出速率(001: 128SPS, 010: 250SPS, 011: 490SPS 等)
4 COMP_MODE 比较器模式(0: 传统比较器,1: 窗口比较器)
3 COMP_POL 比较器输出极性(0: 低有效,1: 高有效)
2 COMP_LAT 比较器锁存使能(0: 非锁存,1: 锁存)
1 COMP_QUE 比较器队列配置(00: 禁用,01: 1次,10: 2次,11: 4次)
0 保留 保留位,必须为0

6.1.3 转换结果寄存器(CONVERSION)读取

转换结果寄存器(CONVERSION)是一个16位寄存器,存储最新的ADC转换结果。其数据格式如下:

  • 12位ADC结果 :占据高位12位(bit15~bit4),为补码格式。
  • 低4位(bit3~bit0) :保留位,读出为0。

例如,当输入电压为0V时,读出结果为0x0000;当输入为满量程时(根据增益不同),读出结果为0x7FF(正满量程)或0x800(负满量程)。

6.2 ADS1110寄存器配置方法

正确配置ADS1110是实现高精度ADC采集的前提。本节将介绍初始化配置流程、输入通道与增益设置、以及转换模式与数据速率选择。

6.2.1 初始化配置流程

初始化ADS1110的典型流程如下:

  1. 设置输入通道(MUX)
  2. 配置增益(PGA)
  3. 选择转换模式(单次或连续)
  4. 设定数据输出速率(DR)
  5. 写入配置寄存器(CONFIG)

6.2.2 输入通道与增益设置

ADS1110支持6个输入通道,包括5个外部通道和1个内部温度传感器通道。以下为MUX字段设置对照表:

MUX 值 输入通道配置
000 AIN0
001 AIN1
010 AIN2
011 AIN3
100 AIN0 - AIN1
101 AIN2 - AIN3
110 内部温度传感器
111 GND

PGA字段用于设置增益,从而调整输入电压范围。例如:

PGA 值 增益倍数 输入范围(Vref=2.048V)
001 1x ±2.048V
010 2x ±1.024V
011 4x ±0.512V
100 8x ±0.256V
101 16x ±0.128V

6.2.3 转换模式与数据速率选择

ADS1110支持两种转换模式:

  • 单次转换模式(MODE = 1) :每次转换后自动进入低功耗状态。
  • 连续转换模式(MODE = 0) :持续进行转换,适用于需要高频率采样的场景。

数据输出速率(DR)字段控制采样率,常见设置如下:

DR 值 数据输出速率(SPS)
001 128
010 250
011 490
100 920

6.3 启动ADC转换与状态等待机制

在完成配置后,需要根据工作模式启动ADC转换,并等待结果。

6.3.1 启动单次转换的方法

在单次转换模式下,需要手动启动每次转换。具体步骤如下:

  1. 设置OS位为1(写入CONFIG寄存器)
  2. 等待转换完成(通过状态位或延时)
  3. 读取CONVERSION寄存器获取结果
uint16_t config = 0x8583;  // 示例配置:AIN0, 1x增益, 单次模式, 128SPS
HAL_I2C_Mem_Write(&hi2c1, ADS1110_ADDRESS << 1, ADS1110_REG_CONFIG, 1, (uint8_t*)&config, 2, HAL_MAX_DELAY);

逐行解释:

  • 0x8583 是配置值,对应:
  • OS = 1 (启动单次转换)
  • MUX = 000 (选择AIN0)
  • PGA = 001 (1x增益)
  • MODE = 1 (单次模式)
  • DR = 001 (128SPS)
  • HAL_I2C_Mem_Write() :通过I2C总线向ADS1110的CONFIG寄存器写入配置值

6.3.2 连续转换的配置与控制

在连续转换模式下,ADC会持续进行转换,适合需要高频率采样的应用场景。配置步骤如下:

  1. 设置MODE位为0
  2. 设置OS位为1(仅首次启动)
  3. 循环读取CONVERSION寄存器获取数据
uint16_t config = 0x0583;  // MODE=0: 连续模式
HAL_I2C_Mem_Write(&hi2c1, ADS1110_ADDRESS << 1, ADS1110_REG_CONFIG, 1, (uint8_t*)&config, 2, HAL_MAX_DELAY);

逐行解释:

  • MODE位设为0表示进入连续模式
  • OS位设为1启动首次转换,后续自动连续运行

6.3.3 状态寄存器查询与中断响应

ADS1110没有专用的状态寄存器,但可以通过以下方式判断转换是否完成:

  1. 延时等待法 :适用于单次模式,已知转换时间
  2. 查询CONVERSION寄存器 :在连续模式中,读取新值即可

此外,ADS1110提供一个ALERT引脚,可用于比较器触发中断。通过配置COMP_MODE和阈值寄存器,可以实现超出范围中断通知。

graph TD
    A[开始ADC采集] --> B{是否单次模式?}
    B -->|是| C[启动单次转换]
    B -->|否| D[进入连续模式]
    C --> E[等待转换完成]
    D --> F[循环读取转换结果]
    E --> G[读取CONVERSION寄存器]
    F --> G
    G --> H[处理ADC数据]

小结

本章深入解析了ADS1110的寄存器结构及其配置方法,重点介绍了如何通过STM32控制其进行ADC转换。通过对配置寄存器(CONFIG)的各个字段进行解析,读者可以灵活配置输入通道、增益、转换模式与采样率。此外,还详细说明了单次与连续转换的启动方式,以及如何读取转换结果并设计中断响应机制。

下一章将继续深入探讨如何将ADC数据转化为实际的物理量(如电压、温度等),并实现完整的采集与应用系统设计。

7. 高精度ADC数据采集与应用设计实践

7.1 读取12位ADC转换结果

ADS1110作为一款12位高精度ADC芯片,其输出结果为12位二进制数,范围为0~4095(对应于输入电压范围),需要根据参考电压(VREF)进行物理量的转换。

7.1.1 数据格式与转换公式

ADS1110的转换结果存储在 CONVERSION 寄存器中(地址为0x00),是一个16位寄存器,其中高4位为符号位(用于表示负电压,但ADS1110仅支持单端输入,通常为正),低12位为有效数据。

// 读取转换结果(假设使用HAL库)
uint16_t read_adc_value(I2C_HandleTypeDef *hi2c, uint8_t dev_addr) {
    uint8_t reg = 0x00;  // CONVERSION寄存器地址
    uint8_t data[2];
    // 发送寄存器地址
    HAL_I2C_Master_Transmit(hi2c, dev_addr, &reg, 1, HAL_MAX_DELAY);
    // 读取16位数据
    HAL_I2C_Master_Receive(hi2c, dev_addr, data, 2, HAL_MAX_DELAY);
    // 合并高位与低位
    uint16_t adc_value = (data[0] << 8) | data[1];
    return adc_value;
}

7.1.2 温度、电压等物理量的转换方法

以测量电压为例,假设使用1倍增益(PGA=1),则输入电压范围为0~2.048V,对应的ADC值为0~4095。

计算公式如下:

V_{in} = \frac{ADC_{value}}{4095} \times V_{REF}

例如,若测得ADC值为2048,VREF=2.048V,则:

V_{in} = \frac{2048}{4095} \times 2.048 ≈ 1.024V

7.1.3 数据滤波与校准处理

为了提升采集精度,通常采用以下几种方法:

  • 滑动平均滤波 :取最近N次采样值的平均值。
  • 中值滤波 :剔除异常值后再取平均。
  • 软件校准 :通过标准电压进行系统校准,计算偏移量与增益误差。
// 滑动平均滤波示例
#define SAMPLE_BUFFER_SIZE 10
uint16_t buffer[SAMPLE_BUFFER_SIZE];
uint8_t buffer_index = 0;

uint16_t sliding_average_filter(uint16_t new_value) {
    buffer[buffer_index++] = new_value;
    if (buffer_index >= SAMPLE_BUFFER_SIZE) buffer_index = 0;

    uint32_t sum = 0;
    for (int i = 0; i < SAMPLE_BUFFER_SIZE; i++) {
        sum += buffer[i];
    }
    return sum / SAMPLE_BUFFER_SIZE;
}

7.2 STM32与ADS1110的完整通信流程

7.2.1 初始化流程与通信顺序

整个通信流程包括:

  1. 配置STM32的I2C外设(SCL/SDA引脚、时钟源、波特率等)。
  2. 初始化ADS1110的配置寄存器(CONFIG),设置输入通道、增益、模式等。
  3. 启动一次ADC转换(单次模式)或设置为连续模式。
  4. 读取转换结果并进行处理。

7.2.2 数据采集与传输的时序控制

在STM32中使用HAL库进行I2C通信时,必须注意通信时序。ADS1110的转换时间约为1ms(128SPS),因此读取前需等待转换完成,或查询状态位。

graph TD
    A[初始化I2C外设] --> B[写入ADS1110配置寄存器]
    B --> C{是否为单次转换模式?}
    C -->|是| D[发送启动转换命令]
    C -->|否| E[设置为连续转换模式]
    D --> F[等待转换完成]
    E --> G[定时读取转换结果]
    F --> H[读取CONVERSION寄存器]
    G --> H
    H --> I[数据处理与滤波]

7.2.3 完整代码示例与调试方法

void ads1110_init(I2C_HandleTypeDef *hi2c, uint8_t dev_addr) {
    uint8_t config[3];
    config[0] = 0x01;  // CONFIG寄存器地址
    config[1] = 0x84;  // 单次转换模式,通道0,增益1x
    config[2] = 0x83;  // 数据速率128SPS,比较器模式关

    HAL_I2C_Master_Transmit(hi2c, dev_addr, config, 3, HAL_MAX_DELAY);
}

uint16_t get_adc_value(I2C_HandleTypeDef *hi2c, uint8_t dev_addr) {
    uint8_t reg = 0x00;
    uint8_t data[2];
    HAL_I2C_Master_Transmit(hi2c, dev_addr, &reg, 1, HAL_MAX_DELAY);
    HAL_I2C_Master_Receive(hi2c, dev_addr, data, 2, HAL_MAX_DELAY);
    return (data[0] << 8) | data[1];
}

调试时可使用逻辑分析仪或串口打印转换结果进行验证。

7.3 嵌入式系统中高精度ADC采集应用设计

7.3.1 在传感器系统中的实际应用

ADS1110可用于高精度传感器数据采集,如:

  • 压力传感器 :通过放大器将压力信号转换为电压后接入ADS1110。
  • 温度传感器 :如PT100搭配恒流源,转换为电压信号后测量。
  • pH值检测 :利用差分电压采集pH探头的输出信号。

7.3.2 多通道数据采集与处理

ADS1110支持4个单端输入通道(AIN0~AIN3),可以通过配置寄存器切换通道进行多通道采集:

// 选择AIN1通道
config[1] = 0xA4;  // 通道1,增益1x

多通道采集时,建议采用轮询方式依次读取各通道值,并进行滤波处理。

7.3.3 实时性与稳定性优化策略

为提升采集系统的稳定性与实时性,可采取以下措施:

  • 中断触发采集 :结合ADS1110的比较器中断功能,实现阈值触发采集。
  • DMA传输 :使用DMA提升I2C通信效率,减少CPU占用。
  • 硬件滤波 :在ADS1110输入端加RC低通滤波电路。
  • 电源去耦 :为ADS1110提供稳定的参考电压,并在VDD加10uF和0.1uF电容。
// 示例:使用中断方式触发采集
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == ADS1110_INT_PIN) {
        adc_value = get_adc_value(&hi2c1, ADS1110_ADDRESS);
        process_adc_data(adc_value);
    }
}

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本文围绕STM32微控制器与ADS1110高精度ADC芯片之间的I2C通信展开,介绍了如何通过STM32配置I2C外设实现对ADS1110的模拟驱动。内容涵盖GPIO配置、I2C协议解析、寄存器设置、数据读取及错误处理等关键步骤,旨在帮助开发者构建高效可靠的嵌入式信号采集系统。配套的驱动代码可直接用于项目实践,提升开发效率。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐