NTC查表法,采用二分法,查表效率提升约20倍!

做温控器,传感器采用NTC热敏电阻,前几年做的代码,为了省事方便,直接采用查询方法,从头到尾查询一边,一个200个元素的一维数组,例如NTC_ADC_TAB[200],最多要查询200次!方法很笨!

对于强迫症的工程师来说,这是个打心眼里别扭的事情,就像穿西装,打领带这么别扭!

最近项目不忙,对温控器的代码做了优化重构,顺便把温度查表函数做了优化更改,采用二分法,效率显著提升,废话不多,SHOW THE CODE:

以下代码采用编程平台:IAR FOR STM8
硬件平台:stm8l152
ADC分辨率:12位
已经在产品上验证并批量出货!PS:做一个靠谱的网友!

/*********************** 宏定义 *********************************/
#define NTC_ADC_MAX    201

/**************** NTC热敏电阻转换成ADC的值 ***********************/
const uint16_t NTC_ADC_Tab[NTC_ADC_MAX]={
    2559 ,2555 ,2551 ,2546 ,2542 ,2538 ,2534 ,2529 ,2525 ,2521 ,// 25.0~25.9 ℃
    2517 ,2513 ,2508 ,2504 ,2500 ,2496 ,2491 ,2487 ,2483 ,2479 ,// 26.0~26.9 ℃
    2474 ,2470 ,2466 ,2461 ,2457 ,2453 ,2449 ,2444 ,2440 ,2436 ,// 27.0~27.9 ℃
    2432 ,2427 ,2423 ,2419 ,2415 ,2410 ,2406 ,2402 ,2397 ,2393 ,// 28.0~28.9 ℃
    2389 ,2385 ,2380 ,2376 ,2372 ,2368 ,2363 ,2359 ,2355 ,2350 ,// 29.0~29.9 ℃
    2346 ,2342 ,2338 ,2333 ,2329 ,2325 ,2320 ,2316 ,2312 ,2308 ,// 30.0~30.9 ℃
    2303 ,2299 ,2295 ,2291 ,2286 ,2282 ,2278 ,2273 ,2269 ,2265 ,// 31.0~31.9 ℃
    2261 ,2256 ,2252 ,2248 ,2243 ,2239 ,2235 ,2231 ,2226 ,2222 ,// 32.0~32.9 ℃
    2218 ,2214 ,2209 ,2205 ,2201 ,2196 ,2192 ,2188 ,2184 ,2179 ,// 33.0~33.9 ℃
    2175 ,2171 ,2167 ,2162 ,2158 ,2154 ,2150 ,2145 ,2141 ,2137 ,// 34.0~34.9 ℃
    2133 ,2128 ,2124 ,2120 ,2116 ,2111 ,2107 ,2103 ,2099 ,2095 ,// 35.0~35.9 ℃
    2090 ,2086 ,2082 ,2078 ,2073 ,2069 ,2065 ,2061 ,2057 ,2052 ,// 36.0~36.9 ℃
    2048 ,2044 ,2040 ,2036 ,2031 ,2027 ,2023 ,2019 ,2015 ,2010 ,// 37.0~37.9 ℃
    2006 ,2002 ,1998 ,1994 ,1990 ,1985 ,1981 ,1977 ,1973 ,1969 ,// 38.0~38.9 ℃
    1965 ,1960 ,1956 ,1952 ,1948 ,1944 ,1940 ,1936 ,1932 ,1927 ,// 39.0~39.9 ℃
    1923 ,1919 ,1915 ,1911 ,1907 ,1903 ,1899 ,1895 ,1890 ,1886 ,// 40.0~40.9 ℃
    1882 ,1878 ,1874 ,1870 ,1866 ,1862 ,1858 ,1854 ,1850 ,1846 ,// 41.0~41.9 ℃
    1842 ,1838 ,1833 ,1829 ,1825 ,1821 ,1817 ,1813 ,1809 ,1805 ,// 42.0~42.9 ℃
    1801 ,1797 ,1793 ,1789 ,1785 ,1781 ,1777 ,1773 ,1769 ,1765 ,// 43.0~43.9 ℃
    1761 ,1757 ,1753 ,1750 ,1746 ,1742 ,1738 ,1734 ,1730 ,1726 ,// 44.0~44.9 ℃
    1722 ,// 45 ℃
};

/**
  * @brief  二分法查表法,得出单路温度值
  * @param  pos
  * @retval TempSingleValue
  */
uint16_t get_single_temp(uint8_t pos)
{
    uint16_t    End = NTC_ADC_MAX - 1;// 数组下标最后一个数
    uint16_t    Front = 0;// 数组第一个数
    uint8_t     half = 0;
    uint16_t    TempSingleADC = 0;// 单次转换的ADC值
    uint16_t    TempSingleValue = 0;// 单次换算成的温度值,用来函数返回值;
 
    ADC_Channel_TypeDef    ADC_Channel_X = ADC_Channel_0;
    
    switch(pos)
    {
        case 0:
          ADC_Channel_X = ADC_Channel_0;
          break;
        case 1:
          ADC_Channel_X = ADC_Channel_1;
          break;
        case 2:
          ADC_Channel_X = ADC_Channel_2;
          break;
        default :
          break;
    }
    
    /* Enable ADC1 clock */
    CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, ENABLE);

    /* Initialize and configure ADC1 */
    ADC_Init(ADC1, ADC_ConversionMode_Continuous, ADC_Resolution_12Bit, ADC_Prescaler_2);

    /* ADC channel used for IDD measurement */
    ADC_SamplingTimeConfig(ADC1, ADC_Group_FastChannels, ADC_SamplingTime_192Cycles);

    /* Enable ADC1 */
    ADC_Cmd(ADC1, ENABLE);
    Delay(500);

    /* Disable SchmittTrigger for ADC_Channel, to save power */
    ADC_SchmittTriggerConfig(ADC1, ADC_Channel_X, DISABLE);

    /* Enable ADC1 Channel used for LAD measurement */
    ADC_ChannelCmd(ADC1, ADC_Channel_X, ENABLE);
    Delay(500);
    ADC_SoftwareStartConv (ADC1);//开启软件转换

    while(!ADC_GetFlagStatus (ADC1,ADC_FLAG_EOC));//等待转换结束
    ADC_ClearFlag (ADC1,ADC_FLAG_EOC);//清除相关标识
    TempSingleADC = ADC_GetConversionValue (ADC1);//获取转换值;
    //TempSingleADC = 1722;// 调试二分法查表用的临时赋值,调试代码用;
    
    /* DeInitialize ADC1 */
    ADC_DeInit(ADC1);
    /* Disable ADC1 clock */
    CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, DISABLE);
    ADC_ChannelCmd(ADC1, ADC_Channel_X, DISABLE); 

    /**********二分法查表求温度值*********/
    if((TempSingleADC <= NTC_ADC_Tab[0])&&(TempSingleADC >= NTC_ADC_Tab[NTC_ADC_MAX-1]))
    {
        for(half=100;End-Front != 1;)
        {
            if(TempSingleADC > NTC_ADC_Tab[half])
            {
                End = half;
                half = (End + Front)/2;
            }
            else if(TempSingleADC < NTC_ADC_Tab[half])
            {
                Front = half;
                half = (Front + End)/2;
            }
            else// 正好等于表格中的值
            {
                TempSingleValue = 2500+half*10+(NTC_ADC_Tab[half]-TempSingleADC)*10/(NTC_ADC_Tab[half]-NTC_ADC_Tab[half+1]);
                break;
            }
        }
        if(End-Front == 1)// 在表格两个值之间的数
        {
            TempSingleValue = 2500+half*10+(NTC_ADC_Tab[half]-TempSingleADC)*10/(NTC_ADC_Tab[half]-NTC_ADC_Tab[half+1]);
        }
    }
    else
    {
        TempSingleValue = 0;          // 温度超出数组范围,就返回0度
    }
    return TempSingleValue;
}

PS: 经过几年的小积累,本电工的小公司开张接客啦!目前做电子项目开发,温控器,记录仪,工业现场总线采集模块产品,有需要的朋友,加qq:741684134 !!!

 

你可能感兴趣的:(单片机技术)