[求助] 电容参数测量

大眼睛   2016-7-31 09:50 楼主
采用51单片机和555定时器设计电容参数测量,根据P3.7脚的定时器测量TW 的宽度, 标准计数脉冲的周期为1 微秒,Tw=1.1*R*C,又uln2003A和三个继电器以及四个量程选择按键来选出不同的档位,但在仿真的时候不管选择哪个档位,都能测出某一个电容,有时候还测的是错误的,分析了好久也没头绪,所以来这里求助了。麻烦给位帮忙分析分析。谢谢了

回复评论 (11)

不是每位网友的计算机都装有你所使用的仿真软件。
要想让尽量多的网友看到,应该用通用的图片格式贴图。
点赞  2016-7-31 10:40
“采用51单片机和555定时器设计电容参数测量”
何必使用555定时器?用单片机产生一定宽度的脉冲,比555要方便,而且准确。
点赞  2016-7-31 10:42
主函数
#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
点赞  2016-8-1 09:27
昨天太急了,现在上图
  • 1602
  • 555部分
  • 全图
点赞  2016-8-1 09:28
引用: maychang 发表于 2016-7-31 10:40
不是每位网友的计算机都装有你所使用的仿真软件。
要想让尽量多的网友看到,应该用通用的图片格式贴图。

恩恩,第一次发帖,昨天太急了。下次一定注意,已经上图和程序了。
点赞  2016-8-1 09:34
引用: maychang 发表于 2016-7-31 10:42
“采用51单片机和555定时器设计电容参数测量”
何必使用555定时器?用单片机产生一定宽度的脉冲,比555要 ...

具体怎么做,是单片机某个脚接电容部分然后让单片机产生脉冲么
点赞  2016-8-1 09:37
引用: 大眼睛 发表于 2016-8-1 09:37
具体怎么做,是单片机某个脚接电容部分然后让单片机产生脉冲么

“是单片机某个脚接电容部分然后让单片机产生脉冲么”
是单片机引脚上产生脉冲,脉冲宽度由单片机定时器控制。但通常不能让单片机引脚接电容,因为单片机引脚拉电流灌电流能力比较弱。单片机引脚上脉冲宽度仅为控制时间。应该让单片机引脚驱动一个放大器(可以是数字电路芯片),由此放大器再去控制电容的充电放电。
点赞  2016-8-1 10:43
第二档只能测40nf~500nf
第三档只能测0.5uf到50uf   还有误差,第一档,第四档测不了、
  • 0.5uf
  • 50uf
  • 40nf
  • 500nf
点赞  2016-8-1 11:12
引用: maychang 发表于 2016-8-1 10:43
“是单片机某个脚接电容部分然后让单片机产生脉冲么”
是单片机引脚上产生脉冲,脉冲宽度由单片机定时器 ...

额,我设计电路能力超级弱。。。开始学到现在一直抄别人电路。。。
点赞  2016-8-1 11:16
引用: maychang 发表于 2016-8-1 10:43
“是单片机某个脚接电容部分然后让单片机产生脉冲么”
是单片机引脚上产生脉冲,脉冲宽度由单片机定时器 ...

刚才又捣鼓了半天好像能测一点,不过有误差,而且还有两个档测不了
点赞  2016-8-1 11:17
点赞  2016-8-14 20:27
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复