51单片机简易电容测量仪仿真设计( proteus仿真+程序+讲解视频)仿真图proteus7.8及以上
程序编译器:keil 4/keil 5
编程语言:C语言
设计编号:S0039
51单片机最小系统的相关知识
单片机最小系统,或者称为 最小应用系统,是指用最少的元件组成的单片机可以工作的系统。对51系列单片机来说,最小系统一般应该包括:单片机、晶振电路、复位电路。下面给出一个51单片机的最小系统电路图。
复位电路:
一、复位电路的用途:单片机复位电路就好比电脑的重启部分,当电脑在使用中出现死机,按下重启按钮电脑内部的程序从头开始执行。单片机也一样,当单片机系统在运行中,受到环境干扰出现程序跑飞的时候,按下复位按钮内部的程序自动从头开始执行。单片机复位电路如下图:
二、复位电路的工作原理在书本上有介绍,51单片机要复位只需要在第9引脚接个高电平持续2US就可以实现,那这个过程是如何实现的呢?在单片机系统中,系统上电启动的时候复位一次,当按键按下的时候系统再次复位,如果释放后再按下,系统还会复位。所以可以通过按键的断开和闭合在运行的系统中控制其复位。
开机的时候为什么会复位:在电路图中,电容的的大小是10uF,电阻的大小是10k。所以根据公式,可以算出电容充电到电源电压的0.7倍(单片机的电源是5V,所以充电到0.7倍即为3.5V),需要的时间是10K*10UF=0.1S。也就是说在单片机启动的0.1S内,电容两端的电压时在03.5V增加。这个时候10K电阻两端的电压为从51.5V减少(串联电路各处电压之和为总电压)。所以在0.1S内,RST引脚所接收到的电压是5V~1.5V。在5V正常工作的51单片机中小于1.5V的电压信号为低电平信号,而大于1.5V的电压信号为高电平信号。所以在开机0.1S内,单片机系统自动复位(RST引脚接收到的高电平信号时间为0.1S左右)。
按键按下的时候为什么会复位:在单片机启动0.1S后,电容C两端的电压持续充电为5V,这是时候10K电阻两端的电压接近于0V,RST处于低电平所以系统正常工作。当按键按下的时候,开关导通,这个时候电容两端形成了一个回路,电容被短路,所以在按键按下的这个过程中,电容开始释放之前充的电量。随着时间的推移,电容的电压在0.1S内,从5V释放到变为了1.5V,甚至更小。根据串联电路电压为各处之和,这个时候10K电阻两端的电压为3.5V,甚至更大,所以RST引脚又接收到高电平。单片机系统自动复位。
晶振电路:
晶振电路:晶振是晶体振荡器的简称 在电气上它可以等效成一个电容和一个电阻并联再串联一个电容的二端网络 电工学上这个网络有两个谐振点 以频率的高低分其中较低的频率是串联谐振 较高的频率是并联谐振 由于晶体自身的特性致使这两个频率的距离相当的接近 在这个极窄的频率范围内 晶振等效为一个电感 所以只要晶振的两端并联上合适的电容它就会组成并联谐振电路 这个并联谐振电路加到一个负反馈电路中就可以构成正弦波振荡电路 由于晶振等效为电感的频率范围很窄 所以即使其他元件的参数变化很大 这个振荡器的频率也不会有很大的变化
晶振有一个重要的参数 那就是负载电容值 选择与负载电容值相等的并联电容 就可以得到晶振标称的谐振频率
一般的晶振振荡电路都是在一个反相放大器(注意是放大器不是反相器)的两端接入晶振 再有两个电容分别接到晶振的两端 每个电容的另一端再接到地 这两个电容串联的容量值就应该等于负载电容 请注意一般IC的引脚都有等效输入电容 这个不能忽略
一般的晶振的负载电容为15pF或12.5pF 如果再考虑元件引脚的等效输入电容 则两个22pF的电容构成晶振的振荡电路就是比较好的选择
如上图:晶振是给单片机提供工作信号脉冲的 这个脉冲就是单片机的工作速度 比如 12M晶振 单片机工作速度就是每秒12M 当然 单片机的工作频率是有范围的 不能太大 一般24M就不上去了 不然不稳定
晶振与单片机的脚XTAL0和脚XTAL1构成的振荡电路中会产生偕波(也就是不希望存在的其他频率的波) 这个波对电路的影响不大 但会降低电路的时钟振荡器的稳定性 为了电路的稳定性起见 ATMEL公司只是建议在晶振的两引脚处接入两个10pf-50pf的瓷片电容接地来削减偕波对电路的稳定性的影响 所以晶振所配的电容在10pf-50pf之间都可以的 没有什么计算公式
P0口的上拉电阻:
P0口作为I/O口输出的时候时 输出低电平为0 输出高电平为高组态(并非5V,相当于
悬空状态)。也就是说P0 口不能真正的输出高电平,给所接的负载提供电流,因此必须接上拉电阻(一电阻连接到VCC),由电源通过这个上拉电阻给负载提供电流。 由于P0口内部没有上拉电阻,是开漏的,不管它的驱动能力多大,相当于它是没有电源的,需要外部的电路提供,绝大多数情况下P0口是必需加上拉电阻的。
1.一般51单片机的P0口在作为地址/数据复用时不接上拉电阻。
2.作为一般的I/O口时用时,由于内部没有上拉电阻,故要接上上拉电阻!!
3.当p0口用来驱动PNP管子的时候,就不需要上拉电阻,因为此时的低电平有效; 4.当P0口用来驱动NPN管子的时候,就需要上拉电阻的,因为此时只有当P0为1时候,才能够使后级端导通。
31脚EA/Vpp接电源:
STC89C51/52或其他51系列兼容单片机特别注意:对于31脚(EA/Vpp),当接高电平时,单片机在复位后从内部ROM的0000H开始执行,当接低电平时,复位后直接从外部ROM的0000H开始执行,这一点是初学者容易忽略的。
视频
基于51单片机简易电容测量仪仿真设计( proteus仿真+程序+讲解视频)
1.主要功能:
利用51单片机设计一个简易电容测量仪
1.利用51单片机和555芯片构成的多谐振荡电路设计一电容测量电路
2.通过按键切换测量量程,量程由LED指示灯显示,测量数值通过LCD1602显示。
3.量程10pf-500uf
2.仿真
开始仿真
测量300nF 实测数值269nF
测量30uF 实测数值26.85uF
3. 程序
#include <reg52.h>
#include "1602.h"
#include "delay.h"
sbit vo = P3^2; // 用于检测P3.2口的值,计算时间。 计时器0的开与断
sbit tr = P3^7; // 产生一个低电平脉冲
// 超量程提示灯
sbit ledclc = P2^0;
sbit con1 = P1^5; // 用于控制继电器,实现档位选择
sbit con2 = P1^6;
sbit con3 = P1^7;
sbit key1 = P1^0; // 独立按键部分,用于用户选择量程
sbit key2 = P1^1;
sbit key3 = P1^2;
sbit key4 = P1^3;
sbit led1 = P2^1; // 量程提示灯
sbit led2 = P2^2;
sbit led3 = P2^3;
sbit led4 = P2^4;
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 = 1;
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); // 量程太高
ledclc = 0;
}
else if(tw<=100 && ledclc == 1) //量程太低
{
dispchar3(zimu5);
ledclc = 0;
}
else
{
dispchar1(zimu2);
disp(temp);
}
flag = 0;
}
}
}
void timer0() interrupt 1 // 定时器0中断 用于超量程提示
{
ledclc = 0;
}
void exint1 () interrupt 2 // 外部中断0 用于产生低脉冲,启动555定时器
{
unsigned char a;
tr = 1; // tr端一个负脉冲
a = 1;
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 = 0;
con2 = 0;
con3 = 0;
ledclc = 1;
dispchar1(zimu3);
dispchar2(zimu4);
}
}
if(key2 == 0) // b4按下
{
delay_ms(10);
if(key2 == 0)
{
while(key2==0);
R = 2; // 100k 的电阻 量程5nf~ 500nf
con1 = 1;
con2 = 1;
con3 = 0;
ledclc = 1;
dispchar1(zimu3);
dispchar2(zimu4);
}
}
if(key3 == 0) // b5按下
{
delay_ms(10);
if(key3 == 0)
{
while(key3==0);
R = 3;
con1 = 0; // 1k欧姆 的电阻 量程0.5uf ~ 50uf
con2 = 1;
con3 = 1;
ledclc = 1;
dispchar1(zimu3);
dispchar2(zimu4);
}
}
if(key4 == 0) // b6按下
{
delay_ms(10);
if(key4 == 0)
{
while(key4==0);
R = 4;
con1 = 0; // 100欧姆 的电阻 量程50uf ~ 500uf
con2 = 0;
con3 = 1;
ledclc = 1;
dispchar1(zimu3);
dispchar2(zimu4);
}
}
ledlight(R);
}
void ledlight(unsigned char R)
{
if(1 == R)
{
led1 = 1;
led2 = 1;
led3 = 1;
led4 = 0;
}
if(2 == R)
{
led1 = 1;
led2 = 1;
led3 = 0;
led4 = 1;
}
if(3 == R)
{
led1 = 1;
led2 = 0;
led3 = 1;
led4 = 1;
}
if(4 == R)
{
led1 = 0;
led2 = 1;
led3 = 1;
led4 = 1;
}
}
4.百度云分享链接
下载方式见文章开头视频