【龙印】在龙芯1c上用TM7705+NTC热敏电阻实现温度测量
本文为在用龙芯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 voltager = self.rs * v / (self.vs - v) # resistance of thermistorreturn (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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#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, // 通道1TM7705_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 40
const 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<NUMTEMPS; i++) // 注意,这里是从1开始的,巧妙之处就在这里{if (ad < temptable[i][0]) // 判断是否在这个区间{// t = t0 + (adc-adc0)*kcelsius = temptable[i-1][1] + // t0(ad - temptable[i-1][0]) * // adc-adc0((float)(temptable[i][1]-temptable[i-1][1]) / (float)(temptable[i][0]-temptable[i-1][0])); // k
// printf("[%s] adc=%u, celsius=%f\n", __FUNCTION__, ad, celsius);*temp_p = celsius;return SUCCESS;}}return ERROR;
}// 获取温度值
// @temp_p 温度值,单位摄氏度
// @ret 成功 or 失败
int temp_get(float *temp_p)
{UINT16 ad = 0;int ret = ERROR;// 获取ad值ret = temp_get_ad(TM7705_CH_1, &ad);if (SUCCESS != ret){printf("[%s] get channel 1's ad fail.\n", __FUNCTION__);return ret;}
// printf("[%s] ad=%u\n", __FUNCTION__, ad);// 根据ad计算温度值return temp_calc_from_ad(ad, temp_p);
}// 测试函数
void temp_gest(void)
{float temp = 0.0;int ret = ERROR;ret = temp_get(&temp);if (SUCCESS != ret){printf("[%s] temp_get fail. ret=%d\n", __FUNCTION__, ret);return ;}printf("[%s] current temp=%f\n", __FUNCTION__, temp);return ;
}
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 sys
import getoptclass Thermistor:"Class to do the thermistor maths"def __init__(self, r0, t0, beta, r1, r2):self.r0 = r0 # stated resistance, e.g. 10Kself.t0 = t0 + 273.15 # temperature at stated resistance, e.g. 25Cself.beta = beta # stated beta, e.g. 3500self.vadc = 2.5 # ADC referenceself.vcc = 2.5 # supply voltage to potential dividerself.k = r0 * exp(-beta / self.t0) # constant part of calculationif r1 > 0:self.vs = r1 * self.vcc / (r1 + r2) # effective bias voltageself.rs = r1 * r2 / (r1 + r2) # effective bias impedanceelse:self.vs = self.vcc # effective bias voltageself.rs = r2 # effective bias impedancedef temp(self,adc):"Convert ADC reading into a temperature in Celcius"v = adc * self.vadc / 1024 # convert the 10 bit ADC value to a voltager = self.rs * v / (self.vs - v) # resistance of thermistorreturn (self.beta / log(r / self.k)) - 273.15 # temperaturedef 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 thermistorv = self.vs * r / (self.rs + r) # the voltage at the potential dividerreturn 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 = 1023increment = 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 = 1print "// 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 = 0for adc in adcs:counter = counter +1if 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的误差,看是否在可接受的范围内。
【龙印】在龙芯1c上用TM7705+NTC热敏电阻实现温度测量相关推荐
- 【龙印】用龙芯1c实现3D打印机的总体思路
热熔型3d打印机的工作原理 控制打印头不停的运动,在需要打印的地方将耗材融化并挤出来.就像蜘蛛织网一样,当蜘蛛的网线够大,同时网格够小,那么是不是相邻两格的网线就紧挨着了.我就是这么理解热熔型3d打印 ...
- 【龙芯1c库】封装硬件pwm接口和使用示例
龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库.Git地址:https://gitee.com/caogos/OpenLoongsonLib1c 本文通过"龙芯1 ...
- 【龙芯1c库】封装CAN接口和使用示例
can使用还是比较广泛的,之前有网友在龙芯1b和龙芯1c上已经测试过了在裸机编程中使用CAN接口,这里把他们分享的程序贴上来,供大家参考. 龙芯1b上的测试程序在https://gitee.com/c ...
- 【龙芯1c库】封装硬件定时器接口和使用示例
龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库.完整源码请移步到https://gitee.com/caogos/OpenLoongsonLib1c 龙芯1c库中硬件定时器 ...
- 【龙芯1c库】移植硬浮点FPU
龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库.完整源码请移步到https://gitee.com/caogos/OpenLoongsonLib1c 龙芯1C上有硬浮点协处 ...
- 【龙印】把龙芯1c的pwm用作定时器并产生中断
本文为在用龙芯1c做3D打印机过程中的笔记.龙芯1c做的3d打印机简称"龙印" 3d打印机固件marlin巧妙运用定时器让整个固件不必依赖实时操作系统,即把对实时性要求较高的部分巧 ...
- 【龙印】用龙芯1c的硬件pwm产生单个脉冲来驱动步进电机
本文为在用龙芯1c做3D打印机过程中的笔记.龙芯1c做的3d打印机简称"龙印",Git地址"http://git.oschina.NET/caogos/marlin_ls ...
- 在龙芯1C单片机上使用ESP8266 wifi透传模块
龙芯1C既可以运行linux,也可以当作单片机用.当用作linux时,可以通过USB wifi模块RTL8192C,RTL8188ETV等,当作单片机用时,可以像STM32那样使用串口透传wifi模块 ...
- Buildroot 龙芯1C支持指南
本文转载自:https://github.com/pengphei/smartloong-sphinx/blob/master/source/cn/loongson1c_buildroot_guide ...
- 龙芯处理器可以适配鸿蒙os吗,SylixOS龙芯1C适配总结
1.龙芯1C简介 1.1龙芯1C简介 龙芯 1C300(以下简称 1C)芯片是基于 LS232 处理器核的高性价比单芯片系统,可应用于指纹生物识别.物联传感等领域.1C 包含浮点处理单元,可以有效增强 ...
最新文章
- 大数据、数据挖掘、机器学习三者的区别和联系
- 计算机考研数据库原理真题,四川理工学院计算机学院数据库原理历年考研真题汇编.pdf...
- 使用Java让android手机自动执行重复重启
- 全新的图形数据库云服务Amazon Neptune正式发布
- 为什么我会弃Java,选择了Kotlin——专访《Java编程思想》作者 Bruce Eckel
- 如何使用jQuery刷新页面?
- 论文笔记_S2D.18_2019-ICRA_DeepFusion: 基于单视图深度和梯度预测的单目SLAM实时稠密三维重建
- idea无限重置插件安装
- C语言实例第7期:实现投票统计功能
- Abaqus安装在lincense server1出错
- 【集合论】集合概念与关系 ( 真子集 | 空集 | 全集 | 幂集 | 集合元素个数 | 求幂集步骤 )
- Python+PyCharm+PyQt5抓取链家二手房信息
- ANC主动降噪技术的原理
- 制作纯净系统U盘教程(详细版)
- 第三届上海市大学生网络安全大赛 流量分析
- wingFTP实现访问共享目录
- xkcd 单线程下载图片
- 计算机电源电压的调整,电压调整电路、电压调整方法及其计算机系统
- 2:STM32CubeMX配置STM32F103C8T6驱动-SPI驱动
- 常说的“四层”和“七层”是什么