目录:
一、概述
二、使用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测量,电路和波形示意图如下:

操作流程:

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:测量结果和曲线

附录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();
}

-----------------------------------------------------------------------------------------------------------------

无AD口,经IO口测量温度(asm、C代码)相关推荐

  1. 单片机小白学步系列(二十) IO口原理

    IO口操作是单片机实践中最基本最重要的一个知识,本篇花了比较长的篇幅介绍IO口的原理.也是查阅了不少资料,确保内容正确无误,花了很长时间写的.IO口原理原本需要涉及很多深入的知识,而这里尽最大可能做了 ...

  2. 疯狂的大柚柚带你玩转MSP-ESP430G2(基础篇)----(九)IO口的介绍

    疯狂的大柚柚带你玩转MSP-ESP430G2(基础篇) (九) IO口的介绍 MSP430G2553 共提供了16个IO口,P1.0-P1.7:P2.0-P2.7,即可通用IO口也可以时复用功能. 各 ...

  3. 51c语言单片机io口控制实验报告,单片机I/O口控制实验

    描述 实验 单片机I/O 口控制实验 一. 实验目的 利用单片机的P1 口作IO 口,使用户学会利用P1 口作为输入和输出口. 二. 实验设备及器件 IBM PC 机 一台 DP-51PROC 单片机 ...

  4. 单片机IO口操作总结

    单片机IO口操作总结 一.单片机IO口概述 二.单片机IO口操作 1.输入口使用 2.输出口使用 三.关于上拉电阻 四.休眠状态下IO口配置 4.1.未使用的IO口 4.2 输入口 一.单片机IO口概 ...

  5. 测量ATMEGA8单片机IO口的输入输出内阻

    ➤ 01背景 在 电子小帮手电路中电源开关电路分析 中介绍测量模块电路实验原理的时候,对于ATmega系列的 单片机的输出端口进行了内部描述 .特别是对于端口做为IO输出口的时候,它可以等效为通过电阻 ...

  6. io口模拟spi,stm32f103与MS5611基于spi总线的温度压力高度数据读取

    以下文件为源文件 /** -----------------------MS5611驱动 && IO口模拟SPI驱动------------------------- ******** ...

  7. STM32+MAX6675利用io口模拟SPI获取实时温度数据程序及代码

    STM32+MAX6675利用io口模拟SPI获取实时温度数据程序及代码 本文采用的芯片为STM32F103RCT6 温度芯片为MAX6675 因为芯片的spi口只有3个,有部分需要外接W25Q128 ...

  8. hc05与单片机连接图_单片机科普:单片机的IO口不够用了怎么办?如何扩展单片机的IO口...

    单片机是一种可编程器件,在各种消费类电子.工业电子.汽车电子等行业应用广泛,目前开发产品的构架就是以单片机为核心,根据不同的功能搭建不同的外设电路.同样的功能,每个人.每个团队所做的技术方案都不会相同 ...

  9. 想做数码管显示,单片机IO口资源不够?看看WTV890语音芯片能做些啥

    在开发许多产品时许多工程师都会遇到以下问题,如:想驱动4位或10位的LED数码管显示,但是单片机的IO口不够用:要么更换IO口资源更多的MCU来控制,要么更换脚位丰富的单片机,这无疑在MCU上,加了1 ...

最新文章

  1. 使用简单的轻量级移动web应用开发框架 - Sidetap
  2. 机器狗背上枪成了无人杀手,6.5mm口径1200米射程,制造商已与美澳军队广泛合作...
  3. 先进先出算法(FIFO)——页面置换
  4. 分布式缓存DistributedCache的使用
  5. 图解SQL Server 安全函数的使用
  6. Arrays 的copyOf() - JDK 6 和操作符 instanceof
  7. 聚水潭是如何基于AnalyticDB for PostgreSQL 构筑海量实时数仓平台的
  8. (52)FPGA基础编码D触发器(一)
  9. 说说如何做oracle的SQL审核呢
  10. http://item.jd.com/1275996920.html
  11. Win10 WSL设置启动快捷键
  12. Android iso文件打开,安卓手机iso文件用什么打开?
  13. python中变量名有哪些
  14. RFID医疗废物管理系统解决方案-RFID技术的医疗废弃物管理系统
  15. 美国弗吉尼亚大学计算机科学,弗吉尼亚大学UVa计算机科学Computer Science专业排名第201-250位(2021年THE世界大学商科排名)...
  16. python开源项目贡献_为开源项目做出第一笔贡献
  17. 惠州电子计算机职业学校,惠州市十大中专学校排名
  18. 关于反馈:误码与DTX
  19. 关于密码学古典加密——仿射加密一些问题
  20. 小白勿进!35岁的程序员被裁,这原因我服了

热门文章

  1. ExecutorService - 10个技巧和窍门
  2. 阿里云实名认证(php)
  3. 爱的艺术 - 艾里希·弗洛姆
  4. 未分配利润与利润表不一致_​未分配利润与利润表不一致的原因有哪些
  5. 网名接龙--之“小雨纷纷”的季节
  6. jquery时间戳格式化!!!
  7. 【python游戏】努力制造阳光,让植物有力量对抗僵尸吧~
  8. android 头像选择,裁剪全套解决方案,你值得拥有!
  9. 为什么00后都不知道什么是报销?
  10. AAFD-40故障电弧探测器 检测引起火灾的故障电弧 安科瑞 时丽花