⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fivet140y.c

📁 kp故障检测仪器键盘显示程序 各个通道显示时间计时
💻 C
📖 第 1 页 / 共 2 页
字号:
/********************************************************************************************************************************
FILE NAME: FIVET38.C
AUTHOR: ZHANG YANG
DATE: 2008.8.18
*********************************************************************************************************************************/
#include<reg52.h>
#include<math.h>

#define LED_SEG P2   //段码控制
#define LED_BIT P0   //位控制
unsigned char code table[16]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6,0x9e,0x02,0x00,0x6e,0x8e,0x9c};//字形表0~9,E,- ,灭,H,F,C
idata unsigned int  time=0;//软件计时
idata unsigned int  period=400;//各个通道显示时间计时
idata unsigned char Tns=0;//n秒计时
idata unsigned char Upper[5],Lower[5];//存储上下限
data unsigned char key4_f=0;//记录按下Key4的次数
data unsigned char CHnum=1;//通道号
idata unsigned Upnum=0,Lonum=0;//记录超过限值的通道数
data unsigned char Vcode[7]={0,0,0,0,0,0,0};//待显示的数字存储数组,第一个和第二个是通道号或函数标志,第三个空,后4个是电压量的有效数字
data unsigned char Dis_dat[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};//待显示的数字的字形,初值全灭

bdata bit  EA_f;//用以保存EA状态
bdata bit  nopt;//空操作位
bdata bit  T2ms=1;//2毫秒计时
bdata bit  T1m=1;//1秒计时间到标记
bdata bit  opAD_flag=1;//是否操作AD7708标志
bdata bit  rdAD=0;//是否读取AD转换结果标志
bdata bit  v2c_flag=0;//是否需要刷新换显示内容
bdata bit  single=0;//单通道显示
bdata bit  circle=1;//循环显示模式标志,正常为1
bdata bit  Adj_Zero=0;//调0模式标记
bdata bit  RomEr=0;//eeprom损坏标志
bdata bit  ModeWait=0;//模式确认等待标志
bdata bit  low_f=0;//显示下限标志
bdata bit  up_f=0;//显示上限标志
bdata bit  Modified=0;//上下限是否有修改标志
bdata bit  Relay1=0;//继电器1是否接通标志
bdata bit  Relay2=0;//继电器2是否接通标志
sbit CS=P1^3;//cs of AD7708
sbit DIN=P1^1;//data in of AD7708
sbit DOUT=P1^2;//data out of AD7708
sbit DRDY=P3^2;//ready of AD7708
sbit SCLOCK=P3^3;//clock of AD7708
sbit EpromW=P3^7;//WP of CAT1161
sbit CATCLK=P3^5;//clock of I2C bus
sbit CATDAT=P3^6;//dat of I2C bus

void dog(void);//喂狗函数
void delay(unsigned int );//延时函数
void wait_delay(void);//等待延时函数
void wait(unsigned int );//等待函数
void writetoreg(unsigned char);//写AD7708寄存器函数
unsigned char readfromreg(void);//读AD7708寄存器
void CTRL_R(float);//继电器控制
float readAD(void);//读AD7708转换结果函数
void initAD(void);//初始化AD7708
void opAD(void);//采集AD7708函数
void disbyte(void);//显示函数
void disperr(void);//eprom不存在或损坏信息显示
void single_disp(void);//单通道显示
void circle_disp(void);//循环显示
float AD2T(float,float *);//AD值转换为浮点数电阻值
void V2CODE(float);//浮点数转换到显示缓存数组
unsigned char ScanKey(void);//扫描键盘函数
void KeyWork(unsigned char);//键盘处理函数
void Key1(void);//K1处理函数
void Key2(void);//K2处理函数
void Key3(void);//K3处理函数
void Key4(void);//K4处理函数
void dislow(void);//显示下限
void disup(void);//显示上限
void sendlim(signed char);//送上(下)限值去显示缓存
void FtoE(float,unsigned char);//存浮点数到EEPROM
float EtoF(unsigned char);//从EEPROM读取浮点数
void mnack(void);//I2C非应答函数
void start(void);//I2C总线开始函数
void stop(void);//I2C总线停止函数
unsigned char erxd(void);//I2C字节接收传送函数
void etxd(unsigned char);//I2C字节写传送函数
unsigned char erd(unsigned char);//I2C字节读函数
void ewr(unsigned char,unsigned char);//I2C字节写函数


