实验名称:简易数字电压表。(测试范围0——5V,如需加大范围,改变相关数据类型,鉴于STC12C5A60S2内部AD的特性,有相当误差)实验目的:通过STC12C5A60S2自带AD采集外部电压,将采集到的AD值传给LCD12864。单片机上电后如未接入任何电压,将显示上次输入电压实验手段:STC12C5A60S2单片机内部AD、内部EEPROM、LCD12864(ks108控制器,不带字库)、DD900开发板实验原理图:其中P1.0为电压输入端,电压输入引出一根杜邦线即可。(主要接法)(补充接法)说明:DD900开发板在VEE端接的电阻值只匹配他们店自带的12864(不带字库型),实验结果模糊不可见。原因是对比度不够,也就是VO端电压不匹配。实验电路主要参考左图,对VO端、VEE端接法请参考补充接法。实际电路电阻值接50K,事实上可自我调节阻值大小。实验结果:基本完成每个模块的功能。不足之处:现实运用中,电压表测量电压时,如果没有输入的话,电压表应显示为0,本实验结果是未输入时,电压飘忽不定。原因:AD采集数据不稳定的原因是因为未输入时电压输入通道为悬空状态,AD默认为电压不定,所以会出现上述状况。在有电压输入的时候,状况良好,漂移少见。因为加入EEPROM模块,本想把悬空状态给和谐掉。我也尝试两者间不同(悬空的时候变化剧烈,时刻变化,是否可以用程序的方法和谐??),事实上我试了一个程序思路,发现液晶数值即使在稳定状态,也可能不仅仅是前后两次对比的结果,可能是多次的结果,由于液晶显示需要一定的时间,这样的话,只需要隔一定时间保持相同的值与最先采集的值相等即可。本程序采用的是50次AD结果计算平均值,如需更加稳定,可以考虑中值平滑滤波算法。各个子模块介绍:STC12C5A60S2内部自带AD.IO初始化+AD初始化+AD采集开始+关闭AD(AD电源也可不关闭,省电下可考虑)IO初始化:STC12c5a60s2内部AD的八个通道在P1口,上电默认为输入输出准双向口模式。使用AD时要先将IO口设置为AD输入模式。对P1M0/P1M1寄存器进行操作AD初始化:ADC_CONTR(特别要注意的地方是每给ADC_CONTR赋值操作需要4个nop指令)1)对P1口八个口中那个口设置为AD输入通道(可设置为多个通道,但处理时还是一路一路),即对上图ADC_CONTR中CHS2CHS1CHS0进行设置。2)ADC上电。仅仅以为打开AD电源,并没有开始转换。ADC_POWER。3)对结果寄存器REL/RESL清零。4)通过设置SPEED1SPEED0来设置四种不同AD采集的速度。与晶振相关。AD采集开始:设置ADC_START的值为1。ADC-FLAG:ADC中断标志位,如需采用中断方式,AD采集后FLA置1,需软件清零。下面是AD模块程序:/****************************************************************************单片机IO(AD)初始化****************/voidIO_ADinit(){P1M0|=0x01;//设P1_0为开漏模式如:P1_0=#00000000BP1M1|=0x01;ADC_CONTR=0xe0;//设置P1.0为输入AD转换口_nop_();//ADC_CONTR需要四个指令延时_nop_();_nop_();_nop_();}/***************************************************************************AD上电*******************************/voidADC_Power_On(){ADC_CONTR|=0x80;_nop_();_nop_();_nop_();_nop_();//ADC_CONTR需要四个指令延时}/****************************************************************************AD转换获取AD值***********************/voidget_ad_result()//取AD结果函数。{uinti,q=0;for(i=0;i10;i++)//AD转换循环10次取平均值{tp=0;ADC_RES=0;//高八位数据清零,STC12C5A60S2ADC_RESL=0;//低两位清零ADC_CONTR|=0x08;//启动AD转换while(!tp)//判断AD转换是否完成{tp=0x10;tp&=ADC_CONTR;}ADC_CONTR&=0xe7;ad_average_result=ADC_RES;q=q+ad_average_result;}ad_average_result=q/10;}/*****************************************************************************AD转换调用程序*************************/voidADCONVERT(){ADC_Power_On();IO_ADinit();get_ad_result();}STC12C5A60S2内部EEPROM介绍原理:运用ISP/IAP技术将内部FLASH当作EEPROM来用。规格大小:手册上仅有12C560S2,可能漏写A。内部EEPROM存储空间为1K.。注意事项:在进行EEPROM操作时,一般应将EA=0,待数据处理完毕再打开中断。使用:打开IAP、从EEPROM处读数据、写数据、擦除扇区(每进行一次写操作,都要进行擦除)、关闭IAP。IAP_CMD命令中需要变化的只有MS1MS0也就是下图的B1B0;三个操作:读、写、擦。IAP_TRIG:如果用到IAP_CMD这个命令的话,要想它动作,必须给IAP_TRIG赋值如下来触发。IAP_TRIG=0x5A;IAP_TRIG=0xA5;IAP_CONTR:WT2/WT1/WT0三个参数设置。内部EEPROM完成读写擦操作所需时间,根据所接晶振设置。IAPEN;IAPEN=1,允许FLASH编程。在打开IAP的时候要置1;IAPEN=0,不允许FLASH编程。下面是IAP模块程序。/**函数名:Open_IAP*功能描述:允许ISP/IAP*/voidOpen_IAP(void){EA=0;//防止被中断打断IAP_CONTR=0x80;//充许ISP/IAP,系统时钟20MHz时,设置等待时间WT2,WT1,WT0(010)}/**函数名:Close_IAP*功能描述:禁止ISP/IAP*/voidClose_IAP(void){IAP_CONTR=0x00;//禁止ISP/IAPIAP_ADDRH=0xFF;//将IAP操作地址的高八位与低八位移到非本次操作地址处(防止IAP误操作)IAP_ADDRL=0xFF;EA=1;}/**函数名:Read_IAP_Byte*功能描述:从EEPROM指定的单元读取一个字节数据*/uintRead_IAP_Byte(uintaddr){IAP_CMD=0x01;IAP_ADDRH=(addr&0xFF00)8;IAP_ADDRL=addr&0x00FF;IAP_TRIG=0x5A;IAP_TRIG=0xA5;//对IAP_TRIG先写0x5A再写0xA5,ISP/IAP命令才会生效returnIAP_DATA;}/**函数名:Write_IAP_Byte*功能描述:把一个字节数据写入EEPROM指定的单元,写入数据前应先擦除扇区*输入参数:addr:16bit地址;writeVal:要写入的数据*/voidWrite_IAP_Byte(intaddr,uintwriteVal){IAP_CMD=0x02;IAP_ADDRH=(addr&0xFF00)8;IAP_ADDRL=addr&0x00FF;IAP_DATA=writeVal;IAP_TRIG=0x5A;IAP_TRIG=0xA5;//对IAP_TRIG先写0x5A再写0xA5,ISP/IAP命令才会生效}/**函数名:Erase_IAP_Sector*功能描述:擦除扇区,没有字节擦除*输入参数:addr:扇区地址,扇区中任意一个字节地址都是该扇区地址*/voidErase_IAP_Sector(intaddr){IAP_CMD=0x03;IAP_ADDRH=(addr&0xFF00)8;IAP_ADDRL=addr&0x00FF;IAP_TRIG=0x5A;IAP_TRIG=0xA5;//对IAP_TRIG先写0x5A再写0xA5,ISP/IAP命令才会生效}关于12864模块这个模块我就不说了,网上程序一大堆,原理图也有。我遇到的问题是对比度调节(硬件连接不对,上有提到)。如果显示一部分,应该是延时问题。加延时或者减少晶振先验证一下。整个程序的源代码:(有待规范跟完善)#includestc12c5a60s2.h#includeintrins.h#includeabsacc.h#defineucharunsignedchar#defineuintunsignedint#defineLcd_BusP0//MCUP0------LCM#defineDisp_On0x3f//开显示#defineDisp_Off0x3e//关显示#defineCol_Add0x40//列地址#definePage_Add0xb8//页地址#defineStart_Line0xc0//起始页sbitcs1=P2^3;//Masterchipenablesbitcs2=P2^4;//SlavechipenablesbitEnable=P2^2;//modeEnablesinglesbitDi=P2^0;//DataorInstrumentSelectsbitRW=P2^1;//WriteorReadsbitLcd_Rst=P2^5;//Lcmresetunsignedinta,i,j,k;unsignedchartp,p,plus;uintVin,count;uintad_average_result;unsignedcharcodesz0[]={//数字08*16//0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,};unsignedcharcodesz1[]={//数字18*16//0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,};unsignedcharcodesz2[]={//数字28*16//0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,};unsignedcharcodesz3[]={//数字38*16//0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,};unsignedcharcodesz4[]={//数字48*16//0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,};unsignedcharcodesz5[]={//数字58*16//0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,};unsignedcharco