質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Q&A

解決済

2回答

12066閲覧

RaspberryPiで割り込み処理

Yomogi

総合スコア8

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

0グッド

0クリップ

投稿2017/02/02 14:55

編集2017/02/04 10:38

c言語初心者なため、質問させていただきます。
ラズパイで赤外線LEDや赤外線受光モジュール・LCDディスプレイ・タクトスイッチを使って、サバイバルゲーム企画をゼミで進めています。
ラズパイを組み込み機器のようにして、赤外線銃と赤外線受光部を作ろうと思っています。

使用言語はC言語で開発しています。

機能の概要としては、

  1. ボタン入力を受け取ったときに赤外線を送信し残段数を減らしLCDに表示
  2. 赤外線受光モジュールが赤外線を受光したときに、HPを減らしLCDに表示
  3. 1番とは別のボタン入力を受け取ったときに残弾数回復(いわゆるリロードです)そしてLCDに表示
  4. サバイバルゲーム1試合を管理するゲームの開始・終了・死亡から復活までの待機などの時間管理
  5. 上記イベントが発生したときに,用意しておいた効果音の再生

などを目標にしていました。

1.2.3に関してはwiringPiライブラリの関数であるWiringPiISRで各自GPIOピンに対する割り込みイベントの設定
4に関しては、1秒周期のタイマー割り込みを使用し時刻を更新して条件(開始時刻など)に合致させる
5に関しては、c言語上でsystem関数を使い[aplay]コマンドの実行

などで実装を試みました。

ですが、実際に起動してみると割り込みがそれぞれ衝突してしまうのか、不具合が多く発生してしまいました。
実際に起きている不具合としては

  • LCDディスプレイで意図しない場所に表示がずれてしまう。(HPの場所に残段数が表示される)
  • タイマー割り込みが発生するからなのか、sleep関数 1秒以上(おそらくタイマ割り込みの周期)が使えない
  • タイマ割り込み上でsystem関数を使うと入力を一切受け付けなくなってしまう

などが発生してしまいました

そこでいくつか質問させていただきます。

質問その1wiringPiISRで宣言したイベントを一時的に禁止・停止させる方法はありますか?
もしそれがあるのならば、割り込みイベントAが発生したときに残りの割り込みイベントBなどに対して禁止できれば
割り込みが重なることがないのでは?と考えたためです。

質問その2質問その1の方法ではなくイベントひとつ発生時にほかの割り込みを禁止する方法はありますか?
おなじく、割り込みに重ねた割り込みをとめられるのでは?と思いました。

質問その3タイマー割り込みを使用している場合、sleep関数は使えないものなのですか?
できないのであれば、sleep関数のみで何とか実装しようと思っています。

質問その4そもそもが組み込みプログラム上でのsystem関数はナンセンスでしょうか?
音声の再生時間にCPUが多くとられているのなら、時間的にもったいないのかなと思います。

質問その5組み込み機器での入力の待機処理というのはwhileやforによる無限ループやpause関数で実現しているのですか?
本企画がサバゲーなので、どうしても入力が一切ない待機状態(タイマ割り込みを除く)があるため、どう実装しようか模索中です。

現状での問題点は上記になります。
Raspberryで同じく電子工作をしている方や組み込みに携わったことのある方 ご教授いただけたらと思います。

自分でも調べてはいるんですが、知識が圧倒的に乏しく時間に余裕がないため質問させていただきました。

よろしくお願いします。

2/3 11:00ソースコード追記
先にごり押し版を掲載させていただきます。
ir_game.c

2/4 19:36 ソースコード改変版
ir_test_game.c

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

これは具体的にソースを見せてもらわないと回答は難しいと思います。
が、なんとなく、状態遷移がうまくできていないんじゃないかなという印象があります。

また、割り込み処理内で処理を詰め込みすぎでは?割り込み処理は、できるだけ短時間で済ますべきです。
具体的にはセマフォなどで割り込みが起こったことを通知するだけ、とか、残弾数をデクリメントするだけとかにとどめて、そのほかの処理は全部メインループの中で行うようにすべきだと思います。

こうすれば、状態遷移はメインループ内だけで管理すればよく、また仮に多重割り込みが起こって処理はシリアルなので変なことになりにくくなると思います。

記事を参考に状態遷移図を書いてみるのをお勧めします。
http://www.itmedia.co.jp/keywords/statetransitiontable.html

wiringPiはちょっといじったぐらいなので詳しいことはわからないのですが、
質問その1、質問その2
パッと見で禁止する方法が書いてなさそうだったのですが、割り込み関数にnullを渡すのではだめでしょうか?
ただ、状態遷移がちゃんと管理されていれば別に禁止する必要はなさそうな気がしますし、禁止できたところで状態遷移がちゃんと管理できていなければうまく動かないような気がします。
(不確実な情報ですが、多重割り込みは可能なようでした)

質問その3、質問その4
使えるとは思いますが、割り込み関数の中ではやめたほうが良いでしょう。

質問その5
ウェイトはできるだけタイマー割り込みを使いましょう。

投稿2017/02/02 17:41

CodeLab

総合スコア1939

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Yomogi

2017/02/02 23:32

CodeLabさん、回答ありがとうございます。 確かに割り込み処理内に詰め込みすぎですね。と、いうと割り込み処理内でフラグを立てて、メイン内でフラグに対応した処理を行いすぐにフラグを倒す感じですかね? 割り込み処理にnullを渡すのとは違うんですが、一つのイベントが発生した時に、残り二つのイベントを空のメソッドで宣言してから回らせて、処理から抜ける寸前に正しいイベントを宣言 というゴリ押しをしてみたんですが、まだ少しうまくいかなかったです。 ご指摘を踏まえ、ソースコードの書き直しと状態遷移図の作成をしてみたいと思います。 ソースコードを載せずに申し訳ありません。編集後のソースを後ほど載せます。
guest

