一、简介:
MCP3421是一款18位ΔΣ模数转换器,采用6引脚SOT-23封装,通过I2C接口与主机通信。
二、主要技术特性:
-
分辨率与速率:可编程配置为18位(3.75SPS)、16位(15SPS)、14位(60SPS)、12位(240SPS)。
-
输入结构 :差分输入,支持双极性信号(-Vref ~ +Vref)。
-
内置基准:2.048V ±0.05%,温漂5ppm/°C(部分资料显示15ppm,以5ppm为准)。
-
可编程增益(PGA):1、2、4、8倍。
-
工作模式:单次转换(省电)或连续转换。
-
功耗:连续模式145μA,单次模式39μA (1SPS)。
三、主要应用:
• 便携式仪器
• 称重秤与燃油表
• 采用 RTD 、热敏电阻和热电偶的温度传感
• 压力、应变和力的电桥传感
四、引脚定义:

| 引脚号 | 名称 | 功能描述 | 连接至STM32Lxxx |
|---|---|---|---|
| 1 | VDD | 电源2.7V-5.5V | 3.3V (与STM32同电源或独立) |
| 2 | VIN+ | 差分正输入 | 模拟信号输入 |
| 3 | VIN- | 差分负输入 | 模拟信号输入/AGND |
| 4 | VSS | 地 | GND |
| 5 | SCL | I2C时钟线 | I2C_SCL引脚 (如PB6) |
| 6 | SDA | I2C数据线 | I2C_SDA引脚 (如PB7) |
五、内部原理框图:

