单片机:At89S52
连接类型:232 |485 接口
校验方式:checksum
开发环境:keil C
/*---------------------------------------------------------------
 *                                                             *
 *         float型转为2位char型,并发送至串行                   *
 *          void Convert_AD_VOL_ValueToChar()                  *     
 *                                                             *
---------------------------------------------------------------*/
void Convert_AD_VOL_ValueToChar(uint vol)
{
  float temp_float_vol;
  unsigned  int temp;
  uchar AD_Hight,AD_Low;
  temp_float_vol=vol*0.0048*AD_VOL_PER;
  temp=temp_float_vol*100;
  AD_Hight=temp /100;//取个位数
  AD_Low=temp-AD_Hight*100;//取2位小数
  ComBuf[2]=AD_Hight;
  ComBuf[3]=AD_Low;
  SendByteArray();//发送数据
}
/*--------------------------------
 *                                * 
 *       预先采集一次AD数据       *
 *                                * 
 *--------------------------------*/
void Befor_Once_AD()
{
  uchar i;
   ADCLK=ADOUT=0;
   //----------
   ADCS=0; //开启控制电路,使能DATA OUT和I/O CLOCK
  for(i=1;i<=10;i++)
  {
   ADCLK=1; 
   ADCLK=0;
  }
  ADCS=1;
  delay(25);//两次转换间隔大于21us
}
/*---------------------------------------------------------------      
 *          GetAD()     TLC1549数据采集                          *
 *  sbit ADCLK=P2^0;                                             *
 *  sbit ADOUT=P2^1;                                             *  
 *  sbit ADCS=P2^2;                                              *   
-----------------------------------------------------------------*/
void GetAD()
{
 uchar i=1,w,PickCount;
 uint vol;
 Befor_Once_AD();//预先采集一次AD数据
//---------------
 if (ComBuf[1]==0)ComBuf[1]=0x01;
 PickCount=ComBuf[1];
 for(w=1;w<=PickCount;w++)
 {
   ADCLK=ADOUT=0;
   vol=0; 
   ADCS=0; //开启控制电路,使能DATA OUT和I/O CLOCK
  for(i=1;i<=10;i++)
  {
  //给一个脉冲
    ADCLK=1;
    vol<<=1; 
    if(ADOUT)vol|=0x01;
    ADCLK=0; 
  }
  ADCS=1;
  delay(21);//两次转换间隔大于21us
  //---------------
  ComBuf[1]=w;//发送第几次采集的序号
  Convert_AD_VOL_ValueToChar(vol);//对float转为2位char型,并发送至串行口
  P2=0xff;//p2口置初始状态
 }
}
/*---------------------------------------------------------------
 *                                                               *
 *                     TLC1549数据软件滤波采集                   *
 *                                                               *
-----------------------------------------------------------------*/
void GetAD_With_VOL_Filter()
{
 uchar i,w,j,k,PickCount,AD_Hight=0,AD_Low=0;
 uint Vol=0,VolArray[10],temp;
 float SumVol=0; 
 Befor_Once_AD();//预先采集一次AD数据
//---------------
//---------------
 PickCount=11;
 for(w=0;w<=PickCount;w++)
 {
   ADCLK=ADOUT=0;
   Vol=0;
   ADCS=0; //开启控制电路,使能DATA OUT和I/O CLOCK
  for(i=1;i<=10;i++)
  {
  //给一个脉冲
    ADCLK=1;
    Vol<<=1; 
    if(ADOUT)Vol|=0x01;
    ADCLK=0; 
  }
  ADCS=1;
  delay(21);//两次转换间隔大于21us
  VolArray[w]=Vol;//保存采集来的数据
 //---------------
  P2=0xff;//p2口置初始状态
 }
//-------按从小到大排序--------
//选择排序法..
 for(i=0;i<=PickCount-1;i++)
 { 
   k=i;
   for(j=PickCount+1;j<i;j++)
   {
     if(VolArray[j]>VolArray[k])k=j;
     if(k!=i)
     {
       temp=VolArray[k];
       VolArray[k]=VolArray[i];
       VolArray[i]=temp;
     }    
   }
 }
//----------累加计算平静均值------------
//乎略最小和最大值
  for(i=1;i<=PickCount-1;i++) 
  {
    SumVol=SumVol+VolArray[i];//累加结果
  }
  SumVol=SumVol/(PickCount-1)*0.0048;//电压值=平均值*介数
 /*------------------------------
  0时为正常采集,1为CD4051循环采集
  因为CD4051通道存在电压消耗,
  所以和正常的直接采集的校准值不一样
 -------------------------------*/
     /*电压校准比*/
if(CD4051_Vol_Conver_Flag)
  SumVol*=AD_Loop_PickVol_PER;//采用CD4051时的电压校准值
else 
  SumVol*=AD_VOL_PER;//直接输入时的电压校准值
//----------------
  temp=SumVol*100;//保留2位小位
  AD_Hight=temp /100;//取个位数
  AD_Low=temp-AD_Hight*100;//取2位小数
//ComBuf[1]=w;//发送第几次采集的序号
  ComBuf[2]=AD_Hight;
  ComBuf[3]=AD_Low;
  SendByteArray();//发送数据
}
/*-------------------------------------------------------------------------*
 *                                                                        *
 *               CD4051_PickVol...8路选通TLC1549采集                       *    
 *                                                                         *
 *-------------------------------------------------------------------------*/
