amobbs.com 阿莫电子技术论坛

标题: 二极管4148 三极管9013 PN结温度测量 [打印本页]

作者: kangar0065    时间: 2010-4-12 01:57
标题: 二极管4148 三极管9013 PN结温度测量
看到
想做一个孵小鸡的装置,让孩子孵一只小鸡出来,应该用什么样的加热器件,请指教。
里面提到了二极管的温度测量
上网找了一下原理.张贴如下

(原文件名:D__资料_电子_利用PIC_MCU中的CTMU _二极管_1N4148测量温度.png)


(原文件名:D__资料_电子_利用PIC_MCU中的CTMU _二极管_1N4148测量温度_00002.png)


(原文件名:D__资料_电子_利用PIC_MCU中的CTMU _二极管_1N4148测量温度_00003.png)


(原文件名:D__资料_电子_利用PIC_MCU中的CTMU _二极管_1N4148测量温度_00005.png)


(原文件名:D__资料_电子_利用PIC_MCU中的CTMU _二极管_1N4148测量温度_00006.png)
点击此处下载 ourdev_545583.PDF(文件大小:342K) (原文件名:利用PIC_MCU中的CTMU _二极管_1N4148测量温度.PDF)
点击此处下载 ourdev_545584.PDF(文件大小:337K) (原文件名:充电时间测量单元CTMU.PDF)
作者: millwood0    时间: 2010-4-12 03:18
what the datasheet engineer didn't tell you is that the diversity between two devices of identical type (one 1n4148 vs. another 1n4148 for example) would be so great that you will have to calibrate each device - making this approach less practical.
作者: kangar0065    时间: 2010-4-12 03:27
回复【1楼】millwood0
what the datasheet engineer didn't tell you is that the diversity between two devices of identical type (one 1n4148 vs. another 1n4148 for example) would be so great that you will have to calibrate each device - making this approach less practical.
-----------------------------------------------------------------------

确实存在一个校准的问题,我在坛子上搜索过以前用过这个东西的前辈,他们都说稳定度和线性不错,甚至优于热敏电阻.
而且他们没有使用恒流源供电,还存在着一个电压调制的问题.这个单片机IO内部有恒流源.有一点略微的优势吧
作者: millwood0    时间: 2010-4-12 04:46
you can use an external ccs (a jfet for example), or an external voltage regulator, or an inter Vref to power the diode.

the voltage sensitivity is basic physics and it is very linear.
作者: eduhf_123    时间: 2010-4-12 06:03
MARK PN结测温
作者: master5888    时间: 2010-4-12 08:13
luguo
作者: fsclub    时间: 2010-4-12 08:15
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3320979&bbs_page_no=1&search_mode=3&search_text=fsclub&bbs_id=9999
作者: kangar0065    时间: 2010-4-12 11:41
回复【3楼】millwood0
you can use an external ccs (a jfet for example), or an external voltage regulator, or an inter Vref to power the diode.
the voltage sensitivity is basic physics and it is very linear.

-----------------------------------------------------------------------
可以说的更详细些吗?好像没有相关的资料
作者: fw190d9    时间: 2010-4-13 06:50
不如来个18B20实在。4148等就没有离散性了,做这样的AD不如直接来个NTC。
作者: kangar0065    时间: 2010-4-20 09:13
4148便宜啊
作者: portx    时间: 2010-4-20 09:20
关注,不知道精度能到多少,全温度范围的线性度如何,后期的数据是否需要进行多次方拟合
作者: oxalis    时间: 2010-4-27 20:53
关注
谁来做个试试?
作者: zhihaoa    时间: 2010-6-5 08:38
想法儿不错,作来试试
作者: heyuncun    时间: 2010-6-5 11:29
mark
作者: gxy508    时间: 2010-6-5 12:11
mark
作者: millwood0    时间: 2010-6-5 23:18
I can post my code later if anyone wants it.

the issue with this approach is that you have to be able to find a low-tempco reference voltage (like a bandgap ref). Otherwise, you have to use Vdd, and with a typical 10bit adc, your minimum resolution is 5mv, which is about 2 - 3 degrees.

