kangar0065 发表于 2010-4-12 01:57:47

二极管4148 三极管9013 PN结温度测量

看到
想做一个孵小鸡的装置,让孩子孵一只小鸡出来,应该用什么样的加热器件,请指教。
里面提到了二极管的温度测量
上网找了一下原理.张贴如下
http://cache.amobbs.com/bbs_upload782111/files_28/ourdev_545578.png
(原文件名:D__资料_电子_利用PIC_MCU中的CTMU _二极管_1N4148测量温度.png)

http://cache.amobbs.com/bbs_upload782111/files_28/ourdev_545579.png
(原文件名:D__资料_电子_利用PIC_MCU中的CTMU _二极管_1N4148测量温度_00002.png)

http://cache.amobbs.com/bbs_upload782111/files_28/ourdev_545580.png
(原文件名:D__资料_电子_利用PIC_MCU中的CTMU _二极管_1N4148测量温度_00003.png)

http://cache.amobbs.com/bbs_upload782111/files_28/ourdev_545581.png
(原文件名:D__资料_电子_利用PIC_MCU中的CTMU _二极管_1N4148测量温度_00005.png)

http://cache.amobbs.com/bbs_upload782111/files_28/ourdev_545582.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:20

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:52

回复【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:32

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:19

MARK PN结测温

master5888 发表于 2010-4-12 08:13:31

luguo

fsclub 发表于 2010-4-12 08:15:28

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:11

回复【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:05

不如来个18B20实在。4148等就没有离散性了,做这样的AD不如直接来个NTC。

kangar0065 发表于 2010-4-20 09:13:57

4148便宜啊

portx 发表于 2010-4-20 09:20:51

关注,不知道精度能到多少,全温度范围的线性度如何,后期的数据是否需要进行多次方拟合

oxalis 发表于 2010-4-27 20:53:07

关注
谁来做个试试?

zhihaoa 发表于 2010-6-5 08:38:50

想法儿不错,作来试试

heyuncun 发表于 2010-6-5 11:29:16

mark

gxy508 发表于 2010-6-5 12:11:49

mark

millwood0 发表于 2010-6-5 23:18:25

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:27

静等下文

rqiang 发表于 2010-6-6 21:42:34

在要求不高的产品中试可以使用的。

frogrider 发表于 2010-6-6 22:30:51

mark

elec2000 发表于 2010-6-6 22:59:30

PN结的温度/电压的线性度非常好,但是个体之间的一致性不好,即互换性不好

millwood0 发表于 2010-6-7 00:13:05

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;

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='.';
                s=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, 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, i, 7); lcd_display(LCD_Line_ADCX, vRAM);
//                the following is for calibration purposes
                strcpy(vRAM, str_volt); ltoa(&vRAM, 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, 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:47

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:40

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:56

MARK。

millwood0 发表于 2010-6-7 07:57:43

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.


http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_560067YO6R47.PNG
(原文件名:16F684 temp diode.PNG)

millwood0 发表于 2010-6-7 08:05:58

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;

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='.';
                s=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, 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, i, 7); lcd_display(LCD_Line_ADCX, vRAM);
//                the following is for calibration purposes
                strcpy(vRAM, str_volt); ltoa(&vRAM, 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, 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.


http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_560069HHOS9I.PNG
(原文件名:16F684 temp diode v2.PNG)

millwood0 发表于 2010-6-7 08:11:14

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:34

回复【26楼】millwood0
-----------------------------------------------------------------------
英文好的高手。

jacky1982512 发表于 2010-6-7 09:12:44

回复【1楼】millwood0
-----------------------------------------------------------------------

你装什么,总是用英语!有意思

fsclub 发表于 2010-6-7 10:13:56

在国外,没有中文输入法。。。

fy024 发表于 2010-6-7 16:38:02

mark

kangar0065 发表于 2010-6-7 17:32:10

不错呀。冲这个应该给条裤子。那个英文不好的你有两个选择:一个是把英语学好了来,第二个就是不要看。

tfdsensor 发表于 2010-6-8 08:46:36

回复【28楼】jacky1982512
回复【1楼】millwood0
-----------------------------------------------------------------------
你装什么,总是用英语!有意思
-----------------------------------------------------------------------

1楼老大本来就是说英文, 就如同你装什么呀,说汉语一样.
你不愿意可以不看,如同国外的datasheet一样,你可以只看中文的,没有人逼你看

gpzdc986 发表于 2010-6-8 11:52:43

mark

youz 发表于 2010-6-8 12:25:29

二极管 温度测量 mark

allen 发表于 2010-7-10 17:50:34

值得关注

470036398 发表于 2010-7-10 17:57:57

mark

JQ_Lin 发表于 2010-7-10 22:20:49

回复【28楼】jacky1982512
回复【1楼】millwood0
-----------------------------------------------------------------------
你装什么,总是用英语!有意思
-----------------------------------------------------------------------

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

刚刚注册进来,既要求助,又不懂得尊重别人!少教!

my2009 发表于 2010-7-11 11:50:46

二极管 温度测量, 好资料, mark

huangdog 发表于 2010-7-11 14:29:23

mark

yaya001 发表于 2010-7-13 11:00:40

MARK MARK

longquan 发表于 2010-7-13 11:32:00

暖小鸡要找受精的蛋,这个问题好象比恒温难点:-P

XMLK 发表于 2010-10-2 21:36:47

MARK

cwl0580 发表于 2010-10-6 14:14:01

不错!

hzy789 发表于 2010-10-7 18:42:22

好资料,要收留。

linghu2 发表于 2010-10-13 13:51:36

我来把文件直接上传吧

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:46

关注,要mark

hymculolo 发表于 2010-10-13 16:22:50

mark了,以后慢慢学习~

ITOP 发表于 2010-10-13 16:33:04

MARK!!

nil0 发表于 2010-10-29 15:50:47

学习记号!

intentydh 发表于 2010-11-5 11:47:55

mark,学习,以后能用到.

kbdcj2000 发表于 2010-11-5 12:43:26

MARK

xczxwy 发表于 2010-11-5 12:51:38

曾今做过PN极测温的人飘过,线性非常好,但是一致性很差,量产的时候校正的问题没办法搞定,最终放弃,老实用了DS18B20~~

wwk1996 发表于 2010-11-12 13:41:07

mark,PN结测温。

baolei 发表于 2010-11-13 19:20:06

mark

asma 发表于 2012-2-15 23:14:58

mark

HZKJ 发表于 2012-10-16 14:21:51

kangar0065 发表于 2010-6-7 17:32 static/image/common/back.gif
不错呀。冲这个应该给条裤子。那个英文不好的你有两个选择:一个是把英语学好了来,第二个就是不要看。 ...

很酷的帖子,请问楼主 你孩子孵小鸡成功了吗,现在该长大了吧{:lol:} {:loveliness:}

hclin 发表于 2012-10-17 10:11:55

not bad !!!

a673261839 发表于 2018-7-24 16:32:32


MARK MARK

a673261839 发表于 2018-8-1 08:49:49

make             !!!!

gmyu 发表于 2018-8-1 10:43:20

STM32有CTMU单元么?

zzsczz 发表于 2021-12-15 21:49:21

最近 在 找 基准 相关 信息 。

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

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




页: [1]
查看完整版本: 二极管4148 三极管9013 PN结温度测量