基于单片机的电阻测量设计修改
1.设计目的及其意义
本设计基于单片机和AD 转换器实现电阻的测量。采用ADC0809,实现由模拟电压转换到数字信号,通过单片机系统处理后,由LCD 显示被测量电阻的阻值。测量范围为1Ω~5K Ω,精度大于98%。
2.方案设计
2.1 总体设计思路 本设计包括硬件和软件设计两个部分。模块划分为电压测量(数据采集)、模数转换、阻值显示等子模块。电路结构可划分为:电压测量,电压转换电阻,阻值显示及相关的控制管理软件组成。用户终端完成信息采集、处理、数据传送、显示等功能。
从设计的要求来分析该设计须包含如下结构:电压测量电路,电压转换电路,阻值显示电路、单片机及相关的控制软件组成;它们之间的构成框图如图1总体设计框图所示:
图1 总体设计框图
处理器采用51系列单片机AT89C51。整个系统是在系统软件控制下工作的。当测量一个电阻时,经过电压采集,电压转换为电阻,电阻显示三个部分可以在LCD 上显示该被测电阻的阻值。当被测电阻为100Ω范围以内时,通过开关选择测量量程,再次测量该电阻,以减小误差。
2.2 具体电路模块设计
2.2.1 电压测量的设计
如图2所示为被测电阻电压测量。电压经过已知电阻R1和被测电阻Rx 接到地。通过OUT 输出被测电阻Rx 上的电压。送到ADC0809的IN0口。
图2 被测电阻电压测量图
2.2.2 模数ADC 转换的设计 由电压测量得到的电压经过ADC 模数转换可得到8位的电压值,经过欧姆定律(即电压之比等于电阻之比)可得到被测电阻的阻值的大小。公式如下
本设计用到的R1的阻值为600Ω和300Ω。
由被测电阻得到的电压值经ADC0809的26脚IN0输入,经过内部的AD 转换,在OUT1~7输出数字电压量,经过上述公式的转变,在P2口上的显示的数字量为被测电阻的阻值数字量。如图3所示为被测电阻电压量转换为阻值量。
图3 被测电阻电压量转换为阻值量图
2.2.3 液晶显示电路的设计
经过ADC0809模数转换得到的电阻值数字量,在MCU 的P2口输入,MCU 系统处理后在P0口由LCD1602显示出来该被测电阻的阻值。如图4所示为被测电阻阻值显示。
图4 被测电阻阻值显示图
2.2.4 时钟电路的设计
XTAL1和XTAL2分别为反向放大器的输入和输出。该反向放大器可以配置为片内振荡器。石晶振荡和陶瓷振荡均可采用。如采用外部时钟源驱动器件,XTAL2应不接。
因为一个机器周期含有6个状态周期,而每个状态周期为2个振荡周期,所以一个机器周期共有12个振荡周期,如果外接石英晶体振荡器的振荡频率为12MHZ ,一个振荡周期为1/12us,故而一个机器周期为1us 。如图5所示为时钟电路。
图5 时钟电路图
2.2.5 复位电路的设计
复位方法一般有上电自动复位和外部按键手动复位,单片机在时钟电路工作以后, 在RESET 端持续给出2个机器周期的高电平时就可以完成复位操作[6]。例如使用晶振频率为12MHz 时,则复位信号持续时间应不小于2us 。本设计采用的是外部手动按键复位电路。如图6所示为复位电路。
图6 复位电路图
2.2.6 电源电路的设计 本设计使用USB 接口给电路提供+5V电压。电路中所有的高电平全部接在VCC 端,地接在USB 接口的4号脚上。通电时红灯LED-R 亮。如图7所示为电源电路。
图7 电源电路图
2.2.7 下载电路的设计
本设计使用串口RS232以及烧录芯片MAX232组成的下载电路。MAX232的11和12号脚(R1OUT 、T1IN )与MCU 的10和11号脚(RXD 、TXD )连接,即可向MCU 烧录程序。图8所示为下载电路。
图8 下载电路图
2.3 系统硬件电路的选择及说明 硬件电路的设计见附图示,从以上的分析可知本设计中要用到如下器件:STC89C52RC 、ADC0809转换器、LCD1602、按键等一些单片机外围应用电路,以及单片机的手工复位,单片机电源电路等。其中R3,R6电阻为已知电阻,R4,R5为不同测量精度下的未知电阻,开始工作时可在LCD 上观察到被测电阻的阻值。电路设有2个按键,S1键作为阻值测量精度的选择键,S2键作为电路复位键。
2.4 软件的程序实现
2.4.1主程序工作流程图 按上述工作原理和硬件结构分析可知系统主程序流程图如下图9所示。
图9 主程序工作流程图
3.软件仿真
本设计通过利用Proteus 仿真,将所编写的程序用Keil 软件编译,所仿真原理图见附录二。
本设计所要求达到的目标是测量一个电阻,在误差允许范围内,通过LCD1602显示出该电阻的阻值。测量的部分电阻的阻值如下表1所示。
表1 仿真测量电阻阻值
4.结束语
本设计研究了一种基于单片机技术的电阻测量。由电路知识可以容易测出
一个电阻上的电压,通过欧姆定律又能得到该电阻的阻值。由于测量的电压是模拟量,故用ADC 转换器转换为数字量,再由单片机系统处理即可完成电阻的阻值测量。
由于数字量在数值上是离散的,通过此种方法得到的阻值存在着误差,为了尽可能的减小此误差,在选择已知电阻上,试用了很多电阻。通过大量数据与实际电阻的阻值相比较,以及实验室能提供的电阻,选用了600Ω和300Ω的已知电阻,用不同的量程可以尽可能的减小误差。表1中给出了部分电阻的硬件电路测量结果,从中可以得知,同一电阻,用不同的量程测量得到不同的阻值,存在的误差也很明显。本设计只采用了两种已知电阻,也就是2个量程测量电阻,测量范围从1Ω~5KΩ,精度大于98%。若提高测量精度,只需增加更大的量程,即可完成大电阻的阻值测量。由于硬件电路的连接,元器件不理想等原因,实际测量电阻的阻值与仿真得到的阻值还是有一定误差的。
虽然硬件电路能正常工作,但程序以及元器件的选择不足,使得这次设计并没有达到很好的测量效果,对微欧姆级和K 欧姆级电阻无法测量,还是感到不理想。
通过此次设计,尤其硬件电路的焊接,对单片机系统有了更好的认识。在以后的学习中,会更加注重设计原理与硬件电路的相结合,做好每一个设计,达到理想的要求。
参考文献:
[1] 史翔,张岳涛. 基于AT89C51单片机微电阻测量系统[J]. 甘肃科技,2007年8月
[2] 周瑞景. Proteus在MCS-51&ARM7系统中的应用百例[M]. 北京:电子工业出版社,2006 [3] 李全利. 单片机原理及接口技术[M].2版. 北京:高等教育出版社,2010
[4] 王东峰,王会良. 单片机C 语言应用100例[M].北京:电子工业出版社,2010
[5] 彭伟. 单片机C 语言程序设计实训100例—基于8051+Proteus仿真. 北京:电子工业出版社,2010
附录一 设计编程程序
//*************头文件及宏定义*****************
#include "includes.h" #define TIME0H 0x3C #define TIME0L 0xB0 #define K1 P1_0 #define CLK P1_1
//******************全局变量***************** unsigned char uc_Clock=0; //定时器0中断计数 bit b_DATransform=0;
///>>>>>>>>>>>>>>>>>>>> void vShowRes(unsigned int uiNumber) { unsigned char ucaNumber[4],ucCount;
ucaNumber[0]=uiNumber/1000; //把计算数字的每个位存入数组。 ucaNumber[1]=(uiNumber-1000*(int)ucaNumber[0])/100; ucaNumber[2]=(uiNumber-1000*(int)ucaNumber[0]-100*(int)ucaNumber[1])/10; ucaNumber[3]=uiNumber-1000*(int)ucaNumber[0]-100*(int)ucaNumber[1]-10*(int)ucaNumber[2]; for(ucCount=0;ucCount
//*************************主函数****************************** void main() {
//>>>>>>>>>>>>>>>>>>>>>>>>>>> TMOD=0x21; //定时器0,模式1。定时器1,模式2 TH0=TIME0H; //对定时器0赋初值 TL0=TIME0L;
TH1=0x14; TL1=0x00;
//对定时器1赋初值
TR0=1; //启动定时器0。 ET0=1; //开定时器0中断。 TR1=1; //启动定时器1。 ET1=1; //开定时器1中断。 EA=1; //开总中断 P1=0xFF; vdInitialize();
vWriteCMD(0x80); //写入显示起始地址(第一行第一个位置) vShowChar("Resistance:"); vWriteCMD(0xCD);
vShowChar("(~)"); //显示欧姆符号 while(1)
}
if(b_DATransform==1) { b_DATransform=0; vWriteCMD(0xC4); vShowRes(uiADTransform()); } }
//>>>>>>>>>>>>>>>>>> void Time0() interrupt 1 { if(uc_Clock==0) { uc_Clock=5; b_DATransform=1; } else uc_Clock--; TH0=TIME0H; //恢复定时器0。 TL0=TIME0L; }
void Time1() interrupt 3 { CLK=!CLK; }
//****************************SMC1602驱动程序************************* //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> #include "SMC1602.h"
//>>>>>>>>>>>>>>>>>>>>>>>>> void vWriteCMD(unsigned char ucCommand) { vDelay(); //先延时。 LCDE=1; //然后把LCD改为写入命令状态。 LCDRS=0; LCDRW=0; LCDPORT=ucCommand; //再输出命令。 LCDE=0; //最后执行命令。 }
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> void vWriteData(unsigned char ucData)
vDelay(); LCDE=1; LCDRS=1; LCDRW=0;
//先延时。 //然后把LCD改为写入数据状态。
LCDPORT=ucData; //再输出数据。
LCDE=0; //最后显示数据。 }
void vShowOneChar(unsigned char ucChar) { switch(ucChar) { case ' ': vWriteData(0x20);break; case ':': vWriteData(0x3A);break;
case '(': vWriteData(0x28);break;
case ')': vWriteData(0x29);break; case '0': vWriteData(0x30);break; case '1': vWriteData(0x31);break; case '2': vWriteData(0x32);break; case '3': vWriteData(0x33);break; case '4': vWriteData(0x34);break; case '5': vWriteData(0x35);break; case '6': vWriteData(0x36);break; case '7': vWriteData(0x37);break; case '8': vWriteData(0x38);break; case '9': vWriteData(0x39);break; case 'R': vWriteData(0x52);break; case 'a': vWriteData(0x61);break; case 'c': vWriteData(0x63);break; case 'e': vWriteData(0x65);break; case 'i': vWriteData(0x69);break; case 'n': vWriteData(0x6E);break; case 's': vWriteData(0x73);break; case 't': vWriteData(0x74);break; case '~': vWriteData(0xF4);break; default: break; } }
void vShowChar(unsigned char ucaChar[]) { unsigned char ucCount; for(ucCount=0;;ucCount++)
//显示Ω
{ vShowOneChar(ucaChar[ucCount]); if(ucaChar[ucCount+1]=='\0') break; } }
//>>>>>>>>>>>>>>>>>>>>>>>> void vDelay() { unsigned int uiCount; for(uiCount=0;uiCount
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> #include
#define START P3_4 //ATART,ALE 接口。0->1->0:启动AD 转换。 #define EOC P3_3 //转换完毕由0变1. #define OUTPORT P2 #define K1 P1_0 //AD转换函数,返回转换结果。 //转换结果是3位数 unsigned int uiADTransform() { float uiResult; START=1; //启动AD 转换。 START=0; while(EOC==0); //等待转换结束。 uiResult=OUTPORT; //输入转换结果。 P1=0xFF; if(K1==1) uiResult=uiResult*600/(255-uiResult); //已知电阻为600欧姆,计算未知电阻,测量大电阻,0-9999欧姆 else uiResult=uiResult*300/(255-uiResult); //已知电阻为300欧姆,计算另外的电阻,测量大电阻,0-9999欧姆 return uiResult; }
附录二Proteus 仿真原理图
14
附录三作品实物照片
附录四 部分仿真测量数据