为什么要写这篇
算是一次更深一些的思考吧,对于查数据表,通常都只有一个表格,如果翻看数据手册,就会看到数据表中对应的数值只是一个典型值,而实际情况是传感器的值必定会在某个范围内波动,对应一个上限值和一个下限值。通常使用这个典型值就可以了,方法就是这篇博客:
但如果需要查找两个数据表,分别是上限表和下限表,那该怎么办呢?顺序查表?有没有可能落空呢?我想到一个比较简单的办法,只要在范围内,必定会返回一个数值。
怎么实现
先对ADC采集的数值分别在两个数据表中进行查找,得到两个相近的值(假设是温度),然后再进一步判断(判断是否在该温度的上下限中,若不在两个温度的上下限中,则找最接近的温度),得到最接近的值(温度)。前提是传感器的上下限不存在重合部分,传感器的数值对应唯一温度
程序如下,可直接复制到菜鸟C在线工具中运行
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#define DEBUG_OUTPUT 0
#define ARRAY_SIZE 40
uint16_t lower_limit[40] =
{
6132, 5988, 5842, 5697, 5553, 5411, 5269, 5129, 4991, 4855,
4720, 4588, 4457, 4329, 4203, 4079, 3958, 3839, 3722, 3608,
3497, 3388, 3282, 3178, 3077, 2977, 2881, 2786, 2694, 2604,
2517, 2432, 2350, 2270, 2193, 2119, 2047, 1976, 1909, 1843
};
uint16_t higher_limit[40] =
{
6261, 6115, 5966, 5818, 5671, 5525, 5380, 5237, 5095, 4955,
4817, 4681, 4547, 4415, 4285, 4158, 4033, 3910, 3790, 3673,
3558, 3446, 3336, 3229, 3125, 3022, 2927, 2833, 2741, 2652,
2565, 2481, 2400, 2320, 2243, 2169, 2097, 2027, 1959, 1894
};
uint16_t search_based_on_dichotomy(uint16_t key, const uint16_t *a, uint16_t n);
int main(void)
{
srand((unsigned)time(NULL));
for(uint8_t i=0; i<5; i++)
{
uint16_t random_val = rand() % 4400 + 1845;
printf("random_val is %d \n", random_val);
uint8_t return_val1 = search_based_on_dichotomy(random_val, lower_limit, sizeof(lower_limit)/sizeof(lower_limit[0]));
uint8_t return_val2 = search_based_on_dichotomy(random_val, higher_limit, sizeof(higher_limit)/sizeof(higher_limit[0]));
if((higher_limit[return_val1] > random_val) && (random_val > lower_limit[return_val1]))
{
printf("AA the need value is %d \n\n", return_val1);
}else if((higher_limit[return_val2] > random_val) && (random_val > lower_limit[return_val2]))
{
printf("BB the need value is %d \n\n", return_val2);
}else
{
if((higher_limit[return_val1] - random_val) < (random_val - lower_limit[return_val2]))
{
printf("CC the need value is %d \n\n", return_val1);
}else
{
printf("DD the need value is %d \n\n", return_val2);
}
}
}
return 0;
}
/**
* @brief 基于二分查找法,需要数组是递减序列
* @param key 要查找的值
* @param a 数组元素首地址
* @param n 数组元素个数
* @note 对传入参数进行验证
* @note 不是数组元素也会查找成功,关键是如何判断介于两者之间,终止条件已做更改
* @note 若到两数的间隔相等,则会返回较小的数
* @attention 此处要求数组元素个数2^8 =256应用限制较多,因此改为uint16_t
*/
uint16_t
search_based_on_dichotomy(uint16_t key, const uint16_t *a, uint16_t n) ///< 传入类型更改
{
uint16_t low, high, mid;
uint8_t count=0;
low = 0;
high = n;
if((key > a[0]) || (key < a[ARRAY_SIZE - 1])) //传入参数验证 ///< 递减序列更改
{
#if DEBUG_OUTPUT
printf("The key is not in array range \n");
#endif
return 0;
}
while(low < high)
{
count++; //记录查找次数
#if DEBUG_OUTPUT
printf("\n search times : %d \n", count);
#endif
mid = (low + high) / 2;
if(key == a[mid])
{
return mid;
}else if(key > a[mid]) ///< 递减序列更改
{
#if DEBUG_OUTPUT
printf("key > array[mid] high = %d, mid = %d, low = %d \n", high, mid, low);
printf("array[high] = %d, array[mid] = %d, array[low] = %d \n", a[high], a[mid], a[low]);
#endif
if(key > a[mid - 1]) ///< 递减序列更改
{
high = mid - 1;
}else
{
if(abs(key - a[mid - 1]) < abs(a[mid] - key))
{
#if DEBUG_OUTPUT
printf(" the closer value is array[mid - 1] = %d \n", a[mid - 1]);
#endif
return mid - 1;
}else
{
#if DEBUG_OUTPUT
printf(" the closer value is array[mid] = %d \n", a[mid]);
#endif
return mid;
}
}
}else if(key < a[mid]) ///< 递减序列更改
{
#if DEBUG_OUTPUT
printf("key < array[mid] high = %d, mid = %d, low = %d \n", high, mid, low);
printf("array[high] = %d, array[mid] = %d, array[low] = %d \n", a[high], a[mid], a[low]);
#endif
if(key < a[mid + 1]) ///< 递减序列更改
{
low = mid + 1;
}else
{
if(abs(a[mid + 1] - key) > abs(key - a[mid]))
{
#if DEBUG_OUTPUT
printf(" the closer value is array[mid] = %d \n", a[mid]);
#endif
return mid;
}else
{
#if DEBUG_OUTPUT
printf(" the closer value is array[mid + 1] = %d \n", a[mid + 1]);
#endif
return mid + 1;
}
}
}
}
return 0;
}