數(shù)字式頻率計
一、設(shè)計概述
在電子技術(shù)中,頻率是最基本的參數(shù)之一,數(shù)字頻率計具有精度高、使用方便、測量迅速、以及便于實現(xiàn)測量過程自動化等優(yōu)點,是近代電子技術(shù)領(lǐng)域的重要工具之一,在許多領(lǐng)域得到廣泛應(yīng)用。本系統(tǒng)以超低功耗MSP430G2553單片機為核心處理芯片來測量信號的頻率,通過定時器A采用計數(shù)法完成信號頻率測量,并將被測頻率值通過LCD12864液晶串行顯示。頻率可測量范圍在1Hz到999MHz之間。如需要,范圍可繼續(xù)擴寬,頻率計的誤差在1%以內(nèi)。
二、原理圖
基于MSP430G2553的頻率計設(shè)計原理圖如圖1所示,通過串口方式液晶顯示,只需配置單片機三個口線便可以實現(xiàn)對頻率的測量。其中待測頻率信號從P1.0口輸入,然后可以直接在液晶屏上顯示。
三、引腳說明
(一)MSP430G2553引腳功能說明
由原理圖可以看出,430單片機的最小系統(tǒng)用到1腳電源、16腳復(fù)位端、20腳接地端、配置P1.0口為待測信號輸入端,P1.4為串行數(shù)據(jù)輸出口,P1.5為串行時鐘輸出口,如表1所示。
表1 MSP430G2553引腳功能說明
(二)LCD12864引腳功能說明
LCD12864液晶顯示屏用到1、2腳,電源接口線,19、20腳背光電源接口線,15腳并行/串行接口選擇,5腳串行數(shù)據(jù)口,6腳串行的同步時鐘。LCD12864引腳功能如表2所示。
表2 LCD12864接口說明
四、軟件設(shè)計流程圖
系統(tǒng)軟件設(shè)計包括初始化模塊、中斷模塊和信號頻率顯示模塊。
(一)主函數(shù)
主函數(shù)流程圖如圖2所示。在主程序中,主要對單片機配置進行初始化和屏幕初始化,以及頻率信號數(shù)據(jù)的處理并實時顯示。
(二)單片機初始化函數(shù)
單片機初始化函數(shù)包括對看門狗定時器模式的設(shè)置、I/O口輸入/輸出功能的配置。定時器A所需時鐘源、分頻系數(shù)的選擇,并將總中斷打開。函數(shù)流程圖如圖3所示。
(三)中斷函數(shù)
中斷函數(shù)流程圖如圖4所示。當定時器A溢出后就進入中斷,count就加上65535。
(四)頻率顯示函數(shù)
頻率顯示流程圖如圖5所示。頻率顯示函數(shù)包含對定時器A相關(guān)內(nèi)容的操作,將定時器A計數(shù)寄存器內(nèi)容清零后,設(shè)置定時器A的工作模式,產(chǎn)生1s 計數(shù)閘門,關(guān)閉定時器A,記下count的值即為所測得頻率的大小。最后根據(jù)數(shù)據(jù)的大小,按不同的單位將數(shù)據(jù)通過12864液晶顯示屏串行顯示出來。
五、程序源代碼
/***************************************************************
基于定時器A,采用計數(shù)法完成信號頻率的測量
使用片內(nèi)時鐘DOC,時鐘頻率默認值
采用12864串行顯示
頻率測量范圍:1Hz -- MHz(只要需要,范圍可以繼續(xù)擴寬,誤差在1%以內(nèi))
被測信號輸入管腳P1.0
WR數(shù)據(jù)引腳 P1.4
SCLK模擬時鐘引腳 P1.5
PSB串行/并行選擇引腳 接GND
*****************************************************************/
#include<msp430g2553.h>
#define uint unsigned int
#define uchar unsigned char
#define ulint unsigned long int
ulint count=0;
void delay(uint t);
void delay1(void);
void int_430(void);
void sendbyte(uchar zdata);
void write_com(uchar cmdcode);
void write_data(uchar Dispdata);
void lcdinit();
void print_string( char *s);
void display(void);
/*************主函數(shù)************/
void main()
{
int_430();
lcdinit();
while(1)
{
display();
count=0;
}
}
/*************延時函數(shù)************/
void delay(uint t)
{
uinti,j;
for(i=0;i<t;i++)
for(j=0;j<10;j++);
}
//1s延時的計數(shù)閘門
void delay1(void)
{
unsigned long i;
for(i=0;i<119000;i++)
{
_NOP(); // 該函數(shù)用來產(chǎn)生一個 MSP430 系統(tǒng)時鐘周期的延時
}
}
/*************430初始化函數(shù)************/
void int_430(void)
{
WDTCTL=WDTPW+WDTHOLD; // 關(guān)閉看門狗
P1SEL&=~BIT4;
P1DIR|= BIT4;
P1OUT&=~BIT4;
P1SEL&=~BIT5;
P1DIR|= BIT5;
P1OUT&=~BIT5;
P1SEL|=BIT0; // 設(shè)置 P1.0 為 TimerA 外部計數(shù)信號輸入口
P1DIR&=~BIT0; // 設(shè)置 P1.0 為輸入口
//TimerA 配置
TACTL=TASSEL_0; // 定時器 A 時鐘源選擇:TACLK
TACTL=ID_3; // 計數(shù)時鐘分頻系數(shù)選擇:1
CCTL0= CCIE; //開中斷
CCR0= 65535;
_EINT();
}
/*************數(shù)據(jù)傳送函數(shù)************/
void sendbyte(uchar zdata)
{
ucharcode_seg7,serial_clk, serial_shift;
code_seg7=zdata;
serial_shift=0x80;
for(serial_clk=0; serial_clk<8; serial_clk++)
{
if(code_seg7&serial_shift)
{
P1OUT|=BIT4; //SID為1
}
else
{
P1OUT&=~BIT4; //SID為0
}
P1OUT&=~BIT5; //產(chǎn)生時鐘信號下沿
P1OUT|=BIT5; //產(chǎn)生時鐘信號上沿
serial_shift=serial_shift>>1; //準備發(fā)送下一位數(shù)據(jù)
}
}
/*************寫命令函數(shù)************/
void write_com(uchar cmdcode)
{ //串口控制格式(11111AB0)
//A數(shù)據(jù)方向控制,A=H時讀,A=L時寫
//B數(shù)據(jù)類型選擇,B=H時為顯示數(shù)據(jù),B=L時為命令
sendbyte(0xf8); //MCU向LCD發(fā)命令
sendbyte(cmdcode & 0xf0); //發(fā)高四位數(shù)據(jù)(數(shù)據(jù)格式D7D6D5D4_0000)
sendbyte((cmdcode << 4) & 0xf0); //發(fā)低四位數(shù)據(jù)(數(shù)據(jù)格式D3D2D1D0_0000)
delay(2); //延時等待
}
/*************寫數(shù)據(jù)函數(shù)************/
void write_data(uchar Dispdata)
{
sendbyte(0xfa); //MCU向LCD發(fā)數(shù)據(jù)
sendbyte(Dispdata & 0xf0); //發(fā)高四位數(shù)據(jù)
sendbyte((Dispdata << 4) & 0xf0); //發(fā)低四位數(shù)據(jù)
delay(2);
}
/*************LCD初始化函數(shù)************/
void lcdinit()
{
delay(20000); //復(fù)位等待(內(nèi)部自帶上電復(fù)位電路),時間較長
write_com(0x30); //功能設(shè)定:基本指令集操作
delay(50); //延時等待
write_com(0x0c); //整體顯示,關(guān)游標
delay(50);
}
/*************送字符串函數(shù)************/
void print_string( char *s)
{
while(*s > 0) //C語言里字符串末尾自動加“\0”(ASCII碼值為0)
{
delay(50);
write_data(*s); //發(fā)送字符對應(yīng)的ASCII碼,12864指針可設(shè)置自動指向下一個顯示地址
s++;
}
}
/*************頻率顯示函數(shù)************/
void display(void)
{
ulinta1,a2,a3,a4,a5,a6,a7,a8,a9; // 聲明計數(shù)數(shù)據(jù)變量
TAR=0x0000; // 定時器 A 計數(shù)寄存器內(nèi)容清零
TACTL=MC_2; // 定時器 A 工作模式選擇:連續(xù)模式
delay1(); // 產(chǎn)生 1s 計數(shù)閘門
TACTL=MC_0; // 定時器 A 工作模式選擇:停止模式
count+=TAR;
write_com(0x01); //清屏指令
if(count>=1000000)
{
a1=count/100000000;
a2=count%100000000/10000000;
a3=count%100000000%10000000/1000000;
a4=count%100000000%10000000%1000000/100000;
a5=count%100000000%10000000%1000000/100000;
a6=count%100000000%10000000%1000000%100000/10000;
a7=count%100000000%10000000%1000000%100000%10000/1000;
a8=count%100000000%10000000%1000000%100000%10000%1000/100;
a9=count%100000000%10000000%1000000%100000%10000%1000%100/10;
write_com(0x03);
write_com(0x80); //第一行首地址0x80
print_string("德州儀器MSP430 "); //第一行顯示(必須加一個空格否則不能下載)
write_com(0x90);
print_string("頻率: ");
write_com(0x93); //第二行首地址0x90,從第四個開始顯示
write_data(a1+0x30); //發(fā)送dat1的ASCII碼,顯示dat1的值
write_data(a2+0x30); //發(fā)送dat1的ASCII碼,顯示dat2的值
write_data(a3+0x30); //發(fā)送dat1的ASCII碼,顯示dat3的值
write_data('.'); //發(fā)送"."
write_data(a4+0x30); //發(fā)送dat1的ASCII碼,顯示dat4的值
write_data(a5+0x30); //發(fā)送dat1的ASCII碼,顯示dat5的值
write_data(a6+0x30); //發(fā)送dat1的ASCII碼,顯示dat6的值
write_data(a7+0x30); //發(fā)送dat1的ASCII碼,顯示dat7的值
write_data(a8+0x30); //發(fā)送dat1的ASCII碼,顯示dat8的值
write_data(a9+0x30); //發(fā)送dat1的ASCII碼,顯示dat9的值
write_com(0x88);
print_string("單位: ");
write_data('M'); //發(fā)送H的ASCII碼,顯示M
write_data('H'); //發(fā)送H的ASCII碼,顯示H
write_data('z'); //發(fā)送z的ASCII碼,顯示z;
delay(500);
}
else
{
if(count>=1000)
{
a1=count/100000;
a2=count%100000/10000;
a3=count%100000%10000/1000;
a4=count%100000%10000%1000/100;
a5=count%100000%10000%1000/100;
a6=count%100000%10000%1000%100%10;
write_com(0x03);
delay(50); //延時
// 讀定時器 A 計數(shù)寄存器內(nèi)容
write_com(0x80); //第一行首地址0x80
print_string("德州儀器MSP430 "); //第一行顯示(必須加一個空格否則不能下載)
write_com(0x90);
print_string("頻率: ");
write_com(0x94); //第二行首地址0x90,從第四個開始顯示
write_data(a1+0x30); //發(fā)送dat1的ASCII碼,顯示dat1的值
write_data(a2+0x30); //發(fā)送dat1的ASCII碼,顯示dat2的值
write_data(a3+0x30); //發(fā)送dat1的ASCII碼,顯示dat3的值
write_data('.'); //發(fā)送"."
write_data(a4+0x30); //發(fā)送dat1的ASCII碼,顯示dat4的值
write_data(a5+0x30); //發(fā)送dat1的ASCII碼,顯示dat5的值
write_data(a6+0x30); //發(fā)送dat1的ASCII碼,顯示dat6的值
write_com(0x88);
print_string("單位: ");
write_data('K'); //發(fā)送H的ASCII碼,顯示K
write_data('H'); //發(fā)送H的ASCII碼,顯示H
write_data('z'); //發(fā)送z的ASCII碼,顯示z
delay(500); //較長時間延時,保證下次操作前LCD完成上述功能處于非忙狀態(tài)
}
else
{
count*=1000;
a1=count/100000;
a2=count%100000/10000;
a3=count%100000%10000/1000;
a4=count%100000%10000%1000/100;
a5=count%100000%10000%1000/100;
a6=count%100000%10000%1000%100%10;
write_com(0x03);
delay(50); //延時
// 讀定時器 A 計數(shù)寄存器內(nèi)容
write_com(0x80); //第一行首地址0x80
print_string("德州儀器MSP430 "); //第一行顯示(必須加一個空格否則不能下載)
write_com(0x90);
print_string("頻率: ");
write_com(0x94); //第二行首地址0x90,從第四個開始顯示
write_data(a1+0x30); //發(fā)送dat1的ASCII碼,顯示dat1的值
write_data(a2+0x30); //發(fā)送dat1的ASCII碼,顯示dat2的值
write_data(a3+0x30); //發(fā)送dat1的ASCII碼,顯示dat3的值
write_data('.'); //發(fā)送"."
write_data(a4+0x30); //發(fā)送dat1的ASCII碼,顯示dat4的值
write_data(a5+0x30); //發(fā)送dat1的ASCII碼,顯示dat5的值
write_data(a6+0x30); //發(fā)送dat1的ASCII碼,顯示dat6的值
write_com(0x88);
print_string("單位: ");
write_data('H'); //發(fā)送H的ASCII碼,顯示H
write_data('z'); //發(fā)送z的ASCII碼,顯示z
delay(500); //較長時間延時,保證下次操作前LCD完成上述功能處于非忙狀態(tài)
}
}
}
#pragma vector = TIMER0_A0_VECTOR //Timer_A中斷向量
__interrupt void Tiemr_A(void)
{
count+=65535;
}
|