dポイントプレゼントキャンペーン実施中!

マイコン、電気回路初心者です。 h8 3052で回転計を作製をしたいのですが・・・知識を貸していただきたいです

マイコン初心者です。。。
h8 3052で回転計を作製をしたいのですが・・・知識を貸していただけたら幸いです。

回転数を算出の式として次を用いたいと思います(精度はあまり気にしないでください。。。)
回転数[rpm]=60[sec]/1回転に要する時間[sec]

リードスイッチとマグネット4つを使い回転数を算出したいと思っています。
リードスイッチが4つカウントしたときの時間(1回転に要する時間)を上の式の分母(t)に入れ演算させたいです。
ITUのタイマー割り込みを使い分母の時間をカウントをしカウントが4のときt=0と考えてました。
しかし、カウントを迎えてもtは永遠に1ずつ足され続け0に戻りません。 プログラムの考え方が違うのでしょうか?

使用環境からロータリーエンコーダ、フォトトランジスタなどが使えません。

チャタリングについては、本からRC積分回路(0.1μFとVccに10KΩ)使い、そこからさらに74HC04通してつかっているのですが・・・見よう見まね状態です。

開発環境はHEWを使っています。

勉強不足だと思いますが、10日くらい悩んでいます。力を貸してください。よろしくお願いします。
僕が立てたプログラムは次の通りです。

vector 12 IRQ0 (リードスイッチ 立下りエッジで割り込み要求)
__interrupt(vect=12) void INT_IRQ0(void)
{
count++;
INTC.ISR.BIT.IRQ0F=0;
}

vector 28 IMIA1
__interrupt(vect=28) void INT_IMIA1(void)
{
ITU1.TSR.BIT.IMFA = 0;
taco_interrput-=1;
if(taco_interrput==0)
{
t++;
}
taco_interrput=1;
}

void main()
{
  set_imask_ccr(1); //割り込み禁止
  INTC.ISCR.BIT.IRQ0SC=1; //タコメータ 入力立下りエッジで割り込み発生
  INTC.IER.BIT.IRQ0E=1; //IRQ0割り込み許可(タコメータ)
  
    ITU1.TCR.BIT.CCLR=1; //ITU1カウンタクリア要因
 ITU1.TCR.BIT.TPSC=3; //ITU1 3.125MHz
 ITU1.GRA=3125-1; //ITU1 3.125MHz/3125=1000Hz、周期1ms(0からカウントされるため必ず-1)
 ITU1.TIER.BIT.IMIEA = 1; //ITU1 IMFAフラグによる割り込み許可
 ITU.TSTR.BIT.STR1=1; //ITU1タイマスタート

 taco_interpput=1; //ITU(imia)割り込み回数1 割り込み先で1に戻るので無限

 while(1)
 {
  if(count==4)
   {
    time=t;
    t=0;
    count=0;
    n=60[sec]/time;
   }
  if(count>4) //カウントが4より大きくなってしまったとき
   {
    t=0;
   count=0;
   }
 }
}

(LCDのプログラムは長いので省きました)
LCDの液晶を使い以下のことは確認をしています。
・カウントが4を迎えたときカウントは0に戻っています。(IRQのカウントのことです)
・カウントを何回与えてもtが0に戻りません。なので演算されてないです。(tは永遠に1ずつ足され続けてます)

回転数の使う範囲は50~200rpmです。
tのカウントを0に戻す記述をどうしたいいのかよろしくお願いします。

※添付画像が削除されました。

A 回答 (10件)

 No.9 お礼への回答です。


 cShiftReg に staticが付いているので初期値は0 です。
 とゆうより、まともなパワーオンルーチンが働けば 0で初期化されます。
 わざわざ関数内に cShiftReg を置いているのは、他の関数ではこれを
触る必要もないし、触ってもらっては困るので、他の関数からは見えない
ようにしているわけです。

 P8-0が1の場合1msごとにcShiftRegの内容は以下のように変わって行きます。
  0000,0000
  0000,0001
  0000,0011
  0000,0111 <---- ここでHIと判定される
  0000,1111
 0 になる場合は、自分で考えて下さい。
 いずれにしても3ms間 1/0が連続しないと判定がひっくり返らないので
チャタリングレスになります。
    • good
    • 0
この回答へのお礼

大変遅くなり申し訳ございません。

分かりやすい解説ありがとうございます。誤検知はされないでなんとかできました!

いろいろとお世話になりました。またなにか機会ありましたらよろしくご教授よろしくお願いします。

お礼日時:2009/11/18 18:46

 以下は1msタイマー割込みでP8-0をチェックするようにしてあります。


 main()で何もしない場合、IRQ0によるcountの値とnShiftCountの値が
+/- 1 以内であればcountは正しくカウントされています。
 なお入力のチャタリングが5msなら、5ms間隔、10msなら10ms間隔で
入力をチェックするようにするとCRを付けなくてもチャタリングの影響
が除けます。
---------------------------------------------------------------------
#include "iodefine.h"

typedefunsigned charuchar;
volatileintnShiftCount;
volatileintcount;
volatileinttaco_interrput;
volatileintt;

#defineSHIFT_AND0x07

__interrupt(vect=12) void INT_IRQ0(void)
{
  count++;
  INTC.ISR.BIT.IRQ0F=0;
}

/* vector 28 IMIA1 */
__interrupt(vect=28) void INT_IMIA1(void)
{
  /*----------------------------------------*/
  staticucharcShiftReg;
  staticucharcOldP8_0;
        ucharcAndValue;
  /*----------------------------------------*/

  ITU1.TSR.BIT.IMFA = 0;
  taco_interrput-=1;
  if(taco_interrput==0)
  {
    t++;
  }
  taco_interrput=1;

  /* ------ シフトにより連続1/0確認 ------ */
  cShiftReg <<= 1;
  if (P8.DR.BIT.B0) {/* 現在はHI ?*/
    cShiftReg |= 0x01;
  }

  cAndValue = cShiftReg & SHIFT_AND;

  if (cAndValue == SHIFT_AND) {
    /* 完全なHI*/
    if (cOldP8_0 == 0) {
      cOldP8_0 = 1;
      /* 必要なら立ち上がりの処理*/
    }
  }

  if (cAndValue == 0) {
    /* 完全なLOW*/
    if (cOldP8_0) {
      cOldP8_0 = 0;
      nShiftCount++;
    }
  }
} 
    • good
    • 0
この回答へのお礼

チェック用のプログラムまで作製していただけるとは・・・なんとお礼をしたらよいか。。。実家がペンションで、ご招待したいぐらいです!

ひとつわからないことがあります。
ビット演算子のところを読みながらこのプログラムを見ています。cShiftRegには、もともとどうゆう値が入っているのでしょうか?それに0が1つ補充されORを取るとなど・・・あとは本を見ながらなんとなくですが理解できるのできるのですが。。。

お礼日時:2009/11/16 15:46

 No.6回答へのお礼に対する書込みです。


 オシロスコープの写真見ました。
 チャタリングは完全に取れています。
 小信号用のリードリレーの動作時間は1ms以下のようなので
CRの値は適当であったようですね。
 IRQ入力にしているので、CRを付けたのでしょうが、通常の入力ポートに
スイッチを付けた場合の例を明日アップします。
    • good
    • 0
この回答へのお礼

何度も、協力していただきチェックまでしていただきありがとうございます。

私は機械科ですが、丁寧に教えていただいてるため最近電気のことや情報処理ができてきて大変楽しい毎日を過ごさせていただいてます。

お礼日時:2009/11/16 15:14

 volatile宣言は割り込み処理でいじる変数に付けておき


他の関数内で予期しないタイミングで値が変わる事をコン
パイらに教えて望まない最適化を防ぎます。

voltile int count;
voltile int t;

