STC8的NTC采样方法
硬件连接
- NTC电阻一端接VCC,另一端接GND,中间串联一个固定电阻(如10kΩ),连接至ADC输入引脚。
- 确保ADC参考电压稳定,通常使用VCC或外部基准电压源。
ADC配置
- 初始化ADC模块,选择对应的ADC通道和时钟分频。
- 配置ADC结果格式(左对齐或右对齐),STC8通常支持10位或12位分辨率。
- 启用ADC并等待稳定,可能需短暂延时。
温度计算
- 读取ADC原始值,计算NTC电阻值:
R_{ntc} = \\frac{R_{fixed} \\times ADC_{value}}{ADC_{max} - ADC_{value}}
其中 ( R_{fixed} ) 为固定电阻值,( ADC_{max} ) 为ADC最大值(如1023或4095)。 - 使用Steinhart-Hart公式转换电阻值为温度:
\\frac{1}{T} = A + B \\cdot \\ln(R_{ntc}) + C \\cdot (\\ln(R_{ntc}))\^3
参数A、B、C需根据NTC规格书提供的数据拟合。
代码示例
c
#include "GPIO.h"
#include "Delay.h"
#include "UART.h" // 串口配置 UART_Configuration
#include "NVIC.h" // 中断初始化NVIC_UART1_Init
#include "Switch.h" // 引脚切换 UART1_SW_P30_P31
#include "ADC.h"
#include <math.h> // log()
// 定义一个结构体来存储NTC热敏电阻的参数
typedef struct {
double r_naught; // 参考电阻值 R25 (Ohm)
double b_25_50; // B值常数,适用于较低温范围 (e.g., < 50°C)
double b_25_85; // B值常数,适用于较高温范围 (e.g., >= 50°C)
} NtcParameters;
/**
* @brief 根据NTC热敏电阻的阻值计算温度(摄氏度),支持分段B值以提高精度。
*
* @param resistance_ohm 实际测量到的电阻值 (Ohm)。
* @param params 一个指向NtcParameters结构体的指针,包含热敏电阻的所有参数。
* @return 计算出温度,单位为摄氏度 (°C)。
*/
double ntc_to_celsius_segmented(double resistance_ohm, const NtcParameters* params) {
const double T_NAUGHT_K = 298.15; // 参考温度 T0 (25°C) 的开尔文值
double b_selected; // 将被选择用于最终计算的B值
double temp_kelvin_guess;
double temp_celsius_guess;
double temp_kelvin_final;
// --- 步骤1: 使用默认的B值 (b_25_50) 计算初步温度 ---
temp_kelvin_guess = 1.0 / ( (log(resistance_ohm / params->r_naught) / params->b_25_50) + (1.0 / T_NAUGHT_K) );
temp_celsius_guess = temp_kelvin_guess - 273.15;
// --- 步骤2: 根据初步温度选择更合适的B值 ---
// 我们以50°C作为分段点
if (temp_celsius_guess >= 50.0) {
b_selected = params->b_25_85; // 温度较高,使用高温范围的B值
} else {
b_selected = params->b_25_50; // 温度较低,使用低温范围的B值
}
// --- 步骤3: 使用选定的B值进行最终的精确计算 ---
temp_kelvin_final = 1.0 / ( (log(resistance_ohm / params->r_naught) / b_selected) + (1.0 / T_NAUGHT_K) );
return temp_kelvin_final - 273.15;
}
void GPIO_config() {
GPIO_InitTypeDef info;
// ===== UART1 P30 P31 准双向
info.Mode = GPIO_PullUp; // 准双向
info.Pin = GPIO_Pin_0 | GPIO_Pin_1; // 引脚
GPIO_Inilize(GPIO_P3, &info);
// P04 高阻输入
info.Mode = GPIO_HighZ; // 高阻输入
info.Pin = GPIO_Pin_4; // 引脚
GPIO_Inilize(GPIO_P0, &info);
}
// 串口配置函数的定义
void UART_config(void) {
// >>> 记得添加 NVIC.c, UART.c, UART_Isr.c <<<
COMx_InitDefine COMx_InitStructure; //结构定义
COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
COMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200
COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLE
COMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLE
UART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4
NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
UART1_SW(UART1_SW_P30_P31); // 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}
/******************* AD配置函数 *******************/
void ADC_config(void)
{
ADC_InitTypeDef ADC_InitStructure; //结构定义
ADC_InitStructure.ADC_SMPduty = 31; //ADC 模拟信号采样时间控制, 0~31(注意: SMPDUTY 一定不能设置小于 10)
ADC_InitStructure.ADC_CsSetup = 0; //ADC 通道选择时间控制 0(默认),1
ADC_InitStructure.ADC_CsHold = 1; //ADC 通道选择保持时间控制 0,1(默认),2,3
ADC_InitStructure.ADC_Speed = ADC_SPEED_2X1T; //设置 ADC 工作时钟频率 ADC_SPEED_2X1T~ADC_SPEED_2X16T
ADC_InitStructure.ADC_AdjResult = ADC_RIGHT_JUSTIFIED; //ADC结果调整, ADC_LEFT_JUSTIFIED,ADC_RIGHT_JUSTIFIED
ADC_Inilize(&ADC_InitStructure); //初始化
ADC_PowerControl(ENABLE); //ADC电源开关, ENABLE或DISABLE
NVIC_ADC_Init(DISABLE,Priority_0); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
}
void main() {
u16 adc;
float vol; // 电压
float r; // 电阻
double temp; // 温度
// R25 = 10kΩ
// B-Constant (25-50°C) = 3950
// B-Constant (25-85°C) = 3950 // 这个如果没有,和(25-50°C)值一样
NtcParameters params = {
10000.0,
3950.0,
3950.0, // 这个如果没有,和(25-50°C)值一样
};
EA = 1; // 使能中断总开关
GPIO_config(); // GPIO配置
UART_config(); // 串口配置
ADC_config(); // ADC配置
while (1){
// 读取ADC采样值,是采样值,不是电压值,但和电压有关系
// 参数不能乱写,原理图 芯片手册 P04 对应的通道是 12 通道
adc = Get_ADCResult(ADC_CH12);
// 转换为电压
vol = adc * 2.5 / 4095;
// 计算出电阻
r = vol * 10 / (3.3 - vol);
// 通过查表得到温度
temp = ntc_to_celsius_segmented(r * 1000.0, ¶ms);
printf("r = %.2f, temp = %.1f°\n", r, temp);
// 处理的太快
delay_ms(250);
delay_ms(250);
}
}
注意事项
- 校准ADC参考电压,避免电源波动影响精度。
- 使用查表法替代复杂公式计算,提升实时性。
- 添加软件滤波(如滑动平均)减少噪声干扰。
- NTC的B值需与实际型号匹配,不同型号参数差异较大。