采用51单片机和555定时器设计电容参数测量,根据P3.7脚的定时器测量TW 的宽度, 标准计数脉冲的周期为1 微秒,Tw=1.1*R*C,又uln2003A和三个继电器以及四个量程选择按键来选出不同的档位,但在仿真的时候不管选择哪个档位,都能测出某一个电容,有时候还测的是错误的,分析了好久也没头绪,所以来这里求助了。麻烦给位帮忙分析分析。谢谢了
-
电容参数测量仪.DSN
(2016-7-31 09:43 上传)
119.08 KB, 下载次数: 3
仿真图
不是每位网友的计算机都装有你所使用的仿真软件。
要想让尽量多的网友看到,应该用通用的图片格式贴图。
“采用51单片机和555定时器设计电容参数测量”
何必使用555定时器?用单片机产生一定宽度的脉冲,比555要方便,而且准确。
主函数
#include
#include "1602.h"
#include "delay.h"
sbit vo = P3^2; // 用于检测P3.2口的值,计算时间。 计时器0的开与断
sbit tr = P3^7; // 产生一个低电平脉冲
// 超量程提示灯
sbit ledclc = P2^7;
sbit con1 = P0^0; // 用于控制继电器,实现档位选择
sbit con2 = P0^1;
sbit con3 = P0^2;
sbit key1 = P0^3; // 独立按键部分,用于用户选择量程
sbit key2 = P0^4;
sbit key3 = P0^5;
sbit key4 = P0^6;
sbit led1 = P2^3; // 量程提示灯
sbit led2 = P2^4;
sbit led3 = P2^5;
sbit led4 = P2^6;
unsigned int tw; // 用于获取定时器的数值
float ftemp; // 用于计算电容值的中间变量
unsigned long int c; // 存放电容值
unsigned char need; // 需要测量时置1,一次测量结束置0
unsigned char R; // 表示不同的档位
unsigned char flag; // 数据处理结束置1
unsigned char temp[8]; // 存放电容值的各个位
unsigned char zimu1[] = " range is higher"; //量程太高
unsigned char zimu2[] = "The value of Cap";
unsigned char zimu3[] = "please press key";
unsigned char zimu4[] = " to measure ";
unsigned char zimu5[] = " range is lower ";
void process(unsigned long int c); // 数据处理函数
void keyscan(); // 键盘扫描函数
void ledlight(unsigned char R); // 量程指示灯函数
void init_timer0() // 定时器0 初始化
{
TMOD = 0x09; // gate置1,方式1,16位计时,定时器由P3.2控制开断
TH0 = 0x00;
TL0 = 0x00;
EA = 1;
ET0 = 1;
TR0 = 1;
}
void init_INT1 () // 定时器0 初始化
{
EA = 1;
IT1 = 1; // 下降沿触发
EX1 = 1;
}
void main()
{
ledclc = 1; // 超量程提示灯熄灭
need = 0; // 一开始无需测量
con1 = con2 = con3 = 0;
flag = 0;
init_timer0(); // 初始化
init_INT1();
LCD_init();
dispchar1(zimu3);
dispchar2(zimu4);
while(1)
{
if(need == 1)
{ // 当需要测量时
if(vo == 0 ) //vo == 0时检测计数器的值可能还没开始计数,可能计数结束
{
if(TH0 != 0x00 || TL0 != 0x00) // 是计数结束 若有读数,用tw 存下
{
tw = TH0 << 8;
tw = tw | TL0;
TH0 = 0x00; // 一次结束,计时器清零
TL0 = 0x00;
need = 0; // 需要再次测量时,need置1.避免tw的值被更//改 即不需要测量时,一直保持
EX1 = 1; // 开外部中断1
}
else // 反之,证明没有计数,无电容,默认值tw置0
{
tw = 0;
}
}
ftemp = tw / 1.1 ; // 计算电容值 根据公式 tw = 1.1 * R * C
c = (unsigned long int)(ftemp )*100; //扩大了一百倍 便于后续程序
//取两位小数点
process(c); // 调用数据处理函数,根据不同的R值进行处理
}
if(flag == 1 ) // 数据处理结束 每次处理结束,证明需要更新显示的数据
{
if(tw>=50000 || ledclc == 0) // 量程超出
{
dispchar3(zimu1);
delay_us(100); // 量程太高
ledclc = 0;
}
else if(tw<=100 && ledclc == 1) //量程太低
{
dispchar3(zimu5);
delay_us(100);
ledclc = 0;
}
else
{
dispchar1(zimu2);
delay_us(10);
disp(temp);
}
flag = 0;
}
keyscan();
}
}
void timer0() interrupt 1 // 定时器0中断 用于超量程提示
{ TMOD = 0x09; // gate置1,方式1,16位计时,定时器由P3.2控制开断
TH0 = 0x00;
TL0 = 0x00;
ledclc = 0;
}
void exint1 () interrupt 2 // 外部中断0 用于产生低脉冲,启动555定时器
{
unsigned char a;
tr = 1; // tr端一个负脉冲
a = 20;
while(--a);
tr = 0;
a = 20;
while(--a);
tr = 1; // tr端负脉冲结束 大约40us的负脉冲
need = 1; // 表示需要测量
ledclc = 1; // 关闭先前的超量程提示
EX1 = 0; // 暂时关闭外部中断,一次测量结束,再开放外部中断
}
void process(unsigned long int c)
{
if(R == 1) // 10M 的电阻 量程10pf ~ 5000pf
{
c = c /10;
lcd_pos(0x4a);
LCD_write_Data(' ');
LCD_write_Data('p');
LCD_write_Data('f');
LCD_write_Data(' ');
LCD_write_Data(' ');
}
if(R == 2) // 100k 的电阻 量程5nf~ 500nf
{
c = c /100;
lcd_pos(0x4a);
LCD_write_Data(' ');
LCD_write_Data('n');
LCD_write_Data('f');
LCD_write_Data(' ');
LCD_write_Data(' ');
}
if(R == 3) //1k欧姆 的电阻 量程0.5uf ~ 50uf
{
c = c /1000; // 扩大了一百倍 单位 c = tw/500 uf
lcd_pos(0x4a);
LCD_write_Data(' ');
LCD_write_Data('u');
LCD_write_Data('f');
LCD_write_Data(' ');
LCD_write_Data(' ');
}
if(R == 4) //100欧姆 的电阻 量程50uf ~ 500uf
{
c = c /100; // 扩大了一百倍 单位 c = tw/500 uf
lcd_pos(0x4a);
LCD_write_Data(' ');
LCD_write_Data('u');
LCD_write_Data('f');
LCD_write_Data(' ');
LCD_write_Data(' ');
}
temp[0] = c / 100000; // 千位
temp[1] = c / 10000 % 10; // 百位
temp[2] = c / 1000 % 10; // 十位
temp[3] = c / 100 %10; // 个位
temp[4] = c / 10 % 10;
temp[5] = c % 10;
flag = 1;
}
void keyscan()
{
if(key1 == 0)
{
delay_ms(10);
if(key1 == 0) // b3按下
{
while(key1==0);
R = 1; // 10M 的电阻 量程10pf~ 5000pf(5nf)
con1 = 1;
con3 = 1;
con2 = 0;
ledclc = 1;
dispchar3(zimu2);
disp(temp);dispchar1(temp) ;
/*dispchar2(zimu4);*/
}
}
if(key2 == 0) // b4按下
{
delay_ms(10);
if(key2 == 0)
{
while(key2==0);
R = 2; // 100k 的电阻 量程5nf~ 500nf
con1 = 0;
con3 = 1;
con2 = 0;
ledclc = 1;
dispchar3(zimu2);
disp(temp);
}
}
if(key3 == 0) // b5按下
{
delay_ms(10);
if(key3 == 0)
{
while(key3==0);
R = 3;
con1 = 0; // 1k欧姆 的电阻 量程0.5uf ~ 50uf
con2 = 0;
con3 = 0;
ledclc = 1;
dispchar3(zimu2);
disp(temp);
}
}
if(key4 == 0) // b6按下
{
delay_ms(10);
if(key4 == 0)
{
while(key4==0);
R = 4;
con1 = 0; // 100欧姆 的电阻 量程50uf ~ 500uf
con2 = 1;
con3 = 0;
ledclc = 1;
dispchar3(zimu2);
disp(temp);
}
}
ledlight(R);
}
void ledlight(unsigned char R)
{
if(R == 1)
{
led1 = 1;
led2 = 1;
led3 = 1;
led4 = 0;
}
if(R == 2)
{
led1 = 1;
led2 = 1;
led3 = 0;
led4 = 1;
}
if(R == 3)
{
led1 = 1;
led2 = 0;
led3 = 1;
led4 = 1;
}
if(R == 4)
{
led1 = 0;
led2 = 1;
led3 = 1;
led4 = 1;
}
}
这是1602.c
#include "1602.h"
#include "delay.h"
void LCD_write_com(unsigned char com)
{
RS_CLR;
RW_CLR;
EN_SET;
com = pro_data(com);
P1 = com;
delay_us(300);
EN_CLR;
}
void LCD_write_Data(unsigned char Data)
{
RS_SET;
RW_CLR;
EN_SET;
Data = pro_data(Data);
P1 = Data;
delay_us(300);
EN_CLR;
}
void LCD_init(void)
{
/* LCD_write_com(0x38); // 显示模式设置
delay_ms(5);
LCD_write_com(0x38);
delay_ms(5);
LCD_write_com(0x38);
delay_ms(5); */
LCD_write_com(0x38);
LCD_write_com(0x08); // 显示关闭
LCD_write_com(0x01); // 显示清屏
LCD_write_com(0x06); // 显示光标移动设置
delay_ms(5);
LCD_write_com(0x0c); // 显示开及光标设置
}
void lcd_pos(unsigned char pos)
{
LCD_write_com(0x80|pos);
}
void disp(unsigned char *p) // 第二行显示数据
{
unsigned char i;
lcd_pos(0x43);
for(i=0;i<6;i++)
{
if(i==4)
{
LCD_write_Data(0x2e);
}
LCD_write_Data('0'+(*p));
p++;
}
}
void dispchar1(unsigned char *p) // 第一行显示需要显示的提示字符串
{
lcd_pos(0x00);
while(*p != '\0')
{
LCD_write_Data(*p);
p++;
}
lcd_pos(0x4c);
LCD_write_Data('f');
}
void dispchar2(unsigned char *p) // 第二行显示需要显示的提示字符串
{
lcd_pos(0x40);
while(*p != '\0')
{
LCD_write_Data(*p);
p++;
}
}
void dispchar3(unsigned char *p) // 第一行显示 第二行清空
{
unsigned char i;
lcd_pos(0x00);
while(*p != '\0')
{
LCD_write_Data(*p);
p++;
}
lcd_pos(0x40);
for(i=0;i<16;i++)
{
LCD_write_Data(' ');
}
}
unsigned char pro_data(unsigned char mda) //数据处理函数,将高位和低位互换
{
unsigned char enddat;
unsigned char i;
enddat = 0;
for(i=0;i<8;i++)
{
enddat = enddat << 1;
if(mda & 0x01 == 1)
{
enddat = enddat | 0x01;
}
else
{
enddat = enddat | 0x00;
}
mda = mda >> 1;
}
return enddat;
}
#ifndef __1602_h__
#define __1602_h__
#include
sbit RS = P2^2; //定义端口
sbit RW = P2^1;
sbit EN = P2^0;
#define RS_CLR RS=0
#define RS_SET RS=1
#define RW_CLR RW=0
#define RW_SET RW=1
#define EN_CLR EN=0
#define EN_SET EN=1
unsigned char pro_data(unsigned char mda);
void LCD_write_com(unsigned char com);
void LCD_write_Data(unsigned char Data);
void LCD_init(void);
void lcd_pos(unsigned char pos);
void disp(unsigned char *p);
void dispchar1(unsigned char *p);
void dispchar2(unsigned char *p);
void dispchar3(unsigned char *p);
#endif
#include "delay.h"
void delay_us(uint cnt)
{
uchar i;
for(;cnt>0;cnt--)
{
for(i=0;i<12;i++)
{
;
}
}
}
void delay_ms(uint cnt){
uchar i;
for(;cnt>0;cnt--)
{
for(i=0;i<125;i++)
{
;
}
}
}
#ifndef __delay_h__
#define __delay_h__
#define uchar unsigned char
#define uint unsigned int
void delay_us(uint cnt);
void delay_ms(uint cnt);
#endif
恩恩,第一次发帖,昨天太急了。下次一定注意,已经上图和程序了。
“是单片机某个脚接电容部分然后让单片机产生脉冲么”
是单片机引脚上产生脉冲,脉冲宽度由单片机定时器控制。但通常不能让单片机引脚接电容,因为单片机引脚拉电流灌电流能力比较弱。单片机引脚上脉冲宽度仅为控制时间。应该让单片机引脚驱动一个放大器(可以是数字电路芯片),由此放大器再去控制电容的充电放电。
第二档只能测40nf~500nf
第三档只能测0.5uf到50uf 还有误差,第一档,第四档测不了、
额,我设计电路能力超级弱。。。开始学到现在一直抄别人电路。。。
刚才又捣鼓了半天好像能测一点,不过有误差,而且还有两个档测不了