8051單片機(jī)TLC1549數(shù)據(jù)采集程序源代碼
#i nclude
#i nclude
#i nclude "iic.h"
#define uchar unsigned char
#define uint unsigned int
uint Timer_Pro_Flag=0;//0為顯示處理,1為時序采集處理
sbit TEST_CAP_VOL_CRLT=P1^0;//用于控制外部繼電器
sbit PWM_Pin=P3^7;//PWM輸出
sbit IrDA_in_Pin=P1^0;//紅外脈沖輸入檢測腳
bit PWMFlag=0;
uchar OLD_TH0,OLD_TL0;
#define MAXCMD_LENGTH 7
#define AD_VOL_PER 1.04058 //正常采集時的電壓校準(zhǔn)值
#define AD_Loop_PickVol_PER 1.04058 //CD4051循環(huán)采集時的電壓校準(zhǔn)值
sbit WDTRST=0xA6;//At89S5x看門狗寄存器
sbit ADCLK=P2^0;
sbit ADOUT=P2^1;
sbit ADCS=P2^2;
//--------------------------
/************CD4051---8選1模擬開關(guān)芯片*****************/
/*
|------------------------------------------------------|
| 4 2 1 |
|-----------------------------------------------|------|
|端口 | INH C B A | | |
|------ 7 6 5 4 3 2 1 0 | 正值 | 取反 |
| 通道 |--------------------------------|-------|------|
|------|...............|8 4 2 1 | | |
|------|---------------|----------------|-------|------|
| 0 |0 0 0 0 0 0 0 0 | 0x00 | 0xff |
| 1 |0 0 0 0 0 0 1 0 | 0x02 | 0xf7 |
| 2 |0 0 0 0 0 1 0 0 | 0x04 | 0xfb |
| 3 |0 0 0 0 0 1 1 0 | 0x06 | 0xf3 |
| 4 |0 0 0 0 1 0 0 0 | 0x08 | 0xfd |
| 5 |0 0 0 0 1 0 1 0 | 0x0A | 0xf8 |
| 6 |0 0 0 0 1 1 0 0 | 0x0C | 0xf9 |
| 7 |0 0 0 0 1 1 1 0 | 0x0e | 0xf1 |
|---------------------------------------|-------|------|
*/
uchar CD4051_NUM[]={0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0e}; //0~7編碼
sbit CD4051_A=P1^1;
sbit CD4051_B=P1^2;
sbit CD4051_C=P1^3;
sbit CD4051_INH=P1^4; //CD4051_INH為1時,,所有通導(dǎo)都不導(dǎo)通
bit CD4051_Vol_Conver_Flag=0; //0時為正常采集,1為CD4051循環(huán)采集
//--------------------------
//LED顯示
//--------------------------
uchar LedCount=0;
uchar LED_BIT[5]; //用于顯示的每一位數(shù)據(jù)碼的內(nèi)容
uchar LED_NUM[]={0x00,0x10,0x20,0x40,0x80};//選擇顯示位
//--------------------------------------------------------
void SendByte(unsigned char word)
{
TI=0;
SBUF=word;
while(TI==0);
TI=0;
}
uchar ComBuf[MAXCMD_LENGTH];//用于保存串口的數(shù)據(jù)
/*---少量延時---*/
void delay(uint t)
{
uint i=0;
for(;i<=t;i++);
}
void Pluckdelay(uint t)
{
uint i=0,j;
for(;i<=t;i++)
for(j=1;j<=1000;j++);
}
/*=================================
ComBuf[5]加入CheckSUM校驗(yàn)碼
算法:0x01+not(字節(jié)1+字節(jié)2+...+字節(jié)N)
=================================*/
void SetCheckSUM()
{
ComBuf[5]=0x01+~(ComBuf[0]+ComBuf[1]+ComBuf[2]+ComBuf[3]+ComBuf[4]);
}
/*=============================================================
檢測上位機(jī)發(fā)送來的ComBuf[5]checksum校驗(yàn)碼和計算后的是否相等
正確則返回:1
錯誤則返回:0
==============================================================*/
bit ISCheckSUM()
{
uchar crc;
crc=0x01+~(ComBuf[0]+ComBuf[1]+ComBuf[2]+ComBuf[3]+ComBuf[4]);
if(ComBuf[5]==crc)
return 1;
else
{
ComBuf[1]=crc;//如果錯誤,則返回計算后得到的CHECKSUM校驗(yàn)碼
ComBuf[2]=ComBuf[5];//返回原來上位機(jī)發(fā)送來的CHECKSUM校驗(yàn)碼
return 0;
}
}
/*-----------------------------------
* *
* 等待接收上位機(jī)發(fā)來的指令 *
* *
-------------------------------------*/
void WaitComm()
{
uchar n=0;
RI=0;
while (1)
{
while(!RI);//等接收數(shù)據(jù)
//-----------------
ComBuf[n]=SBUF;
RI=0;
// SBUF=ComBuf[n];
if (ComBuf[n]==0x7e) break;//接收到結(jié)束符則退出
if (n>=MAXCMD_LENGTH)
n=0;//接收10個字節(jié),如果還沒有接收到0x7e結(jié)束符,就重新記錄
else
n++;
}
}
/*-------------------------------
* *
* 發(fā)送combuf數(shù)據(jù)至上位機(jī) *
* *
--------------------------------*/
void SendByteArray()
{
unsigned i;
SetCheckSUM();//加入ComBuf[5]的checkSUM校驗(yàn)碼
ComBuf[4]=P0;//取讀本模塊地址
ComBuf[6]=0x7e;//結(jié)束符
for(i=0;i<=MAXCMD_LENGTH-1;i++)
{
SendByte(ComBuf[i]);
}
}
/*-------------------------------
* *
* 送端口狀態(tài)至上位機(jī) *
* *
--------------------------------*/
void GetP0()
{
switch(ComBuf[2])
{
case 0x00: ComBuf[3]=P0_0; break;
case 0x01: ComBuf[3]=P0_1; break;
case 0x02: ComBuf[3]=P0_2; break;
case 0x03: ComBuf[3]=P0_3; break;
case 0x04: ComBuf[3]=P0_4; break;
case 0x05: ComBuf[3]=P0_5; break;
case 0x06: ComBuf[3]=P0_6; break;
case 0x07: ComBuf[3]=P0_7; break;
default:
ComBuf[3]=P0;//為8時...則以上傳整個port狀態(tài)
}
}
//--------------------
void GetP1()
{
switch(ComBuf[2])
{
case 0x00: ComBuf[3]=P1_0; break;
case 0x01: ComBuf[3]=P1_1; break;
case 0x02: ComBuf[3]=P1_2; break;
case 0x03: ComBuf[3]=P1_3; break;
case 0x04: ComBuf[3]=P1_4; break;
case 0x05: ComBuf[3]=P1_5; break;
case 0x06: ComBuf[3]=P1_6; break;
case 0x07: ComBuf[3]=P1_7; break;
default:
ComBuf[3]=P1;//為8時...則以上傳整個port狀態(tài)
}
}
//---------------
void GetP2()
{
switch(ComBuf[2])
{
case 0x00: ComBuf[3]=P2_0; break;
case 0x01: ComBuf[3]=P2_1; break;
case 0x02: ComBuf[3]=P2_2; break;
case 0x03: ComBuf[3]=P2_3; break;
case 0x04: ComBuf[3]=P2_4; break;
case 0x05: ComBuf[3]=P2_5; break;
case 0x06: ComBuf[3]=P2_6; break;
case 0x07: ComBuf[3]=P2_7; break;
default:
ComBuf[3]=P2;//為8時...則以上傳整個port狀態(tài)
}
}
//--------------
void GetP3()
{
switch(ComBuf[2])
{
case 0x00: ComBuf[3]=P3_0; break;
case 0x01: ComBuf[3]=P3_1; break;
case 0x02: ComBuf[3]=P3_2; break;
case 0x03: ComBuf[3]=P3_3; break;
case 0x04: ComBuf[3]=P3_4; break;
case 0x05: ComBuf[3]=P3_5; break;
case 0x06: ComBuf[3]=P3_6; break;
case 0x07: ComBuf[3]=P3_7; break;
default:
ComBuf[3]=P3;//為8時...則以上傳整個port狀態(tài)
}
}
//-------發(fā)送AT89S5x的指定端口狀態(tài)到上位機(jī)-----
void SendPortData()
{
switch (ComBuf[1])/*Port號*/
{
case 0x00: GetP0(); break;
case 0x01: GetP1(); break;
case 0x02: GetP2(); break;
case 0x03: GetP3(); break;
}
/*--------------------*/
SendByteArray();//發(fā)送數(shù)據(jù)
}
/*-------------------------------
* *
* 各個端口的狀態(tài)設(shè)定 *
* *
--------------------------------*/
void SetP0()
{
switch(ComBuf[2])
{
case 0x00: P0_0=ComBuf[3]; break;
case 0x01: P0_1=ComBuf[3]; break;
case 0x02: P0_2=ComBuf[3]; break;
case 0x03: P0_3=ComBuf[3]; break;
case 0x04: P0_4=ComBuf[3]; break;
case 0x05: P0_5=ComBuf[3]; break;
case 0x06: P0_6=ComBuf[3]; break;
case 0x07: P0_7=ComBuf[3]; break;
default:
P0=ComBuf[3];//為8時...則設(shè)置整個port狀態(tài)
}
}
//=================================
void SetP1()
{
switch(ComBuf[2])
{
case 0x00: P1_0=ComBuf[3]; break;
case 0x01: P1_1=ComBuf[3]; break;
case 0x02: P1_2=ComBuf[3]; break;
case 0x03: P1_3=ComBuf[3]; break;
case 0x04: P1_4=ComBuf[3]; break;
case 0x05: P1_5=ComBuf[3]; break;
case 0x06: P1_6=ComBuf[3]; break;
case 0x07: P1_7=ComBuf[3]; break;
default:
P1=ComBuf[3];//為8時...則設(shè)置整個port狀態(tài)
}
}
//=================================
void SetP2()
{
switch(ComBuf[2])
{
case 0x00: P2_0=ComBuf[3]; break;
case 0x01: P2_1=ComBuf[3]; break;
case 0x02: P2_2=ComBuf[3]; break;
case 0x03: P2_3=ComBuf[3]; break;
case 0x04: P2_4=ComBuf[3]; break;
case 0x05: P2_5=ComBuf[3]; break;
case 0x06: P2_6=ComBuf[3]; break;
case 0x07: P2_7=ComBuf[3]; break;
default:
P2=ComBuf[3];//為8時...則設(shè)置整個port狀態(tài)
}
}
//=================================
void SetP3()
{
switch(ComBuf[2])
{
case 0x00: P3_0=ComBuf[3]; break;
case 0x01: P3_1=ComBuf[3]; break;
case 0x02: P3_2=ComBuf[3]; break;
case 0x03: P3_3=ComBuf[3]; break;
case 0x04: P3_4=ComBuf[3]; break;
case 0x05: P3_5=ComBuf[3]; break;
case 0x06: P3_6=ComBuf[3]; break;
case 0x07: P3_7=ComBuf[3]; break;
default:
P3=ComBuf[3];//為8時...則設(shè)置整個port狀態(tài)
}
}
/*=================================
WritePortData()
按上位機(jī)傳來的格式進(jìn)行端口的設(shè)置
=================================*/
void WritePortData()
{
switch (ComBuf[1])/*Port號*/
{
case 0x00: SetP0(); break;
case 0x01: SetP1(); break;
case 0x02: SetP2(); break;
case 0x03: SetP3(); break;
}
}
/*----------------------------------
* SetEA() *
* *
* 中斷允許設(shè)定,(EA寄存器) *
* ComBuf[1]==>0x00為EA設(shè)定 *
* 0x01為讀取EA值 *
------------------------------------*/
void SetEA()
{
if (ComBuf[1]==0x00)
EA=ComBuf[3];
else
{
ComBuf[3]=EA;
SendByteArray();//發(fā)送數(shù)據(jù)
}
}
/*---------------------------------------------------------------***float型轉(zhuǎn)為2位char型,并發(fā)送至串行**voidConvert_AD_VOL_ValueToChar()***---------------------------------------------------------------*/voidConvert_AD_VOL_ValueToChar(uintvol){floattemp_float_vol;unsignedinttemp;ucharAD_Hight,AD_Low;temp_float_vol=vol*0.0048*AD_VOL_PER;temp=temp_float_vol*100;AD_Hight=temp/100;//取個位數(shù)AD_Low=temp-AD_Hight*100;//取2位小數(shù)ComBuf[2]=AD_Hight;ComBuf[3]=AD_Low;SendByteArray();//發(fā)送數(shù)據(jù)}/*--------------------------------***預(yù)先采集一次AD數(shù)據(jù)****--------------------------------*/voidBefor_Once_AD(){uchari;ADCLK=ADOUT=0;//----------ADCS=0;//開啟控制電路,使能DATAOUT和I/OCLOCKfor(i=1;i<=10;i++){ADCLK=1;ADCLK=0;}ADCS=1;delay(25);//兩次轉(zhuǎn)換間隔大于21us}/*---------------------------------------------------------------*GetAD()TLC1549數(shù)據(jù)采集**sbitADCLK=P2^0;**sbitADOUT=P2^1;**sbitADCS=P2^2;*-----------------------------------------------------------------*/voidGetAD(){uchari=1,w,PickCount;uintvol;Befor_Once_AD();//預(yù)先采集一次AD數(shù)據(jù)//---------------if(ComBuf[1]==0)ComBuf[1]=0x01;PickCount=ComBuf[1];for(w=1;w<=PickCount;w++){ADCLK=ADOUT=0;vol=0;ADCS=0;//開啟控制電路,使能DATAOUT和I/OCLOCKfor(i=1;i<=10;i++){//給一個脈沖ADCLK=1;vol<<=1;if(ADOUT)vol|=0x01;ADCLK=0;}ADCS=1;delay(21);//兩次轉(zhuǎn)換間隔大于21us//---------------ComBuf[1]=w;//發(fā)送第幾次采集的序號Convert_AD_VOL_ValueToChar(vol);//對float轉(zhuǎn)為2位char型,并發(fā)送至串行口P2=0xff;//p2口置初始狀態(tài)}}/*---------------------------------------------------------------***TLC1549數(shù)據(jù)軟件濾波采集***-----------------------------------------------------------------*/voidGetAD_With_VOL_Filter(){uchari,w,j,k,PickCount,AD_Hight=0,AD_Low=0;uintVol=0,VolArray[10],temp;floatSumVol=0;Befor_Once_AD();//預(yù)先采集一次AD數(shù)據(jù)//---------------//---------------PickCount=11;for(w=0;w<=PickCount;w++){ADCLK=ADOUT=0;Vol=0;ADCS=0;//開啟控制電路,使能DATAOUT和I/OCLOCKfor(i=1;i<=10;i++){//給一個脈沖ADCLK=1;Vol<<=1;if(ADOUT)Vol|=0x01;ADCLK=0;}ADCS=1;delay(21);//兩次轉(zhuǎn)換間隔大于21usVolArray[w]=Vol;//保存采集來的數(shù)據(jù)//---------------P2=0xff;//p2口置初始狀態(tài)}//-------按從小到大排序--------//選擇排序法..for(i=0;i<=PickCount-1;i++){k=i;for(j=PickCount+1;jVolArray[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];//累加結(jié)果}SumVol=SumVol/(PickCount-1)*0.0048;//電壓值=平均值*介數(shù)/*------------------------------0時為正常采集,1為CD4051循環(huán)采集因?yàn)镃D4051通道存在電壓消耗,所以和正常的直接采集的校準(zhǔn)值不一樣-------------------------------*//*電壓校準(zhǔn)比*/if(CD4051_Vol_Conver_Flag)SumVol*=AD_Loop_PickVol_PER;//采用CD4051時的電壓校準(zhǔn)值elseSumVol*=AD_VOL_PER;//直接輸入時的電壓校準(zhǔn)值//----------------temp=SumVol*100;//保留2位小位AD_Hight=temp/100;//取個位數(shù)AD_Low=temp-AD_Hight*100;//取2位小數(shù)//ComBuf[1]=w;//發(fā)送第幾次采集的序號ComBuf[2]=AD_Hight;ComBuf[3]=AD_Low;SendByteArray();//發(fā)送數(shù)據(jù)}/*-------------------------------------------------------------------------****CD4051_PickVol...8路選通TLC1549采集****-------------------------------------------------------------------------*/voidCD4051_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采集****-------------------------------------------------------------------------*/voidCD4051_LoopPickVol(){uchari=0,w;w=ComBuf[1]-1;//通導(dǎo)號等于。。。通道數(shù)-1for(;i<=w;i++){ComBuf[1]=i;//通道號CD4051_PickVol();}P1=0xff;//關(guān)閉通道}/*-------------------------------------------------------------------------****電容放電計數(shù)測試**TestCapCount()****-------------------------------------------------------------------------*/voidTestCapCount(){uintVol,TempVol=0xff,Count=0,temp1,temp2;uchari,CAPDELAYTIME;floatTEST_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;//當(dāng)為電容測量時。。下限電壓"}CAPDELAYTIME=ComBuf[3];//延時常量//--------------P1_1=0;//打開LED狀態(tài)指示while(TempVol*0.0048*AD_VOL_PER>=TEST_CAP_OUT_VALUE)//當(dāng)放電到0V時退出{ADCLK=ADOUT=0;Vol=0;ADCS=0;//開啟控制電路,使能DATAOUT和I/OCLOCKfor(i=1;i<=10;i++){//給一個脈沖ADCLK=1;Vol<<=1;if(ADOUT)Vol|=0x01;ADCLK=0;}ADCS=1;delay(21);//兩次轉(zhuǎn)換間隔大于21us//---------------P2=0xff;//p2口置初始狀態(tài)Count++;//計數(shù)ComBuf[0]=0x05;//利用軟件濾波的處理過程顯示if(Count>2)TempVol=Vol;//第一次的取值有可能是1,,去掉不要Convert_AD_VOL_ValueToChar(Vol);//轉(zhuǎn)換并發(fā)送本次數(shù)據(jù)Pluckdelay(CAPDELAYTIME);//采集間隔時間,為ComBuf[4]*1000的時間常數(shù)}//從高到低取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();//發(fā)送數(shù)據(jù)}//--------------------------------------------------------------------------////寫一個字節(jié)到AT24C04EEPROMvoidWriteAT24C04(){ucharaddress,RomData;address=ComBuf[1];RomData=ComBuf[2];WriteByte_24c04(RomData,address);}//讀取AT24C04EEPROM一個字節(jié)voidReadAT24C04(){ComBuf[2]=ReadByte_24c04(ComBuf[1]);SendByteArray();//發(fā)送數(shù)據(jù)}//=================================//看門狗設(shè)置//=================================//voidwatchdog()//{//WDTRST=0x1E;//WDTRST=0xE1;//喂狗指令//}voidSetLedData(){ucharShowData,ShowBit;Timer_Pro_Flag=0;//0為顯示處理,1為時序采集處理ShowBit=ComBuf[1];ShowData=LED_NUM[ShowBit];//選擇位ShowData|=ComBuf[2];//顯示內(nèi)容LED_BIT[ShowBit]=0x00;LED_BIT[ShowBit]=ShowData;TH0=(65536-4000)>>8;TL0=(65536-4000)&0xff;TR0=ComBuf[3];if(ComBuf[3])P0=0x00;//關(guān)閉顯示}/*=========================================PluckPulse----時序采集===========================================*/voidPluckPulse(){Timer_Pro_Flag=1;//0為顯示處理,1為時序采集處理OLD_TH0=ComBuf[2];OLD_TL0=ComBuf[3];TH0=OLD_TH0;TL0=OLD_TL0;TR0=ComBuf[1];//關(guān)閉或啟動計時器}//------------/*=========================================PWM----時序采集===========================================*/voidPWM(){Timer_Pro_Flag=2;//0為顯示處理,1為時序采集處理OLD_TH0=ComBuf[2];OLD_TL0=ComBuf[3];TH0=OLD_TH0;TL0=OLD_TL0;TR0=ComBuf[1];//關(guān)閉或啟動計時器}//------------voidtimer0(void)interrupt1using1{//-------------------switch(Timer_Pro_Flag){case0://LED顯示處理TH0=(0xffff-4000)>>8;TL0=(0xffff-4000)&0xff;if(LedCount>4)LedCount=0;P0=0x00;P0=LED_BIT[LedCount++];break;case1://時序采集TH0=OLD_TH0;TL0=OLD_TL0;SendByte(IrDA_in_Pin);//發(fā)送P1^0引腳狀態(tài)break;case2://模擬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;}}/*===================================================================主程序開始處===================================================================*/voidmain(){//晶振:11.0592,波特率:19200TMOD=0x21;TL1=0xfd;TH1=0xfd;SCON=0xd8;PCON=0x80;//高位為0時不倍頻:9600pbf,1時倍頻:19200bpfTR1=1;//------------------//TMOD=0x01;//工作在定時器方式1,16位計數(shù)器TH0=(65536-4000)/256;TL0=(65536-4000)%256;ET0=1;EA=1;//中斷允許//-------------while(1){WaitComm();//等待接收數(shù)據(jù)//校對checksum校驗(yàn)碼是否正確,如正確則進(jìn)行相關(guān)的操作if(ISCheckSUM()){switch(ComBuf[0]){case0x01:WritePortData();break;//響應(yīng)上位機(jī)發(fā)送的寫操作case0x02:SendPortData();break;//響應(yīng)上位機(jī)發(fā)送的讀操作case0x03:SetEA();break;//中斷允許設(shè)定case0x04:GetAD();break;//TLC1549數(shù)據(jù)采集case0x05:GetAD_With_VOL_Filter();break;//采軟件濾軟件的TLC1549數(shù)據(jù)采集case0x06:CD4051_PickVol();break;//CD4051--8選1TLC1549采集case0x07:CD4051_LoopPickVol();break;//8路巡檢TLC1549采集case0x08:ReadAT24C04();break;//讀取AT24C04EEPROM一個字節(jié)case0x09:WriteAT24C04();break;//寫一個字節(jié)到AT24C04EEPROMcase0x0a:SetLedData();break;//設(shè)定顯示的數(shù)據(jù)case0x0b:TestCapCount();break;//電容放電時間計數(shù)測試case0x0c:PluckPulse();break;//時序采集case0x0d:PWM();break;//控制P2_7模擬輸出PWM}}else//如檢驗(yàn)錯誤則返回上位機(jī)錯誤信息{ComBuf[0]=0xFF;SendByteArray();//返回錯誤信息}}}