首页 > 代码库 > 【龙印】龙芯1C300A片内ADC的测试
【龙印】龙芯1C300A片内ADC的测试
本来是想用1c300a片内自带的ADC+ntc热敏电阻作为3d打印机的温度传感器的。后来测试发现精度不够,只有外挂adc了。测试如下
先用两个电阻串联,用万用表测试开路时的电阻,通电时的电压,并读取1C300A片内ADC的值,通过电压手动计算理论的ADC值。大概的示意图如下
测试结果如下
该ADC是十位的,满量程1023,量程中间(512)附近的精度还可以,量程的两端就有点差了。
其中,第一项R1=4.6k,R0=73.6k是把ntc热敏电阻接到ramps1.4扩展板上测试的结果。
下面是用脚本生成的ntc热敏电阻的ADC值与温度的对应关系。左边为adc值,右边为温度。
// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts)
// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firm
ware/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
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}
};
由上表可知,读到的ADC值989对应的温度为18度,计算得到的理论ADC值962.64对应的温度大约为31度,这个误差是不是大了点啊。
从上表可知,温度18与温度30对应的ADC值分别是989和963,可以算出在此区间内大约ADC值变化2,温度就变化1度,18度到30度是很常见的温度范围,可见用ntc热敏电阻测试温度对ADC的要求。
脚本“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 Generator Generates lookup to temperature values for use in a microcontroller in C format based on: http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.html The main use is for Arduino programs that read data from the circuit board described here: http://make.rrrf.org/ts-1.0 Usage: 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 getopt class 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 = 3.3 # ADC reference self.vcc = 3.3 # 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 reading def 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:])
adc的linux驱动文件“ls1c_3dprinter_temp_sensor.c”
/* * drivers\misc\ls1c_3dprinter_temp_sensor.c * * 用1c的adc+ntc热敏电阻实现温度采集 * 用于测量3d打印机挤出头和热床的温度 * */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/err.h> #include <linux/miscdevice.h> #include <linux/gpio.h> #include <linux/io.h> #include <linux/delay.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/fs.h> #include <linux/time.h> #include <linux/timer.h> #include <linux/errno.h> #include <loongson1.h> #define ADC_POWER_DOWN (1<<6) // 寄存器adc_s_ctrl的power_down #define ADC_POWER_UP (~ADC_POWER_DOWN) #define ADC_START_CONVERT (1<<4) #define ADC_SOFT_RESET (1<<5) #define ADC_BUSY (1<<31) #define CHANNEL_0 (0) /* LS1C ADC register */ #define ADC_CNT 0x00 #define ADC_S_CTRL 0x04 #define ADC_C_CTRL 0x08 #define X_RANGE 0x10 #define Y_RANGE 0x14 #define AWATCHDOG_RANGE 0x18 #define AXIS 0x1c #define ADC_S_DOUT0 0x20 #define ADC_S_DOUT1 0x24 #define ADC_C_DOUT 0x28 #define ADC_DEBOUNCE_CNT 0x2c #define ADC_INT 0x30 #define LS1X_ADC_PRE(x) (((x)&0xFFF)<<20) struct printer_temp_sensor_priv { void __iomem *adc_regs; struct mutex mutex_lock; }; static struct printer_temp_sensor_priv printer_temp_sensor_priv_data; // adc power up static void printer_adc_powerup(void) { unsigned int tmp; tmp = readl(printer_temp_sensor_priv_data.adc_regs+ADC_S_CTRL); writel(tmp&ADC_POWER_UP, printer_temp_sensor_priv_data.adc_regs+ADC_S_CTRL); return ; } // adc power down static void printer_adc_powerdown(void) { unsigned int tmp; tmp = readl(printer_temp_sensor_priv_data.adc_regs+ADC_S_CTRL); writel(tmp|ADC_POWER_DOWN, printer_temp_sensor_priv_data.adc_regs+ADC_S_CTRL); return ; } // Initialize the ADC controller. static void printer_adc_init(void) { // 使能adc模块 __raw_writel(__raw_readl(LS1X_MUX_CTRL0)&(~ADC_SHUT), LS1X_MUX_CTRL0); // powerdown printer_adc_powerdown(); return ; } // 读取指定通道的adc值 // @channel 通道值,只有4个通道,分别0,1,2,3 static unsigned int printer_adc_read(unsigned int channel) { unsigned int tmp; unsigned int adc_data = http://www.mamicode.com/0;>
温度传感器驱动
文件"ls1c_3dprinter_temp_sensor.c"放在目录"drivers\misc"下
在文件“arch\mips\loongson\ls1x\ls1c\platform.c”,增加
// 用1c的adc+ntc热敏电阻实现温度采集
#ifdef CONFIG_LS1C_3DPRINTER_TEMP_SENSOR
static struct resource ls1c_3dprinter_temp_sensor_resources[] = {
{
.start = LS1X_ADC_BASE,
.end = LS1X_ADC_BASE + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device ls1c_3dprinter_temp_sensor = {
.name = "ls1c_3dprinter_temp_sensor",
.id = -1,
.resource = ls1c_3dprinter_temp_sensor_resources,
.num_resources = ARRAY_SIZE(ls1c_3dprinter_temp_sensor_resources),
};
#endif
在static struct platform_device *ls1b_platform_devices[] __initdata中,增加
#ifdef CONFIG_LS1C_3DPRINTER_TEMP_SENSOR
&ls1c_3dprinter_temp_sensor,
#endif
在文件“drivers\misc\Kconfig”中增加配置项,内容如下
config LS1C_3DPRINTER_TEMP_SENSOR
tristate "ls1c 3dprinter temperature sensor"
depends on LS1C_MACH
help
Say Y here if you want to build a 3dprinter temperature sensor for ls1c
在文件“drivers\misc\Makefile”中,增加如下内容
obj-$(CONFIG_LS1C_3DPRINTER_TEMP_SENSOR) += ls1c_3dprinter_temp_sensor.o
make menuconfig
Device Drivers --->
[*] Misc devices --->
<*> ls1c 3dprinter temperature sensor
(测试用的)应用层序temp.c
// 温度相关 #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include "public.h" #define TEMP_ADC_MAX ((0x1<<10)-1) // adc的最大值,adc是十位的 #define TEMP_IS_VALID_ADC(adc) ((TEMP_ADC_MAX>=(adc)) && (0<=(adc))) // 判断adc是在量程范围内 // 以下根据ntc热敏电阻参数用脚本生成的adc值与温度一一对应的表格 // 左边为adc值,右边为温度(单位:摄氏度) // 详细请参考源码目录中的脚本"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 20 short temptable[NUMTEMPS][2] = { {1, 938}, {54, 267}, {107, 217}, {160, 191}, {213, 172}, {266, 158}, {319, 147}, {372, 137}, {425, 127}, {478, 119}, {531, 111}, {584, 103}, {637, 96}, {690, 88}, {743, 80}, {796, 72}, {849, 62}, {902, 50}, {955, 35}, {1008, 2} }; // 从驱动中获取adc的值 // @ret adc的值 unsigned int TempGetAdc(void) { int fd_temp_sensor = 0; int ret = 0; unsigned int adc = 0; fd_temp_sensor = open("/dev/3dprinter_temp_sensor", O_RDWR); if (ERROR == fd_temp_sensor) { printf("[%s] open file /dev/3dprinter_temp_sensor fail.\n", __FUNCTION__); return ERROR; } ret = read(fd_temp_sensor, &adc, sizeof(adc)); if (sizeof(adc) != ret) { printf("[%s] read adc fail. ret=%d\n", __FUNCTION__, ret); return ERROR; } if (!TEMP_IS_VALID_ADC(adc)) { printf("[%s] adc convert fail. adc=%u\n", __FUNCTION__, adc); return ERROR; } return adc; } // 根据adc值计算温度值 // ntc热敏电阻的阻值温度曲线被分为n段,每段可以近似为直线, // 所以温度值的计算就转变为查表再计算 // @adc adc值(取值范围为0-1023) // @ret 对应的温度值(单位摄氏度) int TempCalcFromAdc(unsigned int adc) { float celsius = 0.0; // 温度值,单位摄氏度 int i = 0; // 判断adc值是否在量程范围内 if (!TEMP_IS_VALID_ADC(adc)) { return ERROR; } // 判断是否在表格所表示的范围内 if (adc < temptable[0][0]) // 小于表格的最小adc { return temptable[0][1]; // 取最小值 } if (adc > temptable[NUMTEMPS-1][0]) // 大于表格的最大adc { return temptable[NUMTEMPS-1][1]; // 取最大值 } // 查表 // 这里是从adc由低到高,逐个区间进行比较,没有采用折半查找 for (i=1; i<NUMTEMPS; i++) // 注意,这里是从1开始的,巧妙之处就在这里 { if (adc < temptable[i][0]) // 判断是否在这个区间 { // t = t0 + (adc-adc0)*k celsius = temptable[i-1][1] + // t0 (adc - 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__, adc, celsius); return celsius; } } return ERROR; } // 获取温度值 // @ret 温度值,单位摄氏度 int TempGet(void) { return TempCalcFromAdc(TempGetAdc()); } // 测试函数 void TempTest(void) { float temp = 0.0; temp = TempGet(); printf("[%s] current temp=%f\n", __FUNCTION__, temp); /* temp = TempCalcFromAdc(961.43); // 温度30.99 printf("[%s] expect temp=30.99, calced temp=%f\n", __FUNCTION__, temp); temp = TempCalcFromAdc(1022); // adc超过表格中的最大值,取adc为最大值,温度2 printf("[%s] expect temp=2, calced temp=%f\n", __FUNCTION__, temp); temp = TempCalcFromAdc(0); // adc小于表格中的最小值,取adc为最小值,温度938 printf("[%s] expect temp=938, calced temp=%f\n", __FUNCTION__, temp); */ return ; }
temp.h// 温度相关 #ifndef __TEMP_H #define __TEMP_H #include <stdio.h> // 获取温度值 // @ret 温度值,单位摄氏度 int TempGet(void); // 测试函数 void TempTest(void); #endif
main.c#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include "public.h" #include "temp.h" #define BUFF_LEN (15) int main(void) { int fd_motor = 0; char buff[15] = {0}; int count; int ret; fd_motor = open("/dev/3dPrinter_motor", O_RDWR); if (-1 == fd_motor) { printf("open file /dev/3dPrinter_motor fail.\n"); return fd_motor; } while (1) { /* // 测试电机 count = 16*200; // 16细分,42步进电机的步进角为1.8度,200个脉冲转一圈 while (count--) { write(fd_motor, buff, BUFF_LEN); usleep(5*1000); } */ // 测死温度传感器 TempTest(); usleep(500*1000); // sleep(1); } }
public.h#ifndef __PUBLIC_H #define __PUBLIC_H enum { ERROR = -1, SUCCESS = 0, }; #endif
MakefileSOURCE = $(wildcard *.c) CROSS_COMPILE = mipsel-linux- CXX = gcc CFLAGS += -Wall 3dprinter_app : $(SOURCE) $(CROSS_COMPILE)$(CXX) $(CFLAGS) -o $@ $^ cp $@ /nfsramdisk/LS1xrootfs-demo/test/ clean: rm -f *.o
【龙印】龙芯1C300A片内ADC的测试
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。