void close()//close interrupt
{
  EA_f=EA;
  EA=0;
}

void open()//open interrupt
{EA=EA_f;}

void clock0_init() reentrant using 0//计时器0初始化函数
{
  TCON=0x00;
  TR0=0;
  TH0=0xFC;
  TL0=0x66;//1ms作为基准定时,用模式1,这样1s需要1000个定时过程
  TR0=1;
}


void main() //主函数
{
   data float ADresult=0.0;
   data float Zero[5]={0.0,0.0,0.0,0.0,0.0};//存放0点数值
   idata unsigned char Kcode,i;//Kcode存放按键值


   TMOD=0x01;     //定时器0模式1,
   TH0=0xFC;      //T0定时1ms初始值
   TL0=0x66;

   EpromW=0;//允许CAT1161读写
   initAD();

   ewr(0,0x55);//检查CAT1161的eerom存在否
   wait(10000);
   i=erd(0);//eeprom的0地址存检查信息
   if(i==0x55) //eeprom存在,读取零点值和上下限值
     {
       /*for(i=0;i<5;i++)
          { ewr(21+i,0); wait(10000); }//写下限为0,调试时候用
       for(i=0;i<5;i++)
          { ewr(26+i,100); wait(10000); }//写上限为100 ,调试时候用  */
       for(i=0;i<5;i++)
          Zero[i]=EtoF(i*4+1);//5个零点值的起始地址分别为1,5,9,13,17 ,各占4个字节
       for(i=0;i<5;i++) Lower[i]=erd(21+i);  //读取下限值
       for(i=0;i<5;i++) Upper[i]=erd(26+i);  //读取上限值
       for(i=0;i<5;i++)//若上下限不合理,重写EEPROM
       {
         if(Lower[i]>40||Lower[i]<0)
           { Lower[i]=10;
             ewr(21+i,0);
             wait(10000);
           }
         if(Upper[i]>200||Upper[i]<50)
           { Upper[i]=100;
             ewr(26+i,100);
             wait(10000);
           }
       }

     }
   else {disperr();RomEr=1; }//显示eeprom坏,持续5秒

   IT0=0;//外部中断0为低电平触发
   ET0=1;//打开定时器0中断允许
   EA=1;//开总中断
   TR0=1;//开定时器0
   //EX0=1;//允许外部0中断
  while(1)
  {
   if(!RomEr)
   {
    while(1)
    {
      dog();
        if(opAD_flag&&(!rdAD)){opAD_flag=0;opAD();EX0=1;dog();}//如果操作AD标志为1则去设置AD并开外部0中断

        if(rdAD){

		  ADresult=readAD();  //读取AD转换结果
                  rdAD=0;
                  v2c_flag=1; //刷新显示标志置位
                }
        if(v2c_flag){

		     ADresult=AD2T(ADresult,Zero); //转换成温度
                     close();
                     V2CODE(ADresult);
                     open();
                     CTRL_R(ADresult);
	             v2c_flag=0;
                    }

          close();
          Kcode=ScanKey();//扫描键盘
          open();
	  dog();
          //close();
	  if(Kcode!=0)
             KeyWork(Kcode);//根据键值做对应的处理
          //open();
          if(low_f)
              {dog();dislow();} //显示下限
          if(up_f)
              {dog();disup();}  //显示上限


    }
   }
  }

}

/*初始化AD7708*/
void initAD(void)
{
       idata int tim;
       tim=1000;
  /* PRECONFIGURE...*/
       DRDY=1;

       while(tim--);

       SCLOCK=1;
       DIN=1;
       DOUT=1;
       CS=1;

       writetoreg(0x03); //write to communication register. The next step is writing to FILTER REGISTER
       writetoreg(0x45); //set the FILTER register
       writetoreg(0x07); //write to communication register. The next step is writing to IO REGISTER
       writetoreg(0x30);//IO1和IO2均为输出,初始状态均为0


}

