From 201f1bcff263ce08d01be871c3150de99194e9c8 Mon Sep 17 00:00:00 2001 From: geniushyun <103162383+geniushyun@users.noreply.github.com> Date: Sun, 12 Apr 2026 19:15:59 +0900 Subject: [PATCH] =?UTF-8?q?=EC=98=A8=EB=8F=84=20adc=20=EC=B8=A1=EC=A0=95?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 + boards/nrf52840dk_nrf52840.overlay | 19 ++++- src/drivers/battery/battery_adc.c | 2 +- src/drivers/temperature/tmp235.c | 109 +++++++++++++++++++++++++++++ src/drivers/temperature/tmp235.h | 27 +++++++ src/main.c | 4 +- 6 files changed, 160 insertions(+), 3 deletions(-) create mode 100644 src/drivers/temperature/tmp235.c create mode 100644 src/drivers/temperature/tmp235.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d1ff73..2253d3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ target_include_directories(app PRIVATE src/drivers/battery src/drivers/led src/drivers/imu + src/drivers/temperature ) target_sources(app PRIVATE @@ -20,4 +21,5 @@ target_sources(app PRIVATE src/drivers/battery/battery_adc.c src/drivers/led/led_control.c src/drivers/imu/imu_i2c.c + src/drivers/temperature/tmp235.c ) diff --git a/boards/nrf52840dk_nrf52840.overlay b/boards/nrf52840dk_nrf52840.overlay index f6b4d80..87ef68e 100644 --- a/boards/nrf52840dk_nrf52840.overlay +++ b/boards/nrf52840dk_nrf52840.overlay @@ -12,7 +12,9 @@ * IMU_SDA: P1.15 (I2C0 data) */ +/* ADC 채널 공통 매크로 (ADC_GAIN_*, ADC_REF_*, ADC_ACQ_TIME 등) */ #include +/* nRF SAADC 전용 매크로 (NRF_SAADC_AIN* 채널 번호 정의) */ #include /* nRF 핀 컨트롤 매크로 (NRF_PSEL - I2C/SPI 등 핀 재배치에 필요) */ #include @@ -64,6 +66,20 @@ zephyr,resolution = <12>; zephyr,oversampling = <2>; /* 2^2 = 4X */ }; + + /* 온도 센서 채널 (AIN3 = P0.05, TMP235-Q1) + * 1/6 gain + 0.6V ref → 풀스케일 3.6V + * TMP235 출력 범위: 100mV(-40°C) ~ 2000mV(150°C) */ + channel@3 + { + reg = <3>; + zephyr,gain = "ADC_GAIN_1_6"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,input-positive = ; + zephyr,resolution = <12>; + zephyr,oversampling = <2>; /* 2^2 = 4X */ + }; }; /* P0.04(AIN2)가 DK Arduino 헤더에 GPIO로 잡혀있어서 SAADC 충돌 → 비활성화 */ @@ -76,7 +92,8 @@ /* ADC 채널을 코드에서 참조하기 위한 zephyr,user 노드 */ zephyr,user { - io-channels = <&adc 2>; + io-channels = <&adc 2>, <&adc 3>; + io-channel-names = "battery", "temperature"; }; led diff --git a/src/drivers/battery/battery_adc.c b/src/drivers/battery/battery_adc.c index 798adbe..9ebf0f5 100644 --- a/src/drivers/battery/battery_adc.c +++ b/src/drivers/battery/battery_adc.c @@ -29,7 +29,7 @@ #define ZEPHYR_USER_NODE DT_PATH(zephyr_user) /* 디바이스트리에서 ADC 채널 스펙 가져오기 (gain, ref, acq time, input, resolution, oversampling) */ -static const struct adc_dt_spec battery_adc = ADC_DT_SPEC_GET(ZEPHYR_USER_NODE); +static const struct adc_dt_spec battery_adc = ADC_DT_SPEC_GET_BY_NAME(ZEPHYR_USER_NODE, battery); static int16_t adc_buffer; diff --git a/src/drivers/temperature/tmp235.c b/src/drivers/temperature/tmp235.c new file mode 100644 index 0000000..8140668 --- /dev/null +++ b/src/drivers/temperature/tmp235.c @@ -0,0 +1,109 @@ +/******************************************************************************* + * @file tmp235.c + * @brief TMP235-Q1 온도 센서 드라이버 (Zephyr SAADC, AIN3 = P0.05) + * + * 배터리 ADC와 동일한 방식 (ADC_DT_SPEC_GET_BY_NAME + adc_read_dt). + * 채널 설정은 overlay channel@3에서 관리. + * + * 변환 공식: + * V_mV = raw × 3600 / 4095 (1/6 gain, 0.6V ref, 12-bit) + * T(°C × 100) = (V_mV - 500) × 10 + ******************************************************************************/ +#include +#include +#include +#include + +#include "tmp235.h" +#include "debug_print.h" + +/*============================================================================== + * ADC 디바이스트리 설정 + *============================================================================*/ +#define ZEPHYR_USER_NODE DT_PATH(zephyr_user) + +static const struct adc_dt_spec temp_adc = + ADC_DT_SPEC_GET_BY_NAME(ZEPHYR_USER_NODE, temperature); + +static int16_t adc_buffer; + +/*============================================================================== + * 내부 변환 + *============================================================================*/ + +/** + * @brief ADC raw → 온도 (°C × 100) + * + * V_mV = raw × 3600 / 4095 + * T_cdeg = (V_mV - 500) × 10 + * + * 정수 연산 (오버플로 없음): + * raw 최대 4095 → V_mV 최대 3600 → T_cdeg 최대 31000 → int32 OK + */ +static int16_t raw_to_cdeg(int16_t raw) +{ + if (raw < 0) { + raw = 0; + } + int32_t v_mv = (int32_t)raw * 3600 / 4095; + int32_t t_cdeg = (v_mv - 500) * 10; + return (int16_t)t_cdeg; +} + +/*============================================================================== + * 공개 API + *============================================================================*/ + +int temp_init(void) +{ + if (!adc_is_ready_dt(&temp_adc)) { + DBG_PRINTF("[TEMP] FAIL — ADC device not ready\r\n"); + return -1; + } + + int err = adc_channel_setup_dt(&temp_adc); + if (err) { + DBG_PRINTF("[TEMP] FAIL — channel setup (err=%d)\r\n", err); + return -2; + } + + DBG_PRINTF("[TEMP] OK — TMP235 ch=%d, res=%d, os=%d\r\n", + temp_adc.channel_id, + temp_adc.resolution, + temp_adc.oversampling); + return 0; +} + +int16_t temp_read_cdeg(void) +{ + /* 매번 채널 재설정 (배터리 ADC와 SAADC 공유) */ + int err = adc_channel_setup_dt(&temp_adc); + if (err) { + DBG_PRINTF("[TEMP] FAIL — channel setup (err=%d)\r\n", err); + return INT16_MIN; + } + + struct adc_sequence seq = {0}; + + err = adc_sequence_init_dt(&temp_adc, &seq); + if (err) { + DBG_PRINTF("[TEMP] FAIL — sequence init (err=%d)\r\n", err); + return INT16_MIN; + } + + seq.buffer = &adc_buffer; + seq.buffer_size = sizeof(adc_buffer); + + err = adc_read_dt(&temp_adc, &seq); + if (err) { + DBG_PRINTF("[TEMP] FAIL — read (err=%d)\r\n", err); + return INT16_MIN; + } + + int16_t t = raw_to_cdeg(adc_buffer); + + DBG_PRINTF("[TEMP] raw=%d -> %d.%02d C\r\n", + adc_buffer, t / 100, (t < 0 ? -t : t) % 100); + + return t; +} diff --git a/src/drivers/temperature/tmp235.h b/src/drivers/temperature/tmp235.h new file mode 100644 index 0000000..bcede2a --- /dev/null +++ b/src/drivers/temperature/tmp235.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * @file tmp235.h + * @brief TMP235-Q1 온도 센서 드라이버 (Zephyr SAADC, AIN3 = P0.05) + * + * 출력 공식: V = 500mV + 10mV/°C × T + * → T(°C) = (V_mV - 500) / 10 + * → T(°Cx100) = (V_mV - 500) × 10 + ******************************************************************************/ + +#ifndef TMP235_H__ +#define TMP235_H__ + +#include + +/** + * @brief 온도 센서 초기화 — ADC 채널 설정 + * @return 0 성공, 음수 에러 + */ +int temp_init(void); + +/** + * @brief 온도 1회 측정 + * @return 온도 (°C × 100), 에러 시 INT16_MIN + */ +int16_t temp_read_cdeg(void); + +#endif /* TMP235_H__ */ diff --git a/src/main.c b/src/main.c index c3f3459..5c7d76c 100644 --- a/src/main.c +++ b/src/main.c @@ -24,6 +24,7 @@ #include "battery_adc.h" #include "parser.h" #include "imu_i2c.h" +#include "tmp235.h" LOG_MODULE_REGISTER(vesiscan, LOG_LEVEL_INF); @@ -309,8 +310,9 @@ int main(void) led_init(); battery_adc_init(); battery_timer_init(); - DBG_PRINTF(" gpio/timer/config/led/batt OK\r\n"); imu_init(); + temp_init(); + DBG_PRINTF(" gpio/timer/config/led/batt/imu/temp OK\r\n"); /*── Phase 2: BLE 스택 + NUS ──*/ DBG_PRINTF("[2] BLE Init\r\n");