not to mention calibration issues.

if you use a temperature compensated tl431-type regulator, you can get better precision.
作者: kangar0065    时间: 2010-6-6 21:13
静等下文
作者: rqiang    时间: 2010-6-6 21:42
在要求不高的产品中试可以使用的。
作者: frogrider    时间: 2010-6-6 22:30
mark
作者: elec2000    时间: 2010-6-6 22:59
PN结的温度/电压的线性度非常好,但是个体之间的一致性不好,即互换性不好
作者: millwood0    时间: 2010-6-7 00:13
here is the code.

============16f684 diode temp measurement================

#include <htc.h>
#include <string.h>
#include "delay.h"
//#include "lcd_4bit.h"
#include "lcd_3wi.h"

__CONFIG(MCLRDIS & BORDIS & WDTDIS & PWRTEN & INTIO);

#define sleep()                        asm("sleep")                //put the mcu to sleep
#define AN0                                (1<<0)                                //an0
#define AN2                                (1<<2)                                //an2 - an1 used a vref in this application
#define ADC_CH0                        AN0                                        //adc on an0
#define ADC_CH1                        AN2                                        //adc on an2
#define LCD_Line_ADCX        LCD_Line0                        //L ch on lcd_line0
#define LCD_Line_Temp        LCD_Line1                        //R ch on lcd_line1
#define LED_PIN                        (1<<5)                                //led on GPIO1
#define PA_SET(bits)        PORTA |= (bits);        //set bits on porta
#define PA_CLR(bits)        PORTA &=~(bits);        //clear bits on porta
#define PA_FLP(bits)        PORTA ^= (bits);        //flip bits on porta
#define DLY_main_loop        300                                        //main loop delay, in ms
#define Vref                        2000000ul                        //reference voltage, in uv. Vref=2v
#define adc2_uv(adc_int)        ((signed long) (Vref*((unsigned long)adc_int))>>10)                //convert 10 bits to uv. so 1000 = 1mv.
//caliberation temperatures
#define T1                                0l                                        //1st caliberation temperature, in 0.01C
#define adc_uv_at_T1        699218l                                //adc reading, in uv, at T1
#define T2                                10000l                                //2nd caliberation temperature, in 0.01C
#define adc_uv_at_T2        750000l                                //adc reading, in uv, at T2
#define uv2_tempC(uv)        T1+(signed long) (T2-T1)*((uv)-adc_uv_at_T1)/(adc_uv_at_T2-adc_uv_at_T1)        //convert uv to C. 2 decimal points
#define Tacq_delay()        NOP(); NOP(); NOP(); NOP(); NOP(); NOP()        //delay for tacq

const unsigned char str_adcx[] ="ADC :           ";
const unsigned char str_volt[] ="Volt:         uv";
const unsigned char str_tempC[]="Temp:          C";
const unsigned char str_0[]="16F684 TempMeter";
const unsigned char str_v[]="version 0.2-1234";
unsigned char vRAM[17];

unsigned long random_vN(void) {        //using von Neumann middle square approach to return a random number
        static unsigned long seed=5634;        //3021, 3421
        seed=((seed*seed) & 0x00ffff00) >> 8;
        return seed;
}

void adc_init(void) {                                        //initialize the adc
//        ADCON0 = config_mask;
        ADCS2=0, ADCS1=1, ADCS0=0;                        //adc running at fosc/32
        ADFM=1;                                                                //adc results right justified
        VCFG=1;                                                                //Vref on porta2/an2
        ADON=0;                                                                //adc off
}

