PIC16F84AでDTMFを生成してみる


【初心者】PICでBEEP音を作りたい!!2【親切に】より



15774ワット発電中さん :2007/11/28(水) 16:51:11 ID:LnFJGBNv
DTMFの人です。
あれから、ちょっといろいろ忙しく、
なかなか時間が取れませんでしたので、あまり進展がないですが、一応報告します。

一応、目的の周波数の矩形波を出力する方法は分かりました。
しかし、現段階では、「ずーっと鳴りっぱなし」「2つの周波数を同時に出力できない」
という、ほとんど進展がない状態です。
今後の目標としては、とりあえず、DTMFの信号らしくするために、
2つの周波数を同時に発生して、混合する方法、
トランジスタを利用した混合する回路は出来ました。
それと、200msecの時間でいったん音を切り、
次の違う文字に移る、といったようなことがしたいです。

今回は、いろいろ面倒なので、
PICは、16F84Aで、クロックは4MHzです。

PICCを用い、サンプルの「Delay.h」を使って、
1usecのディレイタイマを使って、
0.5/f(Hz)の時間の繰り返しで周波数を出してみましたが、
他に良い方法があれば、そちらを利用したい所存です。
次のレスに、一応作ったプログラムを書いておきます
(本当に手抜きですみません)

24DTMF :2007/11/29(木) 01:35:32 ID:xMPBfbQc
>>20-22
なるほど…ありましたか

しかし、ここは、もうやけっぱちで、「PICで発振回路を組む」という、
スレ元々のスタンスを大事にしたいと思いますので、
なんとかPICだけで組みたいのです
もう半分以上意地です。
皆様にはご迷惑をおかけいたしますが、
どうかお付き合い下さい。。。

26774ワット発電中さん [sage] :2007/11/29(木) 05:16:44 ID:bVb86jMR
>>24
そのものズバリの回答(ソースプログラムなりHEXなり)が欲しい?
それとも、回答に至るまでの過程が必要?
どういうDTMF信号が出れば正解? CCITT? BELL? その他?

