- /********************************************************
- 項 目:51單片機頻率計
- 單片機:STC89c52RC
- 元 件:24MHZ晶振、1602液晶、MB506超高頻分頻器、
- 74HC393二進制脈沖計數器、BF998雙刪極場效應管、
- 74HC14施密特觸發器。
- 設計思路:參考網上“diy頻率計”帖子重新整理編程。利
- 用T0做定時器、T2做計數器,在一秒內T2計數脈沖
- 數計算頻率
- 測試信號頻率32MHZ到2.4GHZ時,開關撥到高頻位置,
- 信號經MB506放大分頻再輸入到BF998放大——74HC14整
- 形——74HC393計數后由Q1Q2Q3Q4送到單片機的P14 P15
- P16 P17腳,其中Q4也送到單片機的P1.0腳,從
- 而記錄Q4的脈沖個數,計算出信號頻率。
- 測試信號頻率低于32MHZ時,開關撥到低頻位置,
- 被測試信號不經過MB506直接到BF998放大,后面同上
- 編 程:
- ********************************************************/
- #include<at89x52.h>
- #define uchar unsigned char
- #define uint unsigned int
- unsigned char code table[]="f= M K Hz"; //兆hz 千hz
- unsigned char code table1[]="T= m u ns";//微妙 納秒 皮秒
- unsigned char code table2[]="0123456789";
- sbit lcdrs=P2^7;
- sbit lcdrw=P2^6;
- sbit lcden=P2^5;
- sbit LS393_MR=P1^3;
- sbit k200Hz=P2^0;
- sbit GP=P2^1;
- sbit k=P1^2;
- unsigned int jishu,i;
- unsigned long f=0,T,irtime;
- bit a=0; //標志位,為1表示本次測試結束,可進行下次測試
- /****************以下延時函數******************/
- void yanshi500us(uint x)
- {
- uint y;
-
- for(x;x>0;x--)
- for(y=122;y>0;y--);
- }
- void delay1s(void) //誤差 0us
- {
- unsigned char a,b,c,n;
- for(c=167;c>0;c--)
- for(b=39;b>0;b--)
- for(a=152;a>0;a--);
- for(n=1;n>0;n--);
- }
- //================以下是LCD操作=========================
- void read_busy() /*LCD1602 忙等待*/
- {
- lcdrs = 0;
- lcdrw = 1;
- lcden = 1;
- P0 = 0xff;
- while (P0&0x80);
- lcden = 0;
- }
-
- void lcdrw_com(unsigned char com) //寫命令
- {
- read_busy();
- lcdrw=0;
- lcdrs=0;
- P0=com;
- yanshi500us(1);
- lcden=1;
- yanshi500us(1);
- lcden=0;
- // lcdrs=1;
- yanshi500us(10);
- }
-
- void lcdrw_dat(unsigned char dat) //寫數據
- {
- read_busy();
- lcdrw=0;
- lcdrs=1;
- P0=dat;
- yanshi500us(1);
- lcden=1;
- yanshi500us(2);
- lcden=0;
- // lcdrs=1;
- yanshi500us(10);
- }
- void write_lcd(uchar COM,uchar dat)//向LCD寫一個字
- {
- lcdrw_com(COM);
- lcdrw_dat(dat);
-
- }
-
- void lcdinit()
- {
- yanshi500us(30);
- lcdrw_com(0x38); //設置16*2屏顯,5*7點陣,8位數據接口
- yanshi500us(10);
- lcdrw_com(0x38);
- yanshi500us(10);
- lcdrw_com(0x38);
- yanshi500us(10);
- lcdrw_com(0x08); //關閉顯示
- lcdrw_com(0x01); //清屏
- lcdrw_com(0x06); //讀寫一個字符后指針加一光標加一
- lcdrw_com(0x0c); //開顯示,顯示光標,光標閃爍
-
- for(i=0;i<17;i++)
- {
- lcdrw_dat(table[i]); //寫第一行數據f= M K HZ
- }
-
- lcdrw_com(0x80+0x40); //第二行起始位
- for(i=0;i<16;i++)
- {
- lcdrw_dat(table1[i]); //寫第二行數據T= u n ps
- }
-
- }
- /*******************定時器0中斷服務函數**********************/
- void tim0_isr (void) interrupt 1 using 1//定時器0中斷服務函數
- {
- unsigned int fl;
- float ff; //用于計算帶小數點的頻率
- irtime++; //用于計數2個下降沿之間的時間
- if(k200Hz==0)
- {
- if(jishu==2)
- {
- TR0=0;
- TR2=0;
- ff=4000000.00/((irtime)*25); //精確到小數點后兩位
- f=ff*100; //使000.00類型的小數變為00000整數,
- //從而容易分解個十百整數及小數點后兩位小數
- // f=4*f;
-
- if(irtime==0)
- {
- f=0;T=0;
- }
- else
- T=(1000000000/ff); //周期ns
- a=1;
- delay1s();
- }
- }
- else
- {
- if(irtime==20000) //計時夠2秒
- {
- fl=P1>>4; //少于16個脈沖的脈沖數
- TR2=0; //關計數器2
- TR0=0; //關定時器0
- irtime=0;
-
- fl=P1>>4; //少于16個脈沖的脈沖數
- f=((jishu*65536+(TH2*256+TL2))*16+fl)/2;//2秒內總脈沖數即頻率
- if(GP==0)
- {
- f=2*f*64;
- }
- else
- f=2*f;
- if(f==0)
- T=0;
- else //下載時使用6T模式
- T=1000000000/f; //周期ns
- a=1;
- }
- }
- }
- void TIM0init(void)//定時器0初始化
- {
- TMOD=0x02;//定時器0工作方式2,8位初值自動重裝,TH0是重裝值,TL0是初值
- ET0=1; //開中斷
-
- if(k200Hz==0)
- {
- TH0=0xce;//初始值
- TL0=0xce;//自動重裝值,定時25um
- TR2=1; //開計數器2
- TR0=0; //關定時器0
- }
- else
- {
- TH0=0x38;//初始值
- TL0=0x38;//自動重裝值,定時100um
- TR2=1; //開計數器2
- TR0=1; //開定時器0
- }
- }
-
- /*******************T2計數器初始化***********************/
- void t2Init(void) //t2初始化
- {
- TR2=0; //停止計數器2
- T2CON=0x2; //計數器
- T2MOD=0x00;
-
- if(k200Hz==0)
- {
- RCAP2H=0xff;
- RCAP2L=0xfe; // 自動重裝,接收1個脈沖中斷
- }
- else
- {
- RCAP2H=0x0;
- RCAP2L=0x0; // 自動重裝,接收65536個脈沖中斷
- }
- TH2=RCAP2H;
- TL2=RCAP2L; //定時器2賦初值
- EA=1; //開總中斷
- ET2=1; // 開外定時器2中斷
- }
- /*********************T2計數器***************************/
- void timer2() interrupt 5
- {
- TF2=0; //!!!注意!!! 定時器2必須由軟件對溢出標志位清零,硬件不能清零,這里與定時器0和定時器1不同!!!
- jishu++;//T2中斷次數,如果k200Hz=0,來一個脈沖中斷一次,否則65536個脈沖中斷一次
- if(k200Hz==0)
- {
- if(jishu==1) //收到第一個脈沖時開啟計時器
- {
- TR0=1;
- }
- }
- }
- /*****************74LS393 復位*******************/
- void LS393_rest()
- {
- LS393_MR=0;
- LS393_MR=1;
- LS393_MR=0;
- }
- void main()
- {
- yanshi500us(100);
- lcdinit();
- t2Init();
- TIM0init();
-
- yanshi500us(100);
- LS393_rest();
- while(1)
- {
- if(k200Hz==0)
- {
- write_lcd(0x80+9,'z');
- write_lcd(0x80+8,'H');
- write_lcd(0x80+5,'.');
- write_lcd(0x80+10,' ');
- write_lcd(0x80+14,' ');
- write_lcd(0x80+15,' ');
-
- write_lcd(0x80+2,table2[f%100000/10000]);
- write_lcd(0x80+3,table2[f%10000/1000]);
- write_lcd(0x80+4,table2[f%1000/100]);
- write_lcd(0x80+6,table2[f%100/10]);
- write_lcd(0x80+7,table2[f%10]);
- delay1s();
-
- }
- /********************以下顯示頻率*********************/
- else
- {
- write_lcd(0x80+2,table2[f/1000000000]);
- write_lcd(0x80+3,table2[f%1000000000/100000000]);
- write_lcd(0x80+4,table2[f%100000000/10000000]);
- write_lcd(0x80+5,table2[f%10000000/1000000]);
- write_lcd(0x80+7,table2[f%1000000/100000]);
- write_lcd(0x80+8,table2[f%100000/10000]);
- write_lcd(0x80+9,table2[f%10000/1000]);
- write_lcd(0x80+11,table2[f%1000/100]);
- write_lcd(0x80+12,table2[f%100/10]);
- write_lcd(0x80+13,table2[f%10]);
- }
- /**********************以下顯示周期***************************/
- write_lcd(0x80+0x40+2,table2[T/1000000000]);
- write_lcd(0x80+0x40+3,table2[T%1000000000/100000000]);
- write_lcd(0x80+0x40+4,table2[T%100000000/10000000]);
- write_lcd(0x80+0x40+5,table2[T%10000000/1000000]);
- write_lcd(0x80+0x40+7,table2[T%1000000/100000]);
- write_lcd(0x80+0x40+8,table2[T%100000/10000]);
- write_lcd(0x80+0x40+9,table2[T%10000/1000]);
- write_lcd(0x80+0x40+11,table2[T%1000/100]);
- write_lcd(0x80+0x40+12,table2[T%100/10]);
- write_lcd(0x80+0x40+13,table2[T%10]);
- if(a==1)
- {
- a=0;
- jishu=0;
- irtime=0;
- t2Init();
- LS393_rest();
- TIM0init();
- }
- }
- }
復制代碼
|