unsigned int adc_read(unsigned char ch){//read adc
        ADON=1;                                                                //turn on the adc
//        ANSEL |= ch;                                                        //select the adc channel, and adc at fosc/32
//        TRISIO |= ch;                                                //turn it as input
//        CHS1=(ch-1) >> 1;                                                //select the channel
//        CHS0=(ch-1);
        switch (ch) {
                case AN0: CHS2=0, CHS1=0, CHS0=0, ANSEL=AN0; break;
                case AN2: CHS2=0, CHS1=1, CHS0=0, ANSEL=AN2; break;
                default: NOP(); NOP(); NOP(); NOP(); NOP(); break;
        }
//        delay_us(1);                                                                //turn on the adc
//        may need some delays here
        Tacq_delay();                                                //delay for tacq
        GODONE=1;                                                        //start the adc
        while (GODONE) continue;                        //wait for the adc to complete;
        ADON=0;                                                                //turn off the adc
        return (ADRESH<<8) + ADRESL;
//        return random_vN() & 0x3ff;                        //return a random 10bit number, for testing purposes
}

void ltoa(char *s, signed long ul, unsigned char length) {        //convert unsigned long to a string, 3 dps
        unsigned char i;
       
        if (ul<0) {
                ul=-ul;
                *s++='-';
        } else *s++='+';
       
        i=length;
        do {
//                if (i==(length-3)) s[i--]='.';
                s[i--]=ul % 10 + '0';
                ul = ul / 10;
        } while (ul);
}

void mcu_init(void) {
        CMCON0=0x07;                                //turn off comparators;
        //TRISIO=0b11;                        //input on GPIO0, all others digital output;
        ANSEL=0x00;                                //all ports gpio
        IRCF2=1, IRCF1=1, IRCF0=0;        //4Mhz
}

void main(void)
{
        //unsigned char temp=0, gSPad[9], i;
        unsigned int i, tmp, tmp2;
        //unsigned int val_L, val_R;
       
        mcu_init();                                //initialize the mcu
        lcd_init();                                //initialize the lcd
        adc_init();                                //initialize the adc
        strcpy(vRAM, str_0); lcd_display(LCD_Line0, vRAM);
        strcpy(vRAM, str_v); lcd_display(LCD_Line1, vRAM); delay_ms(50);
        strcpy(vRAM, str_adcx); lcd_display(LCD_Line_ADCX, vRAM);
        strcpy(vRAM, str_tempC); lcd_display(LCD_Line_Temp, vRAM);
//        sleep();
        while (1){
                //TODO Auto-generated main function
                i=adc_read(ADC_CH0);
//                strcpy(vRAM, str_adcx); ltoa(&vRAM[5], i, 7); lcd_display(LCD_Line_ADCX, vRAM);
//                the following is for calibration purposes
                strcpy(vRAM, str_volt); ltoa(&vRAM[5], adc2_uv(i), 7); lcd_display(LCD_Line_ADCX, vRAM);
//                the following is for actual displaying, in 1/100th of C. so 4568C means 45.68C; -423C means -4.23C
                strcpy(vRAM, str_tempC); ltoa(&vRAM[5], uv2_tempC(adc2_uv(i)), 7); lcd_display(LCD_Line_Temp, vRAM);
                delay_ms(DLY_main_loop);                        //delay some time
        }
}


=============end of code====================

you will need to do a few things to make it work.

1) specify Vref. now, it is specified at 2v. it should be whatever your vref source is.
作者: millwood0    时间: 2010-6-7 00:14
2) caliberation: you should compile the code, and caliberate it at two temperatures: T0 and T1, both in C. I chose 0C (using ice and water mixture), and 100C (boiling water). Put the diode(s) into T0/T1, and see what the voltage reading is and put it into the code and recompile the code.

then you are done.

improvement opportunities:

1) the display of temperature is in 0.01C, but without the decimal point. you can rewrite the ltoa() to mitigate that.
2) you can also add multiple channels to it.

I will post the schmeatic later.
作者: millwood0    时间: 2010-6-7 01:23
the connection is as follows:

1) the code samples the voltage on RA0/AN0 - which is user-configuration. and it can be AN0/AN2 (already implemented. AN1 is used as the reference voltage. you can expand it to other adc-pins). if you set it up that way, you can sample multiple diodes, and read temperatures as multiple places. However, you have to change the caliberation to make that work.

2) you can use as many diodes in serial as you can, as long as the the total forward drop is less than Vref.

3) the diodes can be powered by a CCS but a resistor will do as well.