/*采集AD7708函数*/
void opAD()
{
       data unsigned char adcon; //adcon配置AD7708的ADCON寄存器

       switch(CHnum)   //根据通道号,计算ADCON的值,
       {
         case 1: adcon=0x82; break;
         case 2: adcon=0x92; break;
         case 3: adcon=0xa2; break;
         case 4: adcon=0xb2; break;
         case 5: adcon=0xc2; break;
         default: return;
       }
          //确保1~5通道的adcon分别为0x82,0x92,0xa2,0xb2,0xc2,输入范围为-80mV~+80mV,增益为32
       close();
       writetoreg(0x02); //write to communication register. The next step is writing to ADC CONTROLO register
       open();
       close();
       writetoreg(adcon); //bipolar,
       open();
       close();
       writetoreg(0x01);//writing to communication register, the next step is write to MODE register
       open();
       close();
       writetoreg(0x13);//chopping,REFIN1,5 fully-differential input,continuous conversion mode
       open();

}

/*写AD7708寄存器*/
void writetoreg(unsigned char byteword)	 //The subroutine write byteword to the corresponding registers of AD7708
{
  data unsigned char temp;
  idata unsigned char i;

  CS=0;

  temp=0x80;

  for(i=0;i<8;i++)
  {
      if((temp&byteword)==0)
           DIN=0;
      else DIN=1;
      SCLOCK=0;
      SCLOCK=1;
      temp=temp>>1;
  }
  CS=1;

}


/*读AD7708转换结果*/
float readAD()
{
        idata unsigned char j;
        data float temp=0.0;
        close();
	writetoreg(0x44);//write to communication register.The next step is reading data from ADC Data register
        open();
        close();
	CS=0;
        for(j=0;j<16;j++)
     	{
           SCLOCK=0;
	   SCLOCK=1;
           if(DOUT==1) temp+=pow(2,15-j);
         }
         CS=1;
         open();
         return(temp);
}

/*根据转换公式把AD转换结果转换为电阻值并减去对应的0点值*/
float AD2T(float ADresult,float Zero[])
{
  data float result=0.0;
  close();
  result=(ADresult/32768-1)*2.56/32;   //电压量
  open();
  close();
  result=(488.7+362*result)/(1.35-result)-270;   //电阻值
  open();
  close();
  if(result>=100)//电阻值大于等于100,温度高于或等于0度,用下面算法
  {
    result=0.0000175926203204-0.0000000232*result;
    result=sqrt(result);
    result=fabs(result);
    result=0.00390802-result;
    result=result/0.00000116;
   }
  else result=0;//否则另温度显示为0(以后加入0度以下的算法)
  open();
  close();
  if(Adj_Zero) //如果是调0模式,记录0值并写入eeprom
  {
        Zero[CHnum-1]=result;
	FtoE(result,(CHnum-1)*4+1);//把0点值写入EEPROM,每个浮点数为32位,CAT1161为8位,
	                         //故要占4个地址,每个0点值的起始地址分别为1,5,9,13,17

  }
  else
  {
    if(result>Zero[CHnum-1]) result-=Zero[CHnum-1];//如果转换结果比0点值大,则减去0点值
    else result=0.0;                               //否则,认为结果为0
  }
  open();
  return(result);
}

/*显示*/
void disbyte()
{
  data unsigned char i;
  for(i=0;i<7;i++)
  {
    LED_SEG=0x00;//全灭
    LED_BIT=0x00;
    LED_BIT=(0x40>>i); //P0位选,选通第N个数码管7654321的顺序,P0.6~P0.0
    LED_SEG=Dis_dat[i];//从P2口输出字形码
    delay(1);
  }
  LED_SEG=0x00;//全灭
}