六、头文件:
/**
* @file mcp3421.h
* @brief MCP3421 18-Bit ADC Driver for STM32Lxxx
*/
#ifndef __MCP3421_H
#define __MCP3421_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32l4xx_hal.h" // 根据具体STM32L系列调整头文件
/* MCP3421 Device Address ----------------------------------------------------*/
#define MCP3421_ADDRESS 0x68 // 7-bit地址,左对齐
#define MCP3421_ADDRESS_WRITE (MCP3421_ADDRESS << 1) // 写地址 0xD0
#define MCP3421_ADDRESS_READ ((MCP3421_ADDRESS << 1) | 1) // 读地址 0xD1
/* Configuration Register Bits -----------------------------------------------*/
// 配置字节格式: [RDY, C1, C0, O/C, S1, S0, G1, G0]
#define MCP3421_CFG_RDY (0x80) // 就绪位: 1=转换完成/就绪
#define MCP3421_CFG_CHAN (0x00) // 通道(单通道固定为0)
// 转换模式
#define MCP3421_MODE_ONESHOT (0x00) // 单次转换模式 (bit4 = 0)
#define MCP3421_MODE_CONTINUOUS (0x10) // 连续转换模式 (bit4 = 1)
// 采样率/分辨率选择 (bits 3-2)
#define MCP3421_RATE_240_12BIT (0x00) // 240 SPS, 12位
#define MCP3421_RATE_60_14BIT (0x04) // 60 SPS, 14位
#define MCP3421_RATE_15_16BIT (0x08) // 15 SPS, 16位
#define MCP3421_RATE_3P75_18BIT (0x0C) // 3.75 SPS, 18位
// PGA增益选择 (bits 1-0)
#define MCP3421_PGA_1 (0x00) // 增益 x1
#define MCP3421_PGA_2 (0x01) // 增益 x2
#define MCP3421_PGA_4 (0x02) // 增益 x4
#define MCP3421_PGA_8 (0x03) // 增益 x8
/* Error Codes ---------------------------------------------------------------*/
#define MCP3421_OK (0x00)
#define MCP3421_ERROR_TIMEOUT (0x01)
#define MCP3421_ERROR_BUSY (0x02)
/* Public Functions ----------------------------------------------------------*/
uint8_t MCP3421_ReadConfig(I2C_HandleTypeDef *hi2c, uint8_t *config);
uint8_t MCP3421_WriteConfig(I2C_HandleTypeDef *hi2c, uint8_t config);
uint8_t MCP3421_TriggerConversion(I2C_HandleTypeDef *hi2c, uint8_t rate, uint8_t pga);
uint8_t MCP3421_ReadResult(I2C_HandleTypeDef *hi2c, int32_t *adcValue, uint8_t *rdyBit);
uint8_t MCP3421_GetSingleConversion(I2C_HandleTypeDef *hi2c, uint8_t pga, int32_t *result);
#ifdef __cplusplus
}
#endif
#endif /* __MCP3421_H */
七、源文件:
/**
* @file mcp3421.c
* @brief MCP3421 Driver Implementation
*/
#include "mcp3421.h"
#include <string.h>
/**
* @brief 读取当前配置寄存器
* @param hi2c: I2C句柄
* @param config: 存储读取到的配置字节
* @retval MCP3421_OK/ERROR
*/
uint8_t MCP3421_ReadConfig(I2C_HandleTypeDef *hi2c, uint8_t *config)
{
// MCP3421支持从指针地址0x00读取配置
uint8_t regAddr = 0x00;
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hi2c, MCP3421_ADDRESS_WRITE, ®Addr, 1, HAL_MAX_DELAY);
if(status != HAL_OK) return MCP3421_ERROR_TIMEOUT;
status = HAL_I2C_Master_Receive(hi2c, MCP3421_ADDRESS_READ, config, 1, HAL_MAX_DELAY);
if(status != HAL_OK) return MCP3421_ERROR_TIMEOUT;
return MCP3421_OK;
}
/**
* @brief 写入配置寄存器(同时触发单次转换)
* @param hi2c: I2C句柄
* @param config: 配置字节
* @retval MCP3421_OK/ERROR
*/
uint8_t MCP3421_WriteConfig(I2C_HandleTypeDef *hi2c, uint8_t config)
{
uint8_t txData[2];
txData[0] = 0x00; // 指针寄存器
txData[1] = config; // 配置字节
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hi2c, MCP3421_ADDRESS_WRITE, txData, 2, HAL_MAX_DELAY);
return (status == HAL_OK) ? MCP3421_OK : MCP3421_ERROR_TIMEOUT;
}
/**
* @brief 触发一次单次转换
* @param hi2c: I2C句柄
* @param rate: 采样率 (MCP3421_RATE_x)
* @param pga: 增益 (MCP3421_PGA_x)
* @retval MCP3421_OK/ERROR
*/
uint8_t MCP3421_TriggerConversion(I2C_HandleTypeDef *hi2c, uint8_t rate, uint8_t pga)
{
uint8_t config = MCP3421_MODE_ONESHOT | rate | pga;
return MCP3421_WriteConfig(hi2c, config);
}
/**
* @brief 读取ADC转换结果(18位/16位/14位/12位)
* @param hi2c: I2C句柄
* @param adcValue: 输出ADC原始值(已符号扩展为32位)
* @param rdyBit: 输出配置寄存器中的RDY位状态
* @retval MCP3421_OK/ERROR/BUSY
*/
uint8_t MCP3421_ReadResult(I2C_HandleTypeDef *hi2c, int32_t *adcValue, uint8_t *rdyBit)
{
uint8_t rxData[3];
uint8_t config;
// 读取3字节:2字节ADC数据 + 1字节配置(18位模式为3字节,其他模式高字节为0)
HAL_StatusTypeDef status = HAL_I2C_Master_Receive(hi2c, MCP3421_ADDRESS_READ, rxData, 3, HAL_MAX_DELAY);
if(status != HAL_OK) return MCP3421_ERROR_TIMEOUT;
// 解析配置字节(第三个字节)
config = rxData[2];
*rdyBit = (config & MCP3421_CFG_RDY) ? 1 : 0;
// 检查转换是否完成
if(*rdyBit == 0) {
return MCP3421_ERROR_BUSY; // RDY=0表示正在转换
}
// 合并ADC数据(MCP3421输出为18位有符号,左对齐)
// 对于18位模式,数据在[17:0];读取的rxData[0]是高字节,rxData[1]是低字节
uint32_t raw = ((uint32_t)rxData[0] << 8) | rxData[1];
// 符号扩展:18位有符号数扩展到32位
if(raw & 0x00020000) { // 测试第17位(符号位)
raw |= 0xFFFC0000; // 符号扩展
}
*adcValue = (int32_t)raw;
return MCP3421_OK;
}
/**
* @brief 单次转换完整流程(阻塞方式)
* @param hi2c: I2C句柄
* @param pga: 增益
* @param result: 输出ADC原始值
* @retval MCP3421_OK/ERROR
*/
uint8_t MCP3421_GetSingleConversion(I2C_HandleTypeDef *hi2c, uint8_t pga, int32_t *result)
{
uint8_t ret;
uint8_t rdy;
int32_t adcRaw;
uint32_t tickstart;
// 1. 触发转换(固定使用18位最高精度)
ret = MCP3421_TriggerConversion(hi2c, MCP3421_RATE_3P75_18BIT, pga);
if(ret != MCP3421_OK) return ret;
// 2. 等待转换完成(18位典型需266ms)
tickstart = HAL_GetTick();
do {
if((HAL_GetTick() - tickstart) > 500) { // 超时500ms
return MCP3421_ERROR_TIMEOUT;
}
HAL_Delay(50);
ret = MCP3421_ReadResult(hi2c, &adcRaw, &rdy);
if(ret == MCP3421_OK && rdy) {
*result = adcRaw;
return MCP3421_OK;
}
} while(1);
}
八、应用示例:
#include "mcp3421.h"
extern I2C_HandleTypeDef hi2c1; // STM32Lxxx I2C句柄
void MCP3421_Example(void)
{
int32_t adc_code;
float voltage;
uint8_t status;
// 使用PGA=1,读取差分电压
status = MCP3421_GetSingleConversion(&hi2c1, MCP3421_PGA_1, &adc_code);
if(status == MCP3421_OK) {
// 转换为实际电压:V = (ADC_Code / 2^17) * 2.048V (18位模式,LSB=15.625μV)
// 公式:电压 = ADC_Code * (2.048 / 131072) 131072 = 2^17
voltage = (float)adc_code * 2.048f / 131072.0f;
printf("ADC Raw: %ld, Voltage: %.3f mV\r\n", adc_code, voltage * 1000);
} else {
printf("ADC Conversion Failed\r\n");
}
}
// 若需连续模式,按以下序列操作:
void MCP3421_ContinuousMode_Example(void)
{
uint8_t cfg;
int32_t adc_val;
uint8_t rdy;
// 1. 写入连续模式配置(16位、15SPS、增益1)
cfg = MCP3421_MODE_CONTINUOUS | MCP3421_RATE_15_16BIT | MCP3421_PGA_1;
MCP3421_WriteConfig(&hi2c1, cfg);
// 2. 延时等待首次转换
HAL_Delay(70);
// 3. 循环读取(每次读取都会返回最新转换值)
for(int i = 0; i < 10; i++) {
if(MCP3421_ReadResult(&hi2c1, &adc_val, &rdy) == MCP3421_OK) {
// 注意:连续模式下RDY位在读取后自动清零,无需额外操作
printf("Cont Value: %ld\r\n", adc_val);
}
HAL_Delay(100);
}
}