I will post the schematic later.
作者: hecat    时间: 2010-6-7 03:11
MARK。
作者: millwood0    时间: 2010-6-7 07:57
here is the schematic: essentially a diode or a series of diodes powered by a current source.

the current source can be a jfet, or resistor (though psrr suffers).

now, only one sensor is sampled, on AN0. but you can easily change the code to sample more.



(原文件名:16F684 temp diode.PNG)
作者: millwood0    时间: 2010-6-7 08:05
here is the revised code: changed ltoa() to incorporate decimal points.

======code==========
#include <htc.h>
#include <string.h>
#include "delay.h"
//#include "lcd_4bit.h"
#include "lcd_3wi.h"

__CONFIG(MCLRDIS & BORDIS & WDTDIS & PWRTEN & INTIO);

#define sleep()                        asm("sleep")                //put the mcu to sleep
#define AN0                                (1<<0)                                //an0
#define AN2                                (1<<2)                                //an2 - an1 used a vref in this application
#define ADC_CH0                        AN0                                        //adc on an0
#define ADC_CH1                        AN2                                        //adc on an2
#define LCD_Line_ADCX        LCD_Line0                        //L ch on lcd_line0
#define LCD_Line_Temp        LCD_Line1                        //R ch on lcd_line1
#define LED_PIN                        (1<<5)                                //led on GPIO1
#define PA_SET(bits)        PORTA |= (bits);        //set bits on porta
#define PA_CLR(bits)        PORTA &=~(bits);        //clear bits on porta
#define PA_FLP(bits)        PORTA ^= (bits);        //flip bits on porta
#define DLY_main_loop        300                                        //main loop delay, in ms
#define Vref                        2000000ul                        //reference voltage, in uv. Vref=2v
#define adc2_uv(adc_int)        ((signed long) (Vref*((unsigned long)adc_int))>>10)                //convert 10 bits to uv. so 1000 = 1mv.
//caliberation temperatures
#define T1                                0l                                        //1st caliberation temperature, in 0.01C
#define adc_uv_at_T1        699218l                                //adc reading, in uv, at T1
#define T2                                10000l                                //2nd caliberation temperature, in 0.01C
#define adc_uv_at_T2        750000l                                //adc reading, in uv, at T2
#define uv2_tempC(uv)        T1+(signed long) (T2-T1)*((uv)-adc_uv_at_T1)/(adc_uv_at_T2-adc_uv_at_T1)        //convert uv to C. 2 decimal points
#define Tacq_delay()        NOP(); NOP(); NOP(); NOP(); NOP(); NOP()        //delay for tacq

const unsigned char str_adcx[] ="ADC :           ";
const unsigned char str_volt[] ="Volt:         mv";
const unsigned char str_tempC[]="Temp:          C";
const unsigned char str_0[]="16F684 TempMeter";
const unsigned char str_v[]="version 0.2-1234";
unsigned char vRAM[17];

unsigned long random_vN(void) {        //using von Neumann middle square approach to return a random number
        static unsigned long seed=5634;        //3021, 3421
        seed=((seed*seed) & 0x00ffff00) >> 8;
        return seed;
}

void adc_init(void) {                                        //initialize the adc
//        ADCON0 = config_mask;
        ADCS2=0, ADCS1=1, ADCS0=0;                        //adc running at fosc/32
        ADFM=1;                                                                //adc results right justified
        VCFG=1;                                                                //Vref on porta2/an2
        ADON=0;                                                                //adc off
}

unsigned int adc_read(unsigned char ch){//read adc
        ADON=1;                                                                //turn on the adc
//        ANSEL |= ch;                                                        //select the adc channel, and adc at fosc/32
//        TRISIO |= ch;                                                //turn it as input
//        CHS1=(ch-1) >> 1;                                                //select the channel
//        CHS0=(ch-1);
        switch (ch) {
                case AN0: CHS2=0, CHS1=0, CHS0=0, ANSEL=AN0; break;
                case AN2: CHS2=0, CHS1=1, CHS0=0, ANSEL=AN2; break;
                default: NOP(); NOP(); NOP(); NOP(); NOP(); break;
        }
//        delay_us(1);                                                                //turn on the adc
//        may need some delays here
        Tacq_delay();                                                //delay for tacq
        GODONE=1;                                                        //start the adc
        while (GODONE) continue;                        //wait for the adc to complete;
        ADON=0;                                                                //turn off the adc
        return (ADRESH<<8) + ADRESL;
//        return random_vN() & 0x3ff;                        //return a random 10bit number, for testing purposes
}

