1. 51單片機的數字頻率計
本應用系統設計的目的是通過在「單片機原理及應用」課堂上學習的知識,以及查閱資料,培養一種自學的能力。並且引導一種創新的思維,把學到的知識應用到日常生活當中。在設計的過程中,不斷的學習,思考和同學間的相互討論,運用科學的分析問題的方法解決遇到的困難,掌握單片機系統一般的開發流程,學會對常見問題的處理方法,積累設計系統的經驗,充分發揮教學與實踐的結合。全能提高個人系統開發的綜合能力,開拓了思維,為今後能在相應工作崗位上的工作打下了堅實的基礎。
1.1數字頻率計概述
數字頻率計是計算機、通訊設備、音頻視頻等科研生產領域不可缺少的測量儀器。它是一種用十進制數字顯示被測信號頻率的數字測量儀器。它的基本功能是測量正弦信號,方波信號及其他各種單位時間內變化的物理量。在進行模擬、數字電路的設計、安裝、調試過程中,由於其使用十進制數顯示,測量迅速,精確度高,顯示直觀,經常要用到頻率計。
本數字頻率計將採用定時、計數的方法測量頻率,採用一個1602A LCD顯示器動態顯示6位數。測量范圍從1Hz—10kHz的正弦波、方波、三角波,時基寬度為1us,10us,100us,1ms。用單片機實現自動測量功能。
基本設計原理是直接用十進制數字顯示被測信號頻率的一種測量裝置。它以測量周期的方法對正弦波、方波、三角波的頻率進行自動的測量。
點擊重新載入
1.2頻率測量儀的設計思路與頻率的計算
圖1 頻率測量原理圖
頻率測量儀的設計思路主要是:對信號分頻,測量一個或幾個被測量信號周期中已知標准頻率信號的周期個數,進而測量出該信號頻率的大小,其原理如右圖1所示。
若被測量信號的周期為,分頻數m1,分頻後信號的周期為T,則:T=m1Tx 。由圖可知: T=NTo
(註:To為標准信號的周期,所以T為分頻後信號的周期,則可以算出被測量信號的頻率f。)
由於單片機系統的標准頻率比較穩定,而是系統標准信號頻率的誤差,通常情況下很小;而系統的量化誤差小於1,所以由式T=NTo可知,頻率測量的誤差主要取決於N值的大小,N值越大,誤差越小,測量的精度越高。
1.3 基本設計原理
基本設計原理是直接用十進制數字顯示被測信號頻率的一種測量裝置。它以測量周期的方法對正弦波、方波、三角波的頻率進行自動的測量。
所謂「頻率」,就是周期性信號在單位時間(1s)內
2. 51單片機製作簡易數字頻率計程序
這里有一個四位數碼管的頻率計,供參考
#include<reg52.h>
#defineucharunsignedchar
#defineuintunsignedint
ucharan[10]={0xc0,0Xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //所需的段的位碼
//ucharwei[4]={0XEf,0XDf,0XBf,0X7f};//位的控制端 (開發板)
ucharwei[4]={0X80,0X40,0X20,0X10};//位的控制端 (模擬)
uintz,x,c,v,date; //定義數據類型
uintdispcount=0;
uintlck=0;
uintdisp=0;
/******************************************************************
延時函數
******************************************************************/
voiddelay(uchart)
{
uchari,j;
for(i=0;i<t;i++)
{
for(j=13;j>0;j--);
{;
}
}
}
/**********************************************************************
數碼管動態掃描
*********************************************************************/
voidxianshi()
{
/*****************數據轉換*****************************/
z=date/1000; //求千位
x=date%1000/100; //求百位
c=date%100/10; //求十位
v=date%10; //求個位
P2=wei[0];
P0=an[z];
delay(50);
P2=wei[1];
P0=an[x];
delay(50);
P2=wei[2];
P0=an[c];
delay(50);
P2=wei[3];
P0=an[v];
delay(50);
}
/*************************************************************************
定時器初值1ms
**************************************************************************/
voidinitTimer(void)
{
TMOD=0x0;
TH0=0xe3;
TL0=0xc;
}
/*************************************************************************
定時器函數
**************************************************************************/
voidtimer0(void)interrupt1
{
TH0=0xe3;
TL0=0xc;
lck++;
if(lck==1000)
{
disp=dispcount;
lck=0;
dispcount=0;
}
}
/*************************************************************************
中斷函數
**************************************************************************/
voidint0(void)interrupt0
{
dispcount++;//每一次中斷,計數加一
}
/*************************************************************************
主函數
**************************************************************************/
voidmain(void)
{
IT0=1;//INT0下降沿中斷
EX0=1;//允許INT1中斷
initTimer();//裝入初值
TR0=1;
ET0=1;
EA=1;
while(1)
{
date=disp;
xianshi();
}
}
3. 做用51單片機做一個頻率計,測量范圍為0.1Hz~10kHz
在不改變定時時間的前提下,也就是0.5秒定時,是不能實現0.1~2Hz頻率的測量的。
你所謂2Hz~10KHz易實現也是基於這個道理。但這個也是理論情況。
當你0.5s內剛好檢測到一個脈沖,你認為這個時候是2Hz而不是2.5hz或者3.9hz?
這中間存在一個測量精度的問題。實際上你所測到的信號是在2hz到4hz之間。
實際上我們在測量信號的時候,低頻一般會採用測周期,高頻用測頻才能提高測量的准確性。
至於高低頻的臨界點,跟你的計數頻率有關,感興趣的話可以去看《電子測量原理》。
下面我來講下測周實現的方法,可以使用邊沿觸發的D觸發器輸出作為單片機的外部定時控制,測量信號作為觸發時鍾,計數值作為該信號的周期。
4. 單片機 程序
下面這個是51單片機的頻率計程序,因51單片機內沒有CCP輸入捕捉模塊,軟體用主程序去不停地查詢輸入引用狀態,電平一發生改變就用定時器計時,這樣就計算出了周期、頻率,P0口接8位數碼管的共陰極,如用三個數碼顯示就接高三位,
利用PIC單片機CCP模塊設計頻率計請參照網頁:
http://danpj.com/PICdanpianji/2009/0403/179.html
http://www.700q.com/article/show.asp?id=57467
#include <AT89X51.H>
//********數碼管位代碼表(P0口)**********//
unsigned char code dispbit[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
//********數碼管段代碼表(P2口,共陰且高位接a,低位接h筆段)**********//
unsigned char code dispcode[]={0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,
0xFE,0xF6,0xEE,0x3E,0x9C,0x7A,0x9E,0x8E,0x00};
//********8位數據緩沖器**********//
unsigned char dispbuf[8];
unsigned char temp[8];
unsigned char dispcount;
unsigned char T0count;
unsigned char timecount;
bit flag;
unsigned long x;
//*********初始化模塊**********//
void initial(void){
TMOD=0x15;
TH0=0;
TL0=0;
TH1=(65536-4000)/256;
TL1=(65536-4000)%256;
TR1=0;
TR0=0;
ET0=1;
ET1=1;
EA=1;
}
//******************************************************//
//*********顯示模塊**********//
void dataDisplay(){
unsigned char i;
for(i=0;i<8;i++){
temp[i]=0;
}
i=0;
while(x/10){
temp[i]=x%10;
x=x/10;
i++;
}
temp[i]=x;
for(i=0;i<8;i++){
dispbuf[i]=temp[i];
}
P2=dispcode[dispbuf[dispcount]];
P0=dispbit[dispcount];
dispcount++;
if(dispcount==8){
dispcount=0;
}
}
//******************************************************//
//*********信號頻率測量模塊**********//
float frequency(float freq){
initial();
TR0=1;TR1=1;
if(timecount==250){
TR0=0;
freq=T0count*65536+TH0*256+TL0;
return(freq);
}
}
//******************************************************//
//*********信號周期測量模塊**********//
float cycle(float count){
initial();
if(P3_4==1){
TR0=1;TR1=1;
if(P3_4==0){
TR0=0;
count=1000000/(timecount*4000+TH1*256+TL1-61536);
}
}
return(count);
}
//******************************************************//
//*********定時中斷服務程序1**********//
void t1(void) interrupt 3 using 0{
//initial();
//TR0=1;
//TR1=1;
TH1=(65536-4000)/256;
TL1=(65536-4000)%256;
timecount++;
}
//******************************************************//
//*********定時中斷服務程序2**********//
void t0(void) interrupt 1 using 0{
//initial();
//TR0=1;
//TR1=1;
T0count++;
}
//******************************************************//
//*********主函數**********//
void main(void){
while(1){
x=frequency(x);
if(x<100){
x=cycle(x);
}
dataDisplay();
}
}
//******************************************************//
5. 51單片機頻率計的中斷程序怎麼設計
定時器11MS中斷一次,5次是5ms,乘200就是1秒種,其初值由晶振頻率決定,有計算軟體
當然,也可以中斷10次或20次,頻率判斷更准確,但響應速度慢了
1600或800方波接入定時器/計數器0的外部輸入引腳上,好像是P3.4
程序如下:
void
init()//初始化設置
{
TMOD=0x15;//定時器0作為計數器,定時器1作為定時器用
TH0=.0;//計數器清0
TL0=0;
EA=1;//開總中斷
ET1=1;//允許定時器1中斷
TH1=......;
TL1=.......;
TR0=1;//啟動計數器
TR1=1;//啟動定時器
aa=0;
}
void
main()//主程序很簡單
{
init();//初始化
while(1)//循環程序
{
dd=bb*256+cc;//
5ms的計數值
ee=200*dd;//換算為1秒鍾的計數值
if((ee>750)&&(ee<850))
{
P3.5=0;
}
if((ee>1550)&&(ee<1650))
{
P3.5=1;
}
}
}
void
timer1()interrupt
3//注意:定時器1的中斷序號為3
{
aa++;
TH1=....;.
TL1=....;.
if(aa==5)//中斷5次,共5ms
{
TR0=0;//暫停計數
aa=0;
bb=TH0;//讀出計數器數據
cc=TL0;
TL0=0;//計數器清0
TH0=0;
TR0=1;//重新啟動計數器
}
}
6. 基於51單片機的數字頻率計設計資料。要C語言的,謝謝。
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define NOP() _nop_()
sbit key1=P1^0;//key1 按此按鍵輸出1000Hz
sbit key2=P1^1;//key2 按此按鍵輸出100Hz
sbit key3=P1^2;//key3 按此按鍵輸出1Hz 1Hz是採用純粹軟體延時
sbit square=P2^7;//方波輸出引腳
sbit fenpin=P2^6;//分頻後信號輸出引腳
uchar TMRH,TMRL;//定時器T1初值寄存器
uchar square_delay;//延時產生方波標志
struct
{
uchar value;//當前鍵值
uchar backvalue;//上次鍵值
uchar done;//按鍵是否響應 1為已經響應
} key;
uchar KeyScan(void); //按鍵掃描 獲取鍵值
void KeyProc(void);//按鍵處理
void KeyAction(void);//按鍵散轉 轉向需要執行的程序
void delay500ms(void);//500ms延時程序 用於產生1Hz方波
void timer0() interrupt 1 using 1 //12M晶振 20ms中斷 用於按鍵掃描 T0中斷
{
TH0=0xB1;
TL0=0xE0;
KeyProc(); //避免按鍵在純粹軟體延時的時候不響應
}
void timer1() interrupt 3 using 1 //T1中斷
{
TH1=TMRH;
TL1=TMRL;
square=~square;
if(square==1)
EX1=1;
}
void EXT_INT1() interrupt 2 using 1 //外部INT1中斷 低電平觸發
{
EX1=0;
fenpin=~fenpin;
}
void main()
{
TMRH=0xFE;
TMRL=0x0C;
TCON=0x00;
EX1=1; //允許INT1中斷
TMOD=0x11; //定時器T0,T1工作在方式1
TH0=0xB1;
TL0=0xE0;
TH1=TMRH;
TL1=TMRL;
ET0=1; //允許T0溢出中斷
ET1=1; //允許T1溢出中斷
TR0=1; //啟動計數器T0
TR1=1; //啟動計數器T1
EA = 1; //開中斷
while(1)
{
if(square_delay)
{
delay500ms();
square=~square;
if(square==1)
EX1=1;
}
}
}
void KeyProc(void)
{
key.value=KeyScan();
if(key.value==key.backvalue)
{
if(!key.done)
{
KeyAction();
key.done=1;
}
}
else
{
key.backvalue=key.value;
key.done=0;
}
}
void KeyAction(void)
{
switch(key.value)
{
case 1:
{
ET1=0;
TR1=0;
TMRH=0xFE; //0.5ms初值
TMRL=0x0C;
TR1=1;
ET1=1;
square_delay=0;
}break;
case 2:
{
ET1=0;
TR1=0;
TMRH=0xEC;//5ms初值
TMRL=0x78;
TR1=1;
ET1=1;
square_delay=0;
}break;
case 3:
{
ET1=0;
TR1=0;
square_delay=1;
}break;
}
}
//獲取鍵值
uchar KeyScan(void)
{
uchar keyval=0;
if (key1==0) keyval=1;
else if(key2==0) keyval=2;
else if(key3==0) keyval=3;
else keyval=0;
return keyval;
}
//500ms延時 晶振12M
void delay500ms(void)
{
unsigned char i,j,k;
for(i=15;i>0;i--)
for(j=202;j>0;j--)
for(k=81;k>0;k--);
}
7. 各位老鐵,小弟在論文進行答辯的時候碰到了點問題,論文題目是基於51單片機的數字頻率計設計
1。單片機測量的是方波信號,如果是其它波形或幅度不合適,就進行放大和整形
2。.該信號進入單片機的哪個引腳,如果用定時器0作為計數器,輸入引腳是P3.4
如果用定時器1作為計數器,輸入引腳是P3.5 如果測單個脈沖寬度(或周期),可以輸入任意引腳,但最好用中斷引腳P3.2或P3.3
3。.信號進入引腳之後怎麼計算它的程序
用另外一個定時器定時50ms,測50ms內有多少個脈沖輸入,然後乘以20(即1S)即是頻率
8. 基於51單片機的數字頻率計設計(proteus模擬)
#include"reg51.h"
#define uchar unsigned char
uchar tt;
void init();
void main(uchar t) //根據需要修改相應的值;
{
t=tt;
init();
while(1)
{
if(tt==t) //如果t==10,那麼周期是1秒,即平率==1Hz;
{
tt=0;
P0^0=~P0^0; //設信號從P0_0口輸出;
}
}
}
void init()
{
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256; //這里周期是100ms,你可以根據你的需要修改
EA=1;
ET0=1;
TR0=1;
}
void timer() interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
tt++;
}
9. 基於51單片機的數字頻率計(0—10MHZ)
再加兩個數碼管,用T1引腳檢測頻率,打開T1中斷,每中斷一次加1計數,
滿1秒中後停止T1計數,讀出T1計數器的TH1 TL1,
頻率= 65536x中斷次數+TH1 HL1。
前提是選擇高速單片機,即只要T1引腳能夠響應10M的頻率就沒有問題
因為要計數65536次才T1才會中斷一次。
10. 求51單片機程序
這是51單片機頻率計程序,弄明白了寫你的程序就 很簡單了
#include <math.h>
#define uint unsigned int
#define uchar unsigned char
//定義以I/O口的功能
sbit beiguang=P3^2;//液晶屏背光
sbit rs=P1^3;//液晶屏寫選擇,0命令 1數據
sbit rw=P1^4;//液晶屏讀寫選擇
sbit lcden=P1^5;//液晶屏使能
#define db P2 //定義P2為數據輸出口,寫數據時用db代替P2,增加液晶屏程序的通用性
//更改硬體接線時,只更改此處,而不必去更改液晶屏讀寫子程序
uchar aa,bb,cc;
uint dd,ee;
void Delay1ms(unsigned int i) //1ms延時程序
{
unsigned int j;
for(;i>0;i--)
{
for(j=0;j<125;j++)
{;}
}
}
void init()//初始化設置
{
TMOD=0x15;//定時器0作為計數器,定時器1作為定時器用
TH0=0;//計數器清0
TL0=0;
EA=1;//開總中斷
ET1=1;//允許定時器1中斷
TH1=0x4c;
TL1=0x5c;
TR0=1;//啟動計數器
TR1=1;//啟動定時器
aa=0;
}
void write_com(uchar com)//向液晶屏寫命令
{
db=com;
rs=0;
rw = 0;
lcden=0;
Delay1ms(10*12);
lcden=1;
Delay1ms(10*12);
lcden=0;
}
void write_date(uchar date)//向液晶屏寫數據
{
db=date;
rs=1;
rw = 0;
lcden=0;
Delay1ms(10*12);
lcden=1;
Delay1ms(10*12);
lcden=0;
}
void init2()//液晶屏初始化
{
beiguang=0;
rw=0;
write_com(0x38);//顯示模式16字*2行,5*7點陣,數據口8位
Delay1ms(10*12);
write_com(0x0f);//開顯示,顯示游標,游標閃爍
Delay1ms(10*12);
write_com(0x06);//寫完數據後數據指針和游標位置自動加1
Delay1ms(10*12);
write_com(0x01);//屏幕清除
Delay1ms(10*12);
}
void display4(unsigned int number) //單行多位顯示程序
{
uchar A1,A2,A3,A4,A5;
init2();//液晶屏初始化
A1=number/10000%10;//分離出十萬,萬,千,百,十,個
A2=number/1000%10;
A3=number/100%10;
A4=number/10%10;
A5=number%10;
write_com(0x80);//第1個數據的位置設定,第1行第1列
Delay1ms(10);
write_date(0x30+A1);//寫數據
Delay1ms(10);
write_date(0x30+A2);
Delay1ms(10);
write_date(0x30+A3);
Delay1ms(10);
write_date(0x30+A4);
Delay1ms(10);
write_date(0x30+A5);
Delay1ms(10);
write_com(0x87);//第6個數據'H'的位置,中間空85和86 二格
write_date('H');
Delay1ms(10);
write_date('z');
Delay1ms(10);
}
void main()//主程序很簡單
{
init();//初始化
while(1)//循環程序
{
dd=bb*256+cc;//0.5S的計數值
ee=2*dd;//換算為1秒鍾的計數值
if(aa==1)
{
if(TH0>12)//預判斷,50ms內TH0>12,1s內計數值將超過可計數的最大值65535
fm=1;//報警
}
display4(ee);//顯示
fm=0;//報警停止
}
}
void timer1()interrupt 3//注意:定時器1的中斷序號為3
{
aa++;
TH1=0x4c;//11.0592Mhz
//TL1=0;//11.0592Mhz
TL1=0x5c;//實際電路振盪頻率11.03705Mhz,對TL1修正
if(aa==10)//中斷10次,共0.5S
{
TR0=0;//暫停計數
aa=0;
bb=TH0;//讀出計數器數據
cc=TL0;
TL0=0;//計數器清0
TH0=0;
TR0=1;//重新啟動計數器
}
}