/********************************************************************************** * ToHo projetc Voltmeter 2011-11-13 电压表(精度约为0.02V) 参考电压取自3.3V IC *P1.1接3.3V 稳压电源,P1.0为输入端 **********************************************************************************/ #include<reg51.h> #include<intrins.h>
/********************************************************************************** * *STC12C5A60S2内置AD转换器特殊功能寄存器功能说明 *和地址定义,P1口用作输入端。 * ***********************************************************************************/
//ADC特殊功能寄存器 sfr ADC_CONTR = 0xBC; sfr ADC_RES = 0xBD; sfr ADC_LOW2 = 0xBE; sfr P1ASF = 0x9D;
//定义ADC_CONTR的运行常数 #define ADC_POWER 0x80 //AD电源控制位(电源开之后要加一个小的延时用以稳定电源)不用时可以关掉节能 #define ADC_FLAG 0x10 //转换结束标志位,用以中断查询,一定要软件清0 #define ADC_START 0x08 //开始转换控制位,置1开始转换,转换结束后为0 #define ADC_SPEEDLL 0x00 //90时钟周期一次 21MHz时约为250KHz(该时钟是CPU内部RC震荡器产生的) #define ADC_SPEEDL 0x20 //180时钟周期 #define ADC_SPEEDH 0x40 //360T #define ADC_SPEEDHH 0x60 //540T
sbit RS=P3^7; sbit RW=P3^6; sbit LCD_E=P2^7; #define uchar unsigned char #define uint unsigned int uchar code daima[10]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};//LCD1602 字符代码 uchar code logo[]="TOHO_Voltmeter By SXL 2011-11 ";//LOGO 显示 uchar code disp[]="The Voltage is :"; unsigned long int m,i; uchar a=1;
/*************************************************************************************
*延时部分 *需精确延时
*************************************************************************************/
/*延时子程序 小于大约 10 us 的延时*/ void delay(uchar x) { uchar a,b; for(a=x;a>0;a--) for(b=17;b>0;b--); }
/*********延时大约1ms ***********/ void delay1(uint x) { uint a,b; for(a=x;a>0;a--) for(b=1700;b>0;b--); }
/********************************************************************************* * *LCD 1602 显示部分 * 含读写驱动程序、初始化程序、时间日期星期温度显示程序、LOGO显示 * *********************************************************************************/ /*LCD1602读状态程序*/ uchar ReadStatusLCD(void) { P0=0xff;//置高用于读取数据 RS=0; RW=1;//RW=1读取 delay(10); LCD_E=0; delay(10); LCD_E=1; while(P0&0x80);//检测忙信号 return(P0); }
/*LCD1602写数据程序*/ void WriteDataLCD(uchar WDLCD) { ReadStatusLCD();//检测忙 P0=WDLCD; RS=1;//RS=1时写入数据 RW=0;//RW=0时写入 delay(10); LCD_E=1;//若晶振速度太高可以在这后加小的延时 delay(10); LCD_E=0; }
/*LCD1602液晶写指令程序*/ void WriteCommandLCD(uchar WCLCD,BuysC) { if(BuysC) ReadStatusLCD();//根据需要检测忙 P0=WCLCD; RS=0; //写指令 RW=0; delay(10); LCD_E=1; delay(10); LCD_E=0; }
/*LCD 1602在指定位置显示一个字符程序*/ void DisplayOneChar(uchar X,uchar Y,uchar DData) { if(Y<2) { Y&=0x01; X&=0xf;//限制X不能大于15,Y不能大于1 if(Y)X|=0x40;//当要显示第二行时地址码+0x40; X|=0x80;//算出指令码 WriteCommandLCD(X,1); WriteDataLCD(DData); } }
/*LOGO 显示*/ void logo1() { uchar a,b; for(b=0;b<2;b++) { for(a=0;a<16;a++) { DisplayOneChar(a,b,logo[a+16*b]); delay1(80); } } delay1(500); } /**************************LCD 1602 初始化程序******************/ void LCD_init(void) { P0=0; WriteCommandLCD(0x38,0);//三次显示模式设置,不检测忙信号 delay(15); WriteCommandLCD(0x38,0); delay(15); WriteCommandLCD(0x38,0); delay(15); WriteCommandLCD(0x38,1);//显示模式设置,开始要求每次检测忙信号 WriteCommandLCD(0x08,1);//关闭显示 WriteCommandLCD(0x01,1);//显示清屏 WriteCommandLCD(0x06,1);//显示光标移动设置 WriteCommandLCD(0x0c,1);//显示开及光标设置 delay(200); }
/**************************ADC初始化程序***********************/ void init_ADC() { P1ASF=0x03; //P1.0作为模拟功能A/D使用 ADC_RES=0; //清ADC转换结果 ADC_CONTR=ADC_POWER|ADC_SPEEDLL|ADC_START|0x01; delay1(5); IE=0xa0; //开AD中断和总中断 }
void main() { uchar a; LCD_init(); logo1(); LCD_init(); for(a=0;a<16;a++) { DisplayOneChar(a,0,disp[a]); } DisplayOneChar(10,1,'V'); DisplayOneChar(7,1,'.'); init_ADC(); while(1); }
/*********************AD中断服务程序**********************/ void ADC_function() interrupt 5 { ADC_CONTR&=!ADC_FLAG; //软件清FLAG标志位 if(a==0) { i=ADC_RES; DisplayOneChar(6,1,daima[(m*i)/256/100]); DisplayOneChar(8,1,daima[((m*i)/256/10)%10]); DisplayOneChar(9,1,daima[((m*i)/256)%10]); ADC_CONTR&=!ADC_POWER; //关AD电源 delay1(100); } if(a==1) { m=84480/ADC_RES; } a++; if(a>1) a=0; ADC_CONTR=ADC_POWER|ADC_SPEEDLL|ADC_START|a; delay1(5); } |