void ltoa(char *s, signed long ul, unsigned char length,  unsigned char dp) {        //convert unsigned long to a string, 3 dps
        unsigned char i;
        char sign=0;        //no sign
               
        if (ul<0) {
                ul=-ul;
                sign=-1;                //negative sign
        } else sign=+1;                //positive sign
       
        i=length;
        do {
                if (i==(length-dp)) s[i--]='.';
                s[i--]=ul % 10 + '0';
                ul = ul / 10;
        } while (ul);
        switch (sign) {
                case -1: s='-'; break;
                case +1: s='+'; break;
        }
}

void mcu_init(void) {
        CMCON0=0x07;                                //turn off comparators;
        //TRISIO=0b11;                        //input on GPIO0, all others digital output;
        ANSEL=0x00;                                //all ports gpio
        IRCF2=1, IRCF1=1, IRCF0=0;        //4Mhz
}

void main(void)
{
        //unsigned char temp=0, gSPad[9], i;
        unsigned int i, tmp, tmp2;
        //unsigned int val_L, val_R;
       
        mcu_init();                                //initialize the mcu
        lcd_init();                                //initialize the lcd
        adc_init();                                //initialize the adc
        strcpy(vRAM, str_0); lcd_display(LCD_Line0, vRAM);
        strcpy(vRAM, str_v); lcd_display(LCD_Line1, vRAM); delay_ms(50);
        strcpy(vRAM, str_adcx); lcd_display(LCD_Line_ADCX, vRAM);
        strcpy(vRAM, str_tempC); lcd_display(LCD_Line_Temp, vRAM);
//        sleep();
        while (1){
                //TODO Auto-generated main function
                i=adc_read(ADC_CH0);
//                strcpy(vRAM, str_adcx); ltoa(&vRAM[5], i, 7); lcd_display(LCD_Line_ADCX, vRAM);
//                the following is for calibration purposes
                strcpy(vRAM, str_volt); ltoa(&vRAM[5], adc2_uv(i)/100, 8,1); lcd_display(LCD_Line_ADCX, vRAM);
//                the following is for actual displaying, in 1/100th of C. so 4568C means 45.68C; -423C means -4.23C
                strcpy(vRAM, str_tempC); ltoa(&vRAM[5], uv2_tempC(adc2_uv(i)), 8,2); lcd_display(LCD_Line_Temp, vRAM);
                delay_ms(DLY_main_loop);                        //delay some time
        }
}
==========================

here is the display.



(原文件名:16F684 temp diode v2.PNG)
作者: millwood0    时间: 2010-6-7 08:11
the calibration here is that 699.2mv=0C, and 750mv=100C - I had it backwards, :).

so 675.7mv = -46.12. let's confirm it:

675.7mv -> 0C + (675.7-699.2)*(100C-0C)/(750mv-699.2mv)=-23.5mv*100/(50.8mv)=46.2mv.

close enough, :) - the error is due to rounding.
作者: exploer    时间: 2010-6-7 08:40
回复【26楼】millwood0  
-----------------------------------------------------------------------
  英文好的高手。
作者: jacky1982512    时间: 2010-6-7 09:12
回复【1楼】millwood0
-----------------------------------------------------------------------

你装什么,总是用英语!有意思
作者: fsclub    时间: 2010-6-7 10:13
在国外,没有中文输入法。。。
作者: fy024    时间: 2010-6-7 16:38
mark
作者: kangar0065    时间: 2010-6-7 17:32
不错呀。冲这个应该给条裤子。那个英文不好的你有两个选择:一个是把英语学好了来,第二个就是不要看。
作者: tfdsensor    时间: 2010-6-8 08:46
回复【28楼】jacky1982512  
回复【1楼】millwood0
-----------------------------------------------------------------------
你装什么,总是用英语!有意思
-----------------------------------------------------------------------