main()
{
  while(1) {
    if (count == 4) <--- volatile宣言でこのままコンパイルされる
    • good
    • 0
この回答へのお礼

実際volatile宣言試したところ、成功しました!
初めてこの予約語の使い方がわかりました。ありがとうございました!

お礼日時:2009/11/13 18:34

 74HC14入力波形ですが



━━┓    ┏━━━ 5V
   ┃    ┃
   ┃    ┃
   ┗━━━┛ 0V
  ↑    ↑ フォントの関係で絵がうまくいきません
         正しい絵を推測して下さい。

 ↑の部分がCRによりなまっているでしょうが、途中に山や
谷が無ければ大丈夫です。
 また、途中に山/谷が有ったとしてもVIH 2.53[v]とVIL 1.25[v]
の間を往復していなければ大丈夫です。
 74HC14とH8/3052 P8-0,1,2入力はヒステリシスを持っているので
多少のノイズは有ってもかまいません。
 なお、電圧値は東芝TC74HC14APの値です。
 使用しているメーカのデータシートで確認して下さい。
 オシロスコープで入力波形を観測したら最高回転数時のLOWレベル
時間を答えて下さい。
 リードスイッチ割り込み回数確認の方法を示す事が出来ます。
    • good
    • 0
この回答へのお礼

大変、遅くなりました。申し訳ございません。
アナログのオシロスコープしかなくデジタルのあるところで波形を止めて観測しました。
http://album.yahoo.co.jp/photos/1672401/4768587/
ウェブアルバムに保存したので、見ていただけたらありがたいです。

常に使いたい回転数が約120rpmであり、その回転数あたりの波形です。 マグネットなんですが大きさを間違えて注文してしまったため、吸着力が弱くリードスイッチが反応しませんでした。なのでマグネットが一つの時の波形しかとれませんでした。

オシロスコープを使ったのが今回で2回目なので、ほんと初心者ですが・・・きれいな波形になったと思うのですがどうなんでしょうか?

お礼日時:2009/11/13 18:03

>10kを100に落とすということでいいのでしょうか?



 違います。10kとコンデンサの接続点からスイッチに行く部分に100Ωぐらいを入れます。
    • good
    • 0

>(0.1μFとVccに10KΩ)



 測定もせずに勘でやるなら、この程度で適当です。

 CRの積が大き過ぎると、スイッチの開閉周波数が高くなるとカウントしなくなる。
 CRの積が小さすぎるとチャタリング除去の効果が無い。
 オシロが有れば74HC14の入出力波形を見れば、適当かどうか分かります。
 スイッチまでの配線が長いと外部ノイズでカウントするかも知れない。インダクタンス分を生じて振動するかも知れない。その場合は、スイッチに直列に100Ωぐらいを入れれば良いでしょう。この抵抗は、コンデンサの急激な放電を制限する働きも有ります。
 
    • good
    • 0
この回答へのお礼

再度、ご教授ありがとうございます。

Cの容量ばかりを気にしていました。 インダクタンス分を生じて振動した場合、10kを100に落とすということでいいのでしょうか?勉強不足で申し訳ございません・・・電流が変わると磁束が変化し逆起電力を誘導するために抵抗を下げるということでいいのでしょうか?

またNo.2の回答のお礼に載せたとおりにプログラムを載せたところ(空白を合わせたつもりが、見にくくてすみません) 判別したところできたのですが、処理が途中で止まってしまいフリーズ状態になってしまいます。 アドバイスとしてvolatile宣言をもらったのですが、調べたのですが使い方と最適化がわからないのですが、どう解釈したらいいのか教えていただければ幸いです。

度々の質問お許しください。

お礼日時:2009/11/11 19:14

 大ざっぱなヒントだけです。



・周波数が高ければ周波数を測定する。
・周波数が低ければ、周期の逆数で周波数を求める。
・チャタリングの所は74HC04ではなく、74HC14を使う。
 オシロで測ってみないと、適正なCRの値か分からない。
・リードスイッチがどの位の周波数まで応答するのか注意。
・簡単な実験回路ならリードスイッチでも良いでしょうが、本格的にやるのなら、近接スイッチを使います。
    • good
    • 0
この回答へのお礼

ご回答、ご指摘ありがとうございます。

機械科なため、わからないことだらけでアドバイスなどとても感謝しています。
周波数=1/周期 というのはわかるのですが、オシロで見てどのような形の波形までになればいいのか教えていただければありがたいです。

74HC14はさっそく使ってみます。

今後ともまたよろしくお願いします。

お礼日時:2009/11/11 17:13

 No.1の回答は無視して下さい。


 リードスイッチオン1回で count が+1される事は確認されている
でしょうから、t,countをvolatile宣言してみるとか。............
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。いろいろあれからやってみたところ次のようにやってなんとか動きました。

vector 28 IMIA1
__interrupt(vect=28) void INT_IMIA1(void)
{
ITU1.TSR.BIT.IMFA = 0;
taco_interrput-=1;
if(taco_interrput==0)
{
t++;
a-=1;
}
void main()
{ 
a=1;
while(1)
 {
  if(a==0)
{ 
    a=1; 
if(count==4)
    {
     time=t;
     t=0;
     count=0;
     n=60[sec]/time;
    }
   if(count>4&&t>3000)//カウントが4より大きくなってしまったとき
    {
    t=0;
    count=0;
    }
  }
}
}

新しくaという変数を作り、while文よりしたのものをaに対するif条件を作りくくりまして、割り込んだ先でa=0にしました。そうしたところ、判別というのでしょうか・・・表現の仕方がわからないんですけど、今どちらの関数にいるのかを明確にしたところt=0になりました。

ただ、まだ不完全であるらしく処理が止まってしまうことがあります。ここで、バグといえばいいのでしょうか?処理を止めてしまう要因はどの辺にあたるのかご指摘あればよろしくお願いします。

お礼日時:2009/11/11 17:06

 よくわからんけど、INT_IRQ0() には飛んできますか。

    • good
    • 0
この回答へのお礼

volatile宣言をし、どう最適化されるのでしょうか?
また、このプログラムには必要になってくるのでしょうか?

すみませんがよろしくお願いします。

お礼日時:2009/11/11 19:16

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!