单片机: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();//返回错误信息 } }}