合計 昨日 今日

チャタリング対策

フォーラムルール
フォーラムルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Name: ぱおぱお
[URL]
Date: 2017年8月10日(木) 16:38
No: 1
(OFFLINE)

 チャタリング対策

初心者です。
ロータリースイッチの切換え時にチャタリングが発生してしまいます。
whileの下にdelayを入れればいいのかと思ったのですが意味をなしていないようです。
PATTERN関数側にもいれてみたのですがこれも駄目でした。
恐らくdelayを入れただけではダメなことは初心者ながらわかったのですが
どこで何をすればいいのかわかりません。
どうすればいいのでしょうか?
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
    while(1){
        __delay_ms(10);
        switch(PORTB){
            case 0b00000001: PATTERN0(); break;
            case 0b00000010: PATTERN1(); break;
            case 0b00000011: PATTERN2(); break;
        }
    }

Name: みけCAT
[URL]
伝説なるハッカー(677,782 ポイント)
Date: 2017年8月10日(木) 16:52
No: 2
(OFFLINE)

 Re: チャタリング対策

試していませんが、適当な間隔でポートを読み、数回同じ値が連続した時、かつその時のみ条件分岐に使う値を更新するといいかもしれません。

↓このサイトでは1ビットですが、複数ビットでも同じと考えられるでしょう。
PICマイコン スイッチの入力 - パレットソフト
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Name: ぱおぱお
[URL]
Date: 2017年8月15日(火) 17:08
No: 3
(OFFLINE)

 Re: チャタリング対策

みけCAT さんが書きました:試していませんが、適当な間隔でポートを読み、数回同じ値が連続した時、かつその時のみ条件分岐に使う値を更新するといいかもしれません。

↓このサイトでは1ビットですが、複数ビットでも同じと考えられるでしょう。
PICマイコン スイッチの入力 - パレットソフト


言っていることはなんとなく理解できたのですが
どうコーディングすればいいのでしょうか?
サンプルコードを見ながら書いているのですが上手くいきません。
よろしくお願いします。

Name: ぱおぱお
[URL]
Date: 2017年8月16日(水) 17:06
No: 4
(OFFLINE)

 Re: チャタリング対策

みけCAT さんが書きました:試していませんが、適当な間隔でポートを読み、数回同じ値が連続した時、かつその時のみ条件分岐に使う値を更新するといいかもしれません。

↓このサイトでは1ビットですが、複数ビットでも同じと考えられるでしょう。
PICマイコン スイッチの入力 - パレットソフト


なにをどうしたらいいかわかりません。
質問①
switchの引数を(SwEdge)にすると前回情報がないので起動時に動作をしません。
どうすればいいですか?SwDataの現在のスイッチ情報だけみればいいのでしょうか?
質問②
特にswitch文に拘ってる訳じゃないのですがこの記述だと飛んだ先の関数で
SwEdgeが更新されないので無限ループに入ってしまいます。
main関数の中でif文で書いてもみたのですがどうしてもうまくいきません。(立てたビットを戻せないとか)
どうすればいいですか?
よろしくお願いします。

コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 while(1){
        SwData = SwGet();       // スイッチの取得
#if 1
        SwChatExcute(SwData);   // スイッチ情報のチャタリング除去 同じ値を数回見ている
        SwData = SwChatGet();   // 現在のスイッチ確定状態を取得
#endif
        SwEdge = (SwBefore ^ SwData) & SwData;  // 前回0で今回1のビットのみ1になる
        SwBefore = SwData;                      // 次回判定用に今回の情報を前回の情報へ
    while(1){
        switch(SwEdge){
            case 0b00000001: PATTERN0(); break;
            case 0b00000010: PATTERN1(); break;
            case 0b00000011: PATTERN2(); break;
        }
    }
void PATTERN0(void){
    while(SwEdge == 0x01){
        PORTAbits.RA0 = 1;
    }
    PORTAbits.RA0 = 0;
    return;
}

Name: みけCAT
[URL]
伝説なるハッカー(677,782 ポイント)
Date: 2017年8月16日(水) 18:47
No: 5
(OFFLINE)

 Re: チャタリング対策

タイマー割り込みが使えるのであれば、
タイマー割り込みでスイッチの状態をポーリングしてチャタリングを除去したスイッチの状態を変数に記録し、
メインの処理ではリアルタイムのスイッチの状態のかわりにその記録した変数を見て処理を行うといいと思います。

※試していません
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Name: ぱおぱお
[URL]
Date: 2017年8月17日(木) 10:00
No: 6
(OFFLINE)

 Re: チャタリング対策

みけCAT さんが書きました:タイマー割り込みが使えるのであれば、
タイマー割り込みでスイッチの状態をポーリングしてチャタリングを除去したスイッチの状態を変数に記録し、
メインの処理ではリアルタイムのスイッチの状態のかわりにその記録した変数を見て処理を行うといいと思います。

※試していません

チャタリングを除去したスイッチの状態はSwDataの変数に格納しています。whileの上にTOIE=1にしてるのでポーリングもしてる(?)と思います。しかし、その変数を見て処理するとスイッチが切り替わらなくなります。それにオンエッジ検出(教えていただいたサイトに書いてある)はしなくていいということですか?
当方まだプログラムを勉強しはじめてひと月も経っていないため言葉だけではまったく理解できないことが多いのでよろしくお願いします。

Name: みけCAT
[URL]
伝説なるハッカー(677,782 ポイント)
Date: 2017年8月17日(木) 11:25
No: 7
(OFFLINE)

 Re: チャタリング対策

ぱおぱお さんが書きました:チャタリングを除去したスイッチの状態はSwDataの変数に格納しています。

SwGet()、SwChatExecute()、SwChatGet()の中身が載っていないので、本当かどうかわかりません。

ぱおぱお さんが書きました:whileの上にTOIE=1にしてるのでポーリングもしてる(?)と思います。

肝心の割り込みハンドラが載っていないので、本当にポーリングしてるかどうかわかりません。

ぱおぱお さんが書きました:しかし、その変数を見て処理するとスイッチが切り替わらなくなります。

提示されたコードではswitch文のみをwhile(1)で囲んで変数を更新していないように見えます(割り込みハンドラで更新している可能性は否定できません)が、変数は更新していますか?

ぱおぱお さんが書きました:それにオンエッジ検出(教えていただいたサイトに書いてある)はしなくていいということですか?

ぱおぱおさんがやりたいことによります。
スイッチが切り替わったタイミングで何か特別な処理をしたいのであればオンエッジ検出をするべきですし、そうでなければしなくていいでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Name: ぱおぱお
[URL]
Date: 2017年8月17日(木) 13:37
No: 8
(OFFLINE)

 Re: チャタリング対策

みけCAT さんが書きました:
ぱおぱお さんが書きました:チャタリングを除去したスイッチの状態はSwDataの変数に格納しています。

SwGet()、SwChatExecute()、SwChatGet()の中身が載っていないので、本当かどうかわかりません。


SwGet()、SwChatExecute()、SwChatGet()の中身はみけCATさんに教えていただいたサイトにサンプルプログラムがありました。それをそのまま使っています。

みけCAT さんが書きました:
ぱおぱお さんが書きました:whileの上にTOIE=1にしてるのでポーリングもしてる(?)と思います。

肝心の割り込みハンドラが載っていないので、本当にポーリングしてるかどうかわかりません。


これは以前、みけCATさんに教えていただいたtmr0についてのコードをそのまま使用しています。

みけCAT さんが書きました:
ぱおぱお さんが書きました:しかし、その変数を見て処理するとスイッチが切り替わらなくなります。

提示されたコードではswitch文のみをwhile(1)で囲んで変数を更新していないように見えます(割り込みハンドラで更新している可能性は否定できません)が、変数は更新していますか?


見ての通りswitch文に入るとPATTERN関数に飛ぶので変数は更新されていません。ということは割り込みハンドラ(?)がポーリングしていないってことですね。main関数内では動いてるように思えたのですが・・・。恐らくここら辺を理解していないのが原因のように思えます。どこで何をどうすればいいのか全然わかりません。ご教示ください。

みけCAT さんが書きました:
ぱおぱお さんが書きました:それにオンエッジ検出(教えていただいたサイトに書いてある)はしなくていいということですか?

ぱおぱおさんがやりたいことによります。
スイッチが切り替わったタイミングで何か特別な処理をしたいのであればオンエッジ検出をするべきですし、そうでなければしなくていいでしょう。
[/quote]

やりたいことはLチカです。2つのLEDを点灯・消灯をいろんなパターンでLチカしたいです。

どうぞよろしくお願いします。

Name: みけCAT
[URL]
伝説なるハッカー(677,782 ポイント)
Date: 2017年8月17日(木) 16:59
No: 9
(OFFLINE)

 Re: チャタリング対策

ぱおぱお さんが書きました:SwGet()、SwChatExecute()、SwChatGet()の中身はみけCATさんに教えていただいたサイトにサンプルプログラムがありました。それをそのまま使っています。

わかりました。

ぱおぱお さんが書きました:これは以前、みけCATさんに教えていただいたtmr0についてのコードをそのまま使用しています。

更新されたコードはわかりませんが、提示されているコードはチャタリング防止どころか入力の処理がありません。
すなわち、ポーリングなんか全くしていませんね。

ぱおぱお さんが書きました:見ての通りswitch文に入るとPATTERN関数に飛ぶので変数は更新されていません。ということは割り込みハンドラ(?)がポーリングしていないってことですね。main関数内では動いてるように思えたのですが・・・。恐らくここら辺を理解していないのが原因のように思えます。どこで何をどうすればいいのか全然わかりません。ご教示ください。

予想ですが、割り込みハンドラでSwChatExecute(PORTB);を呼び出し、メインの処理(各パターンの処理をする関数を含む)でSwEdgeの代わりにSwChatGet()を使うと良さそうだと思います。

ぱおぱお さんが書きました:やりたいことはLチカです。2つのLEDを点灯・消灯をいろんなパターンでLチカしたいです。

やりたいことを実現するプログラムを書けばいいでしょう。
オンエッジ検出の意味はわかっていますか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Name: ぱおぱお
[URL]
Date: 2017年8月22日(火) 11:27
No: 10
(OFFLINE)

 Re: チャタリング対策

みけCAT さんが書きました:予想ですが、割り込みハンドラでSwChatExecute(PORTB);を呼び出し、メインの処理(各パターンの処理をする関数を含む)でSwEdgeの代わりにSwChatGet()を使うと良さそうだと思います。

みけCATさんのアドバイスを基に割り込みハンドラに下記の部分を丸ごと入れてswitchの変数をSwDataにしたら変数が更新されるようになりました。
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
void interrupt InterTimer(void){
    if(T0IF == 1){
        cnt++;
        T0IF = 0;
        if(cnt >= 5){
            cnt = 0;
        SwData = SwGet();
        SwChatExcute(SwData);
        SwData = SwChatGet();
        }
    }
}

しかし、スイッチの切り替え時にものすごく時間がかかるようになった気がします。そこでTMR0の周期を変えたのですが20msecほどずれるのです。以前教わった(tmr0について)ようにTMR0に入れる値を計算したら1,000,000÷(256×8)=781.25になり、256-781.25=-525.25でマイナスになってしまいます。このような場合はどうすればいいのでしょうか?
プリスケール:8
クロック:4MHz
ソフトウェアでの分周:5

みけCAT さんが書きました:オンエッジ検出の意味はわかっていますか?

申し訳ありません。理解していません。ただ単に前回と今回の違いを見ている変数だと思いSwEdgeの変数を使っていました。オンエッジとはどんな意味ですか?どんな時に使うのが正しいのでしょうか?よろしくお願いします。

Name: みけCAT
[URL]
伝説なるハッカー(677,782 ポイント)
Date: 2017年8月22日(火) 11:45
No: 11
(OFFLINE)

 Re: チャタリング対策

ぱおぱお さんが書きました:しかし、スイッチの切り替え時にものすごく時間がかかるようになった気がします。そこでTMR0の周期を変えたのですが20msecほどずれるのです。以前教わった(tmr0について)ようにTMR0に入れる値を計算したら1,000,000÷(256×8)=781.25になり、256-781.25=-525.25でマイナスになってしまいます。このような場合はどうすればいいのでしょうか?

「20msecほどずれる」というのは何がですか?
動作がいい感じになるようにプログラムを修正して書き込めばいいと思いますが、どうなってほしいのですか?

参考として、4MHz ÷ (4(何クロックで1回インクリメントか) × 8(プリスケーラ) × 256(オーバーフローまでのカウント数) × 5(ソフトウェアでの分周)) ≒ 97.7Hz となり、
この速さで5回同じ値が出るのを確認するのにかかる時間は約51.2msとなります。

ぱおぱお さんが書きました:オンエッジとはどんな意味ですか?どんな時に使うのが正しいのでしょうか?

オンエッジとは前回のポーリングではオフだったのに今回のポーリングでオンになったやつ、すなわちオフからオンに切り替わった瞬間のことです。
オフからオンに切り替わったことに反応して何か処理をしたい時に使うのが正しいでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Name: ぱおぱお
[URL]
Date: 2017年8月22日(火) 14:11
No: 12
(OFFLINE)

 Re: チャタリング対策

みけCAT さんが書きました:「20msecほどずれる」というのは何がですか?
動作がいい感じになるようにプログラムを修正して書き込めばいいと思いますが、どうなってほしいのですか?

言葉足らずで申し訳ありません。RA0のbitを1秒ごとにON/OFFしたときにオシロで計測すると1.020msで20msほどずれてしまうのです。この20msをもう少しなんとかしたいのですが、分周をいじればいいのかプリスケーラなのかTMR0に入れる値を変えるのか、タイマーをいまだ理解できておらずどうすればいいのかわかりません。もう少しお知恵をお貸しください。この20msのずれをなくすにはどうしたらいいですか?

みけCAT さんが書きました:オンエッジとは前回のポーリングではオフだったのに今回のポーリングでオンになったやつ、すなわちオフからオンに切り替わった瞬間のことです。
オフからオンに切り替わったことに反応して何か処理をしたい時に使うのが正しいでしょう。

なるほど。とてもよくわかりました。

Name: みけCAT
[URL]
伝説なるハッカー(677,782 ポイント)
Date: 2017年8月22日(火) 14:46
No: 13
(OFFLINE)

 Re: チャタリング対策

ぱおぱお さんが書きました:RA0のbitを1秒ごとにON/OFFしたときにオシロで計測すると1.020msで20msほどずれてしまうのです。この20msをもう少しなんとかしたいのですが、分周をいじればいいのかプリスケーラなのかTMR0に入れる値を変えるのか、タイマーをいまだ理解できておらずどうすればいいのかわかりません。もう少しお知恵をお貸しください。この20msのずれをなくすにはどうしたらいいですか?

どのようなプログラムでやっていますか?
それによって変わると思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Name: ぱおぱお
[URL]
Date: 2017年8月23日(水) 09:33
No: 14
(OFFLINE)

 Re: チャタリング対策

みけCAT さんが書きました:
ぱおぱお さんが書きました:RA0のbitを1秒ごとにON/OFFしたときにオシロで計測すると1.020msで20msほどずれてしまうのです。この20msをもう少しなんとかしたいのですが、分周をいじればいいのかプリスケーラなのかTMR0に入れる値を変えるのか、タイマーをいまだ理解できておらずどうすればいいのかわかりません。もう少しお知恵をお貸しください。この20msのずれをなくすにはどうしたらいいですか?

どのようなプログラムでやっていますか?
それによって変わると思います。

下記のように書いてます。
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
void PATTERN0(void){
    while(SwData == 0x01){
        PORTAbits.RA0 = 1;
        __delay_ms(1000);
        PORTAbits.RA0 = 0;
        __delay_ms(1000);
    }
    return;
}


Return to C言語何でも質問掲示板

オンラインデータ

このフォーラムを閲覧中のユーザー: なし & ゲスト[20人]