按照冲哥的adc,用ntc测温度.可是温度范围不对,好像我哪里错了
用的ai8g1k08a10位的adc ,ntc用的 B3950 10k电路是 VCC3.3V-10K固定电阻,NTC -GND P55脚在NTC和10k固定电阻中间
温度不管怎么降,只能到20°左右.. 用打火机烧也只能到40°,, 环境温度26°,和当前值差不多
因为我用的10位adc, 冲哥教程里用的12位的.我也把4096改成1024了
程序如下.大佬帮看看哪里出问题了.
void AdcSetRate(void) //50KSPS@11.0592MHz
{
ADCCFG &= ~0x0f;
ADCCFG |= 0x02; //SPEED(2)
ADCTIM = 0x35; //CSSETUP(0), CSHOLD(1), SMPDUTY(21)
}
void ADC_Init(void)
{
//1.初始化IO为高祖输入 P55高阻
P5M0 &= ~0x20; P5M1 |= 0x20;
//2.初始化ADC速度
AdcSetRate();
//3.对齐模式
ADCCFG |= 0x20;
//4.打开ADC电源
ADC_CONTR |= 0x80; //ADC_POWER = 1;
}
u16 ADC_Read(u8 no)
{
u16 adcval = 0;
ADC_CONTR &= 0Xf0; //清空低四位
ADC_CONTR |= no;
ADC_CONTR |= 0x40; //ADC_START = 1; //启动ADC转化
_nop_();
_nop_();
while(!(ADC_CONTR & 0x20)); //while(!ADC_FLAG); //等待采集完成
ADC_CONTR &= ~0x20; //ADC_FLAG = 0;
adcval = (((u16)ADC_RES) << 8) + (ADC_RESL); //获取到最终的ADC数值
return adcval;
}
u16 code Temp_Tab[]=
{
140 , //-40
149 ,
159 ,
168 ,
178 ,
188 ,
199 ,
210 ,
222 ,
233 ,
246 ,
259 ,
272 ,
286 ,
301 ,
317 ,
333 ,
349 ,
367 ,
385 ,
403 ,
423 ,
443 ,
464 ,
486 ,
509 ,
533 ,
558 ,
583 ,
610 ,
638 ,
667 ,
696 ,
727 ,
758 ,
791 ,
824 ,
858 ,
893 ,
929 ,
965 ,
1003,
1041,
1080,
1119,
1160,
1201,
1243,
1285,
1328,
1371,
1414,
1459,
1503,
1548,
1593,
1638,
1684,
1730,
1775,
1821,
1867,
1912,
1958,
2003,
2048,
2093,
2137,
2182,
2225,
2269,
2312,
2354,
2397,
2438,
2479,
2519,
2559,
2598,
2637,
2675,
2712,
2748,
2784,
2819,
2853,
2887,
2920,
2952,
2984,
3014,
3044,
3073,
3102,
3130,
3157,
3183,
3209,
3234,
3259,
3283,
3306,
3328,
3351,
3372,
3393,
3413,
3432,
3452,
3470,
3488,
3506,
3523,
3539,
3555,
3571,
3586,
3601,
3615,
3628,
3642,
3655,
3667,
3679,
3691,
3702,
3714,
3724,
3735,
3745,
3754,
3764,
3773,
3782,
3791,
3799,
3807,
3815,
3822,
3830,
3837,
3844,
3850,
3857,
3863,
3869,
3875,
3881,
3887,
3892,
3897,
3902,
3907,
3912,
3917,
3921,
3926,
3930,
3934,
3938,
3942, //120
};
u16 Temp_Cal(u16 adc) //返回结果是放大10背的数值16.9*10 = 169
{
u8 j = 0;
u16 k = 0;
u16 min; //当前的位置
u16 max; //当前最大的位置
u16 i; //温度
adc = 1024 - adc; //得到当前的adc数值 4096 12位 1024 10位
if( adc < Temp_Tab ) //温度最小值检测
return 0xfffe;
if( adc > Temp_Tab ) //温度最大值检测
return 0xfffF;
min = 0;
max = 160;
for( j=0;j<5;j++ ) //实现五次二分法查询
{
k = (min + max)/2;
if( adc <= Temp_Tab )
max = k;
else
min = k;
}
if( adc == Temp_Tab )
i = min *10; //(20*10 - 400)/10 =-20.0
else if( adc == Temp_Tab )
i = max * 10;
else //50 -51之间
{
while(min <= max )
{
min++;
if( Temp_Tab == adc )
{
i = min * 10;
break;
}
else if( adc < Temp_Tab) //超过这一档的温度的adc
{
min --;
i = Temp_Tab; //上一档的adc数值记下来
j = Temp_Tab -Temp_Tab ;//这两档之间的差值 2-8
j = ( adc - i )*10/j;
i = min*10+j;
break;
}
}
}
return i;
}
void main()
{
u16 tempwfdu;
sys_init();
while(1)
{
delayms(500);
tempwfdu = Temp_Cal(ADC_Read(5));
printf("Temp_Cal= %u \r\n",tempwfdu);
}
}
从您描述的问题来看,温度测量范围不准确可能与以下几个因素有关:ADC配置、NTC电阻的计算、电路设计以及程序逻辑。以下是对可能问题的分析和建议:
1. ADC配置问题
您使用的是10位ADC,而教程中使用的是12位ADC。虽然您已经将4096改为1024,但需要注意的是,ADC的分辨率不仅影响数值范围,还可能影响精度和计算方式。建议您检查以下几点:
ADC参考电压:确保ADC的参考电压与电路中的VCC一致(3.3V)。
采样速率:您的代码中设置了50KSPS的采样速率,这可能会影响ADC的精度。可以尝试降低采样速率,以提高稳定性。
对齐模式:您设置了右对齐模式(ADCCFG |= 0x20),这通常是正确的,但需要确保读取ADC值时正确处理高低位。
2. NTC电阻计算问题
NTC(负温度系数热敏电阻)的阻值随温度变化是非线性的,通常需要使用Steinhart-Hart方程或查表法进行温度转换。B3950 10K NTC的典型参数如下:
B值:3950K
标称电阻:10KΩ @ 25°C
您需要根据ADC读取的电压值,计算出NTC的当前阻值,然后通过公式或查表法转换为温度。以下是计算步骤:
1. 计算NTC电阻:
\[
R{NTC} = \frac{R{固定} \times (V{ADC} / V{REF})}{1 - (V{ADC} / V{REF})}
\]
其中,\(R{固定}\)为10KΩ,\(V{ADC}\)为ADC读取的电压值,\(V{REF}\)为参考电压(3.3V)。
2. 计算温度:
使用Steinhart-Hart方程:
\[
\frac{1}{T} = \frac{1}{T0} + \frac{1}{B} \ln\left(\frac{R{NTC}}{R0}\right)
\]
其中,\(T0\)为参考温度(25°C = 298.15K),\(R0\)为参考电阻(10KΩ),\(B\)为B值(3950K)。
3. 电路设计问题
您的电路设计是典型的电压分压电路,理论上没有问题,但需要注意以下几点:
NTC与固定电阻的匹配:确保NTC和固定电阻的阻值在测量范围内能够产生足够的电压变化。
电源稳定性:确保VCC(3.3V)稳定,避免电源波动影响ADC读数。
引脚配置:确保P55引脚配置为高阻输入模式,避免影响分压电路。
4. 程序逻辑问题
您的程序逻辑基本正确,但可以优化以下几点:
ADC读取函数:在读取ADC值时,建议增加延时或等待ADC转换完成的标志位,确保读取的值是稳定的。
温度转换函数:在读取ADC值后,确保正确计算NTC电阻和温度,避免计算错误。
示例代码优化
以下是优化后的ADC读取和温度计算代码示例:
```c
float CalculateTemperature(u16 adcValue) {
float Vadc = (adcValue / 1024.0)3.3; // 计算ADC电压值
float Rntc = (10.0Vadc) / (3.3 - Vadc); // 计算NTC电阻值
float T0 = 298.15; // 参考温度(25°C)
float B = 3950.0; // B值
float R0 = 10000.0; // 参考电阻(10KΩ)
float T = 1.0 / (1.0/T0 + (1.0/B)log(Rntc/R0)); // 计算温度(K)
return T - 273.15; // 转换为摄氏度
}
u16 ADCRead(u8 no) {
u16 adcval = 0;
ADCCONTR &= 0xF0; // 清空低四位
ADCCONTR |= no; // 选择通道
ADCCONTR |= 0x40; // 启动ADC转换
while (!(ADCCONTR & 0x20)); // 等待转换完成
adcval = (ADCRES
[本文内容由国芯人工智能辅助生成,仅供参考] 国芯人工智能 发表于 2025-4-11 21:33
从您描述的问题来看,温度测量范围不准确可能与以下几个因素有关:ADC配置、NTC电阻的计算、电路设计以及程 ...
你可以帮我把我的代码优化一下吗?
如果我的代码里有哪些需要更改的地方,请帮我更改一下.谢谢
ADC位数不同,算法也不同,查表法的表格也要修改
还有一种简单的方法就是读出的10位ADC值直接乘以4,当成12位的再进行下一步计算
修改算法的话可以参考梁工PID温控程序中的实时计算方法
https://www.stcaimcu.com/thread-3720-1-1.html
NTC 热敏电阻温度计算公式:Rt = Ro *EXP(B/T-B/To),温度单位为绝对温度K,开尔文。
(1) Rt 是热敏电阻在温度T下的阻值。T是绝对温度。
(2) Ro是热敏电阻在To(25度)时的阻值。10K的热敏电阻25℃的值为10K(即Ro=10K)。To = (273.15+25)。
(3) EXP(n) 是 e 的 n 次方。
(4) B值是热敏电阻的材料系数。
通过转换可以得到温度T与电阻Rt的关系:T=1/(1/To+ln(Rt/Ro)/B)
对应的摄氏温度t=T-273.15。
电路连接: Vref -- 10K --ADC-- NTC -- GND, 12位ADC,计算出Rt/Ro的ADC值:
ADC = 4096*Rt/(Rt+Ro), 则
Rt/Ro = ADC/(4096-ADC), 从而
T = 1/(1/To+ln(ADC/(4096-ADC))/B)
10位ADC结果*4(或adc <<2)再去查表即可。 梁工 发表于 2025-4-12 15:48
10位ADC结果*4(或adc
好的,梁工,我明天试试,有结果反馈给您 DebugLab 发表于 2025-4-12 10:59
ADC位数不同,算法也不同,查表法的表格也要修改
还有一种简单的方法就是读出的10位ADC值直接乘以4,当成12 ...
好的哥,明天我试试,今天太累了. 明天试出来反馈结果 DebugLab 发表于 2025-4-12 10:59
ADC位数不同,算法也不同,查表法的表格也要修改
还有一种简单的方法就是读出的10位ADC值直接乘以4,当成12 ...
报告哥,好像已经弄好了.
我把adc =4096 - adc*4; 然后printf 就是650了
然后打印的值 -400 , 250 . 实际应该是 25.0 °符合当前温度(手机天气预报显示26°),然后用烟头烫ntc, 温度也能上升到100多°了
梁工 发表于 2025-4-12 15:48
10位ADC结果*4(或adc
报告梁工,好像已经弄好了.
我把adc =4096 - adc*4; 然后printf 就是650了
然后打印的值 -400 , 250 . 实际应该是 25.0 °符合当前温度(手机天气预报显示26°),然后用烟头烫ntc, 温度也能上升到100多°了 vb2002 发表于 2025-4-13 13:15
报告梁工,好像已经弄好了.
我把adc =4096 - adc*4; 然后printf 就是650了
然后打印的值 -400 , 250 ....
祝贺!这个二分法查表算法我很早就实现过,ADC使用12位,10位的ADC要*4,为了避免小数运算,所以使用了无符号整数。
页:
[1]