|
原理上采用32.768K外部晶振產(chǎn)生異步時(shí)鐘信號(hào) ,作為M8定時(shí)器2de時(shí)鐘源,設(shè)定1024de預(yù)分頻,可以得到TCNT2溢出de精確時(shí)間為1s,在溢出中斷時(shí)控制74ls00與非門進(jìn)而控制被測(cè)信號(hào)de通斷,累計(jì)1s 內(nèi)計(jì)數(shù)器獲得de值,經(jīng)過(guò)簡(jiǎn)單de運(yùn)算則可獲得被測(cè)信號(hào)de頻率
M8 采用內(nèi)部 8M 內(nèi)部RC震蕩 工作模式 , 電路采用74ls393 對(duì)被測(cè)信號(hào)進(jìn)行預(yù)分頻,相當(dāng)于擴(kuò)張T1計(jì)數(shù)器de位數(shù),T1 為16位,74ls393為8位,擴(kuò)展后為24位,T1不溢出de話 最高可測(cè) 16.777216M ,溢出則累計(jì)中斷次數(shù)然后進(jìn)行累加即可。(另外添加74ls393進(jìn)行預(yù)分頻de目deshi為了解決T1引腳時(shí)鐘信號(hào)不宜大于單片機(jī)工作頻率de二分之一de問題)
目前測(cè)頻 4M 已經(jīng)成功通過(guò),由于沒有函數(shù)信號(hào)發(fā)生器,所以其他高頻還沒有做測(cè)試
PCB原理圖

