vb2002 发表于 2025-4-11 21:31:32

按照冲哥的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);
               
        }
}


国芯人工智能 发表于 2025-4-11 21:33:00

从您描述的问题来看,温度测量范围不准确可能与以下几个因素有关: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

[本文内容由国芯人工智能辅助生成,仅供参考]

vb2002 发表于 2025-4-11 21:50:08

国芯人工智能 发表于 2025-4-11 21:33
从您描述的问题来看,温度测量范围不准确可能与以下几个因素有关:ADC配置、NTC电阻的计算、电路设计以及程 ...

你可以帮我把我的代码优化一下吗?
如果我的代码里有哪些需要更改的地方,请帮我更改一下.谢谢

DebugLab 发表于 2025-4-12 10:59:10

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)

梁工 发表于 2025-4-12 15:48:53

10位ADC结果*4(或adc <<2)再去查表即可。

vb2002 发表于 2025-4-13 00:13:24

梁工 发表于 2025-4-12 15:48
10位ADC结果*4(或adc

好的,梁工,我明天试试,有结果反馈给您

vb2002 发表于 2025-4-13 00:17:41

DebugLab 发表于 2025-4-12 10:59
ADC位数不同,算法也不同,查表法的表格也要修改
还有一种简单的方法就是读出的10位ADC值直接乘以4,当成12 ...

好的哥,明天我试试,今天太累了. 明天试出来反馈结果

vb2002 发表于 2025-4-13 13:15:11

DebugLab 发表于 2025-4-12 10:59
ADC位数不同,算法也不同,查表法的表格也要修改
还有一种简单的方法就是读出的10位ADC值直接乘以4,当成12 ...

报告哥,好像已经弄好了.
我把adc =4096 - adc*4;        然后printf 就是650了
然后打印的值 -400 , 250 . 实际应该是 25.0 °符合当前温度(手机天气预报显示26°),然后用烟头烫ntc, 温度也能上升到100多°了

vb2002 发表于 2025-4-13 13:15:31

梁工 发表于 2025-4-12 15:48
10位ADC结果*4(或adc

报告梁工,好像已经弄好了.
我把adc =4096 - adc*4;        然后printf 就是650了
然后打印的值 -400 , 250 . 实际应该是 25.0 °符合当前温度(手机天气预报显示26°),然后用烟头烫ntc, 温度也能上升到100多°了

梁工 发表于 2025-4-13 14:42:19

vb2002 发表于 2025-4-13 13:15
报告梁工,好像已经弄好了.
我把adc =4096 - adc*4;      然后printf 就是650了
然后打印的值 -400 , 250 ....
祝贺!这个二分法查表算法我很早就实现过,ADC使用12位,10位的ADC要*4,为了避免小数运算,所以使用了无符号整数。
页: [1]
查看完整版本: 按照冲哥的adc,用ntc测温度.可是温度范围不对,好像我哪里错了