天天看點

無AD口,經IO口測量溫度(asm、C程式)

目錄: 一、概述 二、使用PIC單片機方案 三、使用STC單片機方案 ----------------------------------------------------------------------------------------------------------------- 一、概述 對于沒有ADC的MCU,而又要測量外部的電壓時,使用RC充放電的方式是比較容易實作并且低成本的方法。或可用在觸摸方案,沒有實際試過。 ----------------------------------------------------------------------------------------------------------------- 二、使用PIC單片機方案 這是一段利用單片機IO口作的溫控程式,感溫元件是NTC。功能是當溫度低過某值時開始加熱,随着溫度上升;當高到某值時停止加熱,然後開始冷卻,不斷重複。使用時要注意RC常數,常數過大會造成16位計數溢出,得不到正确結果。程式是作産品前的一個試驗程式,當時調試已認證,能作到±0.5℃。   ;******************************************************

;filename: IOTestNTC.asm

;     mcu: MDT2005EP

;     clock: 4 MHz for EXTXT

;     date: 2006/03/17

;     writer: aLin

;****************************************************** ;計算被測量電阻。隻做比較,不作計算。

;計算公式:Rx = Rf * (Tx/Tf)

;Rx為被測電阻

;Rf為已知電阻,Rf=10K

;Tx為被測電阻對電容C放電的計數值,為16位數

;Tf為被測電阻對電容C放電的計數值,為16位數

;查溫度特性表(NTC型号為:CWF2-473F-3950K,大亞科技制造):

;下限溫度5攝氏度時電阻為121545.44歐,即121.54544K

;換算為:Tx/Tf=Rx/Rf=12.154544

;擴大1000倍後結果為:12154.544,約為12155,即2F76H              

;上限溫度8攝氏度時電阻為104712.92歐,即104.71292K

;換算為:Tx/Tf=Rx/Rf=10.471292

;擴大1000倍後結果為:10471.292,約為10471,即28E7H ;-------------------------------------------------------------------       

               list         p=pic16c54

               #i nclude     "p16c5x.inc"   ;定義I/O口              

               #define      vt     portb,0

               #define      rf     portb,1

               #define      rx     portb,2

               #define      on     portb,4

               #define      off    portb,4

               #define      f0     user,0         ;RAM 配置設定

   CNT         EQU         10H    ;計數器        SOU1        EQU         11H    ;四位元組被除數最低位和16位商的低8位

   SOU2        EQU         12H    ;被除數和16位商高8位

   SOU3        EQU         13H    ;被除數和16位餘數的低8位

   SOU4        EQU         14H    ;四位元組被除數最高位和16位餘數的高8位

   USER        EQU         15H    ;使用者标記位        SOU         EQU         16H    ;被數低8位和積(四位元組積的最低位)和RX電阻計數器低8位

   SOUH        EQU         17H    ;被乘數高8位和積和RX電阻計數器高8位

   RLT         EQU         18H    ;乘數低8位和積

   RLTH        EQU         19H    ;乘數高8位和積(四位元組積的最高位)        TEMP1       EQU         1AH    ;臨時寄存器1-4

   TEMP2       EQU         1BH

   TEMP3       EQU         1CH

   TEMP4       EQU         1DH        RFCNTL      EQU         1EH    ;RF電阻計數器低8位

   RFCNTH      EQU         1FH    ;RF電阻計數器高8位         

;--------------------------------- 

   ORG      0000h 

     start:     bcf       fsr,6  ;選擇bank0

    bcf     fsr,5

    movlw     b'11101111'   ;RB4定義為輸出,其餘輸入,PortB4為一直輸出

    tris      06h

;---------------------------------------------------           

;停止加熱處理程式

;等待溫度降到5攝氏度以下是,重新加熱,跳到加熱處理程式

;

;負溫度系電阻,阻值越大,溫度越低

;用5攝氏度時對應的電阻減去測出的電阻,為負數,表明實際溫度已低過5攝氏度

;需加熱處理 

;

   HOT_DOWN    bcf      off       ;停止加熱