/////////////////////////////以下為程序, 只有一個(gè)文件 main.c /////////////////////////////////
#include <avr/io.h> #include <avr/iom8.h> #include <avr/signal.h> #include <avr/interrupt.h> #include <stdint.h> #include <avr/wdt.h> #include <util/delay.h> #include <stdio.h>
/*----------------------常用參數(shù)定義-------------------*/
#define P0 0 #define P1 1 #define P2 2 #define P3 3 #define P4 4 #define P5 5 #define P6 6 #define P7 7
#define FREQ 8 #define uint unsigned int #define uchar unsigned char
/*----------------------某些端口操作-------------------*/
#define SET_DOOR PORTB|=_BV(P1) #define CLR_DOOR PORTB&=~_BV(P1)
#define SET_CLEAR PORTB|=_BV(P2) #define CLR_CLEAR PORTB&=~_BV(P2)
/*----------------------1602定義-------------------*/
#define SET_LCD_RS PORTD|=_BV(P2) #define CLR_LCD_RS PORTD&=~_BV(P2)
#define SET_LCD_RW PORTD|=_BV(P3) #define CLR_LCD_RW PORTD&=~_BV(P3)
#define SET_LCD_E PORTD|=_BV(P4) #define CLR_LCD_E PORTD&=~_BV(P4)
#define SET_74LS595_SHIFT PORTB|=_BV(P0) #define CLR_74LS595_SHIFT PORTB&=~_BV(P0)
#define SET_74LS595_DI PORTD|=_BV(P6) #define CLR_74LS595_DI PORTD&=~_BV(P6)
#define SET_74LS595_CLK PORTD|=_BV(P7) #define CLR_74LS595_CLK PORTD&=~_BV(P7)
void LCD_ON(void); //啟動(dòng)LCD void LongConvertToChar(unsigned long WD); void LCDInit(void); void WritEDAtaLCD(unsigned char WDLCD); void WriteCommandLCD(unsigned char WCLCD); void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData); void DisplayListChar(unsigned char X, unsigned char Y,unsigned char *DData); void WritEDAtaTo595(unsigned char WDLCD);
const unsigned char Owner[] = {"Hello World !!!"}; const unsigned char uctech[] = {"INPUT FREQUENCE:"}; const unsigned char Init[] = {"Initialization."}; unsigned char net[16] = {"Axin & Cornsoup"}; unsigned char Net_Pointer=0;//net[] de指針
unsigned char Timer1_Counter_H=0; unsigned char Timer1_Counter_L=0; unsigned long Frequence=0; unsigned char T2_OV_Time=1; //T2溢出對(duì)應(yīng)de時(shí)間 unsigned char T1_OV_Times=0; //T1溢出次數(shù)
/*----------------------串口定義-------------------*/
unsigned char SetPrintfConvertMode=0; //使用printf作其他轉(zhuǎn)換,并非輸出到UART
void Uart_Init(void);
int System_putchar(char c, FILE *stream); int System_getchar(FILE *stream);
FILE mystd = FDEV_SETUP_STREAM(System_putchar, System_getchar,_FDEV_SETUP_RW);
/*----------------------常用函數(shù)定義------------------*/
void delay_nms(unsigned int ms) //N ms延時(shí)函數(shù) { uint i; for(i=0;i<ms;i++) _delay_loop_2(FREQ*250); }
/*----------------------系統(tǒng)初始化函數(shù)定義------------------*/
void IO_INIT(void);
/////////////////////////////////////////////////////////////////
int main(void) { wdt_disable(); IO_INIT(); Uart_Init(); LCD_ON(); //初始化 LCD1602 并顯示制作者信息 delay_nms(1500); DisplayListChar(0, 0, uctech); //輸出英文 "Input Frequence:" 到LCD1602 第一行
DisplayListChar(0, 5, Init); //顯示稍等
CLR_DOOR; //關(guān)閉閥門 _delay_loop_2(5); SET_CLEAR; _delay_loop_2(5); //清空74ls393數(shù)據(jù) CLR_CLEAR;
TCNT1H=0; TCNT1L=0; //清空T1計(jì)數(shù)器
ASSR=_BV(AS2); //允許異步時(shí)鐘 TCCR2=_BV(CS22)|_BV(CS20); TCCR1B=_BV(CS12)|_BV(CS11); //外部T1引腳輸入 下降沿有效 (一定要下降沿) TIMSK=_BV(TOIE1)|_BV(TOIE2); //允許溢出中斷
sei();
while(1); }
/*----------------------系統(tǒng)初始化函數(shù)實(shí)體------------------*/
void IO_INIT(void) { DDRB|=0x0f; PORTB&=0x0f; DDRC|=0x00; PORTC&=0x00; DDRD|=0xdc; PORTD&=0xdc; }
/*----------------------系統(tǒng)中斷函數(shù)實(shí)體-----------------*/
ISR(TIMER1_OVF_vect) //定時(shí)器1溢出中斷 { T1_OV_Times++; }
ISR(TIMER2_OVF_vect) //定時(shí)器2溢出中斷 { if(T2_OV_Time==2) { CLR_DOOR;
Timer1_Counter_L=TCNT1L; //讀取TCNT1數(shù)據(jù)要按照順序,先低8位后高8位 Timer1_Counter_H=TCNT1H; Frequence=((unsigned long)Timer1_Counter_H<<16)|((unsigned long)Timer1_Counter_L<<8)|((PINC&0x3c)>>2)|((PINC&0x03)<<6)|(PINB&0x30); if(T1_OV_Times!=0) //其實(shí)這個(gè)shi多余de,這里目deshi測(cè)量16.7M 以上de頻率 不過(guò)我們測(cè)量de頻率不可能達(dá)到這個(gè) { Frequence+=(unsigned long)0xffff*0xff*T1_OV_Times; T1_OV_Times=0; } //printf("\n\nTCNT1H: 0X%X TCNT1L: 0X%x",Timer1_Counter_H,Timer1_Counter_L); //printf("\nOverFlowTimes %d",T1_OV_Times); LongConvertToChar(Frequence); //把Frequence 轉(zhuǎn)換后de數(shù)據(jù) 放到 net[]數(shù)組里面 DisplayListChar(0, 5, net); //把net[]de數(shù)據(jù)輸出到LCD SET_CLEAR; //一定要先把 74ls393 清零 再對(duì)TCNT1 清零 _delay_loop_2(2); //適當(dāng)延時(shí),其實(shí)可不要 CLR_CLEAR; _delay_loop_2(2); TCNT1H=0x00; TCNT1L=0x00;
T2_OV_Time=1; //啟動(dòng)下一次測(cè)量 } else { SET_DOOR; T2_OV_Time=2; } }
/*----------------------LCD_1602函數(shù)實(shí)體------------------*/
void LCD_ON(void) { delay_nms(400); //啟動(dòng)等待,等LCD講入工作狀態(tài) LCDInit(); //LCD初始化 delay_nms(100); //延時(shí)片刻(可不要) DisplayListChar(0, 0, Owner); DisplayListChar(0, 5, net); }
void UsePrintfToConvert(unsigned long WD) //利用 printf de轉(zhuǎn)換功能 爽! ^.^ { SetPrintfConvertMode=1; //設(shè)置 printf 為自定義轉(zhuǎn)換模式 printf("%13ld Hz",WD); //net[]數(shù)組總共有 16 個(gè)成員 與LCD1602de一行16個(gè)位對(duì)應(yīng) SetPrintfConvertMode=0; //還原 printf 為 Uart 輸出模式
/*---------為輸出數(shù)據(jù)添加逗號(hào) 999,999,999 ------------*/
net[2]=net[4]; net[3]=net[5]; net[4]=net[6]; if(net[2]!= ||net[3]!= ||net[4]!= ) { if(net[4]!=-) { net[5]=,; } } net[6]=net[7]; net[7]=net[8]; net[8]=net[9]; if(net[6]!= ||net[7]!= ||net[8]!= ) { if(net[8]!=-) { net[9]=,; } } }
void LongConvertToChar(unsigned long WD) { UsePrintfToConvert(WD); }
void WritEDAtaTo595(unsigned char WDLCD) // 74hc595 串行轉(zhuǎn)并行輸出 { unsigned char i; CLR_74LS595_CLK; for(i=0;i<8;i++) { CLR_74LS595_SHIFT; if(WDLCD&0x01) { SET_74LS595_DI; } else { CLR_74LS595_DI; } WDLCD>>=1; SET_74LS595_SHIFT; } _delay_loop_2(1); SET_74LS595_CLK; }
//寫數(shù)據(jù) void WritEDAtaLCD(unsigned char WDLCD) { delay_nms(1);//適當(dāng)加延時(shí),避免 LCD1602 繁忙 WritEDAtaTo595(WDLCD); SET_LCD_RS; CLR_LCD_RW; CLR_LCD_E; //若晶振速度太高可以在這后加小de延時(shí) _delay_loop_2(1); SET_LCD_E; }
//寫指令 void WriteCommandLCD(unsigned char WCLCD) { delay_nms(1);//適當(dāng)加延時(shí),避免 LCD1602 繁忙 WritEDAtaTo595(WCLCD); CLR_LCD_RS; CLR_LCD_RW; CLR_LCD_E; _delay_loop_2(1); SET_LCD_E; }
void LCDInit(void) //LCM初始化 { WritEDAtaTo595(0); WriteCommandLCD(0x38); //三次顯示模式設(shè)置,不檢測(cè)忙信號(hào) delay_nms(15); WriteCommandLCD(0x38); delay_nms(5); WriteCommandLCD(0x38); delay_nms(5);
WriteCommandLCD(0x38); //顯示模式設(shè)置,開始要求每次檢測(cè)忙信號(hào) WriteCommandLCD(0x08); //關(guān)閉顯示 WriteCommandLCD(0x01); //顯示清屏 WriteCommandLCD(0x06); // 顯示光標(biāo)移動(dòng)設(shè)置 WriteCommandLCD(0x0C); // 顯示開及光標(biāo)設(shè)置 }
//按指定位置顯示一個(gè)字符 void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData) { Y &= 0x1; X &= 0xF; //限制X不能大于15,Y不能大于1 if (Y) X |= 0x40; //當(dāng)要顯示第二行時(shí)地址碼+0x40; X |= 0x80; // 算出指令碼 WriteCommandLCD(X); //這里不檢測(cè)忙信號(hào),發(fā)送地址碼 WritEDAtaLCD(DData); }
//按指定位置顯示一串字符 void DisplayListChar(unsigned char X, unsigned char Y, unsigned char *DData) { unsigned char ListLength;
ListLength = 0; Y &= 0x1; X &= 0xF; //限制X不能大于15,Y不能大于1 while (DData[ListLength]>=0x20) //若到達(dá)字串尾則退出 { if (X <= 0xF) //X坐標(biāo)應(yīng)小于0xF { DisplayOneChar(X, Y, DData[ListLength]); //顯示單個(gè)字符 ListLength++; X++; } } }
/*----------------------串口函數(shù)實(shí)體------------------*/
void Uart_Init(void) { UCSRB=_BV(RXEN)|_BV(TXEN); UBRRL=51; stdout=&mystd; stdin=&mystd; }
int System_putchar(char c, FILE *stream) { if(SetPrintfConvertMode==1) { net[Net_Pointer]=c; Net_Pointer++; if(Net_Pointer>=16) { Net_Pointer=0; } } else { if (c == \n) System_putchar(\r, stream); loop_until_bit_is_set(UCSRA, UDRE); UDR = c; }
return 0; }
int System_getchar( FILE *stream) { loop_until_bit_is_set(UCSRA,RXC); return UDR; }
|