![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?5a7ff87)
こんにちわ。
大学の研究で声の周波数をH8/3052で
示そうと考えています。周期を使ったプログラムですが、
声をA/D変換された電圧で、電圧が0になった所を0.125秒間で何回かカウントして
d = 0.1025 * 2 / count;//一周期分=半周期×2倍÷カウント(0になった数)
F=1/d (周波数=1/周期)を使い、ある範囲の周波数内になったらLEDが光るというプログラムを作りたいのですが、何も表示されません。皆様の知識をお借りしたいです。よろしくお願いします。プログラム乗せますのでご指摘お願いします。
//A/Dコンバータテストプログラム
//AN0からの入力電圧をLCDに表示
#include <3048F.h>
#include <io.h>
#define E_SIG 0x20
#define RS_SIG 0x10
void ioinit(void)
{
P5.DDR = 0xff;
}
void adinit(void)
{
AD.CSR.BIT.ADF = 0; //ADFフラグクリア
AD.CSR.BIT.SCAN = 0; //単一モード選択
AD.CSR.BIT.CKS = 1; //クロックセレクト
AD.CSR.BIT.CH = 0; //チャネルセレクト AN0単一モード
}
void wait(void)
{
int t = 1000;
while(t--);
}
int main(void)
{
int add; //変換された信号を記憶する
int i;
int t;
int b;
int d;
int f;
int v;
int count;
ioinit();
adinit();
wait(); //電源ONで15ms以上待ち
while(1)
{
AD.CSR.BIT.ADST = 1; //A/D変換スタート
while(AD.CSR.BIT.ADF == 0); //変換終了を待つ
add = AD.DRA >> 6; //AN0入力、6ビット右にシフト、大切
AD.CSR.BIT.ADF = 0; //フラグクリア
add=(int)((add*(5.0/1024.0)*1000.0)+0.5);//入力データを電圧値に換算
v=add;
while(b = 8500) //0.125s間
{
while(b--);
if(0==v)//0Vになったときカウント
{
count++;
}
}
d = 0.1025 * 2 / count;//半周期×2倍÷カウント(0になった数)
f = 1 / d;//F=1/T(周波数= 1 ÷ 周期)
}
wait();
if(4000<=f<=8000)//周波数Fが4000~8000Hzになったら実行
{
lcdxy2(); //2行目指定
dsp1g(" O K "); //2行目クリア
wait();
}
}
}
A 回答 (5件)
- 最新から表示
- 回答順に表示
No.5
- 回答日時:
連投申し訳ありませんが, 気になったので追記いたします.
wait関数で減算させている初期値ですが1000で足りていますでしょうか?
コメントから15msec以上と読み取りましたが, 動作クロックとwait関数内のwhileループ部分の実行サイクル数の確認が必要です.
規定時間待つ為には, タイマ割り込みを利用してある程度正確な時間を取得するのが一般的ですが, 多少コーディングの難易度が上がります.
簡易的なビジーループを用いる場合は十分な時間が待てているかの確認が必須です.
300Hのコンパイラが今手元にないため概算ですが, 最適化を正しく抑制しておいた場合,
少なくとも"減算命令+比較判定+ジャンプ命令"は実施されますので5~7サイクル程度になるだろうと見積もりました.
実行サイクル数についてはアセンブラ出力から最終的な確認が必要です.
仮に動作クロックが1MHzだった場合でも, カウントダウンに5~7msec程度しか掛かりません.
3052の上限は50MHzだったはずですのでカウント値1000では最悪100usec程度しか待機しない可能性もあります.
対策として動作クロックに併せてカウント値を増やす場合には, さらに16bitのint型で表現できる値に収まるかの注意が必要です.
無難に volatile unsigned long 辺りに変更しておけば, 型の問題は起きないと思います.
No.4
- 回答日時:
#2の方と同意見です.
提示のコードでは突っ込むべき所が多く, 問題点の抽出は難しいです.
各モジュール(ドライバ)単位で動作確認を行い, 問題点の切り分けを行うのがデバッグの第一歩です.
どなたもまだ挙げていない問題点が, wait関数の実装にあります.
開発環境が不明なので断言はできませんが, 現状のカウント値の減算によるビジーループでは機能しない可能性が高いでしょう.
変数tの減算によりループを実装していますが, 最終的な値が0になることが明白であるためコンパイラの最適化によって減算処理が省略されてしまいます.
(最適化の精度や, コンパイルオプション, 変数の割付位置等によりどう扱われるかは提示の情報からは見極めできません)
コンパイラの最適化の対象外とさせるため, 初期化を伴う変数の定義時にvolatileを付加する必要があります.
組み込みの世界では知ってて当然の知識として扱われるため, 注意が必要です.
"volatile"でweb検索してみてください. 私がここに記述するよりも良いヒントが多く見つかると思います.
//-- sample
void wait(void)
{
volatile int t = 1000;
while(t--);
}
![](http://oshiete.xgoo.jp/images/v2/common/profile/M/noimageicon_setting_04.png?5a7ff87)
No.3
- 回答日時:
ちょっと補足です。
5.0/1024.0 は、「小数点付きの定数は double」なので、
double で計算されます。
このため、
(5.0/1024.0)*1000.0)+0.5)
は、double 型の結果を返します。
さらに、
int * double は、int -> double への変換が発生します。
このため、
add*(5.0/1024.0)*1000.0)+0.5
は、全体で、double として計算されます。
>d = 0.1025 * 2 / count;
これは、* と / は、左 → 右 の順に結合するので、
(0.1025 * 2) / count
と結合します。
いずれも、double * int, double / int になるので、
全体として、double で計算はされます。
ただし、d が int である以上
1 / d は、意味を持たない結果になるでしょう。
>if(4000<=f<=8000)
これは、意図したとおりには動かないでしょうが、文法的には
間違っていません。
なので、コンパイルは動きます。
if ((4000 <= f) <= 8000)
と解釈されます。
この結果、
4000 <= f の真偽で、1 または 0 が返り、
最終的に、
if (1 <= 8000) か、(4000 <= f の場合)
if (0 <= 8000) になります(こちらは、4000 > f の場合)
いずれにしても、if (4000 <= f <= 8000) は、常に真
です。
No.2
- 回答日時:
こんにちは。
ソースを拝見して申し上げたい事は山のようにありますが・・・。
まずはコーディングの事について。
整数型(int)の変数しかないのに、実数の計算があります。
>add=(int)((add*(5.0/1024.0)*1000.0)+0.5);
この中の、"5.0/1024.0"は、ゼロになっちゃうので、計算は成り立ちません。
同様に、
>d = 0.1025 * 2 / count;
>f = 1 / d;
も無理です。
あと、
>if(4000<=f<=8000)
コンパイルできていますか?
次に、研究と開発の手法についてです。
特に、こういう複雑なシステムについて言えますが、作っていきなり完動する事は、まず「あり得ない」と断言できます。
本件の場合、ざっと考えただけでも、
1.マイコンそのもの
2.LCD
3.A/Dコンバータ
4.LED
5.音声を電圧に変換する
6.周波数を測定する
といった数多くの要素があり、現在お困りの件でも、1~4をすべて動かす必要があります。
どこまで動いている事が確認できていますか?
いきなり全部、ではなく、一つ一つ確かめていかれる事をお勧めいたします。
あと、そもそもな話ですが、その方法論で本当にお望みの機能が実現できるのか、確認されていますか?
音声を電圧に変換した際に、どのような波形で入力されるのか、確かめていますか?
入力された電圧が、どのようなデータに変換されるか、確かめていますか?
マイコンの選定は、大丈夫ですか?
そのマイコンのA/Dコンバータの性能で、8kHzのゼロクロスを測定できるほどのサンプリングができる事は、確認できていますか?
![](http://oshiete.xgoo.jp/images/v2/common/profile/M/noimageicon_setting_04.png?5a7ff87)
No.1
- 回答日時:
if(4000<=f<=8000) //周波数Fが4000~8000Hzになったら実行
記述が間違っているので、思った通りの動きはしません。
{
lcdxy2(); //2行目指定
dsp1g(" O K "); //2行目クリア
wait();
}
条件が合致したときに「表示」していますが、条件が合致しないときには何もしないので、一度表示されたら消えることがありません。
while(b = 8500) //0.125s間
{
while(b--);
if(0==v) //0Vになったときカウント
{
count++;
}
}
ここは、単なるミスなのか、または、非常に誤解を招きやすい記述をあえてしているのかどちらかですが、たとえば、
for(b = 8500; b; b--);
if(0==v) //0Vになったときカウント
{
count++;
}
とか、
for(b = 0; b <= 8500; b++);
if(0==v) //0Vになったときカウント
{
count++;
}
という動きを意図したのでしょうか?
また、count++;
が実行されるのは、(コメントが正しければ)最大でも 0.125s に一度です。
これから、
d = 0.1025 * 2 / count
f = 1/d = 1/(0.0125 * 2 / count)
= 1/0.0125/2 * count;
= 4.8 * count;
f が 4000 に到達するのは、(ゼロクリアされていると仮定すると)最短でも、104秒後
また、count は、インクリメントされるのみで、クリアも(初期化も)されていませんから、実際にはどうなるかわかりません。少なくとも、周波数を反映してはいません。
あと、前提条件として、
> 電圧が0になった所を0.125秒間で何回かカウントして
というのは、いろいろな点で不都合です。
・周波数をカウントするには、ゼロクロス点(上から下に横切る or 下から上に横切る)を数える必要がある。無音だったら、ゼロが連続するのではないか?
・そもそも、AD コンバータにはどういう信号が入っているのか? 本当に無音がゼロ?
・特に、「声」の場合ノイズ成分がとても多い。単純にゼロ点(とか、ゼロクロス点とか)をカウントすると、ノイズ成分のために、とんでもなく高い周波数がカウントされる。
など。
また、このソフトでは、そもそも、AD 変換が 0.125秒以上の間隔でしか動きませんが、入力される周波数の上限の2倍程度の頻度で動かす必要があります。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
- C言語・C++・C# このプログラミングの問題を教えて欲しいです。 キーボードから整数kを入力し、kが配列aの中に何個存在 2 2022/12/19 22:50
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# このプログラミングの問題を教えてほしいです。 キーボードからデータ数nとn個のデータを入力し、平均値 3 2022/12/19 22:51
- C言語・C++・C# C言語 3 2022/10/04 15:07
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# C言語 3 2022/11/09 13:27
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
intとlongは同じ?
-
2の補数を計算するプログラム
-
迷路を脱出する経路探索プログ...
-
再起呼び出しの回数をカウント...
-
3のつく数と3の倍数を表示 C言語
-
C言語プログラミング 漸化式に...
-
乱数生成について
-
プログラミングの問題で分から...
-
異なるn個の整数からr個の整数...
-
カードシャッフルのブログラム...
-
コマンドプロンプトを使用して...
-
[初級]C言語:コマンドラインか...
-
argvのNULLチェック
-
C言語の問題
-
whileとifを使い偶数を出すには
-
C言語で簡単なパックマンゲーム...
-
C言語のプログラムについて(...
-
【C#】SQL文の中に変数を埋め込...
-
分数の足し算をさせるプログラ...
-
C言語のプログラム
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
intとlongは同じ?
-
C言語で%を使わない余りの出し方
-
2の補数を計算するプログラム
-
再起呼び出しの回数をカウント...
-
画像の拡大・縮小
-
迷路を脱出する経路探索プログ...
-
分数の足し算をさせるプログラ...
-
OpenCVによる4値化について
-
3のつく数と3の倍数を表示 C言語
-
C言語で簡単なパックマンゲーム...
-
ヌメロンのプログラム
-
C++で表を作成したいのです ...
-
複数の共有メモリの作成
-
カードシャッフルのブログラム...
-
whileとifを使い偶数を出すには
-
関数とビット列
-
【C#】SQL文の中に変数を埋め込...
-
異なるn個の整数からr個の整数...
-
c言語プログラミングについて f...
-
条件が多い場合
おすすめ情報