;               call     d1s       ;延時1秒

               call     io_rm     ;調用測量電阻程式

               call     DUMUL     ;調用16位無符号乖法程式

               call     DUDIV     ;調用32位除以16位無符号除法程式

;比較商大小

;0E10 對應36K電阻,溫度是31度

               MOVLW    2FH      

               MOVWF    TEMP1

               MOVF     SOU2,W

               SUBWF    TEMP1,W   ;商高8位先減

               BTFSS    STATUS,C  ;檢查是否有借位,有借位時C=0

               GOTO     HOT_UP    ;有借位,被減數小于減數,跳到加熱程式 

               BTFSS    STATUS,Z  ;無借位,查相減結果是否為0  

               GOTO     HOT_DOWN  ;結果不為0,則被減數大于減數,跳到停止加熱程式

               MOVLW    76H       ;商高8位相等,商低8位相減

               MOVWF    TEMP1

               MOVF     SOU1,W

               SUBWF    TEMP1,W

               BTFSS    STATUS,C

               GOTO     HOT_UP

               BTFSS    STATUS,Z

               GOTO     HOT_DOWN                                GOTO     HOT_DOWN  ;兩數相等,傳回              

;--------------------------------------

;加熱程式處理程式

;

;當溫度大于8攝氏度時跳到停止加熱程式

;            

    HOT_UP             bsf      on        ;加熱

;              call     d1s       ;延時1秒

               call     io_rm     ;調用測量電阻程式

               call     DUMUL     ;調用16位無符号乖法程式

               call     DUDIV     ;調用32位除以16位無符号除法程式

;比較商大小  

;07D0對應電阻20K,溫度45度  

               MOVLW    28H      

               SUBWF    SOU2,W    ;商高8位先減

               BTFSS    STATUS,C  ;檢查是否有借位,有借位時C=0

               GOTO     HOT_DOWN  ;有借位,被減數小于減數,跳到停止加熱程式 

               BTFSS    STATUS,Z  ;無借位,查相減結果是否為0  

               GOTO     HOT_UP    ;結果不為0,則被減數大于減數,跳到加熱程式

               MOVLW    0E7H      ;商高8位相等,商低8位相減

               SUBWF    SOU1,W

               BTFSS    STATUS,C

               GOTO     HOT_DOWN

               BTFSS    STATUS,Z

               GOTO     HOT_UP              

               GOTO     HOT_UP    ;溫度未低過下限溫度,傳回繼續等待   ;----------------------------------------           

;    

      io_rm    clrf     SOUH

               clrf     SOU

               clrf     RFCNTH

               clrf     RFCNTL                                call     fullcharge    ;讓電容充電。

               call     rxdischarge   ;調用測量rx放電時間子程式             

               call     fullcharge    ;讓電容充電

               call     rfdischarge   ;調用測量rf放電時間子程式。

               call     fulldischarge ;讓電容完全放電。

               retlw    00h

;-----------------------------------------

;

;電容充電子程式

;

 fullcharge                  movlw    b'11101110'  ;vt口轉為輸出,rf、rx為輸入,PortB4一直輸出

               tris     06h

               bsf      vt           ;vt口輸出高電平,讓電容充電

               movlw    .40          ;延時,讓電容有足夠時間充滿電至Voh。

               movwf    CNT

               decfsz   CNT,F

               goto     $-1

               retlw    00h

;---------------------------------------

;

;電容放電

;

fulldischarge

               movlw    b'11101110'  ;vt口轉為輸出,rf、rx為輸入,PortB4一直輸出

               tris     06h

               bcf      vt           ;vt口輸出低電平,讓電容放電

               retlw    00h

;-----------------------------------------

;       

;測量rf放電時間子程式

;

rfdischarge

               movlw    b'11101101' ;vt口轉為輸入,rf口轉為輸出,rx口輸入,PortB4一直輸出

               tris     06h

               bcf      rf          ;rf口輸出低電平,電容對rf電阻放電.

     _rfdis    btfss    vt

               goto     _rfdisdone

               incf     RFCNTL,f

               skpnz

               incf     RFCNTH,f

               goto     _rfdis

 _rfdisdone

               movlw    b'11101111'  ;斷開rf電阻,由輸出改為輸入,PortB4一直輸出

               tris     06h

               retlw    00h

