OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 9040|回复: 28

热敏电阻换成温度

[复制链接]

10

主题

32

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2011-10-26
在线时间
10 小时
发表于 2018-9-17 14:16:06 | 显示全部楼层 |阅读模式
10金钱
请问各位,通过ADC采样得到电压值了,要怎么通过热敏电阻曲线换成温度值,非常感谢。

最佳答案

查看完整内容[请看2#楼]

“查表”其实就是插值算法,一般用“线性插值”即可,问下百娘,资料好多。 如果想做高精度“查表”,可以用非线性插值,一般用三次样条插值算法。不过用在热敏电阻上就大材小用了,还不如把表格弄密点。 我刚好做了个温度测量,可以参考下: [mw_shl_code=c,true] #define NTC_ADC_CHN ADC_Channel_10 // adc位数 #define ADC_BIT_COUNT 12 #define ADC_MAX ((1U = _rtTab[0][1]) { _temp = _rtTab[0 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

312

帖子

0

精华

高级会员

Rank: 4

积分
907
金钱
907
注册时间
2011-10-19
在线时间
196 小时
发表于 2018-9-17 14:16:07 | 显示全部楼层
dby12 发表于 2018-9-17 15:30
热敏电阻的表格都是1度一个值,要精确到小数点两位,要将每一度之间的值再分成100份?
                ...

“查表”其实就是插值算法,一般用“线性插值”即可,问下百娘,资料好多。
如果想做高精度“查表”,可以用非线性插值,一般用三次样条插值算法。不过用在热敏电阻上就大材小用了,还不如把表格弄密点。
我刚好做了个温度测量,可以参考下:
[mw_shl_code=c,true]
#define NTC_ADC_CHN    ADC_Channel_10

// adc位数
#define ADC_BIT_COUNT 12
#define ADC_MAX ((1U << ADC_BIT_COUNT) - 1)

// 分压电阻阻值(K Ohms)
#define Rs 10.0


static float _temp;

static const float _rtTab[][2] =
{
        {-40, 277.2},
        {-38, 250.1},
        {-36, 224.0},
        {-34, 199.6},
        {-32, 177.3},
        {-30, 157.2},
        {-28, 139.4},
        {-26, 123.7},
        {-24, 110.0},
        {-22, 97.90},
        {-20, 87.43},
        {-18, 78.44},
        {-16, 70.53},
        {-12, 57.33},
        {-8 , 46.89},
        {-4 , 38.53},
        {0  , 31.77},
        {2  , 28.82},
        {4  , 26.16},
        {6  , 23.77},
        {8  , 21.62},
        {10 , 19.68},
        {15 , 15.62},
        {25 , 10.00},
        {30 , 8.064},
        {35 , 6.538},
        {40 , 5.327},
        {50 , 3.592},
        {60 , 2.472},
        {70 , 1.735},
        {90 , 0.908},
        {100, 0.674},
};
static void _TempInit(void)
{
    ADC_InitTypeDef ADC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    _temp = 0;

#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
    /* ADCCLK = PCLK2/2 */
    RCC_ADCCLKConfig(RCC_PCLK2_Div2);
#else
    /* ADCCLK = PCLK2/4 */
    RCC_ADCCLKConfig(RCC_PCLK2_Div4);
#endif
    /* Enable peripheral clocks --------------------------------------------------*/
    /* Enable ADC1 and GPIO_LED clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2 | RCC_APB2Periph_GPIOC, ENABLE);

    /* Configure  analog input -------------------------*/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    /* ADC2 configuration ------------------------------------------------------*/
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC2, &ADC_InitStructure);

    ADC_RegularChannelConfig(ADC2, NTC_ADC_CHN, 1, ADC_SampleTime_239Cycles5);
    /* Enable ADC2 */
    ADC_Cmd(ADC2, ENABLE);

    /* Enable ADC2 reset calibration register */
    ADC_ResetCalibration(ADC2);
    /* Check the end of ADC2 reset calibration register */
    while(ADC_GetResetCalibrationStatus(ADC2));

    /* Start ADC2 calibration */
    ADC_StartCalibration(ADC2);
    /* Check the end of ADC2 calibration */
    while(ADC_GetCalibrationStatus(ADC2));
}

/**
* 线性插值
* @param x1 第1点的x坐标
* @param y1 第1点的y坐标
* @param x2 第2点的x坐标
* @param y2 第2点的y坐标
* @param x  待插值点的x坐标
* @return 待插值点的y坐标
*/
float _Interpolate(float x1, float y1, float x2, float y2, float x)
{
    float y;

    y = y1 + (x - x1) * (y2 - y1) / (x2 - x1);

    return y;
}

float BspLcd_TempMeasure(void)
{
    uint32_t adc;
    size_t i, n;
    float rt;

    /* ADC2 regular channel14 configuration */
    ADC_RegularChannelConfig(ADC2, NTC_ADC_CHN, 1, ADC_SampleTime_239Cycles5);

    adc = 0;
    n = 4;
    /* Start ADC2 Software Conversion */
    ADC_SoftwareStartConvCmd(ADC2, ENABLE);
    for(i = 0; i < n; i++)
    {
        while(ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC) != SET);
        ADC_ClearFlag(ADC2, ADC_FLAG_EOC);
        adc += ADC_GetConversionValue(ADC2);
    }
    /* Start ADC2 Software Conversion */
    ADC_SoftwareStartConvCmd(ADC2, DISABLE);
    adc /= n;
//    debug("adc: %lu\r\n", adc);

    rt = Rs * adc / (ADC_MAX - adc);
    if(rt >= _rtTab[0][1])
    {
        _temp = _rtTab[0][0];
        debug("Rt too large: %.2f(Kohm)!\r\n", rt);
        return _temp;
    }
    else if(rt <= _rtTab[ARRAY_SIZE(_rtTab) - 1][1])
    {
        _temp = _rtTab[ARRAY_SIZE(_rtTab) - 1][0];
        debug("Rt too small: %.2f(Kohm)!\r\n", rt);
        return _temp;
    }

    for(i = 0; i < ARRAY_SIZE(_rtTab); i++)
    {
        if(rt > _rtTab[1])
        {
            _temp = _Interpolate(_rtTab[i -1][1], _rtTab[i -1][0], _rtTab[1], _rtTab[0], rt);
            break;
        }
    }

    return _temp;
}
[/mw_shl_code]
回复

使用道具 举报

4

主题

380

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3087
金钱
3087
注册时间
2015-10-17
在线时间
320 小时
发表于 2018-9-17 14:27:42 | 显示全部楼层
哪里有这么简单的事情。如果电阻一致性很好,就电压和实际值对比,建立校验表格了,这是最实在了,毕竟电路,和材料都影响很大
回复

使用道具 举报

10

主题

32

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2011-10-26
在线时间
10 小时
 楼主| 发表于 2018-9-17 14:46:23 | 显示全部楼层
hgr211 发表于 2018-9-17 14:27
哪里有这么简单的事情。如果电阻一致性很好,就电压和实际值对比,建立校验表格了,这是最实在了,毕竟电路 ...

表格也只能精确到个位,如果想精确到小数点后1位应该怎么做?
回复

使用道具 举报

4

主题

380

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3087
金钱
3087
注册时间
2015-10-17
在线时间
320 小时
发表于 2018-9-17 14:57:52 | 显示全部楼层
那就精确到小数点一位。我的做法,精确到多少位,你就做到多少位的表格,输入excle,然后excle有个将点转换为曲线的,曲线可以查看转为一个曲线函数,程序用这个函数转就可以了。
回复

使用道具 举报

9

主题

796

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
2038
金钱
2038
注册时间
2017-8-2
在线时间
522 小时
发表于 2018-9-17 14:58:06 | 显示全部楼层
这种东西一般都是查表.....

小数点后一位无非就是表变复杂了....
猪猪熊呢?
回复

使用道具 举报

5

主题

35

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
221
金钱
221
注册时间
2018-7-31
在线时间
34 小时
发表于 2018-9-17 15:08:35 | 显示全部楼层
如果线性度好的话,采样℃-V,用Excel生成回归方程。
回复

使用道具 举报

10

主题

32

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2011-10-26
在线时间
10 小时
 楼主| 发表于 2018-9-17 15:30:51 | 显示全部楼层
hgr211 发表于 2018-9-17 14:57
那就精确到小数点一位。我的做法,精确到多少位,你就做到多少位的表格,输入excle,然后excle有个将点转换 ...

热敏电阻的表格都是1度一个值,要精确到小数点两位,要将每一度之间的值再分成100份?
               最小            典型         最大
24℃       103.7544    104.8521    105.9508
25℃       99.0000     100.0000    101.0000
26℃       94.3996     95.3981     96.3975

比如我测试到电阻为103R,要怎么确定是25.几呢?
回复

使用道具 举报

10

主题

32

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2011-10-26
在线时间
10 小时
 楼主| 发表于 2018-9-17 15:32:50 | 显示全部楼层
323232 发表于 2018-9-17 14:58
这种东西一般都是查表.....

小数点后一位无非就是表变复杂了....

查表的话,要把每个温度对应的值都写进去?如果精确到小数点后1位,数据量就*10倍,后两位就*100倍了。真的是这样查吗?
回复

使用道具 举报

9

主题

796

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
2038
金钱
2038
注册时间
2017-8-2
在线时间
522 小时
发表于 2018-9-17 15:51:22 | 显示全部楼层
dby12 发表于 2018-9-17 15:32
查表的话,要把每个温度对应的值都写进去?如果精确到小数点后1位,数据量就*10倍,后两位就*100倍了。真 ...

首先你得找一颗典型的电阻。

然后依次分别记录0 0.1 0.2……温度下 它的阻值为:(假设)130.4 129.9 129.4……
然后实际测量时若测出阻值在129.9~130.4之间时,则温度为0;若在129.4~129.9之间则温度为0.1……依次类推

软件上如要想办法排除电阻的误差,可以这样做:生产时,在25度的环境下,程序第一次上电运行,自动运行一次ad采样函数,然后与25度时典型的电阻AD值比较,这时,算出误差值并存入ROM中,以后每次都加上或者减去这个误差值尽量将误差的影响减少到最小
猪猪熊呢?
回复

使用道具 举报

3

主题

312

帖子

0

精华

高级会员

Rank: 4

积分
907
金钱
907
注册时间
2011-10-19
在线时间
196 小时
发表于 2018-9-17 16:14:59 | 显示全部楼层
稍微优化下代码:
[mw_shl_code=c,true]#define NTC_ADC_CHN    ADC_Channel_10

// adc位数
#define ADC_BIT_COUNT 12
#define ADC_MAX ((1U << ADC_BIT_COUNT) - 1)

// 分压电阻阻值(K Ohms)
#define Rs 10.0

static float _temp;

// 热敏电阻的温度电阻表
static const struct
{
    float t; // 温度
    float r; // 阻值
} _rtTab[] =
{
        {-40, 277.2},
        {-38, 250.1},
        {-36, 224.0},
        {-34, 199.6},
        {-32, 177.3},
        {-30, 157.2},
        {-28, 139.4},
        {-26, 123.7},
        {-24, 110.0},
        {-22, 97.90},
        {-20, 87.43},
        {-18, 78.44},
        {-16, 70.53},
        {-12, 57.33},
        {-8 , 46.89},
        {-4 , 38.53},
        {0  , 31.77},
        {2  , 28.82},
        {4  , 26.16},
        {6  , 23.77},
        {8  , 21.62},
        {10 , 19.68},
        {15 , 15.62},
        {25 , 10.00},
        {30 , 8.064},
        {35 , 6.538},
        {40 , 5.327},
        {50 , 3.592},
        {60 , 2.472},
        {70 , 1.735},
        {90 , 0.908},
        {100, 0.674},
};

static void _TempInit(void)
{
    ADC_InitTypeDef ADC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    _temp = 0;

#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
    /* ADCCLK = PCLK2/2 */
    RCC_ADCCLKConfig(RCC_PCLK2_Div2);
#else
    /* ADCCLK = PCLK2/4 */
    RCC_ADCCLKConfig(RCC_PCLK2_Div4);
#endif
    /* Enable peripheral clocks --------------------------------------------------*/
    /* Enable ADC1 and GPIO_LED clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2 | RCC_APB2Periph_GPIOC, ENABLE);

    /* Configure  analog input -------------------------*/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    /* ADC2 configuration ------------------------------------------------------*/
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC2, &ADC_InitStructure);

    ADC_RegularChannelConfig(ADC2, NTC_ADC_CHN, 1, ADC_SampleTime_239Cycles5);
    /* Enable ADC2 */
    ADC_Cmd(ADC2, ENABLE);

    /* Enable ADC2 reset calibration register */
    ADC_ResetCalibration(ADC2);
    /* Check the end of ADC2 reset calibration register */
    while(ADC_GetResetCalibrationStatus(ADC2));

    /* Start ADC2 calibration */
    ADC_StartCalibration(ADC2);
    /* Check the end of ADC2 calibration */
    while(ADC_GetCalibrationStatus(ADC2));
}

/**
* 线性插值
* @param x1 第1点的x坐标
* @param y1 第1点的y坐标
* @param x2 第2点的x坐标
* @param y2 第2点的y坐标
* @param x  待插值点的x坐标
* @return 待插值点的y坐标
*/
static float _Interpolate(float x1, float y1, float x2, float y2, float x)
{
    float y;

    y = y1 + (x - x1) * (y2 - y1) / (x2 - x1);

    return y;
}

float BspLcd_TempMeasure(void)
{
    uint32_t adc;
    size_t i, n;
    float rt;

    /* ADC2 regular channel14 configuration */
    ADC_RegularChannelConfig(ADC2, NTC_ADC_CHN, 1, ADC_SampleTime_239Cycles5);

    adc = 0;
    n = 4;
    /* Start ADC2 Software Conversion */
    ADC_SoftwareStartConvCmd(ADC2, ENABLE);
    for(i = 0; i < n; i++)
    {
        while(ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC) != SET);
        ADC_ClearFlag(ADC2, ADC_FLAG_EOC);
        adc += ADC_GetConversionValue(ADC2);
    }
    /* Start ADC2 Software Conversion */
    ADC_SoftwareStartConvCmd(ADC2, DISABLE);
    adc /= n;
//    debug("adc: %lu\r\n", adc);

    rt = Rs * adc / (ADC_MAX - adc);
    if(rt >= _rtTab[0].r)
    {
        _temp = _rtTab[0].t;
        debug("Rt too large: %.2f(Kohm)!\r\n", rt);
        return _temp;
    }
    else if(rt <= _rtTab[ARRAY_SIZE(_rtTab) - 1].r)
    {
        _temp = _rtTab[ARRAY_SIZE(_rtTab) - 1].t;
        debug("Rt too small: %.2f(Kohm)!\r\n", rt);
        return _temp;
    }

    for(i = 0; i < ARRAY_SIZE(_rtTab); i++)
    {
        if(rt > _rtTab.r)
        {
            _temp = _Interpolate(_rtTab[i -1].r, _rtTab[i -1].t, _rtTab.r, _rtTab.t, rt);
            break;
        }
    }

    return _temp;
}
[/mw_shl_code]
回复

使用道具 举报

3

主题

102

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
228
金钱
228
注册时间
2018-9-7
在线时间
22 小时
发表于 2018-9-17 16:41:23 | 显示全部楼层
有公式,不要用查表,太麻烦了!Rt&#8194;=&#8194;R&#8194;*EXP(B*(1/T1-1/T2))
像屎壳螂一样做人,在粪斗中成长......
回复

使用道具 举报

10

主题

32

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2011-10-26
在线时间
10 小时
 楼主| 发表于 2018-9-17 16:51:07 | 显示全部楼层
Page 发表于 2018-9-17 16:41
有公式,不要用查表,太麻烦了!Rt&#8194;=&#8194;R&#8194;*EXP(B*(1/T1-1/T2))

能麻烦你讲解一下参数吗?谢谢
回复

使用道具 举报

1

主题

192

帖子

0

精华

高级会员

Rank: 4

积分
596
金钱
596
注册时间
2014-4-14
在线时间
104 小时
发表于 2018-9-17 17:12:14 | 显示全部楼层
本帖最后由 翼间 于 2018-9-17 17:13 编辑
dby12 发表于 2018-9-17 16:51
能麻烦你讲解一下参数吗?谢谢

NTC热敏电阻有个B值,其定义为两个温度下零功率电阻值的自然对数之差与这两个温度倒数之差的比值,这个值和材料相关,NTC厂家会在数据手册里给出来,你拿到这个B值,加上起始温度T1和结束温度点T2,就可以算出T1和T2之间这个曲线上任意一个R值对应的T值。
回复

使用道具 举报

3

主题

312

帖子

0

精华

高级会员

Rank: 4

积分
907
金钱
907
注册时间
2011-10-19
在线时间
196 小时
发表于 2018-9-18 00:36:33 | 显示全部楼层
翼间 发表于 2018-9-17 17:12
NTC热敏电阻有个B值,其定义为两个温度下零功率电阻值的自然对数之差与这两个温度倒数之差的比值,这个值 ...

据我了解,那个公式,只是一个经验公式,并不真实代表NTC温度变化规律。
我以前就用公式跟厂商的RT表比对过,确实并不一致。
但我只验过一次,到底是不是那厂商给的参数或RT表有问题就不得而知了。
回复

使用道具 举报

3

主题

312

帖子

0

精华

高级会员

Rank: 4

积分
907
金钱
907
注册时间
2011-10-19
在线时间
196 小时
发表于 2018-9-18 00:41:07 | 显示全部楼层
翼间 发表于 2018-9-17 17:12
NTC热敏电阻有个B值,其定义为两个温度下零功率电阻值的自然对数之差与这两个温度倒数之差的比值,这个值 ...

我回想起来了,NTC有好几个参数,其B值也会随温度变化,所以那个公式并非可靠。
所以用厂商提供的RT表应该(?)就没什么问题。
回复

使用道具 举报

3

主题

102

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
228
金钱
228
注册时间
2018-9-7
在线时间
22 小时
发表于 2018-9-18 08:38:07 | 显示全部楼层
dby12 发表于 2018-9-17 16:51
能麻烦你讲解一下参数吗?谢谢

1. Rt 是热敏电阻在T1温度下的阻值;
2. R是热敏电阻在T2常温下的标称阻值;
3. B值是热敏电阻的重要参数;
4. EXP是e的n次方;
Rt可用通过AD采集进行计算,其他的参数都可以在规格书中找到,根据公式就可以算出T1的值了。
像屎壳螂一样做人,在粪斗中成长......
回复

使用道具 举报

3

主题

312

帖子

0

精华

高级会员

Rank: 4

积分
907
金钱
907
注册时间
2011-10-19
在线时间
196 小时
发表于 2018-9-18 08:43:01 | 显示全部楼层
Page 发表于 2018-9-18 08:38
1. Rt 是热敏电阻在T1温度下的阻值;
2. R是热敏电阻在T2常温下的标称阻值;
3. B值是热敏电阻的重要参 ...

参见楼上,B值也会随温度变化,公式并不可靠。
回复

使用道具 举报

3

主题

102

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
228
金钱
228
注册时间
2018-9-7
在线时间
22 小时
发表于 2018-9-18 08:51:55 | 显示全部楼层
Page 发表于 2018-9-18 08:38
1. Rt 是热敏电阻在T1温度下的阻值;
2. R是热敏电阻在T2常温下的标称阻值;
3. B值是热敏电阻的重要参 ...

