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