博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【龙印】在龙芯1c上用TM7705+NTC热敏电阻实现温度测量
阅读量:2360 次
发布时间:2019-05-10

本文共 10463 字,大约阅读时间需要 34 分钟。

本文为在用龙芯1c做3D打印机过程中的笔记。龙芯1c做的3d打印机简称“龙印”,Git地址“https://gitee.com/caogos/marlin_ls1c”

本文重点放在TM7705和ntc热敏电阻结合实现测量温度上,另外有一篇重点放在TM7705的驱动上。详见《【龙印】龙芯1c上双路16位AD芯片TM7705的linux驱动》http://blog.csdn.net/caogos/article/details/53034196

电路分析

手里只有在淘宝上买的“安富莱”的TM7705模块,接上NTC热敏电阻测了一下,测量电压精度还不错。测得ad=555,通过计算得到热敏电阻电压=5/1024*555=2.71v,用万用表测得NTC热敏电阻两端电压为2.66V,误差0.05V,精度还不错。

虽然这个模块测量电压精度还不错,但是用这个模块通过测量NTC热敏电阻的阻值来间接测量温度的精度确不理想。下面来看测试的一组结果

先介绍下背景知识,NTC热敏电阻测温的电路如下

如旁边的英文注释所说,通常上图的R1不接,R2=4.7k。开源3D打印机的扩展板ramps1.4中的电路也是这样的。

也就是说,只需要一个4.7k电阻和NTC热敏电阻就可以用TM7705测温了。好,接上后测得如下结果

AD=555

用万用表测得NTC热敏电阻的为138.1k。

查询“100K 3950 NTC热敏电阻阻值温度表”(这个表百度上很多)可知:当NTC阻值=138.1K时,温度约为18度。

然后用AD值查询脚本“createTemperatureLookup.py”生成的AD与温度对应的表得到的结果确不是18度。

脚本“createTemperatureLookup.py”来源于https://github.com/reprap/firmware/blob/master/createTemperatureLookup.py,注解在http://www.reprap.org/wiki/Thermistor

marlin中的“createTemperatureLookupMarlin.py”功能相同,都是生成AD与阻值的对应表。(个人)认为还是reprap firmware中的脚本“createTemperatureLookup.py”的源码更好理解。

可是脚本中的参数应该改为多少了?模块用的是2.5的基准电源,但是模拟输入端用两个10k电阻并联分压了,是不是可以认为基准电压应该为2.5*2呢?

由于龙芯1c的spi的sck线是3.3v的,所以TM7705的电源也是3.3v的,那NTC热敏电阻和4.7k电阻的电源是3.3v呢?还是5v呢?

首先可以用3.3v的,如果用5v的,可能超过tm7705测量的最大值,因为Tm7705是3.3v电源,也就是NTC热敏电阻两端电压超过3.3v后,不论是多少都是0xffffff。满量程了。

好,就接3.3v,可是把脚本“createTemperatureLookup.py”中的self.vcc改为3.3,不论把self.vadc改为2.5还是5,生成的AD和温度对应表(AD=555对应的温度)都不对。

后来发现在TM7705模块输入端不是还有两个10k电阻吗,再看看前面的NTC热敏电阻测温的标准电路图,发现TM7705模块模拟输入端的串联的两个10k电阻的“位置”有点像标准电路图中的R1.即R1=20k,如下图所示

脚本“createTemperatureLookup.py”中默认的是0,修改脚本后,重新生成,发现也不对。

没办法,只有分析脚本源码了,看看到底是哪里的问题。脚本也不复杂,关键是函数temp(self,adc),输入ad值,返回的就是温度,就三行代码如下

def temp(self,adc):        "Convert ADC reading into a temperature in Celcius"        v = adc * self.vadc / 1024          # convert the 10 bit ADC value to a voltage        r = self.rs * v / (self.vs - v)     # resistance of thermistor        return (self.beta / log(r / self.k)) - 273.15        # temperature
注释已经写得很清楚,第一行就是将ad值转换为电压值,第二行通过电压和流过的电流算出电阻,第三行就是根据电阻算出温度。