/*循环显示控制*/
void circle_disp()
{
  CHnum++;
  if(CHnum>5)
   { CHnum=1;
     if(Adj_Zero) Adj_Zero=0;//如果在调零模式下,CHnum到了5以后,退出调零模式
   }
  opAD_flag=1;

}

/*单通道显示控制*/
void single_disp()
{
   opAD_flag=1;  //一秒钟采集一次
}

/*浮点数转换到显示缓存数组*/
void V2CODE(float value)
{
  data int Vtemp;
  idata unsigned char i;
  idata unsigned char DotId,Num=0;//DotId记录小数点位置Num记录无效的0的个数

    if(Adj_Zero) //调0模式
    {
      Vcode[0]=15;//"C"给DS7
      Vcode[1]=CHnum;//通道号,给DS6
    }
    else//测量模式
    {
      Vcode[0]=CHnum;//通道号,给DS7
      Vcode[1]=12;//灭,给DS6
    }


  if(value<1.0) {DotId=3; value=floor(value*1000);Vtemp=(int)value;}//0.001<=value<1.0,小数点在DS4上,即Vcode[3]
  else
    {
         for(i=1;i<4;i++)
		     if(value<pow(10,i))
			    {
				  //Vtemp=(int)(value*pow(10,4-i));//取整
				  value=floor(value*pow(10,4-i));
				  Vtemp=(int)value;
				  DotId=i+2;
                  break;
				}
    }

     for(i=0;i<3;i++)//把后面无效的0(最多3个)消去,并移动小数点,对应有几个无效的0,前面就有几个LED灭
	 {
	  if((Vtemp%10)==0) { DotId++;Num++;Vtemp=Vtemp/10;Vcode[3+i]=12;}
	  else break;
	 }
     for(i=6;i>2+Num;i--)//Vcode[6]放数值最低位,Vcode[3]放最高位
     {
	   Vcode[i]=Vtemp%10;
       Vtemp=Vtemp/10;
     }


    for(i=0;i<7;i++)
    {
       Dis_dat[i]=table[Vcode[i]];   //转换成字形并放入DiCATDAT[]数组
       if(i==DotId&&DotId!=6) {Dis_dat[i]|=0x01;}//加小数点,如果DotId==6说明小数点在DS1上,不加
    }

}

/*扫描键盘*/
unsigned char ScanKey(void)//P1.7--K4, P1.6--K3, P1.5--K2, P1.4--K1
{
  idata int t=8000;
  idata unsigned char a,b,c,i,K;
  //TR0=0;
  //ET0=0;//扫描键盘时候停止T0计数并关闭T0中断
  P1=P1|0xf0;//先给P1.7 P1.6 P1.5 P1.4置位
  a=P1;//读P1端口
  if((a&0xf0)!=0xf0) while(t--);//有键按下,延时,看是否抖动

  a=P1;//再读一次P1端口
  if((a&0xf0)!=0xf0) //确实有键按下,
  {
    b=0x80;//从K4(P1.7)开始,向右扫描
    c=0xff;
    for(i=4;i>0;i--)//从K4到K1扫描
    {
      c=a&b;
	  if(c==0) {K=i;break;}//如果扫描到有键按下,记录键值i,停止扫描
      b=b>>1;//右移,扫描下一个
	}
   }
  else K=0;
  //TR0=1;
  //ET0=1;
  return(K); //无键按下,返回0
}

/*根据键值做对应的处理*/
void KeyWork(unsigned char Kcode)
{
  switch(Kcode)
  {
    case 1: {Key1();break;}
    case 2: {Key2();break;}
    case 3: {Key3();break;}
    case 4: {Key4();break;}
  }
  return;
}

/*确认键K1处理函数*/
void Key1()
{
  ModeWait=0;
  Tns=0;
  if(low_f)//如果是在显示下限模式下,则做以下处理
     {
	    if(Modified)//如果下限值有被修改,//将修改过的下限值写入EEPROM
		   {   close();
                       ewr(20+CHnum,Lower[CHnum-1]);
                       //wait(10000);
                       open();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -