本文为在用龙芯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热敏电阻实现温度测量相关推荐

  1. 【龙印】用龙芯1c实现3D打印机的总体思路

    热熔型3d打印机的工作原理 控制打印头不停的运动,在需要打印的地方将耗材融化并挤出来.就像蜘蛛织网一样,当蜘蛛的网线够大,同时网格够小,那么是不是相邻两格的网线就紧挨着了.我就是这么理解热熔型3d打印 ...

  2. 【龙芯1c库】封装硬件pwm接口和使用示例

    龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库.Git地址:https://gitee.com/caogos/OpenLoongsonLib1c 本文通过"龙芯1 ...

  3. 【龙芯1c库】封装CAN接口和使用示例

    can使用还是比较广泛的,之前有网友在龙芯1b和龙芯1c上已经测试过了在裸机编程中使用CAN接口,这里把他们分享的程序贴上来,供大家参考. 龙芯1b上的测试程序在https://gitee.com/c ...

  4. 【龙芯1c库】封装硬件定时器接口和使用示例

    龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库.完整源码请移步到https://gitee.com/caogos/OpenLoongsonLib1c 龙芯1c库中硬件定时器 ...

  5. 【龙芯1c库】移植硬浮点FPU

    龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库.完整源码请移步到https://gitee.com/caogos/OpenLoongsonLib1c 龙芯1C上有硬浮点协处 ...

  6. 【龙印】把龙芯1c的pwm用作定时器并产生中断

    本文为在用龙芯1c做3D打印机过程中的笔记.龙芯1c做的3d打印机简称"龙印" 3d打印机固件marlin巧妙运用定时器让整个固件不必依赖实时操作系统,即把对实时性要求较高的部分巧 ...

  7. 【龙印】用龙芯1c的硬件pwm产生单个脉冲来驱动步进电机

    本文为在用龙芯1c做3D打印机过程中的笔记.龙芯1c做的3d打印机简称"龙印",Git地址"http://git.oschina.NET/caogos/marlin_ls ...

  8. 在龙芯1C单片机上使用ESP8266 wifi透传模块

    龙芯1C既可以运行linux,也可以当作单片机用.当用作linux时,可以通过USB wifi模块RTL8192C,RTL8188ETV等,当作单片机用时,可以像STM32那样使用串口透传wifi模块 ...

  9. Buildroot 龙芯1C支持指南

    本文转载自:https://github.com/pengphei/smartloong-sphinx/blob/master/source/cn/loongson1c_buildroot_guide ...

  10. 龙芯处理器可以适配鸿蒙os吗,SylixOS龙芯1C适配总结

    1.龙芯1C简介 1.1龙芯1C简介 龙芯 1C300(以下简称 1C)芯片是基于 LS232 处理器核的高性价比单芯片系统,可应用于指纹生物识别.物联传感等领域.1C 包含浮点处理单元,可以有效增强 ...

最新文章

  1. 大数据、数据挖掘、机器学习三者的区别和联系
  2. 计算机考研数据库原理真题,四川理工学院计算机学院数据库原理历年考研真题汇编.pdf...
  3. 使用Java让android手机自动执行重复重启
  4. 全新的图形数据库云服务Amazon Neptune正式发布
  5. 为什么我会弃Java,选择了Kotlin——专访《Java编程思想》作者 Bruce Eckel
  6. 如何使用jQuery刷新页面?
  7. 论文笔记_S2D.18_2019-ICRA_DeepFusion: 基于单视图深度和梯度预测的单目SLAM实时稠密三维重建
  8. idea无限重置插件安装
  9. C语言实例第7期:实现投票统计功能
  10. Abaqus安装在lincense server1出错
  11. 【集合论】集合概念与关系 ( 真子集 | 空集 | 全集 | 幂集 | 集合元素个数 | 求幂集步骤 )
  12. Python+PyCharm+PyQt5抓取链家二手房信息
  13. ANC主动降噪技术的原理
  14. 制作纯净系统U盘教程(详细版)
  15. 第三届上海市大学生网络安全大赛 流量分析
  16. wingFTP实现访问共享目录
  17. xkcd 单线程下载图片
  18. 计算机电源电压的调整,电压调整电路、电压调整方法及其计算机系统
  19. 2:STM32CubeMX配置STM32F103C8T6驱动-SPI驱动
  20. 常说的“四层”和“七层”是什么

热门文章

  1. Java项目源码下载S2SH基于java的保险业务管理系统
  2. 抖音大数据,教你爬爬爬!
  3. STM32 通用 Bootloader
  4. 怎么把java程序打包?java源代码打包方法
  5. 常见搜索引擎蜘蛛大全
  6. html5毕业设计程序,网页毕业设计制作流程
  7. 转行python算法_转:Python:SMOTE算法
  8. python自动生成字幕_语音自动转文字和自动生成字幕
  9. php开源源码管理后台小程序团购,秒杀,分销 高可用
  10. Flutter文本或图片生成PDF文件