新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 交直流电压及测频板

交直流电压及测频板

作者: 时间:2012-09-14 来源:网络 收藏
/********关于多周期测频法,精度与晶振和闸门时间有关。晶振越大,闸门时间越长,都可以提高精度。**********/#include stc89c52.h>#include intrins.h>#define uchar  unsigned char#define uint  unsigned int#define LCD12864_IO    P0#define CLERADISPLAY   LCD12864_command(0x01);int a1=0,a2=0,a3=0,a4=0,a5=0,a6=0;//存储电压值的每一位,设计a4,a5是小数位. const uchar num[]="0123456789. ";//AD转换控制脚 sbit  CLK = P1^0; //TLC1543 18Psbit  ADDRESS = P1^1; //17Psbit  SDATA = P1^2; //16Psbit  CS  = P1^3; //15P /********************************************************************/sbit LCD12864_RS=P2^5;  // 12864-st7920 4P RS sbit LCD12864_RW=P2^6;  //RW(5P) sbit LCD12864_EN=P2^7;   //E(6P)    /********************************************************************/void LCD12864_busy(void);void LCD12864_command(unsigned char command);void LCD12864_data(unsigned char dat);void LCD12864_address(unsigned char row,unsigned char line);void LCD12864_string(unsigned char row,unsigned char line,unsigned char *s);void LCD12864_picture(unsigned char *gImage);void LCD12864_init(void);void LCD12864_char (unsigned char row,unsigned char line,unsigned char a);unsigned char LCD12864_ReadData();void LCD12864_Drawpoint(uchar X,uchar Y);void LCD12864_LineX(unsigned char X0, unsigned char X1, unsigned char Y);void LCD12864_LineY( unsigned char X, unsigned char Y0, unsigned char Y1);void LCD12864_DrawPicture( unsigned char code *pic);void clrgdram();/********************************************************************///double DAT[7]={115.0, 115.1, 115.2, 285.0,1500.0, 400.0,3100.0};//       U     V      W      E     N     F   CINT     // 控制脚 sbit CONTRL=P1^7; //测频控制脚 sbit SCANF =P2^0; //键盘扫描控制脚 sbit LED1  =P2^1; //状态显示控制脚1 sbit LED2  =P2^2; //状态显示控制脚2 sbit SHUCHU=P2^3; //继电器输出控制脚 //bit FLAG; //测频标志位bit xunhuanflag;//显示方式标志位 bit outflag; //允许输出标志 bit  eding;//额定状态标志   // 按键存储   bdata uchar key; //键值存储 sbit key0=key^0;//停机    sbit key1=key^1;//启动按钮 sbit key2=key^2; //显示方式(高循环) sbit key3=key^3; //自检    sbit key4=key^4;//灯检   sbit key5=key^5;//复位    sbit key6=key^6;//应急  (高应急)  sbit key7=key^7;//油压(高有油压)    uint t1h,t1l,t2h,t2l;//测频变量 double cnt1,cnt2;double AD; //定义为float 类型,可以防止下面做四则运算时每一步的值超出 范围 unsigned long int  X;/****************************************************************/         uint rd1543(uchar address);//AD转换程序 void voltage(); //电压检测 void init();   //初始化 void zhuansu();   //计算转速 void reset();//测频计数定时复位 uchar scanf(); //键盘扫描 void keychuli();  //按键处理程序 void baohu();void display(unsigned long int sx); //显示函数 void displayFX(unsigned long int sx);/*************************************************************/void delayus(uint);void delayms(uint);void delays(uint m); //延时秒 unsigned char code Bmp019[]={/*------------------------------------------------------------------------------;  若数据乱码,请检查字模格式设置,注意选择正确的取模方向和字节位顺序。;  源文件 / 文字 : C:Documents and SettingsAdministrator桌面888.bmp字模;  宽×高(像素): 128×64;  字模格式/大小 : 单色点阵液晶字模,横向取模,字节正序/1024字节;  数据转换日期  : 2010-7-26 20:46:48------------------------------------------------------------------------------*//****************************0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 上半屏行坐标,表示的是多少列 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 下半屏行坐标,每组8列,每列16位,共128位, 0x800x810x820x83........0x9f    //列坐标,共32个,表示的是行数 ,分两个半屏,每个32行,共64行 //Y坐标 只是用来确定具体坐标,在哪一行    功能:图形模式下,显示(X,Y)点    输入:X(0~127) Y(0~63) 相对屏幕坐标  输出:无点亮某一点的操作步骤: 1.求出水平坐标X对应的地址和是哪一位  0x80-----0x8f  (范围0-15) X/16求地址 X%16求该地址哪一位2.求垂直坐标Y对应的地址和上下半屏  0x80------0x9f(范围0-63) Y本身就是8位地址,Y=63-Y ,Y--(0-31)3.写入行列地址(Y是行X是列),0x80+Y  ,0X80+X/164.读要显示的数据 DAT5.区分上下半屏(X%16=7X%16>=0是上半屏)写入数据每一位 DAT|0x80 ;DAT1注意:这个函数显示某一点时,可能会把上次显示的处于同一地址的其他位的点擦掉,所以先保存所有数据,最后显示,就连贯起来了*******************************//*******************************************************************//**************************************************************///------------------清整个GDRAM空间----------------------------/**************************************************************/void clrgdram(){unsigned char x,y ;for(y=0;y64;y++)for(x=0;x16;x++){LCD12864_command(0x34);LCD12864_command(y+0x80);LCD12864_command(x+0x80);LCD12864_command(0x30);LCD12864_data(0x00);LCD12864_data(0x00);}}/******************************************//*******8==========================================================================功能:图形模式下,显示(X,Y)点    输入:X(0~127) Y(0~63)     输出:无  0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 上半屏行坐标,表示的是多少列,X地址 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 下半屏行坐标,X地址 (水平地址 )     0x80  (垂直地址) 0x810x820x83........0x9f    //列坐标,共32个,表示的是行数 ,分两个半屏,每个32行,共64行 ====================================================================**********/   void LCD12864_Drawpoint(uchar X,uchar Y){uchar i= 0, j = 0,ok=0;uchar temp1 = 0x00,temp2 = 0x00;   LCD12864_command(0x34);  //8位,扩充指令,绘图关 LCD12864_command(0x36);  //8位,扩充指令,绘图开 i = X/16;  //计算出X字节地址(0X80-0X8F) j = X%16;  //计算出该字节的具体位(0-15)       //Y = 63 - Y;if(Y>=0  Y=31)//判断上下半屏 {ok=1;}else if(Y>=32  Y=63)//下半屏{Y = Y - 32;//Y只有0-31共32个 地址 i = i + 8;//X地址进入下半屏 (0X88-0X8F)ok=1;}if(ok){ //读数据操作LCD12864_command(0x80+Y);   //第一步:设置Y坐标,读数据先写地址,写GDRAM时先写垂直地址(0X80-0X9F)LCD12864_command(0x80+i);  //第二步:设置X坐标   LCD12864_ReadData();    //第三步:空读取一次   temp1 =LCD12864_ReadData();    //第四步:读取高字节,先读高字节 temp2 =LCD12864_ReadData();   //第五步:读取低字节    //图形模式下的写数据操作    LCD12864_command(0x80+Y);    //第一步:设置Y坐标  LCD12864_command(0x80+i);   //第二步:设置X坐标  if(j>=0  j=7)   //判断是高字节 {  LCD12864_data(temp1|(0x80>>j));  //第三步:写高字节数据  LCD12864_data(temp2);      //第四步:写低字节数据     }else if(j>7  j=15)   //判断是低字节 {   j = j - 8;  LCD12864_data(temp1);LCD12864_data(temp2|(0x80>>j));  //改变字节里的位   }   }}/******************************************///画线 /********************************************///画水平线void LCD12864_LineX(unsigned char X0, unsigned char X1, unsigned char Y){unsigned char Temp ;if( X0 > X1 ){Temp = X1 ;    //交换X0 X1值  X1 = X0 ;     //大数存入X1X0 = Temp;   //小数存入X0}for( ; X0 = X1 ; X0++ )LCD12864_Drawpoint(X0,Y);}//画垂直线  void LCD12864_LineY( unsigned char X, unsigned char Y0, unsigned char Y1){unsigned char Temp ;if( Y0 > Y1 )//交换大小值 {Temp = Y1 ;Y1 = Y0 ;Y0 = Temp ;}for(; Y0 = Y1 ; Y0++)LCD12864_Drawpoint( X, Y0) ;}/******************************************//**************画图************************/void LCD12864_DrawPicture( unsigned char code *pic){unsigned char i, j, k ;LCD12864_command(0x34);//开扩充指令 LCD12864_command(0x36);//开绘图功能   for( i = 0 ; i  2 ; i++ )//分上下两屏写    {for( j = 0 ; j  32 ; j++)//垂直地址递加 ,行扫方式 {LCD12864_command( 0x80 + j ) ;//写Y坐标(Y的范围: 0X80-0X9F )if( i == 0 ) //写X坐标 {LCD12864_command(0x80);//上半屏 }else{LCD12864_command(0x88);//下半屏开始地址 }for( k = 0 ; k  16 ; k++ ) //写一整行数据 {LCD12864_data( *pic++ );//前面只写入首地址,后面依次写入数据,地址会自动递增  }}}LCD12864_command( 0x30);//恢复到一般模式 }////          初始化设置/*******************************************************************/void LCD12864_init(void){CLERADISPLAY      //  clear DDRAMLCD12864_command(0x30);     //  8 bits unsigned interface,basic instrumentLCD12864_command(0x02);     //  cursor returnLCD12864_command(0x0c);     //  display,cursor onLCD12864_command(0x03);   LCD12864_command(0x06);CLERADISPLAY       //  clear DDRAM}////显示函数void display(unsigned long int sx){a1=sx/100000;a2=sx%100000/10000;a3=sx%10000/1000;//千位 a4=sx%1000/100;//百位 a5=sx%100/10;//十位 a6=sx%10;//个位 LCD12864_command(0x90); //指定显示位置 LCD12864_data(num[a1]); //从最高位开始显示 LCD12864_data(num[a2]);LCD12864_data(num[a3]);LCD12864_data(num[a4]);LCD12864_data(num[a5]);LCD12864_data(num[10]);//小数点 LCD12864_data(num[a6]);}void displayFX(unsigned long int sx){a1=sx/100000;a2=sx%100000/10000;a3=sx%10000/1000;a4=sx%1000/100;a5=sx%100/10;a6=sx%10;LCD12864_command(0x98); //指定显示位置 LCD12864_data(num[a1]); //从最高位开始显示 LCD12864_data(num[a2]);LCD12864_data(num[a3]);LCD12864_data(num[a4]);LCD12864_data(num[a5]);LCD12864_data(num[a6]);}/*********************************主函数入口 /********************************************/ //主函数入口 // main(){uchar ii=0;CONTRL=0;Mcu_init();CLERADISPLAY delays(1);LCD12864_char(1,2,'A');LCD12864_string(1,4,"shaozhanyu");delays(2);clrgdram();CLERADISPLAYdelays(1);clrgdram();delays(1);LCD12864_LineX(8,113,25);clrgdram();CLERADISPLAYdelays(2);clrgdram();LCD12864_LineY(55,29,57);delays(2);clrgdram();delays(1);LCD12864_DrawPicture(Bmp019);delays(3);Mcu_init();CLERADISPLAY LCD12864_string(3,1,"N F U V W E");LCD12864_char(2,1,'D');LCD12864_string(4,1,"计数");LCD12864_string(1,3,"少占鱼做");display(123456); /***************8888P0=0x10;//怠速,准备打开K5继电器,关闭其他输出继电器 SHUCHU=0;//打开输出闸门 SHUCHU=1;//关闭闸门 outflag=0;//输出标志位******************/ AD=0.0;keychuli(); //扫描并处理按键 delayms(5200);///初始化 init();while(1){ while(!FLAG); //等待频率测出 keychuli(); //扫描并处理按键 LCD12864_string(1,3,"开始转换");delayms(300);voltage();  //采样电压 LCD12864_string(1,3,"转换完成");delayms(400);baohu();//判断采样数据保护 for(;ii6;ii++){display(DAT[ii]);LCD12864_string(1,3,"显示下组");delayms(1200);//  keychuli();if(xunhuanflag==0)  //定点 {display(DAT[ii]);break;}}if(ii==6)ii=0;display(DAT[ii]);displayFX(DAT[6]);LCD12864_string(1,3,"下轮复位");delayms(1000);init();}}/*************************************///初始化函数  void init(){  /******T1定时器模式,外部INT1控制开启,T0计数器不允许中断,外部控制INTO开启,外部中断0允许(EX0=1),   定时器T2中断允许 (ET2=1) ************/  CONTRL=0;FLAG=0;EX0=0;ET2=0;//三个定时器方式设置 TMOD=0x9d; //T0T1方式控制    T2MOD=0x00;T2CON=0x00;//定时器2,16位定时方式,自动重装。      TH0= 0x00; // T0高8位TL0= 0x00; // T0低8位TH1= 0x00; // T1高8位TL1= 0x00; // T1低8位EXEN2=0;  TH2=256/256;TL2=256%256; RCAP2H=256/256;RCAP2L=256%256;//中断设置        5EX0=1;//允许外部0输入中断(INT0引脚)ET2=1; //开定时中断2 IT0=1; //外部中断0边沿触发,下降沿到来触发 //优先级设置PX0=1;//预置T0,T1TR1=1;//先允许T1定时,因T1的GATE=1,还要等外部INT1高电平才计数TR0=1;//先允许T0计数 ,同T1一样,等待INTO高电平     TR2=1;//启动T2定时,不用外部控制,直接启动   EA=1; //开全局中断 CONTRL=1;//初始化完成......}/**********************************void reset(){CONTRL=0;FLAG=0;TL0=0x00;TH0=0x00;TL1=0x00;TH1=0x00;TF2=0;TH2=256/256;TL2=256%256;TR1=1;//先允许T1定时,因T1的GATE=1,还要等外部INT1高电平才计数TR0=1;//先允许T0计数 ,同T1一样,等待INTO高电平     TR2=1;//启动T2定时,不用外部控制,直接启动     EA=1; //开全局中断 CONTRL=1;}*******************************///键盘扫描 uchar scanf(){uchar value;P0=0xff;delayms(1);SCANF=0;//打开键扫闸门 value=P0;delayms(2);value=P0;SCANF=1;return  value;}/********************************///键处理 void keychuli(){uchar k;//关于指示灯,交流和频率是一组,直流和其他项是一组 /***************************************//******************/key=scanf();/******************///启动键判断 if(key1==0key7==0DAT[4]==0)//启动位 ,油压和转速为0 {for(k=0;k3;k++)//三次启动循环 {P0=0x04;//准备 输出K6继电器 SHUCHU=0;//打开闸门 delays(3);//隔三秒响应一次停机键    //响应停机键     key=scanf();if(key0==0key7==1DAT[4]>500)//停机开关状态,油压高,转速达到500,其他继电器都停止工作 ,所以 ,P0=0x08 {P0=0x03;//准备 输出K0继电器 SHUCHU=0;//打开输出闸门 SHUCHU=1;//关闭闸门 outflag=0;//输出标志位 }if(key1==0key7==1DAT[4]>430) //每启动一次都判断是否成功,成功直接跳出 break ; //判断启动成功,立即跳出启动for 循环 delays(3);//没有启动成功,继续启动3秒 key=scanf();if(key1==0key0==0key7==1DAT[4]>500)//停机,油压高,转速达到500,其他继电器都停止工作 ,所以 ,P0=0x08 {P0=0x03;//准备 输出K0继电器 SHUCHU=0;//打开输出闸门 SHUCHU=1;//关闭闸门 outflag=0;//输出标志位 }if(key1==0key7==1DAT[4]>430) //每启动一次都判断是否成功,成功直接跳出 break ;delays(3);key=scanf();if(key0==0key7==1DAT[4]>500)//停机,油压高,转速达到500,其他继电器都停止工作 ,所以 ,P0=0x08 {P0=0x03;//准备 输出K0继电器 SHUCHU=0;//打开输出闸门 SHUCHU=1;//关闭闸门 outflag=0;//输出标志位 }if(key1==0key7==1DAT[4]>430) //每启动一次都判断是否成功,成功直接跳出 break ;P0=0x00;//停止启动 SHUCHU=0;SHUCHU=1;delays(9);}//for启动循环结束 SHUCHU=1;//关闭闸门 /**********************///启动失败判断 if(key7==0) //油压低 if(DAT[4]440){P0=0x01;//点亮启动失败灯 LED1=0;//开启573输入 LED1=1;//关闭使能,74HC573锁定状态 outflag=0;//输出标志位清0,表示输出未允许 }}//停机键判断 /********************/if(key0==0key7==1DAT[4]>500)//停机,油压高,转速达到500,其他继电器都停止工作 ,所以 ,P0=0x08 {P0=0x03;//准备 输出K0继电器 SHUCHU=0;//打开输出闸门 SHUCHU=1;//关闭闸门 outflag=0;//输出标志位 }/*****************///应急键判断 if(key6==1)//应急/正常,高电位应急 {eding=1;//应急标志 }else if(key6==0) //进入怠速 {eding=0;//怠速标志 }if(eding==0)//对怠速的处理 {P0=0x08;//怠速,准备打开K5继电器,关闭其他输出继电器 SHUCHU=0;//打开输出闸门 SHUCHU=1;//关闭闸门 outflag=0;}if(eding==1outflag==0)//对额定的处理 {P0=0x00;//额定,准备关闭K5继电器,进入额定,其他继电器都停止工作 ,所以 ,P0=0x00SHUCHU=0;//打开输出闸门 SHUCHU=1;//关闭闸门 delayms(2);if(DAT[0]>110DAT[1]>110DAT[2]>110DAT[5]>390)//三相交流大于110 ,频率大于390 {P0=0x30;//准备合闸(交流,直流 内控制 )   SHUCHU=0;SHUCHU=1;outflag=1;//合闸后,输出标志位置1}}/******************************///循环键 if(key2==1) //处理循环定点显示标志位xunhuanflag=1;else if(key2==0)xunhuanflag=0;/**********保护函数*******************/void baohu(){if(outflag==1){//立即保护值 if((DAT[0]80||DAT[1]80||DAT[2]80) || (DAT[0]>180||DAT[1]>180||DAT[2]>180) || DAT[5]>445||DAT[5]320)//立即断闸保护 {{P0=0x00;//准备断闸(交流,直流 内控制 )   SHUCHU=0;SHUCHU=1;outflag=1;//合闸后,输出标志位清0 }if((DAT[0]>180||DAT[1]>180||DAT[2]>180)DAT[5]>445){P0=0x05;/*******************************///转速计算  ,频率计算 void zhuansu(){t1h=TH0;t1l=TL0;t2h=TH1;t2l=TL1;cnt1=t1l+(t1h8);cnt2=t2l+(t2h8);DAT[6]=cnt1/cnt2*1000000.200;//计数值 DAT[4]=cnt1/cnt2*1000000.200/124.00*600.00; //计算转速,信号频率就是计数频率的整数倍   ,这里这样写是怕cnt1 cnt2 超出范围 //注意这里: cnt1 cnt2  的类型不能是 uint 否则第一步计算除法会得0 , 如果你要先乘1000000.0,也不行。因为超出了uint 范围 DAT[5]=DAT[4]*16.00/60.000;//电压频率计算 }/******************************///外部中断0,调用转速计算 void interint0()  interrupt 0 //using **//外部中断0处理      {EA=0;zhuansu();//调用转速函数 FLAG=1;/***注意:因为TO T1是外部引脚控制的,所以,这时外部低电平,自动停止。不用软件停止**/  }     void intertimer2()  interrupt 5 //using **//T2定时中断处理      {  TR2=0;CONTRL=0;//关闭闸门信号   }     /*******************************///AD转换程序 /************************************************///常测数据函数 void voltage() //电压测量 {uchar i;AD=0.00;X=0;for(i=0;i20;i++){AD+=rd1543(0x08); //读取AD值 }//AD=AD/20;X=AD*46.0001*50.00/1023.00;//转换成电压值 ,分辨率是10位 DAT[0]=X;AD=0.00;delayus(2);//for(i=0;i20;i++){AD+=rd1543(0x08); //读取AD值 }//AD=AD/20;X=AD*46.0001*50.00/1023.00;//转换成电压值 ,分辨率是10位 DAT[1]=X;//AD=0.00;delayus(2);//for(i=0;i20;i++){AD+=rd1543(0x08); //读取AD值 }//AD=AD/20;X=AD*46.0001*50.00/1023.00;//转换成电压值 ,分辨率是10位 DAT[2]=X;//AD=0.00;delayus(2);///*********for(i=0;i20;i++){AD+=rd1543(0x07); //读取AD值 }//AD=AD/20;X=AD*50.000/1023.000*28.500/4.000;DAT[3]=X;//**********/}/***********************************************///TLC1543输入模拟电压范围: 0-4.9152 V //TLC1543AD 10个时钟方式  方式1 。 LC1543 有四位精度 。  输入 0.0024v 时,AD值为0000000001  //0.0048时,还为1。  0.0072为 2    也就是0.0048 为一个 宽度  0.0048*AD 就是电压值 . uint rd1543(uchar addr){uint date_out=0;uchar k;// uchar j;CLK=0;CS=0;ADDRESS=(bit)(addr0x08); //用这种愚蠢的方法比用FOR循环快的多 。 CLK=1;CLK=0;addr=addr*2; //用乘法比用左移快 ADDRESS=(bit)(addr0x08);CLK=1;CLK=0;addr=addr*2; //用乘法比用左移快 ADDRESS=(bit)(addr0x08);CLK=1;CLK=0;addr=addr*2; //用乘法比用左移快 ADDRESS=(bit)(addr0x08);CLK=1;CLK=0;addr=addr*2; //用乘法比用左移快 // for (j=0;j6;j++)     //填充6 个CLOCK     // {CLK=1;CLK=0;   //这里不用循环,省时间 CLK=1;CLK=0;CLK=1;CLK=0;CLK=1;CLK=0;CLK=1;CLK=0;CLK=1;CLK=0;CLK=0;// }CS=1;delayus(8);  //等待AD 转换CS=0;                   for(k=0;k10;k++){SDATA=1;                 //非P0口作为数据总线使用时,读入数据前要赋值1,特别CLK = 1;         //是既用于写有用于读的情况下.date_out=1;if(SDATA) date_out += 1;  //这样写法比下面的方法速度快(5us)// date_out=date_out|SDATA;//用时6US CLK = 0;}return(date_out);}

上一页 1 2 下一页

评论


相关推荐

技术专区

关闭