基于STM8L的NTC热敏检测

3 篇文章 0 订阅
1 篇文章 0 订阅

随手小记一下,如果有错误还望大佬指正。测温2.0版本

至关重要的就是确定型号,程序其实没多少东西。

首先你要先确定你的热敏电阻的型号,如果你是从淘宝购买,可以去问客服。如果你不知道型号如何,可以列一个表,在STM中利用你的分压公式,计算出你的电阻在温度多少的时候,电阻是多少。程序在下方,如图。要想问参考温度怎么得到的,那就是用另一个温度传感器。

热敏电阻的电阻值是随着温度的变化而变化的,温度越高电阻越小。电阻值与温度对应表在以下网址http://www.thermistors.cn/news/238.htmlhttp://www.mcnic.com/rt/103.html,如果都对应不上那你需要继续百度了,因为本人实力有限,建了个数组用来查询。

const float temp_res[61] = {
/*43.1172,41.1663,39.3153,37.5587,35.891,  //中值
34.3074,32.8029,31.3734,30.0145,28.7225,
27.4936,26.3245,25.2119,24.1527,23.1442,   //中值是他给的标准阻值
22.1835,21.2682,20.3959,19.5644,18.7714,   //阻值   
18.0151,17.2935,16.6048,15.9475,15.3198,
14.7203,14.1475,13.6003,13.0772,12.5771,    //版本1.0使用的是标准阻值,2.0使用最大阻值 说不定3.0版本就用最小阻值了 233333 
12.0988,11.6413,11.2037,10.7848,10.3839,
10,9.6324,9.2802,8.9428,8.6195,
8.3096,8.0124,7.7275,7.4541,7.1919,
6.9403,6.6987,6.4669,6.2442,6.0304,
5.825,5.6276,5.438,5.2557,5.0804,
4.9119,4.7498,4.5939,4.4439,4.2995,
4.1605*/
45.9395,43.8406,41.8501,39.962,38.1703, //最大阻值
36.4696,34.8547,33.3209,31.8635,30.4785,  
29.1618,27.9096,26.7184,25.585,24.5062,
23.479,22.5008,21.5689,20.6809,19.8345,
19.0275,18.2579,17.5237,16.8232,16.1545,
15.5162,14.9066,14.3243,13.7679,13.2362,
12.728,12.242,11.7772,11.3326,10.9072,
10.5,10.1178,9.7515,9.4005,9.0639,
8.7412,8.4317,8.1348,7.8499,7.5764,
7.3139,7.0619,6.8199,6.5874,6.364,
6.1494,5.9431,5.7448,5.5541,5.3707,
5.1943,5.0246,4.8612,4.7041,4.5527,
4.407
}; //数组的【0】代表-10摄氏度,数组最高到50摄氏度 每增加一个数就上升一度  对应的元素代表此温度下的电组值 以K为单位

建好数组后,就要想怎么将阻值采集出来,由于只能采集电压值,所以你要在外围搭建一个小电路,我才用的是串联分压,与10K电阻串联。在中点采集的电压即是这个电阻电压。

AD采集代码

void sys_adc_init(void)
{
  GPIO_DeInit(GPIOB);//复位GPIOB
  GPIO_Init(GPIOB,GPIO_Pin_0,GPIO_Mode_In_FL_No_IT);//初始化B0为浮空输入
  CLK_PeripheralClockConfig (CLK_Peripheral_ADC1,ENABLE);//开启ADC时钟
  ADC_Init (ADC1,ADC_ConversionMode_Single,ADC_Resolution_12Bit,ADC_Prescaler_1);//ADC1,单次采样,12位,1分频
  ADC_Cmd(ADC1,ENABLE);//ADC1使能
  ADC_ChannelCmd (ADC1,ADC_Channel_18,ENABLE);//ADC1 18通道使能  18通道是B0 通道号对应什么引脚在PDF里
}

u16 sys_adc_read(void)
{
  ADC_SoftwareStartConv (ADC1);//开启软件转换         
  while(!ADC_GetFlagStatus (ADC1,ADC_FLAG_EOC));//等待转换结束
  ADC_ClearFlag (ADC1,ADC_FLAG_EOC);//清除相关标识    
  return ADC_GetConversionValue (ADC1);
}

计算电阻公式

float compute_res(u16 adc_value) //计算对应ad值下的电阻值
{
  float res;
  res = (float)(10 * adc_value) / (float)(4095 - adc_value); //10是与热敏电阻串联的电阻大小 以K为单位 4095是12位的分辨率
  return res; 
}

进行电阻值在数组区间查询:

/*void find_temp(float real_res) //计算出电阻值后,用for循环查询估摸出处于哪个区间里。
{
  for(u8 i=0;i<61;i++) //正着数找到温度最大值
  {
    if(real_res > temp_res[i])                            
    {
      temp_max_flag = i;
      break;
    }
  }
  //其实这两个温度就是差1度,也可以temp_min_flag = temp_max_flag - 1;
  
  for(int8_t i=60;i>=0;i--)//倒着数找温度最小值
  {
    if(real_res < temp_res[i])
    {
      temp_min_flag = i;
      break;
    }
  }
}

//温度最低值
temp_min = -20 + temp_min_flag; //-20是最低温度*/

//版本2.0比版本1.0主要加了个超限,其余变化不大,把计算区间温度也集成进去了

//版本2.0

float find_temp(float real_res) //计算出电阻值后,用for循环查询估摸出处于哪个区间里。
{
  int8_t temp_int;//整数部分的温度
  float temp_real_region,temp_region,d,temp; //计算真实温度的变量
  u8 k = 0;//循环变量
  while(1)
  {
    if(real_res <= temp_res[k] && real_res >= temp_res[k+1]) //在数组区间内查找
    {
      temp_int = k+(-10);
      temp_real_region =  temp_res[k] - real_res; //真实区间占的
      temp_region =  temp_res[k+1] - temp_res[k]; //总区间占的
      d = temp_real_region / temp_region;
      temp = (float)temp_int + d;
      break;
    }
    else if(real_res > temp_res[0])  //如果算的值直接比第一个大,说明数组低温不够,把温度整成-99度
    {
      temp = -99;
      break;
    }
    else if(real_res < temp_res[60]) //如果算的值比最后一个还小,说明数组高温不够,把温度接整成99度
    {
      temp = 99;
      break;
    }
    if(k++ > 60) k=0; //由于数组一共61个元素
  }
  return temp;
}

 真实温度计算:

/********************
 看看再这个温度区间里,真实的value占多少,一度这个区间的
相当于在这1度的区间内,将其线性化
********************/
    temp_real_region =  temp_res[temp_min_flag] - c; //c是计算的电阻值。
    temp_region =  temp_res[temp_min_flag] - temp_res[temp_max_flag];
    
    d = temp_real_region / temp_region;
    //真实温度就是最小温度,加上占的那区间的百分比
    temp = (float)temp_min + d; 


//上方版本2.0集成进去了

版本2.0加入了一介滞后滤波:

float Filter(void) //一介滞后滤波
{
  float NewValue;
  NewValue = temp;
  Value = (NewValue * FILTER_A + (1.0 - FILTER_A) * Value);
  return Value;
}

主函数:

/*void main(void)
{
  u16 u16_adc1_value;//记录每次采集的AD值
  int16_t temp_min;//当前阻值温度的可能的最小值
  float c,d;//防止直接给函数赋值失败,先让其计算一下
  float temp_real_region,temp_region,temp; //计算真实温度的变量
  
  sys_clock_init();//时钟初始化
  sys_adc_init();//AD初始化
  usart_init(115200);//串口初始化
  while (1)
  {    
      
    u16_adc1_value = sys_adc_read(); //取出电压值
    
    c = compute_res(u16_adc1_value);//计算
    
    find_temp(c);
    
    temp_min = -10 + temp_min_flag; //估摸一下温度准不准
    
   
    temp_real_region =  temp_res[temp_min_flag] - c;
    temp_region =  temp_res[temp_min_flag] - temp_res[temp_max_flag];
    
    d = temp_real_region / temp_region;
    //真实温度就是最小温度,加上占的那区间的百分比
    temp = (float)temp_min + d; 
    
    
    mprintf("阻值value结果为: "); 
    mprintf("%d\n",u16_adc1_value);
    mprintf("最高阻值为: ");
    mprintf("%f\n",c);
    mprintf("最低温度为: ");
    mprintf("%d\n",temp_min);
    mprintf("真实温度为: ");
    mprintf("%f\n",temp);
  }
}*/

//版本2.0


void main(void)
{
  u16 u16_adc1_value;//记录每次采集的AD值
  float c;//防止直接给函数赋值失败,先让其计算一下
  sys_clock_init();//时钟初始化
  sys_adc_init();//AD初始化
  usart_init(115200);//串口初始化
  
  while (1)
  {   

    u16_adc1_value = sys_adc_read(); //取出电压值
    
    c = compute_res(u16_adc1_value);//计算阻值
    
    temp = find_temp(c);
    
    Filter_Value = Filter(); //测量稳定

    mprintf("最高阻值为: %f\n",c);
    mprintf("真实温度为: %f\n",Filter_Value);
  }
}

还有人问过我,有些变量的问题,如果还缺少变量基本是float类型的

#define FILTER_A 0.01
#define CONNECT_RES 10  //第一个是一介滞后的系数,第二个是串联电阻阻值

float temp,Value,Filter_Value; //这三个是全局变量

得到的结果:

结果还是1.0版本,2.0版本就不放了

经过电压表测量,AD值正确,电阻值正确, 经查表,温度值在电阻值区间内。

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值