本文主要描述 - STM32 ADC NTC热敏电阻二分(折半)查表法测温功能的思路和代码实现

NTC的相关属性:R25=10K±3% B25/50=4100K±3% 10K上拉

STM32 ADC实现NTC测温的电路示意图如下:

STM32的ADC分辨率为12位,模数转换的范围 0~4095(0x000~0xFFF)

针对以上描述的NTC属性以及电路,对应的温度和测量的数字量的关系表:

static const uint16 R10K_TAB[] = { //R25=10K±3% B25/50=4100K±3% 10K上拉3738,3719,3698,3677,3655,3631,3607,3582,3556,3530,   //-20℃ ... -11℃3502,3473,3443,3412,3381,3348,3314,3280,3244,3208,   //-10℃ ...  -1℃3170,3132,3093,3053,3012,2970,2928,2885,2842,2797,   //  0℃ ...   9℃2752,2707,2661,2615,2568,2522,2474,2427,2379,2332,   // 10℃ ...  19℃2284,2237,2189,2142,2095,2048,2001,1954,1908,1863,   // 20℃ ...  29℃1818,1773,1729,1685,1642,1600,1558,1517,1477,1437,   // 30℃ ...  39℃1398,1360,1323,1286,1250,1215,1180,1147,1114,1082,   // 40℃ ...  49℃1051,1020, 990, 961, 933, 905, 878, 852, 827, 802,   // 50℃ ...  59℃778, 755, 732, 710, 688, 668, 647, 628, 609, 590,   // 60℃ ...  69℃572, 555, 538, 522, 506, 491, 476, 461, 447, 434,   // 70℃ ...  79℃421, 408, 395, 384, 372, 361, 350, 340, 330, 320,   // 80℃ ...  89℃311, 302, 293, 284, 276, 268, 261, 253, 246, 239,   // 90℃ ...  99℃233, 226, 220, 214, 209, 203                         //100℃ ... 105℃
};

将数据表的数据放到Excel中查看曲线的形状

从图中可以看出,NTC的温度与数字量的关系比较接近一元线性关系,数字量越大,温度值越低,负相关。那么将两度之间的小数度数几乎可以认为就是线性的,下面介绍计算小数精度的方法按照线性处理。

在数据表中给出的数据,是整数温度对应的数字量,本次实验测量的精度为0.1℃,测量的数字量值很可能是在两个整数度中间,如ADC采样的数字量为 0x80C,十进制是2060,对应在数据表的2048(25℃)和2095(24℃)中间,计算方式按照线性处理如下:

关于二分(折半)查找的方法,肯定是要比逐次对比效率要高很多,至于效率高多少就不分析了,这里我按照二分查找的思路来进行。由于采样的ADC数字量可能在表中查找不到,但是可以查找出在哪个范围内,就如我上述举例的情况,采样是 2060,在2048和2095之间,至于怎么实现二分查找,参考一下下面的代码。

函数方法实现的思路,在第一图电路示意图中如果没有接NTC传感器,相当于是开路,ADC采样的值相当于电源电压;如果将NTC的两个端子用导线短接,ADC采样的值相当于GND;考虑到极限的情况温度低于-20℃,采样的数字量值不在数据表范围内,即大于3738;同样,如果实际测量温度高于105度,采样的数字量值不在数据表范围内,即小于203;其他的情况就属于正常可以查表的数字量。开路测量电源电压时,可能会稍低于0XFFF,我这里留出一些余量0X00F;短路测GND的电压数字量时,可能会稍微高于0X000,也留出余量0X00F。

用图来表示

下面是具体的代码实现:(代码中小数部分,通过*10的倍率来表示,即247代表24.7℃)

z_hardware_adc.c

