前言
单片机在实际读取AD值时,读到的值是不稳定的,在不断的变化,如果不经过处理,直接使用,是很难获得其准确的值,因此我们需要对其进行消抖滤波处理。
滤波
一般来说AD值的不稳,我们可以将一段时间读取到的数值取平均值,为了防止数值突变的影响,我们可以减去最大和最小值。
我们10ms读取一次AD值,取10次AD值的平均值即可。
static u16_t s_wMaxAdVal = 0;
static u16_t s_wMinAdVal = 1023;
static u16_t s_wSumAdVal = 0;
static u16_t s_wAdFiltVal = 0;
static u8_t s_nAdCnt = 0;
void AdFilter(u16_t wAdData)
{
if (wAdData > s_wMaxAdVal)
{
wMaxAdVal = wAdData;
}
if (wAdData < s_wMinAdVal)
{
s_wMinAdVal = wAdData;
}
s_nAdCnt++;
if (s_nAdCnt <= 10)
{
s_wSumAdVal += wAdData;
}
else
{
s_nAdCnt = 0;
s_wSumAdVal -= (s_wMaxAdVal + s_wMinAdVal);
s_wAdFiltVal = s_wSumAdVal >> 3;
s_wMaxAdVal = 0;
s_wMinAdVal = 1023;
s_wSumAdVal = 0;
}
}
该函数中s_wAdFiltVal的值即是滤波后的AD值。
温度转换
通常我们可以使用热敏电阻来检测温度,但是热敏电阻的阻值和温度的关系一般不可以通过数学表达式来描述,而是根据热敏电阻的规格书中阻值和温度的关系表来查找。
因此我们需要在程序中编写查找与AD值对应的温度。
硬件简述
简单的分压计算,通过温度与阻值的关系表,计算出温度与AD值关系表。
下面列出一个计算好的关系表:
#define RT_NUM 160
#define MINTEMP 0
const u16_t wRTtable[RT_NUM] =
{
994, 992, 991, 989, 987, 985, 983, 981, 979, 977,
975, 973, 970, 968, 965, 962, 960, 957, 954, 951,
947, 944, 941, 937, 934, 930, 926, 922, 918, 913,
909, 905, 900, 895, 890, 885, 880, 875, 870, 864,
858, 853, 847, 841, 835, 828, 822, 816, 809, 802,
795, 788, 781, 774, 767, 760, 752, 745, 737, 729,
721, 713, 705, 697, 689, 681, 673, 665, 656, 648,
640, 631, 623, 614, 606, 597, 589, 581, 572, 564,
555, 547, 538, 530, 521, 513, 505, 497, 488, 480,
472, 464, 456, 448, 440, 433, 425, 417, 410, 402,
395, 388, 381, 374, 366, 360, 353, 346, 339, 333,
326, 320, 300, 308, 302, 296, 290, 284, 278, 273,
267, 262, 257, 251, 246, 241, 236, 232, 227, 222,
218, 213, 209, 205, 200, 196, 192, 188, 184, 181,
177, 173, 170, 166, 163, 159, 156, 153, 150, 147,
144, 141, 138, 135, 132, 130, 127, 124, 122, 119,
};
注: 温度应该是连续递增的。
温度查找
学过C语言的同学,应该都知道二分法查找,每次将当前的值与目标范围的中间值进行比较,从而不断缩小查找范围,时间复杂度为O(
log
?
2
n
\log_{2}{n}
log2?n)。
void FindAdcTemp(u16_t wAdcVal, u16_t wTempData)
{
u8_t nBegin = 0;
u8_t nEnd= 0;
u8_t nMiddle = 0;
nEnd = RT_NUM -1;
if (wAdcVal <= *(wRTtable + nEnd))
{
wTempData = RT_NUM + MINTEMP;
}
else if (wAdcVal >= *(wRTtable + nBegin))
{
wTempData = MINTEMP;
}
else
{
while ((nBegin < nEnd) && (wAdcVal != *(wRTtable + nMiddle)))
{
nMiddle = nBegin + (nEnd - nBegin)>>1;
if (wAdcVal > *(wRTtable + nMiddle))
{
nEnd = nMiddle - 1;
}
else
{
nBegin = nMiddle + 1;
}
}
wTempData = MINTEMP + (nBegin -1);
if (wAdcVal < *(wRTtable + nBegin -1))
{
wDiffAdcVal = (*(wRTtable + nBegin -1) - wAdcVal)*10;
wDiffAdcVal /= *(wRTtable + nBegin -1) - *(wRTtable + nBegin);
if (wDiffAdcVal >= 5)
{
wTempData = MINTEMP + nBegin;
}
}
}
}
我们只要调用FindAdcTemp这个函数,就可以根据当前的AD值,计算得到最接近的温度值。
|