Files
FilmForge/Src/ntc.c
T

111 lines
3.9 KiB
C
Raw 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.
#include "ntc.h"
#include "gd32f4xx_adc.h"
#include "gd32f4xx_rcu.h"
#include "gd32f4xx_gpio.h"
#include "board_config.h"
#include <math.h>
/**
* @brief 配置 NTC 引脚(PC5 模拟输入)与 ADC0 常规通道。
*/
static void ntc_gpio_adc_config(void) {
/* 使能 GPIOC 与 ADC0 时钟 */
rcu_periph_clock_enable(NTC_GPIO_RCU);
rcu_periph_clock_enable(NTC_ADC_RCU);
/* PC5 模拟输入模式 */
gpio_mode_set(NTC_GPIO_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, NTC_GPIO_PIN);
/* ADC0 独立模式,常规通道软件触发、单次转换、右对齐 */
adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT);
adc_special_function_config(NTC_ADC, ADC_CONTINUOUS_MODE, DISABLE);
adc_special_function_config(NTC_ADC, ADC_INSERTED_CHANNEL, DISABLE);
adc_external_trigger_config(NTC_ADC, ADC_ROUTINE_CHANNEL, EXTERNAL_TRIGGER_DISABLE);
adc_data_alignment_config(NTC_ADC, ADC_DATAALIGN_RIGHT);
adc_channel_length_config(NTC_ADC, ADC_ROUTINE_CHANNEL, 1U);
adc_routine_channel_config(NTC_ADC, 0U, NTC_ADC_CHANNEL, NTC_SAMPLETIME);
adc_enable(NTC_ADC);
adc_calibration_enable(NTC_ADC);
}
void ntc_init(void) {
ntc_gpio_adc_config();
}
/**
* @brief 触发一次转换并读取 12bit 原始值。
*/
static uint16_t ntc_read_raw_once(void) {
adc_flag_clear(NTC_ADC, ADC_FLAG_EOC);
adc_software_trigger_enable(NTC_ADC, ADC_ROUTINE_CHANNEL);
/* 等待转换完成(EOC) */
while (SET != adc_flag_get(NTC_ADC, ADC_FLAG_EOC)) {}
return (uint16_t)adc_routine_data_read(NTC_ADC);
}
float ntc_read_temperature(void) {
uint16_t samples[NTC_SAMPLE_COUNT];
uint32_t sum = 0U;
/* 采集 NTC_SAMPLE_COUNT 个样本 */
for (uint8_t i = 0; i < NTC_SAMPLE_COUNT; i++) {
samples[i] = ntc_read_raw_once();
}
/* 插入排序(16 元素,开销可忽略),为修剪均值做准备 */
for (uint8_t i = 1; i < NTC_SAMPLE_COUNT; i++) {
uint16_t key = samples[i];
int8_t j = (int8_t)(i - 1);
while (j >= 0 && samples[j] > key) {
samples[j + 1] = samples[j];
j--;
}
samples[j + 1] = key;
}
/* 修剪均值:去掉每端 NTC_TRIM_COUNT 个极值(野值/毛刺)后取平均 */
for (uint8_t i = NTC_TRIM_COUNT; i < (NTC_SAMPLE_COUNT - NTC_TRIM_COUNT); i++) {
sum += samples[i];
}
float adc_val = (float)sum / (float)(NTC_SAMPLE_COUNT - 2U * NTC_TRIM_COUNT);
/* 分压点电压:上拉 R_PULL 在 VREF 侧,NTC 接 GND 侧 */
float voltage = adc_val * NTC_VREF / NTC_ADC_MAX;
/* 开路/短路判定:电压贴近电源轨说明 NTC 支路没有形成分压通路 */
if (voltage >= 0.97f * NTC_VREF) {
return -273.15f; /* 开路(PC5 被上拉拉满,NTC 未连通) */
}
if (voltage <= 0.03f * NTC_VREF) {
return -274.15f; /* 短路(PC5 被拉到 GND) */
}
/* 反解 NTC 阻值:V = VREF * R / (R_PULL + R) => R = R_PULL * V / (VREF - V) */
float r_ntc = NTC_R_PULL * voltage / (NTC_VREF - voltage);
/* B 值公式:1/T = 1/T25 + ln(R/R25)/B */
float t_k = 1.0f / (1.0f / NTC_T25 + logf(r_ntc / NTC_R25) / (float)NTC_B_VALUE);
return t_k - 273.15f;
}
/******************************************************************************/
/* 后台采样 + 全局最新值:各消费者(debug 打印 / M1 / M2 上报)共享一次采样 */
/******************************************************************************/
static float s_ntc_last_temp = -273.15f; /* 最新温度(初值 = 开路标记) */
static uint16_t s_ntc_sample_divider = 0; /* 主循环 10ms 圈分频计数 */
void ntc_sample_task(void) {
/* 主循环周期 10ms:按 NTC_SAMPLE_PERIOD_MS 分频触发一次采样 */
if (++s_ntc_sample_divider >= (NTC_SAMPLE_PERIOD_MS / 10U)) {
s_ntc_sample_divider = 0;
s_ntc_last_temp = ntc_read_temperature();
}
}
float ntc_get_temperature(void) {
return s_ntc_last_temp;
}