Files
ldc1612_cmake_vscode/i2c_wait.c
2025-08-17 02:58:32 +08:00

543 lines
16 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Private function prototypes */
static i2c_status_t ldc1612_write_register(uint8_t reg_addr, uint16_t value);
static i2c_status_t ldc1612_read_register(uint8_t reg_addr, uint16_t *value);
static uint16_t ldc1612_calculate_clock_dividers(uint8_t channel);
static uint32_t ldc1612_parse_raw_result(uint32_t raw_result);
/*!
\brief 初始化LDC1612传感器
\param[in] none
\param[out] none
\retval ldc1612_status_t
*/
ldc1612_status_t ldc1612_init(void) {
i2c_status_t i2c_status;
uint16_t device_id, manufacturer_id;
/* 复位传感器 */
i2c_status = ldc1612_reset();
if (i2c_status != I2C_STATUS_SUCCESS) {
return LDC1612_STATUS_ERROR;
}
/* 等待复位完成 */
delay_ms(10);
/* 验证设备ID */
device_id = ldc1612_get_device_id();
manufacturer_id = ldc1612_get_manufacturer_id();
if (device_id != 0x3055 || manufacturer_id != 0x5449) {
return LDC1612_STATUS_ERROR;
}
return LDC1612_STATUS_SUCCESS;
}
/*!
\brief 复位LDC1612传感器
\param[in] none
\param[out] none
\retval ldc1612_status_t
*/
ldc1612_status_t ldc1612_reset(void) {
i2c_status_t status = ldc1612_write_register(LDC1612_RESET_DEV, LDC1612_RESET_VALUE);
return (status == I2C_STATUS_SUCCESS) ? LDC1612_STATUS_SUCCESS : LDC1612_STATUS_ERROR;
}
/*!
\brief 配置单通道模式
\param[in] channel: 通道号 (0或1)
\param[out] none
\retval ldc1612_status_t
*/
ldc1612_status_t ldc1612_config_single_channel(uint8_t channel) {
i2c_status_t status;
uint16_t clock_dividers;
if (channel > 1) {
return LDC1612_STATUS_INVALID_PARAM;
}
/* 进入休眠模式进行配置 */
status = ldc1612_write_register(LDC1612_CONFIG, LDC1612_SENSOR_CONFIG_SLEEP);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
/* 计算并设置时钟分频 */
clock_dividers = ldc1612_calculate_clock_dividers(channel);
status = ldc1612_write_register(LDC1612_CLOCK_DIVIDERS_CH0 + channel, clock_dividers);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
/* 设置稳定时间 */
status = ldc1612_write_register(LDC1612_SETTLECOUNT_CH0 + channel, LDC1612_SETTLECOUNT_CH0_DEFAULT);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
/* 设置转换时间 */
status = ldc1612_write_register(LDC1612_RCOUNT_CH0 + channel, LDC1612_CONVERSION_TIME_CH0);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
/* 设置错误配置 */
status = ldc1612_write_register(LDC1612_ERROR_CONFIG, LDC1612_ERROR_CONFIG_DEFAULT);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
/* 设置驱动电流 */
status = ldc1612_write_register(LDC1612_DRIVE_CURRENT_CH0 + channel, LDC1612_DRIVE_CURRENT_DEFAULT);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
/* 设置MUX配置 */
status = ldc1612_write_register(LDC1612_MUX_CONFIG, LDC1612_MUX_CONFIG_DEFAULT);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
/* 退出休眠模式,开始转换 */
status = ldc1612_write_register(LDC1612_CONFIG, LDC1612_SENSOR_CONFIG_ACTIVE);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
return LDC1612_STATUS_SUCCESS;
}
/*!
\brief 读取制造商ID
\param[in] none
\param[out] none
\retval uint16_t 制造商ID
*/
uint16_t ldc1612_get_manufacturer_id(void) {
uint16_t id = 0;
ldc1612_read_register(LDC1612_MANUFACTURER_ID, &id);
return id;
}
/*!
\brief 读取设备ID
\param[in] none
\param[out] none
\retval uint16_t 设备ID
*/
uint16_t ldc1612_get_device_id(void) {
uint16_t id = 0;
ldc1612_read_register(LDC1612_DEVICE_ID, &id);
return id;
}
/*!
\brief 读取通道原始数据
\param[in] channel: 通道号
\param[out] result: 结果结构体指针
\retval ldc1612_status_t
*/
ldc1612_status_t ldc1612_read_channel(uint8_t channel, ldc1612_result_t *result) {
uint16_t msb, lsb;
uint32_t raw_data;
i2c_status_t status;
if (channel > 1 || result == NULL) {
return LDC1612_STATUS_INVALID_PARAM;
}
/* 读取MSB */
status = ldc1612_read_register(LDC1612_DATA_CH0_MSB + (channel * 2), &msb);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
/* 读取LSB */
status = ldc1612_read_register(LDC1612_DATA_CH0_LSB + (channel * 2), &lsb);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
/* 组合32位数据 */
raw_data = ((uint32_t)msb << 16) | lsb;
/* 解析结果 */
result->raw_data = raw_data;
result->frequency = ldc1612_parse_raw_result(raw_data);
/* 检查错误 */
if (result->frequency >= 0x10000000) {
result->error_flag = true;
result->error_code = (result->frequency >> 24) & 0xFF;
return LDC1612_STATUS_ERROR;
} else {
result->error_flag = false;
result->error_code = 0;
}
return LDC1612_STATUS_SUCCESS;
}
/*!
\brief 设置驱动电流
\param[in] channel: 通道号
\param[in] current: 电流值
\param[out] none
\retval ldc1612_status_t
*/
ldc1612_status_t ldc1612_set_drive_current(uint8_t channel, uint16_t current) {
if (channel > 1) {
return LDC1612_STATUS_INVALID_PARAM;
}
i2c_status_t status = ldc1612_write_register(LDC1612_DRIVE_CURRENT_CH0 + channel, current);
return (status == I2C_STATUS_SUCCESS) ? LDC1612_STATUS_SUCCESS : LDC1612_STATUS_ERROR;
}
/*!
\brief 自动检测驱动电流
\param[in] channel: 通道号
\param[out] none
\retval ldc1612_status_t
*/
ldc1612_status_t ldc1612_auto_detect_drive_current(uint8_t channel) {
uint16_t config_value, drive_current_reg;
uint16_t init_value, drive_current;
i2c_status_t status;
if (channel > 1) {
return LDC1612_STATUS_INVALID_PARAM;
}
/* 进入休眠模式 */
status = ldc1612_write_register(LDC1612_CONFIG, LDC1612_SENSOR_CONFIG_SLEEP);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
/* 设置时钟分频 */
uint16_t clock_dividers = ldc1612_calculate_clock_dividers(channel);
status = ldc1612_write_register(LDC1612_CLOCK_DIVIDERS_CH0 + channel, clock_dividers);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
/* 读取当前配置并禁用Rp覆盖 */
status = ldc1612_read_register(LDC1612_CONFIG, &config_value);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
config_value &= ~(1 << 12); // 禁用RP_OVERRIDE_EN
status = ldc1612_write_register(LDC1612_CONFIG, config_value);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
/* 启动测量 */
status = ldc1612_write_register(LDC1612_CONFIG, LDC1612_SENSOR_CONFIG_ACTIVE);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
/* 等待至少一次转换完成 */
delay_ms(10);
/* 读取初始驱动电流值 */
status = ldc1612_read_register(LDC1612_DRIVE_CURRENT_CH0 + channel, &drive_current_reg);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
init_value = (drive_current_reg >> 6) & 0x1F;
drive_current = (init_value << 11) | 0x0000;
/* 写入检测到的驱动电流 */
status = ldc1612_write_register(LDC1612_DRIVE_CURRENT_CH0 + channel, drive_current);
if (status != I2C_STATUS_SUCCESS) return LDC1612_STATUS_ERROR;
return LDC1612_STATUS_SUCCESS;
}
/*!
\brief 获取状态字符串
\param[in] status: 状态码
\param[out] none
\retval const char* 状态字符串
*/
const char* ldc1612_get_status_string(ldc1612_status_t status) {
switch (status) {
case LDC1612_STATUS_SUCCESS:
return "SUCCESS";
case LDC1612_STATUS_ERROR:
return "ERROR";
case LDC1612_STATUS_TIMEOUT:
return "TIMEOUT";
case LDC1612_STATUS_INVALID_PARAM:
return "INVALID_PARAM";
case LDC1612_STATUS_NO_COIL:
return "NO_COIL";
case LDC1612_STATUS_UNDER_RANGE:
return "UNDER_RANGE";
case LDC1612_STATUS_OVER_RANGE:
return "OVER_RANGE";
default:
return "UNKNOWN";
}
}
/* Private Functions Implementation */
/*!
\brief 写入寄存器
\param[in] reg_addr: 寄存器地址
\param[in] value: 写入值
\param[out] none
\retval i2c_status_t
*/
static i2c_status_t ldc1612_write_register(uint8_t reg_addr, uint16_t value) {
uint8_t data[2];
data[0] = (value >> 8) & 0xFF;
data[1] = value & 0xFF;
return i2c_write_16bits(LDC1612_ADDR, reg_addr, data);
}
/*!
\brief 读取寄存器
\param[in] reg_addr: 寄存器地址
\param[out] value: 读取值指针
\retval i2c_status_t
*/
static i2c_status_t ldc1612_read_register(uint8_t reg_addr, uint16_t *value) {
uint8_t data[2];
i2c_status_t status;
if (value == NULL) {
return I2C_STATUS_INVALID_PARAM;
}
status = i2c_read_16bits(LDC1612_ADDR, reg_addr, data);
if (status == I2C_STATUS_SUCCESS) {
*value = ((uint16_t)data[0] << 8) | data[1];
}
return status;
}
/*!
\brief 计算时钟分频值
\param[in] channel: 通道号
\param[out] none
\retval uint16_t 分频值
*/
static uint16_t ldc1612_calculate_clock_dividers(uint8_t channel) {
uint16_t fin_div, fref_div;
float sensor_freq;
/* 计算传感器频率 (MHz) */
sensor_freq = 1.0f / (2.0f * 3.14159f * sqrtf(LDC1612_COIL_L_UH * LDC1612_COIL_C_PF * 1e-18f)) * 1e-6f;
/* 计算FIN分频 */
fin_div = (uint16_t)(sensor_freq / 8.75f + 1);
/* 计算FREF分频 */
if (fin_div * 4 < 40) {
fref_div = 2;
} else {
fref_div = 4;
}
return (fin_div << 12) | fref_div;
}
/*!
\brief 解析原始结果
\param[in] raw_result: 原始数据
\param[out] none
\retval uint32_t 解析后的数据
*/
static uint32_t ldc1612_parse_raw_result(uint32_t raw_result) {
uint32_t calibration_value;
uint8_t error_code;
calibration_value = raw_result & 0x0FFFFFFF;
/* 检查无线圈错误 */
if (calibration_value == 0x0FFFFFFF) {
return LDC1612_ERROR_NO_COIL;
}
error_code = (raw_result >> 24) & 0xFF;
/* 检查各种错误 */
if (error_code & 0x80) {
return LDC1612_ERROR_UNDER_RANGE;
}
if (error_code & 0x40) {
return LDC1612_ERROR_OVER_RANGE;
}
if (error_code & 0x20) {
return LDC1612_ERROR_WATCHDOG;
}
if (error_code & 0x10) {
return LDC1612_ERROR_AMPLITUDE;
}
return calibration_value;
}
// ldc1612.h
//
// Created by dell on 24-12-3.
// LDC1612 Inductive Sensor Driver Header
//
#ifndef LDC1612_H
#define LDC1612_H
#include "gd32e23x_it.h"
#include "gd32e23x.h"
#include "systick.h"
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "board_config.h"
#include "i2c.h"
/******************************************************************************/
/* LDC1612 I2C Address */
#define LDC1612_ADDR (0x2B) // 7-bit address
/* Register Addresses */
/******************************************************************************/
#define LDC1612_DATA_CH0_MSB 0x00
#define LDC1612_DATA_CH0_LSB 0x01
#define LDC1612_DATA_CH1_MSB 0x02
#define LDC1612_DATA_CH1_LSB 0x03
#define LDC1612_RCOUNT_CH0 0x08
#define LDC1612_RCOUNT_CH1 0x09
#define LDC1612_OFFSET_CH0 0x0C
#define LDC1612_OFFSET_CH1 0x0D
#define LDC1612_SETTLECOUNT_CH0 0x10
#define LDC1612_SETTLECOUNT_CH1 0x11
#define LDC1612_CLOCK_DIVIDERS_CH0 0x14
#define LDC1612_CLOCK_DIVIDERS_CH1 0x15
#define LDC1612_STATUS 0x18
#define LDC1612_ERROR_CONFIG 0x19
#define LDC1612_CONFIG 0x1A
#define LDC1612_MUX_CONFIG 0x1B
#define LDC1612_RESET_DEV 0x1C
#define LDC1612_DRIVE_CURRENT_CH0 0x1E
#define LDC1612_DRIVE_CURRENT_CH1 0x1F
#define LDC1612_MANUFACTURER_ID 0x7E
#define LDC1612_DEVICE_ID 0x7F
/* Channel Definitions */
/******************************************************************************/
#define LDC1612_CHANNEL_0 0
#define LDC1612_CHANNEL_1 1
/* Configuration Values */
/******************************************************************************/
#define LDC1612_CONVERSION_TIME_CH0 0x0546 // 转换时间
#define LDC1612_DRIVE_CURRENT_DEFAULT 0x9000 // 驱动电流
#define LDC1612_MUX_CONFIG_DEFAULT 0x020C // 无自动扫描滤波器带宽3.3MHz
#define LDC1612_SENSOR_CONFIG_ACTIVE 0x1601 // 激活配置
#define LDC1612_SENSOR_CONFIG_SLEEP 0x2801 // 休眠配置
#define LDC1612_ERROR_CONFIG_DEFAULT 0x0000 // 错误配置
#define LDC1612_SETTLECOUNT_CH0_DEFAULT 0x001E // 稳定时间
#define LDC1612_RESET_VALUE 0x8000 // 复位值
/* Coil Parameters */
/******************************************************************************/
#define LDC1612_COIL_RP_KOHM 7.2f // 并联电阻 (kΩ)
#define LDC1612_COIL_L_UH 33.0f // 电感值 (μH)
#define LDC1612_COIL_C_PF 150.0f // 电容值 (pF)
#define LDC1612_COIL_Q_FACTOR 35.97f // 品质因数
#define LDC1612_COIL_FREQ_HZ 2262000 // 谐振频率 (Hz)
/* Error Codes */
/******************************************************************************/
#define LDC1612_ERROR_NONE 0x00000000
#define LDC1612_ERROR_NO_COIL 0xF0000000
#define LDC1612_ERROR_UNDER_RANGE 0x80000000
#define LDC1612_ERROR_OVER_RANGE 0x40000000
#define LDC1612_ERROR_WATCHDOG 0x20000000
#define LDC1612_ERROR_AMPLITUDE 0x10000000
/* Status Definitions */
/******************************************************************************/
typedef enum {
LDC1612_STATUS_SUCCESS = 0,
LDC1612_STATUS_ERROR,
LDC1612_STATUS_TIMEOUT,
LDC1612_STATUS_INVALID_PARAM,
LDC1612_STATUS_NO_COIL,
LDC1612_STATUS_UNDER_RANGE,
LDC1612_STATUS_OVER_RANGE
} ldc1612_status_t;
typedef struct {
uint32_t raw_data;
uint32_t frequency;
float distance_mm;
bool error_flag;
uint8_t error_code;
} ldc1612_result_t;
/******************************************************************************/
/* Function Declarations */
/*!
\brief 初始化LDC1612传感器
\param[in] none
\param[out] none
\retval ldc1612_status_t
*/
ldc1612_status_t ldc1612_init(void);
/*!
\brief 复位LDC1612传感器
\param[in] none
\param[out] none
\retval ldc1612_status_t
*/
ldc1612_status_t ldc1612_reset(void);
/*!
\brief 配置单通道模式
\param[in] channel: 通道号 (0或1)
\param[out] none
\retval ldc1612_status_t
*/
ldc1612_status_t ldc1612_config_single_channel(uint8_t channel);
/*!
\brief 读取制造商ID
\param[in] none
\param[out] none
\retval uint16_t 制造商ID
*/
uint16_t ldc1612_get_manufacturer_id(void);
/*!
\brief 读取设备ID
\param[in] none
\param[out] none
\retval uint16_t 设备ID
*/
uint16_t ldc1612_get_device_id(void);
/*!
\brief 读取通道原始数据
\param[in] channel: 通道号
\param[out] result: 结果结构体指针
\retval ldc1612_status_t
*/
ldc1612_status_t ldc1612_read_channel(uint8_t channel, ldc1612_result_t *result);
/*!
\brief 设置驱动电流
\param[in] channel: 通道号
\param[in] current: 电流值
\param[out] none
\retval ldc1612_status_t
*/
ldc1612_status_t ldc1612_set_drive_current(uint8_t channel, uint16_t current);
/*!
\brief 自动检测驱动电流
\param[in] channel: 通道号
\param[out] none
\retval ldc1612_status_t
*/
ldc1612_status_t ldc1612_auto_detect_drive_current(uint8_t channel);
/*!
\brief 获取状态字符串
\param[in] status: 状态码
\param[out] none
\retval const char* 状态字符串
*/
const char* ldc1612_get_status_string(ldc1612_status_t status);
#endif //LDC1612_H