單片機系統(tǒng)要實現(xiàn)DTMF撥號,常用的有2種方法:
第一是使用HT9200+晶震的方法,開銷是3個I/O口和一片HT9200,一個晶震, 第二是使用具有PWM功能的單片機,軟件合成DTMF,單片機運行要比較快才行,也要定時器。
本人提出第3種方法,就是使用普通2個I/O口加一個16位定時器的方法(當(dāng)然也可以使用2個16位定時器,這樣程序就很簡單,問題是有的單片機只有一個16位定時器就不好辦),這2個I/O分別輸出高低頻,再分別加2個RC低通濾波器即可。當(dāng)然這些方法都要加DTMF放大。
本方法是:一個I/O輸出高頻,另一個輸出低頻。問題的關(guān)鍵是只有一個定時器怎么輸出2個不同頻率的波形呢?思路是:
先讓定時器定時在高頻所要的時間上,等定時到后,高頻端口輸出取反一次,然后看下一個高頻輸出和低頻輸出那個先到,就將那個剩下的時間做為新的定時常數(shù)給定時器,如此類推。如果這個過程完全由軟件計算實現(xiàn),MCU就有可能忙不過來(因為要計算int數(shù)據(jù)),最好的辦法就是事先算好,只查表速度就完全沒問題。經(jīng)過計算,如果數(shù)據(jù)不事先經(jīng)過任何選擇就建表的話,這個表大約要2K空間,一般單片機無法接受。研究表明,在頻率0.5%誤差范圍內(nèi),將定時常數(shù)適當(dāng)改變,可以將這個表減少到620字節(jié)左右,這樣就可以接受了。當(dāng)然,這個計算方法要點技巧。下面是C51定時輸出雙音頻的程序。TimeConst[]就是要建的表。程序很簡潔,全是字節(jié)操作,生成的匯編代碼也很少。有興趣進一步討論的請聯(lián)系solar_pcb@163.com。
void TimeCount1(void) interrupt 3 using 2 { ii=TimeConst[addr]; //取定時常數(shù)高字節(jié) TH1=(ii | 0x80); //高字節(jié)的D7是輸出高頻或低頻的標志 addr++; TL1=TimeConst[addr]; //取定時常數(shù)低字節(jié) addr++; if(cLen==0){ //一個輪回時高低同時改變 PH=~PH; PL=~PL; } else{ if((ii & 0x80)==0){ //如果是高頻 PH=~PH; } else{ //如果是低頻 PL=~PL; } } cLen=cLen+2; if(cLen>=CircleLen){//這里沒使用cLen=cLen%CircleLen是因為這個表達式的匯編代碼太長,執(zhí)行時間也長。 cLen=0; //一個輪回,地址重新開始 addr=n+n; } }
|