/*
在博文“时基电路 555 的应用”中,做而论道介绍了使用555构成多谐振荡器,并利用该电路测量电容器容量的方法。
通过合理设计电路,可以使得脉冲周期的 ms 数,等于电容器容量的 uF 数。
详细内容可见:http://hi.baidu.com/do_sermon/item/fa8586d8f91de910e0f46f91


使用示波器观察 ms 数,远远不如使用单片机直观方便。
下面介绍一个利用单片机测量周期的方法,测量上述电路中电容器的电容量。


大家都知道,51 单片机的外部中断,可以设定为下降沿触发。

当第一次下降沿来临时,在中断程序中,启动定时器的计时;在第二次下降沿来临时,再停止定时器。
这样一来,计时器所统计的数值,就代表了脉冲的周期。

定时器在计时方式下,是针对机器周期计数,在晶振为 12MHz 时,计时的结果将在 0~65536us 范围内。
以 ms 为单位,就是:00.000 ~ 65.535,也就是:00.000 ~ 65.535 uF。

直接用显示器把这个数字显示出来,这就是测量电容的结果。


如果电容器的容量,超出了这范围,可以显示超量程的信息,提示使用者换用不同的档位,就是换用不同的电阻。

使用单片机测量电容的仿真电路如下:

利用51单片机测量电容量 - 非著名博主 - 电子信息角落
图片连接:http://xiangce.baidu.com/picture/detail/2776d1bacedd2e7b086f49f008d859e9f24b9b6b


超量程的提示显示如下:

利用51单片机测量电容量 - 非著名博主 - 电子信息角落
图片连接:http://xiangce.baidu.com/picture/detail/045f76180831956a08cc9ea432e7bcbcc6776579


单片机的程序如下:
*/
#include "reg51.h"
#include "intrins.h"

#define LCD_IO P0

sbit RS = P2^0;      //1602写地址
sbit RW = P2^1;      //1602写数据
sbit EN = P2^2;      //1602工作使能

sbit RST_5 = P3^0;   //555芯片工作控制
sbit K_STA = P3^1;   //开始测量的按键

unsigned char a[16] = "Measure Capac...";
//Measure Capacitance
unsigned char b[16] = " C: 00.000 uF   ";
unsigned int Cap;
bit  Flg;

//*************延时1ms*******************
void Delay1ms(unsigned int mm)
{
    unsigned int i;
    for(; mm > 0; mm--)  for(i = 100; i > 0; i--);
}
//*************LCD 延时******************
void LCD_delay(void)   
{
    char i;
    for (i = 10; i > 0; i--); 
}
//*************检查忙否******************
void Checkstates()
{
    RS = 0; RW = 1;
    while(LCD_IO & 0x80) {
      EN = 0; LCD_delay();
      EN = 1; LCD_delay();
    };
    EN = 0;
}
//*************向写LCD命令***************
void wcomd(unsigned char cmd)
{
    Checkstates();
    RS = 0; RW = 0;
    LCD_IO = cmd; LCD_delay(); 
    EN = 1; LCD_delay(); EN = 0;
}
//*************向写LCD数据***************
void wdata(unsigned char dat)
{
    Checkstates();
    RS = 1; RW = 0;
    LCD_IO = dat; LCD_delay(); 
    EN = 1; LCD_delay(); EN = 0;
}
//*************初始化LCD*****************
void LCD_INIT()
{
    Delay1ms(5);
    wcomd(0x38);  Delay1ms(10);//功能设置
    wcomd(0x01);  Delay1ms(1); //清屏
    wcomd(0x08);  Delay1ms(1); //关显示
    wcomd(0x0c);  Delay1ms(1); //开显示,不开光标
}
//*************LCD显示*******************
void Display(void) //显示
{
    unsigned char i;
    wcomd(0x80);  Delay1ms(5); //显示第一行
    for(i = 0; i < 16; i++)  wdata(a[i]); 
    wcomd(0xc0);  Delay1ms(5); //显示第二行
    for(i = 0; i < 16; i++)  wdata(b[i]);
}
//-------------------------------------------------
void main()
{
    RST_5 = 0;        //关闭555
    LCD_INIT();
    Display();        //显示

    TMOD = 0x01;      //T0定时方式1
    TH0 = 0x00;       //初始值为零
    TL0 = 0x00;
    IT0 = 1;          //下降沿触发中断
    IE = 0x03;        //开放局部中断

    while(1)  {
      while(!K_STA)   { //当测量键被按下
        RST_5 = 1;      //启动555
        Flg = 0;
        Delay1ms(100);  //稍稍延时, 让555稳定工作
        EA = 1;         //开总中断
        while (EA == 1);//等待测量完毕, 下面进行数据处理
//因为硬件设计合理, 所以数据很简单, 无需复杂处理, 分离出过大过小的即可
        if(Cap < 1000)  { //计数值小于100, 显示small, 提示换量程
           b[4] = 't'; b[5] = 'o'; b[6] = 'o'; b[7] = ' '; b[8] = 's'; b[9] = 'm';
          b[10] = 'a';b[11] = 'l';b[12] = 'l';b[13] = '.';b[14] = ' ';b[15] = ' ';
        }
        else if(Cap > 60000)  { //大于60000, 显示large, 提示量程
           b[4] = 't'; b[5] = 'o'; b[6] = 'o'; b[7] = ' '; b[8] = 'l'; b[9] = 'a';
          b[10] = 'r';b[11] = 'g';b[12] = 'e';b[13] = '.';b[14] = ' ';b[15] = ' ';
        }
        else {
          b[4] = '0' + Cap / 10000 % 10;
          b[5] = '0' + Cap / 1000 % 10;
          b[6] = '.';
          b[7] = '0' + Cap / 100 % 10;
          b[8] = '0' + Cap / 10 % 10;
          b[9] = '0' + Cap % 10;
          b[10] = ' ';b[11] = 'u';b[12] = 'F';b[13] = ' ';b[14] = ' ';b[15] = ' ';
        }
        Display();      //显示
        while(!K_STA);  //等待按键释放
    } }
}
//-------------------------------------------------
void X0_INT(void) interrupt 0 //控制计时的启动、停止
{
    Flg = ~Flg;
    if(Flg)  TR0 = 1;   //开始计时
    else  {
      TR0 = 0;          //停止计时
      EA = 0;           //关闭中断
      RST_5 = 0;        //关闭555
      Cap = TH0 * 256 + TL0; //取出机器周期数
      TH0 = 0x00;       //恢复T0初值
      TL0 = 0x00;
    }
}
//-------------------------------------------------
void T0_INT(void) interrupt 1 //测量超时
{
    EA = 0;             //关闭中断
    RST_5 = 0;          //关闭555
    TR0 = 0;            //停止定时
    TH0 = 0x00;         //恢复T0初值
    TL0 = 0x00;
    Cap = 65535;        //超出值
    Flg = 0;
}
//-------------------------------------------------

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