標(biāo)題: 單片機(jī)頻率計數(shù)器(程序) [打印本頁]
作者: daming 時間: 2014-12-30 15:46
標(biāo)題: 單片機(jī)頻率計數(shù)器(程序)
本帖最后由 daming 于 2014-12-30 15:47 編輯
該程序能實現(xiàn)測量10至3MHZ的TTL信號頻率,液晶顯示4為有效數(shù)字,同時能夠測量脈沖占空比,精度在0.5%左右...
需要硬件支持:C8051F360單片機(jī),鍵盤,液晶顯示器
main()
{
int xdata flag1=0;
float sum1=0,sum2=0;
float xdata sum3[10];
int i;
Init_device();
LCD_REST();
LCD_INIT();
f=0;
f1=0;
while(1)
{
if(flag)
{
if(f>=10&&f<=99) 額,不得不說,取11個數(shù)求平均值確實不好,讀數(shù)不能穩(wěn)定的說....
{
sum2=(jishu[0]+jishu[1]+jishu[2]+jishu[3]+jishu[4]+jishu[5]+jishu[6]+jishu[7]+jishu[8]+jishu[9]+jishu[10])/11;
get_flow(sum2);
LCD_HZ(0x80,TAB_WORD);
LCD_HZ(0x90,F_DISPLOW);
flag=0;
}
else if(f>=100&&f<= 999)
{
get_flowhigh();
LCD_HZ(0x80,TAB_WORD);
LCD_HZ(0x90,F_DISPLOWHIGH);
flag=0;
}
else if (f>=1000&&f<=9999)
{
get_high();
LCD_HZ(0x80,TAB_WORD);
LCD_HZ(0x90,F_DISPHIGH);
flag=0;
}
else if(f>=10000&&f<=99999)
{
get_highone();
LCD_HZ(0x80,TAB_WORD);
LCD_HZ(0x90,F_DISPHIGHONE);
flag=0;
}
else if(f>=100000&&f<=999999)
{
get_highone();
LCD_HZ(0x80,TAB_WORD);
LCD_HZ(0x90,F_DISPHIGHONE); 內(nèi)部數(shù)據(jù)存儲器只有128位,為節(jié)約空間與上個數(shù)組存在同一空間
(內(nèi)部數(shù)據(jù)存儲器空間用完的說...)
flag=0;
}
else
{
get_highthree();
LCD_HZ(0x80,TAB_WORD);
LCD_HZ(0x90,F_DISPHIGHTHREE);
flag=0;
}
}
if((key_num&0xf0)==0)
{
TR0=0;
ET1=1;
TMOD=0x10;
TCON=0x40;
for(i=0;i<10;i++)
{
while(CHUFA==0);
TH1=0;
TL1=0;
f1=0;
TR0=0;
while(CHUFA==1);
while(CHUFA==0);
TR1=1;
while(CHUFA==1);
TR1=0;
m=f1*65536+256*TH1+TL1;
while(CHUFA==0);
TH1=0;
TL1=0;
f1=0;
TR1=0;
while(CHUFA==1);
TR1=1;
while(CHUFA==0);
TR1=0;
f=f1*65536+256*TH1+TL1;
key_num=0xf0;
sum1=m;
sum2=m+f;
sum1=sum1/sum2;
sum3[ i]=sum1;
}
sum2=0;
for(i=0;i<10;i++)
{
sum2=sum2+sum3[ i];
}
sum2=sum2/10;
if(sum2>=0.1&&sum2<=0.40)
{
sum2=sum2-0.07;
}
else if(sum2>0.40&&sum2<=0.44)
{
sum2=sum2-0.04;
} 占空比程序設(shè)計,本想用個中斷來著,試驗不成功簡單的算了
由于每次運行指令要耗費時間,精度不高,故加個實測校準(zhǔn)程序
O(∩_∩)O哈哈~
測評時能達(dá)到0.5%的精度,踩狗屎運了... else if(sum2>0.44&&sum2<=0.55)
{
sum2=sum2-0.02;
}
else if(sum2>0.55&&sum2<=0.63)
{
sum2=sum2+0.03;
}
else sum2=sum2+0.07;
get_f(sum2);
LCD_HZ(0x88,TAB_WORD1);
LCD_HZ(0x98,F_DISP);
flag1=1;
}
if(flag1==1) 讓程序能范圍繼續(xù)測量頻率
{
TMOD=0x51;
CKCON=0;
TCON=0x50;
flag1=0;
}
}
}
作者: daming 時間: 2014-12-30 15:47
頻率計數(shù)器就(3.ASCII液晶輸出函數(shù)):
void get_f(float s1)
{
int term;
term=(int)(s1*10000);
F_DISP[0]=term/1000%10+0x30;
F_DISP[1]=term/100%10+0x30;
F_DISP[2]=0x2E;
F_DISP[3]=term/10%10+0x30;
F_DISP[4]=term%10+0x30; 占空比(原值一般為0.****)
}
//*******************************************
void get_flow(float s1)
{ int term;
term=(int)(s1*100);
F_DISPLOW[0]=term/1000%10+0x30;
F_DISPLOW[1]=term/100%10+0x30;
F_DISPLOW[2]=0x2E;
F_DISPLOW[3]=term/10%10+0x30;
F_DISPLOW[4]=term%10+0x30; 頻率讀數(shù)輸出顯示(10——99HZ)
}
//********************************************
void get_flowhigh(void)
{
F_DISPLOWHIGH[0]=f/100%10+0x30;
F_DISPLOWHIGH[1]=f/10%10+0x30;
F_DISPLOWHIGH[2]=f%10+0x30;
F_DISPLOWHIGH[3]=0x2E;
F_DISPLOWHIGH[4]=0x30; 頻率讀書輸出顯示(100——999HZ)以下類推...
}
//********************************************
void get_high(void)
{
F_DISPHIGH[0]=f/1000%10+0x30;
F_DISPHIGH[1]=f/100%10+0x30;
F_DISPHIGH[2]=f/10%10+0x30;
F_DISPHIGH[3]=f%10+0x30;
}
//*******************************************
void get_highone(void)
{
if(f>=10000&&f<=99999)
{
F_DISPHIGHONE[0]=f/10000%10+0x30;
F_DISPHIGHONE[1]=f/1000%10+0x30;
F_DISPHIGHONE[2]=0x2E;
F_DISPHIGHONE[3]=f/100%10+0x30;
F_DISPHIGHONE[4]=f/10%10+0x30;
}
else
{ F_DISPHIGHONE[0]=f/100000%10+0x30;
F_DISPHIGHONE[1]=f/10000%10+0x30;
F_DISPHIGHONE[2]=f/1000%10+0x30;
F_DISPHIGHONE[3]=0x2E;
F_DISPHIGHONE[4]=f/100%10+0x30;
}
}
//******************************************
void get_highthree(void)
{
F_DISPHIGHTHREE[0]=f/1000000%10+0x30;
F_DISPHIGHTHREE[1]=0x2E;
F_DISPHIGHTHREE[2]=f/100000%10+0x30;
F_DISPHIGHTHREE[3]=f/10000%10+0x30;
F_DISPHIGHTHREE[4]=f/1000%10+0x30;
}
作者: daming 時間: 2014-12-30 15:48
頻率計數(shù)器(2.初始化及中斷):
void PCA_INIT(void)
{
PCA0CN=0X40; //允許PCA計數(shù)器、定時器
PCA0MD=0; //禁止看門狗定時器
}
//***********************************************
void INT_INIT(void)
{
EX0=1; //INIT0,鍵盤
PX0=0; //INT0為低優(yōu)先級
ET0=1; //T0
ET1=1; //T1
ET2=0; //T2
EIE1=0X0; //0X08,允許ADC中斷
ES0=0; //uart
EA=1;
}
//**************************************************
void Init_device(void)
{
OSC_INIT();
IO_INIT();
XRAM_INIT();
SMB_INIT();
UART_INIT();
DAC_INIT();
ADC_INIT();
INT0_INIT();
TIMER_INIT();
PCA_INIT();
INT_INIT();
}
//**************************************************
void LCD_REST(void)
{
int i;
LCD_RST=0;
for(i=0;i<255;i++);
LCD_RST=1;
}
//********************************************************
void LCD_WC(unsigned char command) //LCD寫命令
{
while(RCOMADDR&0X80);
WCOMADDR=command;
}
//********************************************************
void LCD_INIT(void) //LCD初始化
{
LCD_WC(0X30); //設(shè)為基本命令集
LCD_WC(0X01);
LCD_WC(0X02); //將DDRAM填滿20H,并設(shè)定DDRAM地址計數(shù)器為0
LCD_WC(0X0C); //開整體顯示
}
//***********************************************************
void LCD_WD(unsigned char d) //LCD寫數(shù)據(jù)
{
while(RCOMADDR&0X80);
WDATADDR=d;
}
//**********************************************************
void LCD_HZ(unsigned char x,unsigned char temp[]) //顯示一行字符
{
int i=0;
LCD_WC(x); //x代表位置,=0x80對應(yīng)左上角
while(temp[i]!=0)
{
LCD_WD(temp[i]);
i++;
}
}
//********************************************************
void LCD_BYTE(unsigned char x,unsigned char temp) //顯示一行字符
{
LCD_WC(x); //x代表位置,=0x80對應(yīng)左上角
LCD_WD(temp);
}
//*********************************************************
void LCD_CLR(void) //LCD清屏
{
LCD_WC(0X01);
}
//********************************************************
void KEY_INIT0(void) interrupt 0
{
key_num=KEYCS&0x0f;
}
//*****T0中斷服務(wù)***************************************
void TT0_INT0(void) interrupt 1
{
int j=0;
TL0=0x66; //0Xb0;
TH0=0x3d; //0X3c;每單位0.5微秒*50000*40
擦,難道上次精度不夠是因為參數(shù)還沒改正確?
fp--;
if(fp) return;
TR1=0;
fp=T_C; //1s
f=65536*f1+256*TH1+TL1;
if(n==0)
{
jishu[n%11]=f;
}
else
{
if(abs(jishu[n%11-1]-f)>=10)
{
for(j=0;j<=10;j++)
{
jishu[j]=f;
}
}
else
{
jishu[n%11]=f;
}
}
n++;
flag=1;
TH1=0;
TL1=0;
f1=0;
TR1=1;
}
//******************************************
void TT1_INT1(void ) interrupt 3
{
f1++; 定時器中斷3,當(dāng)計數(shù)器有溢出時會引發(fā)中斷
}
作者: daming 時間: 2014-12-30 15:49
頻率計數(shù)器(1.液晶初始及鍵盤等):
#define WDATADDR XBYTE[0XC009] //LCD寫數(shù)據(jù)地址
#define RDATADDR XBYTE[0XC00B] //LCD讀數(shù)據(jù)地址
#define WCOMADDR XBYTE[0XC008] //LCD寫命令地址
#define RCOMADDR XBYTE[0XC00A] //LCD讀命令地址
#define KEYCS XBYTE[0XC00C] //鍵盤片選地址
#define T_C 40
sbit LCD_RST=P3^0;
sbit CHUFA=P0^6;
unsigned char code TAB_WORD[]={"Frequency="};
unsigned char code TAB_WORD1[]={"DUTY="};
unsigned char F_DISP[]={"00000%"};
unsigned char F_DISPLOW[]={"00000HZ "};
unsigned char F_DISPLOWHIGH[]={"00000HZ "} ;
unsigned char F_DISPHIGH[]={"0000HZ "} ;
unsigned char F_DISPHIGHONE[]={"00000*1kHZ"};
unsigned char F_DISPHIGHTHREE[]={"00000*1MHZ"};
unsigned char jishu[11]={ 0,0,0,0,0,0,0,0,0,0,0}; 低頻采用堆棧求平均值方法,但貌似最終對數(shù)不能穩(wěn)定,難道是因為取11個數(shù)不好?
unsigned long n=0;
unsigned long m=0;
unsigned char fp;
unsigned long f;
unsigned char f1;
bit flag=0;
unsigned char key_num=0xff; //存鍵號
void OSC_INIT (void)
{
SFRPAGE=0X0F;
OSCICL=OSCICL+4;
OSCICN=0XC3;
CLKSEL=0X30;
SFRPAGE=0;
}
//********************************************
void IO_INIT(void)
{
SFRPAGE=0X0F;
P0MDIN=0Xe7;
P0MDOUT=0X83;
P0SKIP=0XF9;
P1MDIN=0XFF;
P1MDOUT=0XFF;
P1SKIP=0XFF;
P2MDIN=0XFE;
P2MDOUT=0XFF;
P2SKIP=0XFF;
P3MDIN=0XFF;
P3MDOUT=0XFF;
P3SKIP=0XF9; //0xfd,增加P3.2作T1輸入
P4MDOUT=0XFF;
XBR0=0X09;
XBR1=0Xe0; //0xc0,增加T1
SFRPAGE=0X0;
}
//********************************************
void XRAM_INIT(void)
{
SFRPAGE=0X0F;
EMI0CF=0X07;
SFRPAGE=0;
}
//********************************************
void SMB_INIT(void)
{
SMB0CF=0XC1;
}
//********************************************
void UART_INIT(void)
{
SCON0=0X0;
//********************************************
void DAC_INIT(void)
{
IDA0CN=0XF2;
}
//********************************************
void ADC_INIT(void)
{
REF0CN=0; //VDD為基準(zhǔn)
AMX0P=0X08; //正端接P20
AMX0N=0X1F; //負(fù)端接GND
ADC0CF=0X2C; //左對齊,轉(zhuǎn)換時鐘2MHZ
ADC0CN=0X80; //寫ADOBUSY啟動AD
}
//********************************************
void INT0_INIT(void)
{
IT01CF=0X05; //P0.5為INT0
IT0=1; //下降沿觸發(fā)
}
//********************************************
void TIMER_INIT(void)
{
TMOD=0x51; //T0、T1方式1,T1計數(shù)方式
CKCON=0; //系統(tǒng)時鐘12分頻
TL0=0x66;
TH0=0x3e;
TL1=0X0;
TH1=0X0; //計數(shù)器清0
fp=T_C;
TMR2CN=0X04; //16位自動重裝
TMR2RLL=0XF0; //10MS
TMR2RLH=0XD8;
TMR3CN=0X0C; //雙8位自動重裝入,系統(tǒng)時鐘1/12
TMR3RLL=0XE0; //定時100us
TMR3RLH=0XFF;
TR0=1;
TR1=1;
}
作者: showmeeh 時間: 2014-12-30 15:59
好 非常好
作者: huangguanhua 時間: 2023-12-13 22:17
daming 發(fā)表于 2014-12-30 15:49
頻率計數(shù)器(1.液晶初始及鍵盤等):
#define WDATADDR XBYTE[0XC009] //LCD寫 ...
夠詳細(xì),值得學(xué)習(xí)
歡迎光臨 (http://www.torrancerestoration.com/bbs/) |
Powered by Discuz! X3.1 |