给你一段参考代码,这是我6年前用的公式,不过近半年才发现公式好像是“错的”,但是计算结果是对的,而且时间久了找不到之前演算这公式的数据了。既然结果是我想要的,那我也只能暂且相信之前演算这公式的过程没有错误了。这个公式得出的温度值跟用红外测温枪测得的实际值+-0.1左右。/**
  * 函数名称:RADTemp_Update
  * 功能描述:温度数据更新
  * 输      入:无
  * 输      出:无
  */
void RADTemp_Update(void)
{
        uint8_t i;
        float Vtemp_voltage = 0.0;
       
/**
        * 计算温度的AD引脚的电压
        * 注意:AVDD_Power指的是模拟电源的电压
        **/
       
        /*** 获取当前通道的AD采样值 ***/
        for(i = 0;i < Num_To_Sample;i++)
        {
                Temp_Buffer = Converte_Value[1];
                delay_us(100);
        }
       
        /* 计算当前通道的电压 */
        Vtemp_voltage = (Average_Filter(Temp_Buffer,Num_To_Sample) * AVDD_Power)/4095;
       
        /* 计算温度值 */
        RAD_Temp = (float)((Temp_Tn*((float)Vtemp_voltage)*Temp_Rn*Temp_Exp*Temp_B)/
                                                                ((((AVDD_Power*Temp_R)-(((float)Vtemp_voltage)*Temp_R))*Temp_Tn)+
                                                                (((float)Vtemp_voltage)*Temp_Rn*Temp_Exp*Temp_B)));
}



1.jpg


像屎壳螂一样做人,在粪斗中成长......
回复

使用道具 举报

3

主题

102

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
228
金钱
228
注册时间
2018-9-7
在线时间
22 小时
发表于 2018-9-18 08:53:46 | 显示全部楼层
ufbycd 发表于 2018-9-18 08:43
参见楼上,B值也会随温度变化,公式并不可靠。

如果你要非常高的精度的,那就没办法了。
而且B值在一定的温度范围内变化还是不大的
像屎壳螂一样做人,在粪斗中成长......
回复

使用道具 举报

3

主题

312

帖子

0

精华

高级会员

Rank: 4

积分
907
金钱
907
注册时间
2011-10-19
在线时间
196 小时
发表于 2018-9-18 09:11:06 | 显示全部楼层
本帖最后由 ufbycd 于 2018-9-18 09:18 编辑
Page 发表于 2018-9-18 08:53
如果你要非常高的精度的,那就没办法了。
而且B值在一定的温度范围内变化还是不大的

这个“不大”所引起的温度计算结果跟RT表比的偏差是多少呢?

欢迎提供数据,我有空也再次验证下。
PS:我用过挺多厂商的热敏电阻,无一例外,没有一个厂商的规格书会提供一个类似上述几楼的计算公式来指代其阻值随温度变化规律,而都是提供RT表。从这个侧面就说明:“经验公式”的可信度不高!

回复

使用道具 举报

10

主题

32

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2011-10-26
在线时间
10 小时
 楼主| 发表于 2018-9-18 09:53:36 | 显示全部楼层
Page 发表于 2018-9-18 08:51
给你一段参考代码,这是我6年前用的公式,不过近半年才发现公式好像是“错的”,但是计算结果是对的,而 ...

我用公式模拟演算了一下,已知25度的电阻值和10度的电阻值,求计算结果是否为10度。热敏电阻参数如下图公式为:209.71=100*2.72*4250*(1/T-1/25),这个公式计算出来的T值并不是10度,是我哪里理解错了吗?谢谢
RT.png
回复

使用道具 举报

10

主题

32

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2011-10-26
在线时间
10 小时
 楼主| 发表于 2018-9-18 09:55:17 | 显示全部楼层
Page 发表于 2018-9-18 08:51
给你一段参考代码,这是我6年前用的公式,不过近半年才发现公式好像是“错的”,但是计算结果是对的,而 ...

