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

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

ただいまの
回答率

90.48%

  • Python 3.x

    6863questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • Raspberry Pi

    846questions

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

トグル動作によるLEDの点灯制御について

解決済

回答 6

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,102

myu

score 12

トグルスイッチでのLEDの点灯を制御したいのですが、
下記のようなソースで割り込みの箇所
pi.wiringPiISRの関数で、トグルスイッチを押すとプログラムが終了してしまいます。
本来は、無限ループなので、プログラムが終了することはないのですが。
原因が、わかりません。

import time, wiringpi as pi

led_pin = 23
bt_pin = 17
counter = 0

pi.wiringPiSetupGpio()
pi.pinMode( bt_pin, 0 )
pi.pullUpDnControl( bt_pin, 2)
pi.pinMode( led_pin, 1 )

def Warikomi():
  global counter
  if ( pi.digitalRead( bt_pin ) == 0 ):
    counter = counter + 1

try:
 ret = pi.wiringPiISR( bt_pin, pi.INT_EDGE_BOTH , Warikomi )
  while True:
    if ( counter % 2  == 0 ):
      pi.digitalWrite( led_pin, 1 )
      time.sleep(0.5)
      pi.digitalWrite( led_pin, 0 )
      time.sleep(0.1)
except KeyboardInterrupt:
  pi.pinMode( led_pin, 0 )
finally :
  pi.pinMode( led_pin, 0 )


動作としては、プログラムが開始すると、LEDが点滅します。
ボタンを押して、LEDの点滅を止めようとすると、プログラムが終了(正常終了?異常終了?)してしまいます。

下記は、その時の結果(添付画像が何故かさかさまになります。すみません。)
イメージ説明

問題を単純化してみたのが次のコードです。

global counter
bt_pin = 17
counter = 0

pi.wiringPiSetupGpio()

def Warikomi():
  print( "割り込み関数通過" )

try:
  ret = pi.wiringPiISR( bt_pin, pi.INT_EDGE_RISING , Warikomi )
  while True:
    time.sleep(0.5)
    counter = counter + 1
    print( counter )
    time.sleep(0.5)
except KeyboardInterrupt:
  print ("except通過" )
finally :
  print ("finally通過" )


このプログラムが開始すると、ディスプレイに1ずつカウントアップされ、
ボタンが押されたときにプログラムが終了(正常終了?異常終了?)してしまいます。
finally句は通りません。Warikomi関数も実行されません。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    退会済みユーザー

    2017/09/08 06:56

    WiringPlとWiringPl2があるんですね。紛らわしいですが違いがよくわからず。importでWiringPl(最終更新2017-08)の人とWiringPl2(最終更新2016-03)の人が居ました。 https://pypi.python.org/pypi?%3Aaction=search&term=wiringpi&submit=search

    キャンセル

  • mituha

    2017/09/08 08:25

    Package Ownerの違いでバージョンへの追従具合が違うだけに見えますね。実際どうなんだろ?

    キャンセル

  • myu

    2017/09/08 11:27

    なるほど。勉強になります。slashさんのリンクしているサイトからwiringPi.cを確認しているのですが、(Raspbianの中のwiringPi.cが現在、探せていません。)正直、怪しいところにprintfを入れて確認したいのですが、それをコンパイルする方法(技量がない)がわからないので、(本題からそれてる気がします)調査中です。

    キャンセル

回答 6

checkベストアンサー

+3

とりあえず、 time.sleep の代わりに pi.delay とWiringPIで用意されている関数を使用することで動作するようです。

examples でも delay を使っているので何か理由があるのだとは思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/11 09:45

    mituhaさん、ありがとうございます。time.sleepのところをpi.delayに置き換えてうまくいきました。色々調べていたのですが、exampleの方までたどり着かず、迷宮入りしそうでした。本当にありがとうございました。

    キャンセル

+1

PythonもWiringPiも使用していないので的外れかもしれませんが…

 ret = pi.wiringPiISR( bt_pin, pi.INT_EDGE_BOTH , Warikomi() )

の Warikomi() の () はいるのですか?  
割り込み用の関数登録だと他の言語では括弧なしで関数自体の登録になるのでは?
(Pythonは知りません)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/06 11:34

    ご意見ありがとうございます。すみません。確かに必要ありませんでした。ただ、現象は、やはり同じです。ご指摘ありがとうございます。

    キャンセル

  • 2017/09/06 12:35

    後、wiringPiISRはwhileの外で1回のみ呼び出すべきではないでしょうか?
    wiringPiISRが複数の登録を想定していた場合は落ちそうです。

    キャンセル

  • 2017/09/07 10:45

    ご意見ありがとうございます。連絡遅くなりました。whileの外に出し、wiringPiISRを実行しても結果が変わりませんでした。ご指摘ありがとうございます。

    キャンセル

  • 2017/09/07 11:18

    一般的な作りとして気になるのは、
    INT_EDGE_BOTH の場合、立ち上がり、立ち下がりの2回割り込みが走る。
    割り込みの中でSleep等を行って良いか?
    ですかね。
    後、counterが奇数時にもsleepをいれた方が負荷が少ないかもしれません。

    キャンセル

  • 2017/09/07 16:58

    ご意見ありがとうございます。「INT_EDGE_BOTHのところ」は、本来の仕様では、INT_EDGE_RISINGです。(wiringPiISRの関数がうまくいかないので、いろいろ変えていたら、戻すことを忘れていました。)「割り込みの中でSleep等を行って良いか?」なのですが、LEDの点滅を行う際、どうしてもsleepを使わないと出来ないため、(他に方法がわかりません。python、ラズパイ初心者です。)使用しております。ご指摘ありがとうございます。

    キャンセル

  • 2017/09/07 17:18

    あ、点滅側は多分Sleepで問題ないと思います。
    むしろ、点滅させない時にSleepが入っていない方が問題になるかも。

    気になるのは、Warikomi側のSleepです。
    一般的には割り込んだ処理の中では色々しないほうが無難です。

    私の方もPython、ラズパイ共にほとんど使用しておらず、、
    別な言語や装置等の場合の話ですので、今回の症状のヒントぐらいと思ってください。

    キャンセル

  • 2017/09/07 18:32

    >気になるのは、Warikomi側のSleepです。
    そうですね。Warikomi側のSleepは、必要ないです。
    ご指摘ありがとうございます。

    キャンセル

  • 2017/09/09 11:00

    とりあえず、症状が再現することをラズパイ3で確認しました。
    環境依存ではなさそうですね

    キャンセル

  • 2017/09/11 11:54

    現象を再現してくださったのですね。ありがとうございます。

    キャンセル