void CD4051_PickVol()
{
  CD4051_Vol_Conver_Flag=1;
  P1=CD4051_NUM[ComBuf[1]];//CD4051通道选通
 // delay(2300);//通道切换时间间隔,避免电路的残余电
  GetAD_With_VOL_Filter();
  CD4051_Vol_Conver_Flag=0;
}
/*-------------------------------------------------------------------------*
 *                                                                        *
 *               CD4051_LoopPickVol()...8路巡检TLC1549采集                 *    
 *                                                                         *
 *-------------------------------------------------------------------------*/
void CD4051_LoopPickVol()
{
  uchar i=0,w;
  w=ComBuf[1]-1;//通导号等于。。。通道数-1
  for(;i<=w;i++)
  { 
    ComBuf[1]=i;//通道号
    CD4051_PickVol();
  }
 P1=0xff;//关闭通道
}
/*-------------------------------------------------------------------------*
 *                                                                        *
 *                   电容放电计数测试                                      *
 *                     TestCapCount()                                      *    
 *                                                                         *
 *-------------------------------------------------------------------------*/
void TestCapCount()
{
  uint Vol,TempVol=0xff,Count=0,temp1,temp2;
 uchar i,CAPDELAYTIME;
 float TEST_CAP_OUT_value="/0.05;
 " P1=CD4051_NUM[1];//CD4051通道选通,1号通道
  TEST_CAP_VOL_CRLT=0;//打开电源
 if (ComBuf[1]==0x00)//为0x00时为电容测量方式,0x01为电压测量方式
 {
  for(i=0;i<=ComBuf[2];i++)delay(60000);//等待电容充电
   TEST_CAP_VOL_CRLT=1;//断开电源
   TEST_CAP_OUT_value="/0.01;//当为电容测量时。。下限电压
 } " 
  CAPDELAYTIME=ComBuf[3];//延时常量 
//--------------
  P1_1=0;//打开LED状态指示
 while(TempVol*0.0048*AD_VOL_PER>=TEST_CAP_OUT_VALUE)//当放电到0V时退出
 {
    ADCLK=ADOUT=0;
    Vol=0;
    ADCS=0; //开启控制电路,使能DATA OUT和I/O CLOCK
    for(i=1;i<=10;i++)
    {
    //给一个脉冲
      ADCLK=1;
      Vol<<=1; 
      if(ADOUT)Vol|=0x01;
      ADCLK=0; 
    }
    ADCS=1;
    delay(21);//两次转换间隔大于21us
   //---------------
    P2=0xff;//p2口置初始状态
    Count++;//计数
    ComBuf[0]=0x05;//利用软件滤波的处理过程显示
    if(Count>2)TempVol=Vol;//第一次的取值有可能是1,,去掉不要
    Convert_AD_VOL_ValueToChar(Vol);//转换并发送本次数据
    Pluckdelay(CAPDELAYTIME);//采集间隔时间,为ComBuf[4]*1000的时间常数
  }
//从高到低取
 P1=0xff;//初始P1口
 ComBuf[0]=0x0b;
 temp1=Count/1000;//取前1-2位
 ComBuf[1]=temp1;
 temp2=Count/10-temp1*100;//得到3-4位
 ComBuf[2]=temp2;
 ComBuf[3]=Count-(temp1*1000+temp2*10);
 SendByteArray();//发送数据
}
//--------------------------------------------------------------------------//
//写一个字节到AT24C04EEPROM 
void WriteAT24C04()           
{
  uchar address,RomData;
  address=ComBuf[1];
  RomData=ComBuf[2];
  WriteByte_24c04(RomData,address);
}
//读取AT24C04EEPROM一个字节
void ReadAT24C04()
{
  ComBuf[2]=ReadByte_24c04(ComBuf[1]);
  SendByteArray();//发送数据
}
//=================================
//         看门狗设置
//=================================
//void watchdog()
//{
//WDTRST=0x1E;
//WDTRST=0xE1;//喂狗指令
//}
void SetLedData()
{
  uchar ShowData,ShowBit;
  Timer_Pro_Flag=0;//0为显示处理,1为时序采集处理
  ShowBit=ComBuf[1];
  ShowData=LED_NUM[ShowBit];//选择位
  ShowData|=ComBuf[2];//显示内容 
  LED_BIT[ShowBit]=0x00;
  LED_BIT[ShowBit]=ShowData;
  TH0=(65536-4000)>>8;
  TL0=(65536-4000)&0xff;
  TR0=ComBuf[3];
  if(ComBuf[3]) P0=0x00;//关闭显示
}
/*=========================================
          PluckPulse----时序采集
===========================================*/
void PluckPulse()
{
  Timer_Pro_Flag=1;//0为显示处理,1为时序采集处理
  OLD_TH0=ComBuf[2];
  OLD_TL0=ComBuf[3];
  TH0=OLD_TH0;
  TL0=OLD_TL0;
  TR0=ComBuf[1];//关闭或启动计时器
}
//------------
/*=========================================
          PWM----时序采集
===========================================*/
void PWM()
{
  Timer_Pro_Flag=2;//0为显示处理,1为时序采集处理
  OLD_TH0=ComBuf[2];
  OLD_TL0=ComBuf[3];
  TH0=OLD_TH0;
  TL0=OLD_TL0;
  TR0=ComBuf[1];//关闭或启动计时器
}
//------------
void timer0(void) interrupt 1 using 1
{
//-------------------
 switch(Timer_Pro_Flag)
 {
 case 0:
        //LED显示处理
        TH0=(0xffff-4000)>>8;
        TL0=(0xffff-4000)&0xff;
  
        if (LedCount>4) LedCount=0;
        P0=0x00;
        P0=LED_BIT[LedCount++];
        break;
 case 1:
        // 时序采集
        TH0=OLD_TH0;
        TL0=OLD_TL0;
        SendByte(IrDA_in_Pin);//发送P1^0引脚状态
        break;
 case 2://模拟PWM输出
       if(!PWMFlag)
       { 
         TH0=OLD_TH0;
         TL0=OLD_TL0;
         TR0=1;
         PWMFlag=1;
         PWM_Pin=0;
       }
       else
       {
         PWM_Pin=1;
         TR0=0;
         TH0=OLD_TH0;
         TL0=OLD_TL0;
         TR0=1;
         PWMFlag=0;
       }      
       break;
 }
}
/*===================================================================
                          主程序开始处
===================================================================*/
void main()
{
//晶振:11.0592,波特率:19200
 TMOD=0x21;
 TL1=0xfd;
 TH1=0xfd;
 SCON=0xd8;
 PCON=0x80;//高位为0时不倍频:9600pbf,1时倍频:19200bpf
 TR1=1;
//------------------
 // TMOD=0x01;//工作在定时器方式1,16位计数器
  TH0=(65536-4000)/256;
  TL0=(65536-4000)%256;
  ET0=1;
  EA=1;//中断允许
 //-------------
 while(1)
 {
  WaitComm();//等待接收数据
  //校对checksum校验码是否正确,如正确则进行相关的操作
  if(ISCheckSUM())
  {
    switch (ComBuf[0])
   {
     case 0x01:WritePortData(); break;       //响应上位机发送的写操作       
     case 0x02:SendPortData(); break;        //响应上位机发送的读操作      
     case 0x03:SetEA();break;                //中断允许设定               
     case 0x04:GetAD();break;                //TLC1549数据采集             
     case 0x05:GetAD_With_VOL_Filter();break;//采软件滤软件的TLC1549数据采集
     case 0x06:CD4051_PickVol();break;       //CD4051--8选1TLC1549采集 
     case 0x07:CD4051_LoopPickVol();break;   //8路巡检TLC1549采集
     case 0x08:ReadAT24C04();break;          //读取AT24C04EEPROM一个字节
     case 0x09:WriteAT24C04();break;         //写一个字节到AT24C04EEPROM 
     case 0x0a:SetLedData();break;           //设定显示的数据
     case 0x0b:TestCapCount();break;         //电容放电时间计数测试
     case 0x0c:PluckPulse();break;           //时序采集
     case 0x0d:PWM();break;                  //控制P2_7模拟输出PWM
    }
  }
  else//如检验错误则返回上位机错误信息
  {
    ComBuf[0]=0xFF;
    SendByteArray();//返回错误信息
  }
 }
}
           畅学电子
畅学电子