既然这样,那就手动算一下

AD=555,那么V=5/1024*555=2.71v,流过4.7k电阻的电流=(3.3-2.71)/4.7=0.125,流过TM7705模拟输入端两个串联的10k电阻的电流=2.71/20=0.1355。这时候你会发现,不对啊,怎么流过4.7k电阻的电流还要小一些呢?

是的,上面的计算都是理论值的计算,实际上,电源电压不是3.3v,而是3.38v;4.7k电阻的阻值是4.6k,两个串联的10k电阻的阻值应该也不是刚好20k。

基于此,把TM7705模拟输入端的两个串联的电阻取下来,并把基准电源引出来给4.7k电阻和NTC热敏电阻供电。电路如下

修改后的模块

修改前的模块

测试发现,效果不错。

我们要的是准确的AD值,与基准电压是多少没关系。可以直接给tm7705供电的3.3v电源作为基准电源,同时给4.7k电阻和NTC热敏电阻供电,只是不知道这种情况精度怎么样。

源码

好说了这么多,还是贴源码出来

temp.c

// 温度相关#include 
#include
#include
#include
#include
#include
#include
#include "public.h"#define TEMP_AD_MAX ((0x1<<10)-1) // ad的最大值,ad是十位的#define TEMP_IS_VALID_AD(ad) ((TEMP_AD_MAX>=(ad)) && (0<=(ad))) // 判断ad是在量程范围内#define TEMP_BUFF_SIZE (64) // 缓存大小// TM7705的通道enum{ TM7705_CH_1 = 0, // 通道1 TM7705_CH_2 = 1 // 通道2};// 以下根据ntc热敏电阻参数用脚本生成的adc值与温度一一对应的表格// 左边为adc值,右边为温度(单位:摄氏度)// 详细请参考源码目录中的脚本"createTemperatureLookup.py"// python createTemperatureLookup.py// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts)// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py)// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=3950 --max-adc=1023// r0: 100000// t0: 25// r1: 0// r2: 4700// beta: 3950// max adc: 1023#define NUMTEMPS 40const short temptable[NUMTEMPS][2] = { {1, 938}, {27, 326}, {53, 269}, {79, 239}, {105, 219}, {131, 204}, {157, 192}, {183, 182}, {209, 174}, {235, 166}, {261, 160}, {287, 153}, {313, 148}, {339, 143}, {365, 138}, {391, 133}, {417, 129}, {443, 125}, {469, 120}, {495, 116}, {521, 113}, {547, 109}, {573, 105}, {599, 101}, {625, 98}, {651, 94}, {677, 90}, {703, 86}, {729, 82}, {755, 78}, {781, 74}, {807, 70}, {833, 65}, {859, 60}, {885, 54}, {911, 48}, {937, 41}, {963, 31}, {989, 18}, {1015, -8}};// 读取指定通道的ad值// @channel 通道号// @adc_p 读到的ad值// @ret 成功 or 失败int temp_get_ad(int channel, UINT16 *adc_p){ const char ch1_path[] = {"/sys/bus/spi/drivers/TM7705/spi0.1/ch1"}; const char ch2_path[] = {"/sys/bus/spi/drivers/TM7705/spi0.1/ch2"}; const char *dev_file_path = NULL; int fd = 0; int ret = 0; unsigned int value = 0; char buff[TEMP_BUFF_SIZE] = {0}; // 不同的通道对应/sys下不同的文件 if (TM7705_CH_1 == channel) { dev_file_path = ch1_path; } else { dev_file_path = ch2_path; } fd = open(dev_file_path, O_RDONLY); if (-1 == fd) { printf("[%s] open device file fail.\n", __FUNCTION__); return ERROR; } memset(buff, 0, TEMP_BUFF_SIZE); ret = read(fd, buff, TEMP_BUFF_SIZE-1); if (0 > ret) { printf("[%s] not read data. ret=%d\n", __FUNCTION__, ret); close(fd); return ERROR; } sscanf(buff, "%u\n", &value); value = value >> 6;// printf("[%s] value=%u, buff=%s\n", __FUNCTION__, value, buff); close(fd); if (!TEMP_IS_VALID_AD(value)) { printf("[%s] adc convert fail. ad=%u\n", __FUNCTION__, value); return ERROR; } *adc_p = value; // 输出ad值 return SUCCESS;}// 根据adc值计算温度值// ntc热敏电阻的阻值温度曲线被分为n段,每段可以近似为直线,// 所以温度值的计算就转变为查表再计算// @ad ad值(取值范围为0-1023)// @temp_p 温度值,单位摄氏度// @ret 成功 or 失败int temp_calc_from_ad(UINT16 ad, float *temp_p){ float celsius = 0.0; // 温度值,单位摄氏度 int i = 0; // 判断adc值是否在量程范围内 if (!TEMP_IS_VALID_AD(ad)) { return ERROR; } // 判断是否在表格所表示的范围内 if (ad < temptable[0][0]) // 小于表格的最小adc { *temp_p = temptable[0][1]; // 取最小值 return SUCCESS; } if (ad > temptable[NUMTEMPS-1][0]) // 大于表格的最大adc { *temp_p = temptable[NUMTEMPS-1][1]; // 取最大值 return SUCCESS; } // 查表 // 这里是从adc由低到高,逐个区间进行比较,没有采用折半查找 for (i=1; i
createTemperatureLookup.py