#ifndef __Z_HARDWARE_ADC_H
#define __Z_HARDWARE_ADC_H
#include "z_hardware_adc.h"
#endif#define SHORT_CIRCUIT_THRESHOLD 15
#define OPEN_CIRCUIT_THRESHOLD 4080static const u16 R10K_TAB[] = { //R25=10K±3% B25/50=4100K±3% 10K??3738,3719,3698,3677,3655,3631,3607,3582,3556,3530,   //-20? ... -11?3502,3473,3443,3412,3381,3348,3314,3280,3244,3208,   //-10? ...  -1?3170,3132,3093,3053,3012,2970,2928,2885,2842,2797,   //  0? ...   9?2752,2707,2661,2615,2568,2522,2474,2427,2379,2332,   // 10? ...  19?2284,2237,2189,2142,2095,2048,2001,1954,1908,1863,   // 20? ...  29?1818,1773,1729,1685,1642,1600,1558,1517,1477,1437,   // 30? ...  39?1398,1360,1323,1286,1250,1215,1180,1147,1114,1082,   // 40? ...  49?1051,1020, 990, 961, 933, 905, 878, 852, 827, 802,   // 50? ...  59?778, 755, 732, 710, 688, 668, 647, 628, 609, 590,   // 60? ...  69?572, 555, 538, 522, 506, 491, 476, 461, 447, 434,   // 70? ...  79?421, 408, 395, 384, 372, 361, 350, 340, 330, 320,   // 80? ...  89?311, 302, 293, 284, 276, 268, 261, 253, 246, 239,   // 90? ...  99?233, 226, 220, 214, 209, 203                         //100? ... 105?
};void init_adc(void)
{GPIO_InitTypeDef GPIO_InitStructure;ADC_InitTypeDef ADC_InitStructure;ErrorStatus HSEStartUpStatus;RCC_DeInit();RCC_HSEConfig(RCC_HSE_ON);HSEStartUpStatus = RCC_WaitForHSEStartUp();if(HSEStartUpStatus == SUCCESS) {RCC_HCLKConfig(RCC_SYSCLK_Div1);RCC_PCLK2Config(RCC_HCLK_Div1);RCC_PCLK1Config(RCC_HCLK_Div2);RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);RCC_PLLCmd(ENABLE);while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);while(RCC_GetSYSCLKSource() != 0x08);}RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;//PC4GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOA, &GPIO_InitStructure);ADC_DeInit(ADC1);ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;ADC_InitStructure.ADC_ScanConvMode = DISABLE;ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_NbrOfChannel = 1;ADC_Init(ADC1, &ADC_InitStructure);ADC_Cmd(ADC1, ENABLE);ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1));ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1));ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}u16 func_get_adc_valve_ch7(void)
{   ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 1, ADC_SampleTime_55Cycles5);ADC_SoftwareStartConvCmd(ADC1, ENABLE);while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));return ADC_GetConversionValue(ADC1);
}u8 func_get_ntc_temp(u16 value_adc, s16* value_temp)
{u8 index_l, index_r;u8 r10k_tab_size = 126;s32 temp = 0;if(value_adc <= SHORT_CIRCUIT_THRESHOLD){return 1;}else if(value_adc >= OPEN_CIRCUIT_THRESHOLD){return 2;}else if(value_adc > R10K_TAB[0]){return 3;}else if(value_adc < R10K_TAB[r10k_tab_size - 1]){return 4;}index_l = 0;index_r = r10k_tab_size - 1;for(;index_r - index_l > 1;){if((value_adc <= R10K_TAB[index_l]) && (value_adc > R10K_TAB[(index_r + index_l)%2 == 0 ? (index_r + index_l)/2 : (index_r + index_l)/2 + 1])){index_r = (index_r + index_l) % 2 == 0 ? (index_r + index_l)/2 : (index_r + index_l)/2 + 1;}else{index_l = (index_r + index_l)/2;}}if(R10K_TAB[index_l] == value_adc){temp = (((s16)index_l) - 20)*10;//rate *10}else if(R10K_TAB[index_r] == value_adc){temp = (((s16)index_r) - 20)*10;//rate *10}else{if(R10K_TAB[index_l] - R10K_TAB[index_r] == 0){temp = (((s16)index_l) - 20)*10;//rate *10}else{temp = (((s16)index_l) - 20)*10 + ((R10K_TAB[index_l] - value_adc)*100 + 5)/10/(R10K_TAB[index_l] - R10K_TAB[index_r]);}        }*value_temp = temp;return 0;
}

z_hardware_adc.h

#ifndef __STM32F10X_H
#define __STM32F10X_H
#include "stm32f10x.h"
#endifvoid init_adc(void);
u16 func_get_adc_valve_ch7(void);u8 func_get_ntc_temp(u16 value_adc, s16* value_temp);

测试的主函数代码:

#ifndef __STM32F10X_H
#define __STM32F10X_H
#include "stm32f10x.h"
#endif#ifndef __Z_UTIL_TIME_H
#define __Z_UTIL_TIME_H
#include "z_util_time.h"
#endif#ifndef __Z_HARDWARE_USART2_H
#define __Z_HARDWARE_USART2_H
#include "z_hardware_usart2.h"
#endif#ifndef __Z_HARDWARE_ADC_H
#define __Z_HARDWARE_ADC_H
#include "z_hardware_adc.h"
#endif#ifndef __Z_HARDWARE_LED_H
#define __Z_HARDWARE_LED_H
#include "z_hardware_led.h"
#endifint main()
{u8 buf[8];u16 val;s16 value_temp;u8 res;init_adc();init_hardware_usart2_dma(9600);init_led();val = func_get_adc_valve_ch7();for(;;){ val = func_get_adc_valve_ch7();res = func_get_ntc_temp(val, &value_temp);if(res == 0){buf[0] = value_temp >> 8;buf[1] = value_temp;func_usart2_dma_send_bytes(buf, 2);}func_led1_on();delay_ms(1000);func_led1_off();delay_ms(1000);}}

测试的效果,通过串口将16进制值打印出来如下:

STM32 ADC NTC热敏电阻二分(折半)查表法实现测温功能相关推荐

  1. 单片机c语言NTC温度查表程序,STM32查表法读NTC值并显示温度

    STM32查表法读NTC值并显示温度 #include "stm32f10x.h"Y'+F0IZ+ #include "delay.h"pU'`9fLi_ #i ...

  2. HAL库教程14:查表法测量NTC热敏电阻

      STM32F4的AD采样的结果是12位的,即采样的最大值为4096.而参考电压是3.3V,所以3.3V与4096是对应的.当然3.3V只是理想状态,实际上可能略有偏差.假设单片机的AD采集引脚电压 ...

  3. NTC查表法,采用二分法

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

  4. crc16modbus查表法_查表法计算CRC16校验值

    /******************************************************************************* * Copyright (c) 201 ...

  5. FPGA之道(63)“万能”的查表法

    文章目录 前言 "万能"的查表法 正弦波发生器示例 前言 又好几天没更新了,这就是又停止了读书的节奏,终于在毕业论文可以稍微舒缓下来的时候更新了博客,完成一个系列,读完一本书等等都 ...

  6. 嵌入式C语言查表法的项目应用

    嵌入式C实战项目开发技巧:如何对一个有规律的数组表进行位移操作 就像下面的这个表 之前写过上面这个标题的一篇文章,讲的是以位移的方式去遍历表中的数据,效率非常高,但是,如果要实现一个乱序的流水灯或者跑 ...

  7. VTK修炼之道23:图像基本操作_灰度图像映射成伪彩色图像(查表法)

    1.查表法伪彩图映射 图像彩色映射的原理是首先生成一个颜色查找表,然后根据图像的一个标量值向颜色查找表中查找对应的颜色,并用新颜色值替代原来的像素值.VTK中vtkImageMapToColors负责 ...

  8. 数组---进制转换(查表法)

    package com.shuzu; public class shuzuJinZhiZhuanHuan { * @param a 所要转换的十进制数,b 不同进制所要与(&)的数不同,wei ...

  9. 查表法实现反正切_关于python实现CRC32的应用和总结

    关于python实现CRC32的应用和总结 目前使用的Crc计算包含Crc32和Crc32mpeg2两种计算方式. 循环冗余检验 CRC 差错检测技术能够证明数据是完整的,是无差错的(只是非常近似的认 ...

最新文章

  1. linux中html图标格式,如何在Linux上将HTML页面转化成png图片
  2. java按钮监听休眠_java-休眠监控解决方案
  3. pytorch tensor 筛选排除
  4. 【Flutter】屏幕像素适配方案 ( flutter_screenutil 插件 )
  5. 有一种感情,叫“发小”
  6. Android屏幕大小适配问题解决
  7. 吴恩达机器学习作业4(python实现)
  8. html图片分四面切割播,JS+CSS实现3D切割轮播图
  9. 刚体运动学公式_刚体的运动学与动力学问题 (二)
  10. [CTF]Brainfuck/Ook!编码
  11. amoeba mysql读写分离_MySQL和Amoeba实现同步读写分离centos7
  12. oracle中todate函数实例,pl/sql to_date 函数使用实例讲解
  13. [Servlet] HttpServletRequest
  14. css写七步诗,兄弟情谊的诗句
  15. 注册用户数破亿 平安金管家APP成全球寿险首个过亿应用
  16. 32位系统的内存访问
  17. 【CCF会议期刊推荐】CCF推荐国际学术期刊/会议(网络与信息安全)
  18. 美国推进隐私保护立法 加剧全球网络空间治理复杂性
  19. 蜜芽CEO刘楠:垂直电商黄金时代已落幕 坚定转型品牌之路
  20. 博途V15TIA Portal V15S7-PLCSIM V15仿真时出现(数值无法写入PLC)解决方案

热门文章

  1. 【Node.js】解决中文乱码问题
  2. 合并两个有序数组(java算法)
  3. 车辆路径问题相关benchmark汇总
  4. kindeditor上传图片配置upload_json.jsp文件出现500错误
  5. Volo.Abp.EntityFrameworkCore.MySQL 使用
  6. 使用 VMware-Workstation-9 或者 Vmware10 安装 fedora9时卡住了
  7. 特步2020年总收入81.72亿元,主品牌下半年显著复苏
  8. Unity物理系统中碰撞体、刚体、isKinematic、isTrigger的关系(附动画演示)
  9. 使用CruiseControl搭建自己的持续集成环境
  10. PHP Laravel框架 微信模板消息发送