;--------------------------

;            

;測量rx放電時間子程式

;                                            

rxdischarge

               movlw    b'11101011'  ;vt口轉為輸入,rx口轉為輸出,rf口輸入,PortB4一直輸出

               tris     06h

               bcf      rx           ;rx口輸出低電平,電容對rx電阻放電.

     _rxdis    btfss    vt

               goto     _rxdisdone

               incf     SOU,f

               skpnz

               incf     SOUH,f

               goto     _rxdis

 _rxdisdone

               movlw    b'11101111'  ;斷開rx電阻,由輸出改為輸入,PortB4一直輸出

               tris     06h

               retlw    00h                        

;---------------------

;

;本程式實作四位元組除以雙位元組無符号數除法。

;

;入口參數:被除數在SOU4~SOU1中,除數在RLTH、RLT中。

;出口參數:商在SOU2、SOU1中,餘數在SOU4、SOU3中.

      DUDIV    MOVLW    .16         ;循環16次

               MOVWF    CNT

               MOVF     RLTH,W      ;被除數,32位,最高8位

               MOVWF    SOU4

               MOVF     RLT,W

               MOVWF    SOU3                          

               MOVF     SOUH,W

               MOVWF    SOU2

               MOVF     SOU,W

               MOVWF    SOU1        ;被除數,32位,最低8位 

               MOVF     RFCNTH,W    ;除數高8位 

               MOVWF    RLTH

               MOVF     RFCNTL,W    ;除數低8位

               MOVWF    RLT    

       LOOP    BCF      STATUS,C    ;C清0

               RLF      SOU1,F

               RLF      SOU2,F

               RLF      SOU3,F

               RLF      SOU4,F

               BTFSS    STATUS,C

               GOTO     CLR_F0       ;C=0, 跳到CLR_F0,清F0

               BSF      F0           ;C=1, 置F0

     SUB_LO    BCF      STATUS,C                   

               MOVF     RLT,W

               SUBWF    SOU3,W      ;SOU3-RLT -> W

               MOVWF    TEMP1       ;送TEMP1儲存

               BTFSS    STATUS,C    ;有借位時C=0                  GOTO     SUB_HI      ;低8位相減時有借位,被減數高8位要借1,相當于減數加1                  MOVF     RLTH,W

               SUBWF    SOU4,W

      THAN     BTFSC    F0          ;若夠減,跳到SAVE

               GOTO     SAVE

               BTFSS    STATUS,C 

               GOTO     NEXT        ;若不夠減,跳到NEXT

      SAVE     MOVWF    SOU4        ;儲存相減結果 

               MOVF     TEMP1,W

               MOVWF    SOU3

               INCF     SOU1,F

      NEXT     DECFSZ   CNT,F

               GOTO     LOOP             

               RETLW    00H     

     SUB_HI    INCF     RLTH,W

               SUBWF    SOU4,W

               GOTO     THAN      

     CLR_F0    BCF      F0

               GOTO     SUB_LO            

;***************DUMUL***********

;本程式實作雙位元組無符号數乘法。

;入口參數:被乘數在SOUH、SOU中,乘數在RLTH、RLT中。