#!/usr/bin/python## Creates a C code lookup table for doing ADC to temperature conversion# on a microcontroller# based on: http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.html"""Thermistor Value Lookup Table GeneratorGenerates lookup to temperature values for use in a microcontroller in C format based on: http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.htmlThe main use is for Arduino programs that read data from the circuit board described here:http://make.rrrf.org/ts-1.0Usage: python createTemperatureLookup.py [options]Options:  -h, --help            show this help  --r0=...          thermistor rating where # is the ohm rating of the thermistor at t0 (eg: 10K = 10000)  --t0=...          thermistor temp rating where # is the temperature in Celsuis to get r0 (from your datasheet)  --beta=...            thermistor beta rating. see http://reprap.org/bin/view/Main/MeasuringThermistorBeta  --r1=...          R1 rating where # is the ohm rating of R1 (eg: 10K = 10000)  --r2=...          R2 rating where # is the ohm rating of R2 (eg: 10K = 10000)  --num-temps=...   the number of temperature points to calculate (default: 20)  --max-adc=...     the max ADC reading to use.  if you use R1, it limits the top value for the thermistor circuit, and thus the possible range of ADC values"""from math import *import sysimport getoptclass Thermistor:    "Class to do the thermistor maths"    def __init__(self, r0, t0, beta, r1, r2):        self.r0 = r0                        # stated resistance, e.g. 10K        self.t0 = t0 + 273.15               # temperature at stated resistance, e.g. 25C        self.beta = beta                    # stated beta, e.g. 3500        self.vadc = 2.5                     # ADC reference        self.vcc = 2.5                      # supply voltage to potential divider        self.k = r0 * exp(-beta / self.t0)   # constant part of calculation        if r1 > 0:            self.vs = r1 * self.vcc / (r1 + r2) # effective bias voltage            self.rs = r1 * r2 / (r1 + r2)       # effective bias impedance        else:            self.vs = self.vcc                   # effective bias voltage            self.rs = r2                         # effective bias impedance    def temp(self,adc):        "Convert ADC reading into a temperature in Celcius"        v = adc * self.vadc / 1024          # convert the 10 bit ADC value to a voltage        r = self.rs * v / (self.vs - v)     # resistance of thermistor        return (self.beta / log(r / self.k)) - 273.15        # temperature    def setting(self, t):        "Convert a temperature into a ADC value"        r = self.r0 * exp(self.beta * (1 / (t + 273.15) - 1 / self.t0)) # resistance of the thermistor        v = self.vs * r / (self.rs + r)     # the voltage at the potential divider        return round(v / self.vadc * 1024)  # the ADC readingdef main(argv):    r0 = 100000;    t0 = 25;    beta = 3950;    r1 = 0;    r2 = 4700;    num_temps = int(40);        try:        opts, args = getopt.getopt(argv, "h", ["help", "r0=", "t0=", "beta=", "r1=", "r2=", "num-temps="])    except getopt.GetoptError:        usage()        sys.exit(2)            for opt, arg in opts:        if opt in ("-h", "--help"):            usage()            sys.exit()        elif opt == "--r0":            r0 = int(arg)        elif opt == "--t0":            t0 = int(arg)        elif opt == "--beta":            beta = int(arg)        elif opt == "--r1":            r1 = int(arg)        elif opt == "--r2":            r2 = int(arg)        elif opt == "--num-temps":            num_temps = int(arg)    if r1:        max_adc = int(1023 * r1 / (r1 + r2));    else:        max_adc = 1023    increment = int(max_adc/(num_temps-1));                t = Thermistor(r0, t0, beta, r1, r2)    adcs = range(1, max_adc, increment);#   adcs = [1, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 110, 130, 150, 190, 220,  250, 300]    first = 1    print "// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts)"    print "// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py)"    print "// ./createTemperatureLookup.py --r0=%s --t0=%s --r1=%s --r2=%s --beta=%s --max-adc=%s" % (r0, t0, r1, r2, beta, max_adc)    print "// r0: %s" % (r0)    print "// t0: %s" % (t0)    print "// r1: %s" % (r1)    print "// r2: %s" % (r2)    print "// beta: %s" % (beta)    print "// max adc: %s" % (max_adc)    print "#define NUMTEMPS %s" % (len(adcs))    print "short temptable[NUMTEMPS][2] = {"    counter = 0    for adc in adcs:        counter = counter +1        if counter == len(adcs):            print "   {%s, %s}" % (adc, int(t.temp(adc)))        else:            print "   {%s, %s}," % (adc, int(t.temp(adc)))    print "};"    def usage():    print __doc__if __name__ == "__main__":    main(sys.argv[1:])
可以用万用表测量NTC热敏电阻阻值,然后查询阻值与温度对应关系表,得到的温度值T1,用AD查询脚本“createTemperatureLookup.py”生成表对应的温度值T2,比较T1和T2的误差,看是否在可接受的范围内。

你可能感兴趣的文章
两个不错的 Matlab 时频分析工具箱
查看>>
【转】研究生必读→如何获得全文文献
查看>>
考博心得集锦——成功因素、相关准备工作
查看>>
考博联系导师的办法[转]
查看>>
考博考硕联系导师的注意事项
查看>>
2008北航博士考试总结【转】
查看>>
揭秘卡耐基•梅陇大学机器蛇
查看>>
【转】免费学术资源网址
查看>>
【转】免费进入学术数据库
查看>>
【转】matlab 使用的一点儿体会(for beginner)
查看>>
蚂蚁的哲学
查看>>
朴素的美丽、抑郁中的缕缕阳光——“红衣妹妹”于洋博文选粹
查看>>
最新的计算机方向的国际会议/期刊的排名
查看>>
《蚁群算法原理及其应用》(段海滨)附录Matlab源程序
查看>>
新的探索!
查看>>
小波图像分解与重构程序存在的问题与解决办法
查看>>
小波图像分解 Matlab 程序 - V2.0版
查看>>
小波图像重构 Matlab 程序 - V2.0版
查看>>
投到 ICIC 2008 的蚁群算法论文被录用了,喜忧参半!
查看>>
写科研论文的高级方法学 -- 小木虫上的精华(推荐阅读)
查看>>