/* NTC 换算。电路与出处见 ntc.h。 */ #include "ntc.h" #include /* NCP18XH103F03RB 的 R-T 表(Murata 规格书,−40 ~ 125 °C,5 °C 一格),单位 Ω。 ⚠️ 单调**递减**是这张表唯一不能破的性质 —— `test_ntc.c` 逐格查。 抽查:25 °C = 10000(标称);50 °C = 4161 与 B3380 公式算出的 4160 吻合。 */ #define NTC_T0_MC (-40000) #define NTC_STEP_MC 5000 static const uint32_t k_ohm[] = { 195652, 148171, 113347, 87559, 68237, 53650, 42506, 33892, /* −40 … −5 */ 27219, 22021, 17926, 14674, 12081, 10000, 8315, 6948, /* 0 … 35 */ 5834, 4917, 4161, 3535, 3014, 2586, 2228, 1925, /* 40 … 75 */ 1669, 1452, 1268, 1110, 974, 858, 758, 672, /* 80 … 115 */ 596, 531, /* 120, 125 */ }; #define NTC_N ((int)(sizeof(k_ohm) / sizeof(k_ohm[0]))) _Static_assert(NTC_N == 34, "表应当覆盖 −40 ~ 125 °C,5 °C 一格"); bool ntc_mc_from_ohm(uint32_t ohm, int32_t *milli_c) { if (milli_c == NULL || ohm > k_ohm[0] || ohm < k_ohm[NTC_N - 1]) { return false; } for (int i = 0; i < NTC_N - 1; i++) { const uint32_t hi = k_ohm[i]; /* 较冷的一端,电阻大 */ const uint32_t lo = k_ohm[i + 1]; /* 较热的一端 */ if (ohm <= hi && ohm >= lo) { /* 格内按电阻线性插值。分子最大 190000 × 5000 ≈ 9.5e8,int64 稳妥。 */ const int64_t frac = (int64_t)(hi - ohm) * NTC_STEP_MC / (int64_t)(hi - lo); *milli_c = NTC_T0_MC + i * NTC_STEP_MC + (int32_t)frac; return true; } } return false; /* 走不到:上面的范围判断已经把表外挡掉了 */ } bool ntc_mc_from_mv(int32_t mv, int32_t vref_mv, int32_t *milli_c) { if (milli_c == NULL || vref_mv <= 2 * NTC_RAIL_MARGIN_MV) { return false; } if (mv < NTC_RAIL_MARGIN_MV || mv > vref_mv - NTC_RAIL_MARGIN_MV) { return false; /* 贴地 = 短路,贴 +3V3 = 开路:都不是温度 */ } /* 下臂分压:mv / vref = R / (Rpu + R) ⇒ R = Rpu × mv / (vref − mv)。 */ const uint64_t ohm = (uint64_t)NTC_PULLUP_OHM * (uint64_t)mv / (uint64_t)(vref_mv - mv); if (ohm > 0xFFFFFFFFull) { return false; } return ntc_mc_from_ohm((uint32_t)ohm, milli_c); }