それから、しょうもない要望で申し訳ないけど、アップローダは中間ステップの少ないとこ
(この板でよく使われる ttp://aikofan.dee.cc/aikoup1/aikoup.htm とか)を
使ってもらえると嬉しい。

27DTMF :2007/11/29(木) 09:45:09 ID:xMPBfbQc
>>26
ごめんなさい。
アップローダーはこちらを利用させて頂きます
>>25と同じものです
ttp://aikofan.dee.cc/aikoup1/src/f0399.png

ズバリ言いますと…「正解のソース」が欲しいです…。
HEXですと、答えはその中にありますが、
内容の理解が出来ないのと、
改造が出来ないのがキツイです。
なので、とりあえず「正解のソース」を頂ければ、
それを理解するために勉強したいと思います。
ここでも話し合っても良いですし、
自分で勉強しても良いですし。

DTMFですが、「矩形波の混合」である時点で、
正式な信号ではないですよね。
正式なDTMFは、「正弦波の混合」ですから…
なので、希望としては、「とりあえずDTMFとして認識できればいいじゃね?」
くらいの信号で構いません。

それと、開発環境を、16F648Aも可能になりました。
>>16のソースをいろいろ弄って、16F648Aでも同じように動くことを確認しましたので。
しょーもない自分でごめんなさい。。。



28774ワット発電中さん [sage] :2007/11/29(木) 10:00:47 ID:bVb86jMR
少し真面目に考えてみた。

PIC16F648AだとTimer2が使えるから楽なんだが、とりあえず面倒なPIC16F84Aを使う
方向で。DTMF信号のスペックはCCITT DTMFが目標ということで。

CCITT DTMFだと周波数偏差の許容値は±1.5%以内。セラロックの周波数偏差を(甘く)
見積もって±1%以内とすると、プログラム上で許される周波数偏差は±0.5%。

高群の最高周波数1633Hzを発音するとして、PICからの出力信号を方形波とすると、
この信号はH/Lとも306.2±1.5usずつの繰り返し。

高群の最高周波数941Hzを発音するとして、PICからの出力信号を方形波とすると、
この信号はH/Lとも531.3±2.7usずつの繰り返し。

クロックを4MHzとすると1命令サイクルは1usなので、H/Lの命令サイクル数は、
上記のusを命令サイクルに読み替えればよい。

1633Hzと941Hzを同時に発音するには、約306命令サイクルごとにあるポートを
トグルし、同時に約531命令サイクルごとに別のあるポートをトグルすればよい。

・・・この2つの周波数に固定したとしても、かなり厳しい条件のような気がする。
306と531の最大公約数は9だから、9命令サイクルで1ループできればとりあえずこの
2つの発音はできることになるが、9命令サイクルで2ポート分のカウントとポート
反転は無理。(306±1と531±2の範囲でいちばん大きい最大公約数は9みたい。)

これではどうしようもないので、周波数偏差の許容値を±0.5%から±1.0%に大きく
してみる。そうすると、トグル周期が306.2±3.0usと531.3±5.4usになる。
この範囲内で最大の最大公約数を探すと304と532で76になる。76命令サイクルあれば、
アセンブラなら何とか2ポート分のカウントとポート反転がこなせるような気がする。

こんな厳しいタイミングでは任意の2周波数の発音は無理だろうから、上記みたいに
高群から1音と低群から1音を選んで、その2音を発音する専用ルーチンを作成、
これを16ルーチン(高群4音と低群4音の総当りの組み合わせ)作成するしかないんで
ないかな。

ただし、ここまでやっても方形波出力だとスプリアスが大量に出るので、CCITT DTMFの
スペックの1つ「スプリアス-30dB以下」は全く満たせないのだが。

30774ワット発電中さん [sage] :2007/11/29(木) 10:55:59 ID:bVb86jMR
>>28のやり方でいくとして、高群と低群の各組み合わせで許容周波数偏差±1%のときに
命令サイクル数の最大公約数の最大がいくつになるか計算してみた。

高群1209Hz (410us〜417us), 低群697Hz (711us〜724us): 最大公約数(412, 721) == 103
高群1209Hz (410us〜417us), 低群770Hz (643us〜655us): 最大公約数(413, 649) == 59
高群1209Hz (410us〜417us), 低群852Hz (581us〜592us): 最大公約数(415, 581) == 83
高群1209Hz (410us〜417us), 低群941Hz (527us〜536us): 最大公約数(413, 531) == 59
高群1336Hz (371us〜377us), 低群697Hz (711us〜724us): 最大公約数(374, 714) == 34
高群1336Hz (371us〜377us), 低群770Hz (643us〜655us): 最大公約数(372, 651) == 93
高群1336Hz (371us〜377us), 低群852Hz (581us〜592us): 最大公約数(371, 583) == 53
高群1336Hz (371us〜377us), 低群941Hz (527us〜536us): 最大公約数(371, 530) == 53
高群1477Hz (336us〜341us), 低群697Hz (711us〜724us): 最大公約数(336, 720) == 48
高群1477Hz (336us〜341us), 低群770Hz (643us〜655us): 最大公約数(340, 646) == 34
高群1477Hz (336us〜341us), 低群852Hz (581us〜592us): 最大公約数(336, 588) == 84
高群1477Hz (336us〜341us), 低群941Hz (527us〜536us): 最大公約数(336, 528) == 48
高群1633Hz (304us〜309us), 低群697Hz (711us〜724us): 最大公約数(309, 721) == 103
高群1633Hz (304us〜309us), 低群770Hz (643us〜655us): 最大公約数(304, 646) == 38
高群1633Hz (304us〜309us), 低群852Hz (581us〜592us): 最大公約数(308, 588) == 28
高群1633Hz (304us〜309us), 低群941Hz (527us〜536us): 最大公約数(304, 532) == 76

1633Hz/852Hzのときの28命令サイクルってのがいちばん厳しい。
許容偏差±2%まで広げても1633Hz/852Hzのときがいちばん厳しくて39命令サイクル。


31774ワット発電中さん [sage] :2007/11/29(木) 10:58:58 ID:bVb86jMR
小出しですまん。いま気付いたんだが、高群1633HzはA〜Dに対応するから、
テンキーしか使わないのであれば高群1633Hzは使わないね。

その場合、±1%のときにいちばん厳しいところが34命令サイクル、±2%だと
47命令サイクル。

32774ワット発電中さん [sage] :2007/11/29(木) 11:07:07 ID:jjxM9kUx
下記サイトに「PIC16F628AでDTMFジェネレーター」という記事があったんだが、これでOK?
ttp://www.mars.dti.ne.jp/~m7030/index.html


33DTMF :2007/11/29(木) 11:57:31 ID:xMPBfbQc
>>ID:bVb86jMRさま
いろいろアドバイスありがとうございます。
今回は、クロックには水晶発振子を使用したいと思いますので、
セラロックほどの誤差はないと思います。

それと、残念ですが、今回のテーマであるのは、
「VoIP技術において、アマチュア無線で使う」というものがありますので、
そのリモートコントロール用に回路を作成したいので、
どうしても「D」のDTMF信号が必要なのです…
前スレに書き漏らしていたかもしれませんので、
謝っておきます。
必ずしも、テンキーを使ってDTMF信号を打つ必要はなく、
必要な、決まった文字列のDTMFをボタン一つで再生できれば問題ないです
それを、何パターンか用意しておいて、
「戻る」「次へ」「再生」くらいのスイッチで信号を再生出来れば良いと思っております。
いろいろごちゃごちゃですみません…。

>>32
興味深い記事です。
ご紹介ありがとうございます。
しかし、PWMは…まだ触れたことがないので、何とも言えないのが現状です…orz
すみませんです。。

34DTMF :2007/11/29(木) 12:00:45 ID:xMPBfbQc
前スレにうpした、今回の最終目標のDTMFです。
ttp://aikofan.dee.cc/aikoup1/src/f0400.wav
「#0510D」と再生しています。

実際には、これは正弦波をPCで再生させたものですので、
これが矩形波、または方形波に変わっても問題ありません。

40774ワット発電中さん [sage] :2007/11/29(木) 21:20:23 ID:bVb86jMR
>>33-34
先に断わっておくが、PWM (Timer 2)使うほうがはるかに簡単だよ。動作する
プログラムも既に>>32があるわけだし。そっちを使うことを考えたほうが無難。

あくまでPIC16F84Aで苦難の道を行く場合、クロックに水晶を使うのなら基準発振の
誤差は無視できる程度だから、プログラム上の許容周波数偏差を±1.5%まで許す
ことにすると、クロック4MHzのとき最小の1ループは31命令サイクル。

このサイクル数だと、Cだけで書くのは厳しい。骨組みはCで書くとして、細かい調整は
インラインアセンブラを併用しないといけないかも。1ループの命令数は、がんばっても
多分20命令前後までしか減らせないと思う(これでも1音あたり10命令)が、発音の
H/Lの各期間に許される命令サイクル数の誤差は高群最高音のときで8サイクルしかない
ので、DDAによる発音では誤差が大きすぎる。

クロック源の水晶の周波数を20MHzにしていいなら最小は194命令サイクルになる。
このくらい周期に余裕があれば割り込みが使えるから、ルーチンを分けずに一本化して、
全部Cで書くのも何とかなりそう。また、発音のH/Lの各期間に許される命令サイクル数の
誤差は高群最高音のときで45サイクルあるから、1ループが40命令程度以下に収まれば
DDAによる発音でも許容誤差以内で発音できる。

41DTMF :2007/11/29(木) 21:53:36 ID:xMPBfbQc
皆様、いろいろほんとうにありがとうございます。
私としては、PWMを使わずに、矩形波発振だけで行きたかったのですが、
どうにも無理そうだ…という結論ですので、
諦めてPWMを使ってしまおうかと思います。

しかしながら、>>32のプログラム…全く理解できないのが現状です…orz
いろいろ無理を言ってしまい、ほんとうに申し訳ありませんが、
PWMの解説を含め、私の目的に合ったプログラムを作成できれば…と思います。
このスレにおいては、高度すぎますでしょうか。
もし、ふさわしくないのなら、誘導していただけましたら、移動します。

90774ワット発電中さん :2007/12/25(火) 12:43:09 ID:JwBFP2yk
PICでDTMF発振器を作りたいっていってたやつ、
ズバリこれのことじゃないか?
用途もWiRES(だっけ?)用みたいだし。
ttp://jm7muu.com/index.php?DTMF%C1%F7%BF%AE%B5%A1%A5%AD%A5%C3%A5%C8
キット化されているみたいだし、
参考に買ってみるのも良いんじゃない?
ってか、これがあったら自作する意味ないよね(それ言っちゃオシマイか)

10928,40 [sage] :2007/12/28(金) 22:45:46 ID:sFbW+M+u
言うばっかりでは何なんで、そのうち実装してみようとは思っていたんだが、ようやく
無駄な遊びをする精神的余裕が出てきたんで、やってみた。

http://xcrosgs2wy.web.fc2.com/dtmf/src/main.c    ソース(CCS C v3.249向け)
http://xcrosgs2wy.web.fc2.com/dtmf/src/main.hex   HEXファイル


PIC16F84Aを使ってDTMFを生成。クロックは「DTMFの人」にあわせて4MHz。
出力はPWMなんでパルス状だが、波形テーブルはいちおうサインカーブなので、
フィルタを通せば正弦波っぽくなる。PWM周期は約18kHzなんで、無線で使うので
あれば(どうせそんな高音が乗るわけないから)フィルタを別途付けなくても
結果は変わらないと思う。

出力周波数は、クロックが正確に4MHzの場合、誤差±0.1%以内に入っているはず。
クロックが正確に4MHzでない場合に対応するため。±10.0%の範囲で0.1%刻みに
DTMF周波数の微調整が可能。

出力ピンは>>32>>90のDTMFジェネレータと同じくRB3を使用。ソースレベルで
変えればどの出力ピンにでも変えられる。

入力はキーパッドではなく、RB6/RB7を使った1200bpsシリアルコマンド方式。
PICkit2を持っていれば、ICSPで接続したままコマンドの入出力が可能。


コマンドはこういう感じ。

・DTMF発音(0123456789*#ABCD)
  コマンド文字(1文字)を送信すると、すぐに発音を開始。発音を終了すると
  「OK」を返す。

・DTMF発音長設定(S1=nnn)
  コマンド文字列(S1=nnn, nnnは40から3000の数値)に続けてEnterを送信すると
  「OK」を返し、それ以降のDTMF発音の長さをnnn(単位はミリ秒)に設定する。
  発音長の初期値は95ミリ秒。nnnが範囲外の場合は「ERROR」を返す。

・DTMF発音長設定問い合わせ(S1?)
  コマンド文字列(S1?)に続けてEnterを送信すると、現在の発音長の設定を
  「S1=nnn」の形で返し、続けて「OK」を返す。

・DTMF周波数設定(S2=nnn)
  コマンド文字列(S2=nnn, nnnは900から1100の数値)に続けてEnterを送信すると
  「OK」を返し、それ以降のDTMF周波数を標準に対してnnn/10(単位はパーセント)に
  設定する。初期値は1000(100%)。nnnが範囲外の場合は「ERROR」を返す。

・DTMF周波数設定問い合わせ(S2?)
  コマンド文字列(S2?)に続けてEnterを送信すると、現在のDTMF周波数設定を
  「S2=nnn」の形で返し、続けて「OK」を返す。


HEXファイルのほうは、プログラムFLASHが1024ワードのうち1000ワード、RAMが
68バイトのうち66バイトを使用。作成途中で、入りきらなくなって何度もソースを
手作業で最適化したくらいなんで、これ以上は何も入りそうにない。

最後のテスト中に間違って14Vかけてしまって、1個しか持ってない、なけなしの
PIC16F84Aを飛ばしてしまった・・・クロックジェネレータとして使っていた
PSoCも一緒に昇天www


戻る
inserted by FC2 system