1楼老大本来就是说英文, 就如同你装什么呀,说汉语一样.
你不愿意可以不看,如同国外的datasheet一样,你可以只看中文的,没有人逼你看
作者: gpzdc986    时间: 2010-6-8 11:52
mark
作者: youz    时间: 2010-6-8 12:25
二极管 温度测量 mark
作者: allen    时间: 2010-7-10 17:50
值得关注
作者: 470036398    时间: 2010-7-10 17:57
mark
作者: JQ_Lin    时间: 2010-7-10 22:20
回复【28楼】jacky1982512
回复【1楼】millwood0  
-----------------------------------------------------------------------
你装什么,总是用英语!有意思
-----------------------------------------------------------------------

你唯一的帖子中用单片机测量交流电压的程序里为什么也用了英语呢?
你在装什么呢?难道是如同你自己所说,装比?这就是你回帖的美德?

刚刚注册进来,既要求助,又不懂得尊重别人!少教!
作者: my2009    时间: 2010-7-11 11:50
二极管 温度测量, 好资料, mark
作者: huangdog    时间: 2010-7-11 14:29
mark
作者: yaya001    时间: 2010-7-13 11:00
MARK MARK
作者: longquan    时间: 2010-7-13 11:32
暖小鸡要找受精的蛋,这个问题好象比恒温难点:-P
作者: XMLK    时间: 2010-10-2 21:36
MARK
作者: cwl0580    时间: 2010-10-6 14:14
不错!
作者: hzy789    时间: 2010-10-7 18:42
好资料,要收留。
作者: linghu2    时间: 2010-10-13 13:51
我来把文件直接上传吧

Using the PIC MCU CTMU for Temperature Measurementourdev_589487R1IU5G.pdf(文件大小:342K) (原文件名:Using the PIC MCU CTMU for Temperature Measurement.pdf)
作者: magiczero    时间: 2010-10-13 13:57
关注,要mark
作者: hymculolo    时间: 2010-10-13 16:22
mark了,以后慢慢学习~
作者: ITOP    时间: 2010-10-13 16:33
MARK!!
作者: nil0    时间: 2010-10-29 15:50
学习记号!
作者: intentydh    时间: 2010-11-5 11:47
mark,学习,以后能用到.
作者: kbdcj2000    时间: 2010-11-5 12:43
MARK
作者: xczxwy    时间: 2010-11-5 12:51
曾今做过PN极测温的人飘过,线性非常好,但是一致性很差,量产的时候校正的问题没办法搞定,最终放弃,老实用了DS18B20~~
作者: wwk1996    时间: 2010-11-12 13:41
mark,PN结测温。
作者: baolei    时间: 2010-11-13 19:20
mark
作者: asma    时间: 2012-2-15 23:14
mark
作者: HZKJ    时间: 2012-10-16 14:21
kangar0065 发表于 2010-6-7 17:32
不错呀。冲这个应该给条裤子。那个英文不好的你有两个选择:一个是把英语学好了来,第二个就是不要看。 ...

很酷的帖子,请问楼主 你孩子孵小鸡成功了吗,现在该长大了吧
作者: hclin    时间: 2012-10-17 10:11
not bad !!!
作者: a673261839    时间: 2018-7-24 16:32

MARK MARK
作者: a673261839    时间: 2018-8-1 08:49
make             !!!!
作者: gmyu    时间: 2018-8-1 10:43
STM32有CTMU单元么?
作者: zzsczz    时间: 2021-12-15 21:49
最近 在 找 基准 相关 信息 。

翻到 ST 的 LM336 ,  应该是 很旧的设计了,官网 查不到 这个器件。

PN结温  可以 用来 补偿 某些 电压基准的温漂 。


[attach]571946[/attach]






欢迎光临 amobbs.com 阿莫电子技术论坛 (https://www.amobbs.com/) Powered by Discuz! X3.4