From 4e0ad6e8eb1c51e24a02f2e8b49a5bf6f94ce4fd Mon Sep 17 00:00:00 2001 From: yelvlab Date: Thu, 14 Aug 2025 00:41:12 +0800 Subject: [PATCH] IIC OK but sensor error --- CMakeLists.txt | 3 + Inc/ldc1612.h | 177 +++++++++++++++++++++ Inc/sensor_example.h | 28 ++++ Inc/tmp112.h | 155 ++++++++++++++++++ Src/ldc1612.c | 367 +++++++++++++++++++++++++++++++++++++++++++ Src/main.c | 5 + Src/sensor_example.c | 224 ++++++++++++++++++++++++++ Src/soft_i2c.c | 49 ++++-- Src/tmp112.c | 323 +++++++++++++++++++++++++++++++++++++ 9 files changed, 1315 insertions(+), 16 deletions(-) create mode 100644 Inc/ldc1612.h create mode 100644 Inc/sensor_example.h create mode 100644 Inc/tmp112.h create mode 100644 Src/ldc1612.c create mode 100644 Src/sensor_example.c create mode 100644 Src/tmp112.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 55f7253..192233d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,9 @@ set(TARGET_SRC Src/uart_ring_buffer.c Src/command.c Src/i2c.c + Src/ldc1612.c + Src/tmp112.c + Src/sensor_example.c ) # 设置输出目录 diff --git a/Inc/ldc1612.h b/Inc/ldc1612.h new file mode 100644 index 0000000..7b7c574 --- /dev/null +++ b/Inc/ldc1612.h @@ -0,0 +1,177 @@ +// +// 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 +#include +#include +#include +#include +#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 diff --git a/Inc/sensor_example.h b/Inc/sensor_example.h new file mode 100644 index 0000000..cf9749f --- /dev/null +++ b/Inc/sensor_example.h @@ -0,0 +1,28 @@ +// +// Sensor Usage Example Header +// 传感器使用示例头文件 +// + +#ifndef SENSOR_EXAMPLE_H +#define SENSOR_EXAMPLE_H + +#include "gd32e23x.h" +#include "board_config.h" + +/*! + \brief 传感器初始化示例 + \param[in] none + \param[out] none + \retval none +*/ +void sensors_init_example(void); + +/*! + \brief 传感器读取示例 + \param[in] none + \param[out] none + \retval none +*/ +void sensors_read_example(void); + +#endif // SENSOR_EXAMPLE_H diff --git a/Inc/tmp112.h b/Inc/tmp112.h new file mode 100644 index 0000000..8b8b638 --- /dev/null +++ b/Inc/tmp112.h @@ -0,0 +1,155 @@ +// +// Created by dell on 24-12-20. +// TMP112A Temperature Sensor Driver Header +// + +#ifndef TMP112_H +#define TMP112_H + +#include "gd32e23x_it.h" +#include "gd32e23x.h" +#include "systick.h" +#include +#include +#include +#include +#include +#include "board_config.h" +#include "i2c.h" + +/******************************************************************************/ +/* TMP112A I2C Address */ +#define TMP112A_ADDR (0x48) // 7-bit address (ADD0=GND) + +/* Register Addresses */ +/******************************************************************************/ +#define TMP112A_TEMP_REG 0x00 // 温度寄存器 +#define TMP112A_CONFIG_REG 0x01 // 配置寄存器 +#define TMP112A_TLOW_REG 0x02 // 低温阈值寄存器 +#define TMP112A_THIGH_REG 0x03 // 高温阈值寄存器 + +/* Configuration Register Bits */ +/******************************************************************************/ +#define TMP112A_CONFIG_OS (1 << 15) // One-shot +#define TMP112A_CONFIG_R1 (1 << 14) // Converter resolution bit 1 +#define TMP112A_CONFIG_R0 (1 << 13) // Converter resolution bit 0 +#define TMP112A_CONFIG_F1 (1 << 12) // Fault queue bit 1 +#define TMP112A_CONFIG_F0 (1 << 11) // Fault queue bit 0 +#define TMP112A_CONFIG_POL (1 << 10) // Polarity +#define TMP112A_CONFIG_TM (1 << 9) // Thermostat mode +#define TMP112A_CONFIG_SD (1 << 8) // Shutdown +#define TMP112A_CONFIG_CR1 (1 << 7) // Conversion rate bit 1 +#define TMP112A_CONFIG_CR0 (1 << 6) // Conversion rate bit 0 +#define TMP112A_CONFIG_AL (1 << 5) // Alert +#define TMP112A_CONFIG_EM (1 << 4) // Extended mode + +/* Resolution Settings */ +/******************************************************************************/ +#define TMP112A_RESOLUTION_9BIT 0x0000 // 9-bit (0.5°C) +#define TMP112A_RESOLUTION_10BIT 0x2000 // 10-bit (0.25°C) +#define TMP112A_RESOLUTION_11BIT 0x4000 // 11-bit (0.125°C) +#define TMP112A_RESOLUTION_12BIT 0x6000 // 12-bit (0.0625°C) + +/* Conversion Rate Settings */ +/******************************************************************************/ +#define TMP112A_RATE_0_25HZ 0x0000 // 0.25 Hz (4s) +#define TMP112A_RATE_1HZ 0x0040 // 1 Hz (1s) +#define TMP112A_RATE_4HZ 0x0080 // 4 Hz (250ms) +#define TMP112A_RATE_8HZ 0x00C0 // 8 Hz (125ms) + +/* Default Configuration */ +/******************************************************************************/ +#define TMP112A_CONFIG_DEFAULT (TMP112A_RESOLUTION_12BIT | TMP112A_RATE_4HZ) + +/* Temperature Conversion Constants */ +/******************************************************************************/ +#define TMP112A_TEMP_RESOLUTION 0.0625f // 12-bit resolution (°C/LSB) +#define TMP112A_TEMP_MIN -55.0f // 最低温度 (°C) +#define TMP112A_TEMP_MAX 125.0f // 最高温度 (°C) + +/* Status Definitions */ +/******************************************************************************/ +typedef enum { + TMP112A_STATUS_SUCCESS = 0, + TMP112A_STATUS_ERROR, + TMP112A_STATUS_TIMEOUT, + TMP112A_STATUS_INVALID_PARAM, + TMP112A_STATUS_OUT_OF_RANGE +} tmp112a_status_t; + +typedef struct { + uint16_t raw_data; + float temperature_c; + float temperature_f; + bool alert_flag; +} tmp112a_result_t; + +/******************************************************************************/ +/* Function Declarations */ + +/*! + \brief 初始化TMP112A传感器 + \param[in] none + \param[out] none + \retval tmp112a_status_t +*/ +tmp112a_status_t tmp112a_init(void); + +/*! + \brief 配置TMP112A传感器 + \param[in] config: 配置值 + \param[out] none + \retval tmp112a_status_t +*/ +tmp112a_status_t tmp112a_config(uint16_t config); + +/*! + \brief 读取温度 + \param[in] none + \param[out] result: 结果结构体指针 + \retval tmp112a_status_t +*/ +tmp112a_status_t tmp112a_read_temperature(tmp112a_result_t *result); + +/*! + \brief 设置温度阈值 + \param[in] low_temp: 低温阈值 (°C) + \param[in] high_temp: 高温阈值 (°C) + \param[out] none + \retval tmp112a_status_t +*/ +tmp112a_status_t tmp112a_set_thresholds(float low_temp, float high_temp); + +/*! + \brief 进入关机模式 + \param[in] none + \param[out] none + \retval tmp112a_status_t +*/ +tmp112a_status_t tmp112a_shutdown(void); + +/*! + \brief 退出关机模式 + \param[in] none + \param[out] none + \retval tmp112a_status_t +*/ +tmp112a_status_t tmp112a_wakeup(void); + +/*! + \brief 单次转换 + \param[in] none + \param[out] result: 结果结构体指针 + \retval tmp112a_status_t +*/ +tmp112a_status_t tmp112a_one_shot(tmp112a_result_t *result); + +/*! + \brief 获取状态字符串 + \param[in] status: 状态码 + \param[out] none + \retval const char* 状态字符串 +*/ +const char* tmp112a_get_status_string(tmp112a_status_t status); + +#endif //TMP112_H diff --git a/Src/ldc1612.c b/Src/ldc1612.c new file mode 100644 index 0000000..5d4334c --- /dev/null +++ b/Src/ldc1612.c @@ -0,0 +1,367 @@ +// +// Created by dell on 24-12-3. +// LDC1612 Inductive Sensor Driver Implementation +// + +#include "ldc1612.h" + +/* 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; +} diff --git a/Src/main.c b/Src/main.c index d874632..b3efa70 100644 --- a/Src/main.c +++ b/Src/main.c @@ -40,6 +40,7 @@ OF SUCH DAMAGE. #include #include "i2c.h" #include "board_config.h" +#include "sensor_example.h" bool g_status_switch = false; @@ -79,6 +80,10 @@ int main(void) #ifdef DEBUG_VERBOSE i2c_scan(); #endif + + sensors_init_example(); + sensors_read_example(); + while(1){ diff --git a/Src/sensor_example.c b/Src/sensor_example.c new file mode 100644 index 0000000..d0c3c9d --- /dev/null +++ b/Src/sensor_example.c @@ -0,0 +1,224 @@ +// +// Sensor Usage Example +// 传感器使用示例代码 +// + +#include "ldc1612.h" +// #include "tmp112.h" +#include "i2c.h" + +/*! + \brief 传感器初始化示例 + \param[in] none + \param[out] none + \retval none +*/ +void sensors_init_example(void) { + ldc1612_status_t ldc_status; + // tmp112a_status_t tmp_status; + + /* 初始化I2C总线 */ + i2c_status_t i2c_status = i2c_config(); + if (i2c_status != I2C_STATUS_SUCCESS) { + // 使用串口发送错误信息 + const char* error_msg = "I2C init failed\r\n"; + for (uint8_t i = 0; error_msg[i] != '\0'; i++) { + while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + usart_data_transmit(RS485_PHY, error_msg[i]); + } + while (usart_flag_get(RS485_PHY, USART_FLAG_TC) == RESET) {} + return; + } + + /* 扫描I2C总线 */ + // i2c_scan(); + + /* 初始化LDC1612 */ + ldc_status = ldc1612_init(); + if (ldc_status == LDC1612_STATUS_SUCCESS) { + const char* msg = "LDC1612 init success\r\n"; + for (uint8_t i = 0; msg[i] != '\0'; i++) { + while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + usart_data_transmit(RS485_PHY, msg[i]); + } + while (usart_flag_get(RS485_PHY, USART_FLAG_TC) == RESET) {} + + /* 配置通道0 */ + ldc_status = ldc1612_config_single_channel(LDC1612_CHANNEL_0); + if (ldc_status != LDC1612_STATUS_SUCCESS) { + const char* error = "LDC1612 config failed\r\n"; + for (uint8_t i = 0; error[i] != '\0'; i++) { + while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + usart_data_transmit(RS485_PHY, error[i]); + } + while (usart_flag_get(RS485_PHY, USART_FLAG_TC) == RESET) {} + } + } else { + const char* error = "LDC1612 init failed: "; + for (uint8_t i = 0; error[i] != '\0'; i++) { + while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + usart_data_transmit(RS485_PHY, error[i]); + } + const char* status_str = ldc1612_get_status_string(ldc_status); + for (uint8_t i = 0; status_str[i] != '\0'; i++) { + while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + usart_data_transmit(RS485_PHY, status_str[i]); + } + const char* newline = "\r\n"; + for (uint8_t i = 0; newline[i] != '\0'; i++) { + while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + usart_data_transmit(RS485_PHY, newline[i]); + } + while (usart_flag_get(RS485_PHY, USART_FLAG_TC) == RESET) {} + } + + /* 初始化TMP112A */ + // tmp_status = tmp112a_init(); + // if (tmp_status == TMP112A_STATUS_SUCCESS) { + // const char* msg = "TMP112A init success\r\n"; + // for (uint8_t i = 0; msg[i] != '\0'; i++) { + // while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + // usart_data_transmit(RS485_PHY, msg[i]); + // } + // while (usart_flag_get(RS485_PHY, USART_FLAG_TC) == RESET) {} + + // /* 设置温度阈值 */ + // tmp_status = tmp112a_set_thresholds(-10.0f, 50.0f); + // if (tmp_status != TMP112A_STATUS_SUCCESS) { + // const char* error = "TMP112A threshold config failed\r\n"; + // for (uint8_t i = 0; error[i] != '\0'; i++) { + // while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + // usart_data_transmit(RS485_PHY, error[i]); + // } + // while (usart_flag_get(RS485_PHY, USART_FLAG_TC) == RESET) {} + // } + // } else { + // const char* error = "TMP112A init failed: "; + // for (uint8_t i = 0; error[i] != '\0'; i++) { + // while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + // usart_data_transmit(RS485_PHY, error[i]); + // } + // const char* status_str = tmp112a_get_status_string(tmp_status); + // for (uint8_t i = 0; status_str[i] != '\0'; i++) { + // while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + // usart_data_transmit(RS485_PHY, status_str[i]); + // } + // const char* newline = "\r\n"; + // for (uint8_t i = 0; newline[i] != '\0'; i++) { + // while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + // usart_data_transmit(RS485_PHY, newline[i]); + // } + // while (usart_flag_get(RS485_PHY, USART_FLAG_TC) == RESET) {} + // } +} + +/*! + \brief 传感器读取示例 + \param[in] none + \param[out] none + \retval none +*/ +void sensors_read_example(void) { + ldc1612_result_t ldc_result; + // tmp112a_result_t tmp_result; + ldc1612_status_t ldc_status; + // tmp112a_status_t tmp_status; + + /* 读取LDC1612数据 */ + ldc_status = ldc1612_read_channel(LDC1612_CHANNEL_0, &ldc_result); + if (ldc_status == LDC1612_STATUS_SUCCESS) { + if (!ldc_result.error_flag) { + const char* msg = "LDC1612 Data: 0x"; + for (uint8_t i = 0; msg[i] != '\0'; i++) { + while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + usart_data_transmit(RS485_PHY, msg[i]); + } + + /* 发送32位十六进制数据 */ + uint8_t hex_chars[] = "0123456789ABCDEF"; + for (int8_t i = 7; i >= 0; i--) { + uint8_t nibble = (ldc_result.frequency >> (i * 4)) & 0x0F; + while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + usart_data_transmit(RS485_PHY, hex_chars[nibble]); + } + + const char* newline = "\r\n"; + for (uint8_t i = 0; newline[i] != '\0'; i++) { + while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + usart_data_transmit(RS485_PHY, newline[i]); + } + while (usart_flag_get(RS485_PHY, USART_FLAG_TC) == RESET) {} + } else { + const char* error = "LDC1612 Error Code: 0x"; + for (uint8_t i = 0; error[i] != '\0'; i++) { + while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + usart_data_transmit(RS485_PHY, error[i]); + } + + uint8_t hex_chars[] = "0123456789ABCDEF"; + while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + usart_data_transmit(RS485_PHY, hex_chars[(ldc_result.error_code >> 4) & 0x0F]); + while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + usart_data_transmit(RS485_PHY, hex_chars[ldc_result.error_code & 0x0F]); + + const char* newline = "\r\n"; + for (uint8_t i = 0; newline[i] != '\0'; i++) { + while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + usart_data_transmit(RS485_PHY, newline[i]); + } + while (usart_flag_get(RS485_PHY, USART_FLAG_TC) == RESET) {} + } + } + + /* 读取TMP112A数据 */ + // tmp_status = tmp112a_read_temperature(&tmp_result); + // if (tmp_status == TMP112A_STATUS_SUCCESS) { + // const char* msg = "Temperature: "; + // for (uint8_t i = 0; msg[i] != '\0'; i++) { + // while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + // usart_data_transmit(RS485_PHY, msg[i]); + // } + + // /* 简单的温度显示(整数部分) */ + // int16_t temp_int = (int16_t)tmp_result.temperature_c; + // if (temp_int < 0) { + // while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + // usart_data_transmit(RS485_PHY, '-'); + // temp_int = -temp_int; + // } + + // if (temp_int >= 100) { + // while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + // usart_data_transmit(RS485_PHY, '0' + (temp_int / 100)); + // temp_int %= 100; + // } + // if (temp_int >= 10) { + // while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + // usart_data_transmit(RS485_PHY, '0' + (temp_int / 10)); + // temp_int %= 10; + // } + // while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + // usart_data_transmit(RS485_PHY, '0' + temp_int); + + // const char* unit = " C"; + // for (uint8_t i = 0; unit[i] != '\0'; i++) { + // while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + // usart_data_transmit(RS485_PHY, unit[i]); + // } + + // if (tmp_result.alert_flag) { + // const char* alert = " [ALERT]"; + // for (uint8_t i = 0; alert[i] != '\0'; i++) { + // while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + // usart_data_transmit(RS485_PHY, alert[i]); + // } + // } + + // const char* newline = "\r\n"; + // for (uint8_t i = 0; newline[i] != '\0'; i++) { + // while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {} + // usart_data_transmit(RS485_PHY, newline[i]); + // } + // while (usart_flag_get(RS485_PHY, USART_FLAG_TC) == RESET) {} + // } +} diff --git a/Src/soft_i2c.c b/Src/soft_i2c.c index 201f275..05544c2 100644 --- a/Src/soft_i2c.c +++ b/Src/soft_i2c.c @@ -59,13 +59,13 @@ void soft_i2c_start(void) { \retval none */ void soft_i2c_stop(void) { - // sda_out(); - I2C_SCL_LOW(); - I2C_SDA_LOW(); + I2C_SCL_LOW(); // 确保时钟为低 + I2C_SDA_LOW(); // 拉低数据线 soft_i2c_delay(); - I2C_SCL_HIGH(); + I2C_SCL_HIGH(); // 拉高时钟 soft_i2c_delay(); - I2C_SDA_HIGH(); + I2C_SDA_HIGH(); // 在时钟高电平时拉高数据线产生停止条件 + soft_i2c_delay(); // 添加缺失的延时 } /*! @@ -108,12 +108,13 @@ void soft_i2c_send_nack(void) { \retval 0: ACK received, 1: ACK not received */ uint8_t soft_i2c_wait_ack(void) { - I2C_SDA_HIGH(); + I2C_SDA_HIGH(); // 释放SDA线,让从设备控制 soft_i2c_delay(); - I2C_SCL_HIGH(); + I2C_SCL_HIGH(); // 拉高时钟 soft_i2c_delay(); - uint8_t ack = !I2C_SDA_READ(); - I2C_SCL_LOW(); + uint8_t ack = !I2C_SDA_READ(); // 读取ACK信号(低电平为ACK) + I2C_SCL_LOW(); // 拉低时钟 + soft_i2c_delay(); // 添加缺失的延时 return ack; } @@ -168,8 +169,13 @@ uint8_t soft_i2c_receive_byte(uint8_t ack) { } uint8_t soft_i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[2]) { + /* 参数验证 */ + if (data == NULL || slave_addr > 0x7F) { + return SOFT_I2C_FAIL; + } + soft_i2c_start(); - soft_i2c_send_byte(slave_addr); + soft_i2c_send_byte(slave_addr << 1); // 修复:左移1位,添加写位 if (!soft_i2c_wait_ack()) { soft_i2c_stop(); return SOFT_I2C_FAIL; @@ -185,15 +191,24 @@ uint8_t soft_i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data return SOFT_I2C_FAIL; } soft_i2c_send_byte(data[1]); - if (soft_i2c_wait_ack()){} + if (!soft_i2c_wait_ack()) { // 修复:添加错误处理 + soft_i2c_stop(); + return SOFT_I2C_FAIL; + } soft_i2c_stop(); return SOFT_I2C_OK; } uint8_t soft_i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data) { + /* 参数验证 */ + if (data == NULL || slave_addr > 0x7F) { + return SOFT_I2C_FAIL; + } + + /* 写阶段:发送寄存器地址 */ soft_i2c_start(); - soft_i2c_send_byte(slave_addr); + soft_i2c_send_byte(slave_addr << 1); // 修复:左移1位,写操作 if (!soft_i2c_wait_ack()) { soft_i2c_stop(); return SOFT_I2C_FAIL; @@ -203,15 +218,17 @@ uint8_t soft_i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data soft_i2c_stop(); return SOFT_I2C_FAIL; } - soft_i2c_start(); - soft_i2c_send_byte(slave_addr | 0x01); + + /* 读阶段:重新开始并读取数据 */ + soft_i2c_start(); // 重新开始 + soft_i2c_send_byte((slave_addr << 1) | 0x01); // 修复:正确的读地址 if (!soft_i2c_wait_ack()) { soft_i2c_stop(); return SOFT_I2C_FAIL; } soft_i2c_delay(); - data[0] = soft_i2c_receive_byte(1); - data[1] = soft_i2c_receive_byte(0); + data[0] = soft_i2c_receive_byte(1); // 第一个字节发送ACK + data[1] = soft_i2c_receive_byte(0); // 最后一个字节发送NACK soft_i2c_stop(); return SOFT_I2C_OK; } \ No newline at end of file diff --git a/Src/tmp112.c b/Src/tmp112.c new file mode 100644 index 0000000..12828a4 --- /dev/null +++ b/Src/tmp112.c @@ -0,0 +1,323 @@ +// +// Created by dell on 24-12-20. +// TMP112A Temperature Sensor Driver Implementation +// + +#include "tmp112.h" + +/* Private function prototypes */ +static i2c_status_t tmp112a_write_register(uint8_t reg_addr, uint16_t value); +static i2c_status_t tmp112a_read_register(uint8_t reg_addr, uint16_t *value); +static float tmp112a_raw_to_celsius(uint16_t raw_data); +static uint16_t tmp112a_celsius_to_raw(float temperature); + +/*! + \brief 初始化TMP112A传感器 + \param[in] none + \param[out] none + \retval tmp112a_status_t +*/ +tmp112a_status_t tmp112a_init(void) { + i2c_status_t i2c_status; + + /* 配置传感器为默认设置 */ + i2c_status = tmp112a_config(TMP112A_CONFIG_DEFAULT); + if (i2c_status != I2C_STATUS_SUCCESS) { + return TMP112A_STATUS_ERROR; + } + + /* 等待配置生效 */ + delay_ms(1); + + return TMP112A_STATUS_SUCCESS; +} + +/*! + \brief 配置TMP112A传感器 + \param[in] config: 配置值 + \param[out] none + \retval tmp112a_status_t +*/ +tmp112a_status_t tmp112a_config(uint16_t config) { + i2c_status_t status = tmp112a_write_register(TMP112A_CONFIG_REG, config); + return (status == I2C_STATUS_SUCCESS) ? TMP112A_STATUS_SUCCESS : TMP112A_STATUS_ERROR; +} + +/*! + \brief 读取温度 + \param[in] none + \param[out] result: 结果结构体指针 + \retval tmp112a_status_t +*/ +tmp112a_status_t tmp112a_read_temperature(tmp112a_result_t *result) { + uint16_t raw_data; + i2c_status_t status; + + if (result == NULL) { + return TMP112A_STATUS_INVALID_PARAM; + } + + /* 读取温度寄存器 */ + status = tmp112a_read_register(TMP112A_TEMP_REG, &raw_data); + if (status != I2C_STATUS_SUCCESS) { + return TMP112A_STATUS_ERROR; + } + + /* 解析温度数据 */ + result->raw_data = raw_data; + result->temperature_c = tmp112a_raw_to_celsius(raw_data); + result->temperature_f = result->temperature_c * 9.0f / 5.0f + 32.0f; + + /* 检查温度范围 */ + if (result->temperature_c < TMP112A_TEMP_MIN || result->temperature_c > TMP112A_TEMP_MAX) { + return TMP112A_STATUS_OUT_OF_RANGE; + } + + /* 检查报警标志 */ + uint16_t config_reg; + status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg); + if (status == I2C_STATUS_SUCCESS) { + result->alert_flag = (config_reg & TMP112A_CONFIG_AL) ? true : false; + } else { + result->alert_flag = false; + } + + return TMP112A_STATUS_SUCCESS; +} + +/*! + \brief 设置温度阈值 + \param[in] low_temp: 低温阈值 (°C) + \param[in] high_temp: 高温阈值 (°C) + \param[out] none + \retval tmp112a_status_t +*/ +tmp112a_status_t tmp112a_set_thresholds(float low_temp, float high_temp) { + uint16_t low_raw, high_raw; + i2c_status_t status; + + /* 参数验证 */ + if (low_temp < TMP112A_TEMP_MIN || low_temp > TMP112A_TEMP_MAX || + high_temp < TMP112A_TEMP_MIN || high_temp > TMP112A_TEMP_MAX || + low_temp >= high_temp) { + return TMP112A_STATUS_INVALID_PARAM; + } + + /* 转换温度为原始值 */ + low_raw = tmp112a_celsius_to_raw(low_temp); + high_raw = tmp112a_celsius_to_raw(high_temp); + + /* 写入低温阈值 */ + status = tmp112a_write_register(TMP112A_TLOW_REG, low_raw); + if (status != I2C_STATUS_SUCCESS) { + return TMP112A_STATUS_ERROR; + } + + /* 写入高温阈值 */ + status = tmp112a_write_register(TMP112A_THIGH_REG, high_raw); + if (status != I2C_STATUS_SUCCESS) { + return TMP112A_STATUS_ERROR; + } + + return TMP112A_STATUS_SUCCESS; +} + +/*! + \brief 进入关机模式 + \param[in] none + \param[out] none + \retval tmp112a_status_t +*/ +tmp112a_status_t tmp112a_shutdown(void) { + uint16_t config_reg; + i2c_status_t status; + + /* 读取当前配置 */ + status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg); + if (status != I2C_STATUS_SUCCESS) { + return TMP112A_STATUS_ERROR; + } + + /* 设置关机位 */ + config_reg |= TMP112A_CONFIG_SD; + + /* 写回配置 */ + status = tmp112a_write_register(TMP112A_CONFIG_REG, config_reg); + return (status == I2C_STATUS_SUCCESS) ? TMP112A_STATUS_SUCCESS : TMP112A_STATUS_ERROR; +} + +/*! + \brief 退出关机模式 + \param[in] none + \param[out] none + \retval tmp112a_status_t +*/ +tmp112a_status_t tmp112a_wakeup(void) { + uint16_t config_reg; + i2c_status_t status; + + /* 读取当前配置 */ + status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg); + if (status != I2C_STATUS_SUCCESS) { + return TMP112A_STATUS_ERROR; + } + + /* 清除关机位 */ + config_reg &= ~TMP112A_CONFIG_SD; + + /* 写回配置 */ + status = tmp112a_write_register(TMP112A_CONFIG_REG, config_reg); + if (status != I2C_STATUS_SUCCESS) { + return TMP112A_STATUS_ERROR; + } + + /* 等待传感器启动 */ + delay_ms(1); + + return TMP112A_STATUS_SUCCESS; +} + +/*! + \brief 单次转换 + \param[in] none + \param[out] result: 结果结构体指针 + \retval tmp112a_status_t +*/ +tmp112a_status_t tmp112a_one_shot(tmp112a_result_t *result) { + uint16_t config_reg; + i2c_status_t status; + uint8_t timeout = 100; // 100ms超时 + + if (result == NULL) { + return TMP112A_STATUS_INVALID_PARAM; + } + + /* 读取当前配置 */ + status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg); + if (status != I2C_STATUS_SUCCESS) { + return TMP112A_STATUS_ERROR; + } + + /* 启动单次转换 */ + config_reg |= TMP112A_CONFIG_OS; + status = tmp112a_write_register(TMP112A_CONFIG_REG, config_reg); + if (status != I2C_STATUS_SUCCESS) { + return TMP112A_STATUS_ERROR; + } + + /* 等待转换完成 */ + do { + delay_ms(1); + status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg); + if (status != I2C_STATUS_SUCCESS) { + return TMP112A_STATUS_ERROR; + } + timeout--; + } while ((config_reg & TMP112A_CONFIG_OS) && timeout > 0); + + if (timeout == 0) { + return TMP112A_STATUS_TIMEOUT; + } + + /* 读取转换结果 */ + return tmp112a_read_temperature(result); +} + +/*! + \brief 获取状态字符串 + \param[in] status: 状态码 + \param[out] none + \retval const char* 状态字符串 +*/ +const char* tmp112a_get_status_string(tmp112a_status_t status) { + switch (status) { + case TMP112A_STATUS_SUCCESS: + return "SUCCESS"; + case TMP112A_STATUS_ERROR: + return "ERROR"; + case TMP112A_STATUS_TIMEOUT: + return "TIMEOUT"; + case TMP112A_STATUS_INVALID_PARAM: + return "INVALID_PARAM"; + case TMP112A_STATUS_OUT_OF_RANGE: + return "OUT_OF_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 tmp112a_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(TMP112A_ADDR, reg_addr, data); +} + +/*! + \brief 读取寄存器 + \param[in] reg_addr: 寄存器地址 + \param[out] value: 读取值指针 + \retval i2c_status_t +*/ +static i2c_status_t tmp112a_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(TMP112A_ADDR, reg_addr, data); + if (status == I2C_STATUS_SUCCESS) { + *value = ((uint16_t)data[0] << 8) | data[1]; + } + + return status; +} + +/*! + \brief 将原始数据转换为摄氏度 + \param[in] raw_data: 原始数据 + \param[out] none + \retval float 温度值(°C) +*/ +static float tmp112a_raw_to_celsius(uint16_t raw_data) { + int16_t temp_raw; + + /* TMP112A使用12位分辨率,数据在高12位 */ + temp_raw = (int16_t)(raw_data >> 4); + + /* 处理负数 */ + if (temp_raw & 0x800) { + temp_raw |= 0xF000; // 符号扩展 + } + + /* 转换为摄氏度 */ + return (float)temp_raw * TMP112A_TEMP_RESOLUTION; +} + +/*! + \brief 将摄氏度转换为原始数据 + \param[in] temperature: 温度值(°C) + \param[out] none + \retval uint16_t 原始数据 +*/ +static uint16_t tmp112a_celsius_to_raw(float temperature) { + int16_t temp_raw; + + /* 转换为原始值 */ + temp_raw = (int16_t)(temperature / TMP112A_TEMP_RESOLUTION); + + /* 移位到高12位 */ + return (uint16_t)(temp_raw << 4); +}