;出口參數:結果在RLTH、RLT、SOUH、SOU中。

   DUMUL       MOVLW       .16

               MOVWF       CNT

              ;設乘數RLTH、RLT=03E8H=1000D,即将SOUH、SOU擴大1000倍           

               MOVLW       03H

               MOVWF       RLTH

               MOVLW       0E8H

               MOVWF       RLT

               MOVF        SOU,W

               MOVWF       TEMP3

               MOVF        SOUH,W

               MOVWF       TEMP4

               CLRF        SOU         ;用于暫

               CLRF        SOUH        ;存

               CLRF        TEMP1       ;結

               CLRF        TEMP2       ;果

               BCF         STATUS,C

   LOOP3       RRF         TEMP4,F

               RRF         TEMP3,F     ;将被乘數的某一位送到C中

               BTFSC       STATUS,C

               GOTO        DUADD       ;将RLTH:RLT中的被乘數加上

   BACK        RRF         SOUH,F

               RRF         SOU,F

               RRF         TEMP2,F

               RRF         TEMP1,F     ;被乘數右移

               DECFSZ      CNT,F

               GOTO        LOOP3

               MOVF        SOUH,W      ;儲存結果

               MOVWF       RLTH

               MOVF        SOU,W

               MOVWF       RLT

               MOVF        TEMP2,W     

               MOVWF       SOUH

               MOVF        TEMP1,W

               MOVWF       SOU

               RETLW       00H  

   DUADD       MOVF        RLT,W 

               ADDWF       SOU,F

               MOVF        RLTH,W

               BTFSC       STATUS,C

               INCFSZ      RLTH,W

               ADDWF       SOUH,F

               GOTO        BACK

;---------------------------

;延時1S

;                           

;       d1s     movlw       .16     ; .16時為1.000069S

;               movwf       temp1

;               movlw       .100

;               movwf       temp2

;               movlw       .207

;               movwf       temp3

;               decfsz      temp3,f

;               goto        $-1

;               decfsz      temp2,f

;               goto        $-5

;               decfsz      temp1,f

;               goto        $-9

;               retlw       00h                   

;--------------------------------    

               END ----------------------------------------------------------------------------------------------------------------- 三、使用STC單片機方案 STC15F系列是1T的MCU,其IO口有OPEN-DRAIN模式,此模式可以很容易用一個IO口配合一個定時器實作RC充放電來測量外部未知電壓。如果沒有空餘的定時器,也可以使用指令循環的方式實作。本例使用定時器。 本範例使用P3.2(INT0)來做RC測量,電路和波形示意圖如下:

無AD口,經IO口測量溫度(asm、C程式)
無AD口,經IO口測量溫度(asm、C程式)

  操作流程: 1、初始化程式将P3.2設定成OPEN-DRAIN模式, 并将P3.2輸出0給電容放電。INT0設定成上升沿中斷。Timer 0設定成16位自動重裝定時器模式,時鐘源為12T,允許中斷。 2、測量時,先清Timer 0的TH0、TL0,然後将P3.2輸出1開始對電容充電,接着設定TR0 = 1來啟動Timer 0,然後在INT0中斷裡設定TR0 = 0來停止計數,并将P3.2輸出0對電容放電。讀出TH0、TL0的值就是RC充電時間。 由于MCU工作在5V時,IO口讀到“1”的門限電壓大約為2V,是以要求輸入的電壓高于2V,本例的測試資料從4~12.4V,測試結果參考後面的附錄1。 假設輸入電壓為Ux,IO口門限電壓為2V,則RC充電時間為:T =  - R * C * ln ( 1 – 2 / Ux ) 按圖示參數,當輸入為10V時,RC時間大約為446uS,附錄1中實測為447uS。 由于RC時間跟R和C有關,而R的溫漂一般較小,但普通電容的溫漂較大,是以要使用溫漂小并且漏電也小的電容。 由充電公式或曲線圖可知,Ux和RC值的關系是非線性的,是以實際項目使用時,要根據自己的實際電路做一些标定,這樣可以得 到比較準确的值。 本方法适用于對測量精度要求不是很高的場合。 附錄1:測量結果和曲線

