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