您的代码中的这个公式,有些难以理解
回复

使用道具 举报

3

主题

102

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
228
金钱
228
注册时间
2018-9-7
在线时间
22 小时
发表于 2018-9-18 10:39:02 | 显示全部楼层
本帖最后由 Page 于 2018-9-18 10:40 编辑
dby12 发表于 2018-9-18 09:53
我用公式模拟演算了一下,已知25度的电阻值和10度的电阻值,求计算结果是否为10度。热敏电阻参数如下图公 ...

温敏电阻R-T计算.rar (77.55 KB, 下载次数: 63)
像屎壳螂一样做人,在粪斗中成长......
回复

使用道具 举报

15

主题

184

帖子

0

精华

高级会员

Rank: 4

积分
647
金钱
647
注册时间
2014-4-29
在线时间
299 小时
发表于 2018-9-18 11:43:18 | 显示全部楼层
如果要求实时性高计算快,可以在ROM里做一个AD值-温度值的映射表,表中不体现电压值,如果别的地方 需要用到电压,可以另行计算。
比如你用12位AD,你的分辨率就是4096,你定义一个4096大小的数组,比如 const float table[4096];每个AD值对应一个温度,储存在数组里,这些值需要提前按器件说明书算好。使用的时候不需要“查找”,直接取出相应位置的数组元素即可。比如ADC读出来个1024,那么此时的温度值就是 table[1024].简单快捷。其他按照键值查找的方法都是不切实际的方法。

如果不要求速度,就不必用打表的方法,直接每次当场按公式算出来就行。
回复

使用道具 举报

10

主题

32

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2011-10-26
在线时间
10 小时
 楼主| 发表于 2018-9-18 11:49:15 | 显示全部楼层
xianshasaman 发表于 2018-9-18 11:43
如果要求实时性高计算快,可以在ROM里做一个AD值-温度值的映射表,表中不体现电压值,如果别的地方 需要用 ...

这个方法不错,只是4096个数据,弄起来有可能会抓狂
回复

使用道具 举报

15

主题

184

帖子

0

精华

高级会员

Rank: 4

积分
647
金钱
647
注册时间
2014-4-29
在线时间
299 小时
发表于 2018-9-18 13:07:53 | 显示全部楼层
dby12 发表于 2018-9-18 11:49
这个方法不错,只是4096个数据,弄起来有可能会抓狂

查表就是空间换时间的方法,别的查表方法如果想保证同等的精度,占用空间只会更大,而且会很慢,既然这么慢我直接用公式算不是更好吗。4096只是举个例子,也不一定是用满整个量程,也不一定是用到最小分辨率的,实际表可能更小,也可能更大。AD也有16位的。
回复

使用道具 举报

1

主题

192

帖子

0

精华

高级会员

Rank: 4

积分
596
金钱
596
注册时间
2014-4-14
在线时间
104 小时
发表于 2018-9-19 10:33:10 | 显示全部楼层
ufbycd 发表于 2018-9-18 09:11
这个“不大”所引起的温度计算结果跟RT表比的偏差是多少呢?

欢迎提供数据,我有空也再次验证下。

公式本身没有问题,有问题的是NTC的B值其实不是一个恒定值,在不同温度区间有一定的变化(你去看看大厂家的数据表就知道,他的RT表会连不同温度下的B值都一起给出来),所以如果要精确计算RT值,需要在每一个温度区间里代入温度区间对应的B值计算,所以实际上还是查表法,无非是表稍微小一点而已,现在单片机谁还缺那几百字节的FLASH不成?NTC厂家测不同温度区间的B值比测RT表麻烦多了,直接给个RT表,他也方便你也方便,无非是多花点空间罢了,但是你如果想在它的RT表格最小分辨率里(一般是1℃)精确算出更细的温度点(比方说0.1℃),这个公式加上当前温度间隔里的B值就有用了。
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2022-10-27
在线时间
5 小时
发表于 2022-12-30 09:41:02 | 显示全部楼层
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-24 19:03

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表