利用51单片机测量电容量
2018-05-07 来源:eefocus
/*
在博文“时基电路 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。
直接用显示器把这个数字显示出来,这就是测量电容的结果。
如果电容器的容量,超出了这范围,可以显示超量程的信息,提示使用者换用不同的档位,就是换用不同的电阻。
使用单片机测量电容的仿真电路如下:
图片连接:http://xiangce.baidu.com/picture/detail/2776d1bacedd2e7b086f49f008d859e9f24b9b6b
超量程的提示显示如下:
图片连接: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;
}
//-------------------------------------------------
上一篇:DS18B20 与数字温度计