+1

(Raspberry Piに興味はありますが、まだ触ったことがないので)確証はありませんが、
Re: wiringPi interrupts crashingのGordonさんによれば、

 全体が書いてないからいまいちわからないけれど、wiringPiISR()をループの中で呼び出していないかい?どうもそうっぽいんだけど。プログラム全体の中で、モニターしたいPINごとにただの一回だけ呼び出すようにするべきだよ。

だそうです。こちらの対応でダメであればもう少し調べてみます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/06 19:14

    mituhaさんがお昼にコメントしたものと同じですね o.0

    キャンセル

  • 2017/09/07 10:45

    ご意見ありがとうございます。連絡遅くなりました。whileの外に出し、wiringPiISRを実行しても結果が変わりませんでした。ご指摘ありがとうございます。

    キャンセル

  • 2017/09/07 11:20

    門外漢なので勉強になります。

    キャンセル

+1

def Warikomi():が何も返さないのがエラーの原因かもしれません。

怪しいと思って調べたところ、StackOverflowのnickzamさんによれば、

Cについて造詣はないけれども、オレがソースを見るにこのコード(関数がVOIDを返したりエラーが起きるかどうかチェックする)が原因だと思う。だからオレは、my_int()の中で明示的にTrueを返すようにするか、1を返すようにすることを勧める。
今Pythonの関数の中ではNoneを返しているし、それで(Cのソース中の)関数の末端に来るけれども、(Cのソースによれば)何も返せないってことでしょ。


多分以下のコードで対応できます。

def Warikomi():
  print( "割り込み関数通過" )

  # wiringPiISR requires value
  return True

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/07 21:51

    ご意見ありがとうございます。def Warikomi()にreturn ture, return 1
    両方試しましたが、結果は同じでした。
    問題を単純化したコードでprint( "割り込み関数通過" )が実行されていないので、return tureやreturn 1も実行されていないような気がします。ただ、この問題は、是非とも解決したいので、何かありましたら、連絡ください。私も、https://projects.drogon.net/raspberry-pi/wiringpi/functions/のサイトから、wiringPiISRを調査しています。

    キャンセル

+1

解決としていいのか少々疑問なのですが、
(やりたいことが出来たからよしとします。とりあえず。)
WiringPiの「wiringPiISR」ではダメなのかと思い、
pigpioの「callback」を使用しました。
結果、思い通りの動きをしてくれました。

ご意見、ご指摘をくださった方々、大変ありがとうございました。

出来れば、WiringPiで行いたかったのですが、(pigpioが、現時点で、あまりよくわかっていないため。)
もし何かありましたら連絡ください。

以下のコードは、問題を単純化してみた時のコードをpigpioで書いてみました。
(こう見ると、wiringPiISRの引数にあるwarikomiの関数の引数に問題があるのかといろいろ試しましたが関係なさそうです。)

import pigpio
import time

bt_pin = 17
counter = 0

pi = pigpio.pi()

def warikomi(gpio, level, tick):
    print( "割り込み関数通過" )

cb = pi.callback(bt_pin, pigpio.RISING_EDGE, warikomi)

try:
    while True:
        time.sleep(0.5)
        counter = counter + 1
        print( counter )
        time.sleep(0.5)

except KeyboardInterrupt:
    print ("except通過" )
finally :
    pi.stop()
    print ("finally通過" )

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

終了するのは?ですが、warikomi発動しないのはわかります。

exampleと比較して:

ret = pi.wiringPiISR( bt_pin, pi.INT_EDGE_RISING , Warikomi )

ret に束縛してるのみで実行されていないのでは? つまり登録されていない。
ret =がいらないのでは。 

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/09 20:35

    ごめんなさい。見当違いでした。実行した結果がretに束縛されるはず、ですよね。忘れてください。

    キャンセル

  • 2017/09/11 10:00

    ご意見ありがとうございます。皆さんのおかげで、疑問が解消できました。本当にありがとうございました。

    キャンセル

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

  • ただいまの回答率 90.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python 3.x

    6863questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • Raspberry Pi

    846questions

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