随手小记一下,如果有错误还望大佬指正。测温2.0版本
至关重要的就是确定型号,程序其实没多少东西。
首先你要先确定你的热敏电阻的型号,如果你是从淘宝购买,可以去问客服。如果你不知道型号如何,可以列一个表,在STM中利用你的分压公式,计算出你的电阻在温度多少的时候,电阻是多少。程序在下方,如图。要想问参考温度怎么得到的,那就是用另一个温度传感器。
热敏电阻的电阻值是随着温度的变化而变化的,温度越高电阻越小。电阻值与温度对应表在以下网址http://www.thermistors.cn/news/238.html,http://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值正确,电阻值正确, 经查表,温度值在电阻值区间内。