基于STM32LXXX的模数转换芯片ADC(MCP3421A0T-E/CH)驱动C程序设计

一、简介:

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, &regAddr, 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);

}

}

相关推荐
广药门徒2 小时前
PADS布局时放置同网络部件或过孔的节约空间技巧
嵌入式硬件
爱编码的小八嘎3 小时前
第1章 程序点滴-1.3 正确的入门方法(3)
c语言
浅念-5 小时前
C++ :类和对象(4)
c语言·开发语言·c++·经验分享·笔记·学习·算法
道法自然|~5 小时前
BugkuCTF栅栏密码解题记录(原理+C语言实现)
c语言·开发语言
csg11075 小时前
PIC单片机进阶实战(六):4-20mA/0-5V/0-10V数据采集
单片机·嵌入式硬件·物联网
LeoZY_5 小时前
CH347/339W开源项目:集SPI、I2C、JTAG、SWD、UART、GPIO多功能为一体(5)
stm32·mcu·fpga开发·开源·硬件架构·硬件工程
码农三叔6 小时前
《卷2:人形机器人的环境感知与多模态融合》
人工智能·嵌入式硬件·算法·机器人·人形机器人
Heart of Dream6 小时前
[STM32 HAL源码解析] 为什么中断里要判断挂起寄存器?为什么非要用回调函数?
单片机·嵌入式硬件
liwulin05067 小时前
【ESP32-S3】WINDOWS+VMware+ROS2+YDLIDA X2导航初步调试
windows·stm32·单片机