0

ベストアンサー

割り込みで行うのは最低限のことだけします。つまりフラグを立てる。
例えば、トリガーが引かれたら、トリガー引かれているフラグを立てる。
タイマー割り込みがあったら、やっぱりタイマーフラグを立てる。
条件分岐もしません。粛々とフラグを立てます。

そしてメインループで

フラグ群と
現在の状態(HP、残弾数、リロード残時間、発砲クールタイム残時間など)から
次の状態を算出し、
算出した次の状態から外部への出力(LCD、音)を求め(実行)ます。

特に状態遷移と外部出力を分けることで、コードがわかりやすくなります。


ループ処理の状態更新部分は雰囲気こんな感じです。あくまで雰囲気。

C

1if(!System.ShouldUpdate) // 100Hzとかで状態更新 周期はどこかに定数で持っておくと楽 2 return; 3 4if(Input.ButtonReload && !PreviousState.IsReloading){ 5 State.IsReloading = true; 6 State.TimeToReload = (int)(ReloadTime_ms / SystemTimerInterval_ms); // [ms] / [ms/update] 7} 8if(PreviousState.IsReloading){ 9 State.TimeToReload = PreviousState.TimeToReload - 1; 10} 11 12/* 13... 14*/ 15PreviousState = State; 16ResetFlag()

投稿2017/02/03 02:56

編集2017/02/03 04:57
ozwk

総合スコア13521

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Yomogi

2017/02/03 04:05

ozwkさん、回答ありがとうございます。 ご指摘通り、粛々とフラグを建てていきたいと思います。 重ねて質問なんですが、「タイマー割り込みがあったら、タイマーフラグを立てる」というのはゲームの開始・終了、プレイヤーの死亡・復活などのタイミングでという認識であっているでしょうか。 現時点でのタイマー割り込みは、1秒周期で割り込ませて現在時刻の取得などを逐一行っています。
ozwk

2017/02/03 04:31 編集

> 「タイマー割り込みがあったら、タイマーフラグを立てる」というのはゲームの開始・終了、プレイヤーの死亡・復活などのタイミングでという認識であっているでしょうか。 一秒周期で粛々とフラグ立ててもいいし、その認識の方でもいいです。 例えばリロードなら、 時間が関わる状態更新全般用にタイマ割り込みを用意して、リロードカウントを減らす方法と リロード専用にタイマ割り込みを用意する方法が考えられます。 ちなみに前者の場合は 1秒周期だとリロード終了に最大1秒の誤差が出てプレイヤーが体感できてしまいますが、 ビデオゲームのフレームレートが30-120Hz程度であることを考えると 10ms周期なら人間気になりません。
Yomogi

2017/02/03 04:41

なるほど。タイマー内にカウンターを置くという発想がありませんでした。お恥ずかしい・・・ ありがとうございます。 1秒ごとのタイマー割り込みによってSleep関数による待ちはあきらめていたので助かります。
ozwk

2017/02/03 05:09 編集

まあ要するに 「100Hzごとにここに書いたものが呼び出されます」とか 「現在ボタンが押されているかはInput.KeyPressed(keycode)で取得できます」 みたいな感じでいろいろ用意されていたら便利ですよね? 無いなら作ればいいじゃない。ってことです。
Yomogi

2017/02/04 05:30

了解しました。ありがとうございます。 アドバイス踏まえ、書き直していってます。 返事が遅くてすみません・・・
Yomogi

2017/02/04 10:49

アドバイスありがとうございました。まだタイマ割り込みの周期を変えての実装はしていませんが、変に割り込まなくなりました。 ・・・がしかし、肝心の赤外線の送信・受信が動かなくなってしまい原因を調べ中です。回路のほうはいじっていないので、プログラムのほうだとは思っています。 改変したソースコードを載せましたので、もしご指摘があればどうかよろしくお願いします。
ozwk

2017/02/05 06:19

送受回路はどういうものですか
Yomogi

2017/02/05 07:36

連投失礼します!無事におおまかな機能はうごかせるようになりました。 教えていただいたタイマ割り込みによる状態更新も、まだまだC言語になれていないのもあってフラグの乱立や時間を変数でもっていたりときれいではないですが、なんとか実装できそうです。 具体的な例やすばやい回答本当にありがとうございました。
Yomogi

2017/02/05 07:41

コメントの順番を間違えました、すみません。 電子工作もはじめて進めており、ブレッドボードとジュンパワイヤをつぎはぎにして電子回路を作っていました。 送信回路はトランジスタによるスイッチング回路を使っていました。 受信回路はすみません、ワイヤの一部が断線しているのを今朝方確認しました。 送信に関してなんですが、トランジスタのベースに電気を送るピンをpinMode(n,OUTPUT)で宣言していたのですが、うまくうごかず・・・ 送信直前(digitalWrite)で何度もピンの設定をしてあげると現時点で動くようになりました。
ozwk

2017/02/06 01:29

> 送信直前(digitalWrite)で何度もピンの設定をしてあげると現時点で動くようになりました。 怖い挙動ですね。 変なタイミングでピン設定が変わっているのかなんなのか 回路になんか無理があるのか... まあ動いたんなら何よりです。
Yomogi

2017/03/21 09:27

遅れて申し訳ありません。 ゼミ発表でも、なんとか動かすことができました 本当にありがとうございます!
ozwk

2017/03/21 23:23

間に合ったようでなにより。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問