無AD口,經IO口測量溫度(asm、C程式)
無AD口,經IO口測量溫度(asm、C程式)
無AD口,經IO口測量溫度(asm、C程式)
無AD口,經IO口測量溫度(asm、C程式)
無AD口,經IO口測量溫度(asm、C程式)

  附錄2:C語言程式 #include "reg51.h" #define MAIN_Fosc 22118400L //定義主時鐘 #define uchar char #define uint unsigned int sfr AUXR = 0x8e;    //Auxiliary register sfr P3M1  = 0xB1; //P3M1.N,P3M0.N  =00--->Standard, 01--->push-pull sfr P3M0  = 0xB2; // =10--->pure input, 11--->open drain sbit P_TXD1  = P3^1; //定義模拟序列槽發送腳,列印資訊用 sbit    P_RC = P3^2; //RC port uchar SampleCnt; //發送結果的采樣間隔計數 uchar LineCnt; //每行顯示結果計數 bit B_Over; //逾時标志 bit B_ADC_OK; //檢測完成标志 uint adc; //RC做的ADC值 void RC_start(void); void Tx1Send(uchar dat); void  InitTimer(void); void delay_ms(unsigned char ms); /// void main(void) { InitTimer(); //初始化Timer     P3M1 |=  1 << 2;         //P3.2 config as Open-Drain  P3M0 |=  1 << 2; P_RC = 0;               //Clear RC port to 0 //    TMOD |= 0x00;           //T0 as 16 bits timer, auto reload     while (1)     {         delay_ms(5);   //放電時間 B_ADC_OK = 0; //清除ADC結束标志 B_Over = 0; //清除超量程标志         RC_start();           //RC charge-decharge while(!B_ADC_OK && !B_Over) ; //等待ADC結束或逾時 if(B_ADC_OK) { if(++SampleCnt >= 100) //1秒鐘發一個結果給序列槽 { SampleCnt = 0; Tx1Send(adc / 10000 + '0');           //send to PC from the UART Tx1Send(adc % 10000 / 1000 + '0'); Tx1Send(adc % 1000 / 100 + '0'); Tx1Send(adc % 100 / 10 + '0'); Tx1Send(adc % 10 + '0'); Tx1Send(' '); Tx1Send(' '); if(++LineCnt >= 10) //10個結果後換行 { LineCnt = 0; Tx1Send(0x0d);   //send CR Tx1Send(0x0a); } } }     } } /// //============================================================ // 函數: void  delay_ms(unsigned char ms) // 描述: 延時函數。 // 參數: ms,要延時的ms數. // 傳回: none. // 版本: VER1.0 // 日期: 2010-12-15 // 備注:  //============================================================ void  delay_ms(unsigned char ms) {      unsigned int i;  do  { i = MAIN_Fosc / 14000L; //1T while(--i) ;   //13T per loop      }while(--ms); } void   RC_start(void) {                         //使用Timer 0 計時     TH0 = 0;            //clear Timer 0     TL0 = 0; B_Over = 0; //Clear Over flag     P_RC = 1;           //RC charge     TR0 = 1;            //enable Timer 0 IE0 = 0; //Clear INT0 flag EX0 = 1; //INT0 Enable IT0 = 0; //INT0 上升,下降沿中斷 } void INT0_int (void) interrupt 0 // {     if(INT0 && !B_Over) //上升沿中斷,無逾時 { TR0 = 0;            //deable Timer 0 P_RC = 0;           //decharge adc = TH0;            //read the RC time adc = (adc << 8) + TL0; B_ADC_OK = 1; //标志ADC結束 } } void InitTimer(void) { TMOD = 0; //for STC15Fxxx系列 Timer0 as 16bit reload timer. TH0 = 0; TL0 = 0; ET0 = 1; //允許Timer0中斷 TR0 = 0; EA  = 1; //允許總中斷 } void timer0 (void) interrupt 1 { TR0 = 0; //超量程關閉 B_Over = 1; //标志超量程 } void BitTime(void) //位時間函數 { uint i; i = ((MAIN_Fosc / 100) * 104) / 130000L - 1; //根據主時鐘來計算位時間 while(--i); } //模拟序列槽發送 void Tx1Send(uchar dat) //9600,N,8,1 發送一個位元組 { uchar i; EA = 0; P_TXD1 = 0; BitTime(); for(i=0; i<8; i++) { if(dat & 1) P_TXD1 = 1; else P_TXD1 = 0; dat >>= 1; BitTime(); } P_TXD1 = 1; EA = 1; BitTime(); BitTime(); } -----------------------------------------------------------------------------------------------------------------