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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

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

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1154閲覧

tkinterを使って、root.after(10, readSerial)によってシリアル信号を周期的に受け取る

HiroPokeHero

総合スコア45

Python 3.x

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

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2019/08/18 15:08

実現したいこと

Pythonを使ってArduino(CANシールド搭載)とシリアル通信をして
別のArduino(CANシールド搭載)と通信をしたい。

その際に
tkinterを使って、
ボタン「受信開始」を押すとroot.after(10, readSerial)によって
周期的に信号を受信し、それをテキストボックスに出力する。
そして、ボタン「受信終了」を押すと周期的な受信を終了する。

前提

現状、受信開始ボタンを押すと1度だけの受信ができるようにすると、
正常に受信でき、
周期的に受信させようとすると、受信そのものは周期的にできるが、
その場合ほかのユーザ操作を受けて受けなくなあり、
受信終了ボタンを押すことができずにアプリを閉じないと止まらない。

やったこと

scriptは以下

import tkinter as tk from tkinter import ttk import serial ser = serial.Serial('COM3', 9600, timeout=0.1) figS = True def readSerial(): global ser, figS print("a") ''' i = 0 b = True ser = serial.Serial('COM3', 9600, timeout=0.1, writeTimeout=0) while b == True: data = ser.readall() print(data) i = i + 1 if (i>100): b = False ser.close() ''' #ser = serial.Serial('COM3', 9600, timeout=0.1, writeTimeout=0) if True: #if flgS == True: while True: rxData = ser.readall() rxData2 = rxData.strip().decode('utf-8') #print(rxData) if len(rxData) > 0: txt.insert('end', rxData2) break root.after(1000, readSerial()) def startSerial(): global ser, figS print("Start serial") #ser = serial.Serial('COM3', 9600, timeout=0.1, writeTimeout=0) figS = True readSerial() def stopSerial(): global ser, figS print("Stop serial") #ser.close() figS = False readSerial() def trans1(): sigID = entryBox10.get() sigDLC = entryBox11.get() sigData = [] value = "ID:" + sigID + ", DLC:" + sigDLC +", Data:" sigData.append(entryBox12.get()) sigData.append(entryBox13.get()) sigData.append(entryBox14.get()) sigData.append(entryBox15.get()) sigData.append(entryBox16.get()) sigData.append(entryBox17.get()) sigData.append(entryBox18.get()) sigData.append(entryBox19.get()) value = "ID : " + sigID + ", DLC : " + sigDLC +", Data :" for i in range(int(sigDLC)): value = value + " " + sigData[i] value = value + "\n" #label11["text"] = value txt.insert('end', value) #ser = serial.Serial('COM3', 9600, timeout=0.1) #ser.write(value) ser.write(b"tx:130h,8,FE,F3,33,44,44,22,35,22\n") #ser.close() #readSerial(True) def trans2(): sigID = entryBox20.get() sigDLC = entryBox21.get() sigData = [] value = "ID:" + sigID + ", DLC:" + sigDLC +", Data:" sigData.append(entryBox22.get()) sigData.append(entryBox23.get()) sigData.append(entryBox24.get()) sigData.append(entryBox25.get()) sigData.append(entryBox26.get()) sigData.append(entryBox27.get()) sigData.append(entryBox28.get()) sigData.append(entryBox29.get()) value = "ID : " + sigID + ", DLC : " + sigDLC +", Data :" for i in range(int(sigDLC)): value = value + " " + sigData[i] value = value + "\n" #label11["text"] = value txt.insert('end', value) #ser = serial.Serial('COM3', 9600, timeout=0.1) ser.write(value.encode('utf-8')) #ser.close() #readSerial(True) # メインウィンドウ作成 root = tk.Tk() #メインウィンドウのタイトルを変更 root.title("CAN tool for CAN box 3") #メインウィンドウを640x480にする root.geometry("640x480") #ラベルを追加 label1 = tk.Label(root, text="受信内容"+" Don't Input anything here") label1.place(x=20, y=20) #ボタンを作る button01 = tk.Button(root, text="受信開始", command=startSerial) button01.place(x=400, y=15) #ボタンを作る button02 = tk.Button(root, text="受信中断", command=stopSerial) button02.place(x=500, y=15) #テキストボックス txt = tk.Text(root) #txt.insert(1.0, "Don't Input anything here") txt.place(x = 20, y =40, height = 220, width = 600) #ラベルを追加 label2 = tk.Label(root, text="送信内容") label2.place(x=20, y=280) #送信信号1 y_sig1 = 300 entryBox10 = tk.Entry(root, width = 10) entryBox10.insert(tk.END, "140") entryBox10.place(x=20, y=y_sig1) label11 = tk.Label(root, text="h") label11.place(x=80, y=y_sig1) entryBox11 = tk.Entry(root, width = 2) entryBox11.insert(tk.END, "8") entryBox11.place(x=120, y=y_sig1) entryBox12 = tk.Entry(root, width = 6) entryBox12.insert(tk.END, "FF") entryBox12.place(x=150, y=y_sig1) entryBox13 = tk.Entry(root, width = 6) entryBox13.insert(tk.END, "FF") entryBox13.place(x=200, y=y_sig1) entryBox14 = tk.Entry(root, width = 6) entryBox14.insert(tk.END, "FF") entryBox14.place(x=250, y=y_sig1) entryBox15 = tk.Entry(root, width = 6) entryBox15.insert(tk.END, "FF") entryBox15.place(x=300, y=y_sig1) entryBox16 = tk.Entry(root, width = 6) entryBox16.insert(tk.END, "FF") entryBox16.place(x=350, y=y_sig1) entryBox17 = tk.Entry(root, width = 6) entryBox17.insert(tk.END, "FF") entryBox17.place(x=400, y=y_sig1) entryBox18 = tk.Entry(root, width = 6) entryBox18.insert(tk.END, "FF") entryBox18.place(x=450, y=y_sig1) entryBox19 = tk.Entry(root, width = 6) entryBox19.insert(tk.END, "FF") entryBox19.place(x=500, y=y_sig1) #ボタンを作る button21 = tk.Button(root, text="送信", command=trans1) button21.place(x=560, y=y_sig1-5) #送信信号2 y_sig2 = 340 entryBox20 = tk.Entry(root, width = 10) entryBox20.insert(tk.END, "141") entryBox20.place(x=20, y=y_sig2) labe21 = tk.Label(root, text="h") labe21.place(x=80, y=y_sig2) entryBox21 = tk.Entry(root, width = 2) entryBox21.insert(tk.END, "8") entryBox21.place(x=120, y=y_sig2) entryBox22 = tk.Entry(root, width = 6) entryBox22.insert(tk.END, "FF") entryBox22.place(x=150, y=y_sig2) entryBox23 = tk.Entry(root, width = 6) entryBox23.insert(tk.END, "FF") entryBox23.place(x=200, y=y_sig2) entryBox24 = tk.Entry(root, width = 6) entryBox24.insert(tk.END, "FF") entryBox24.place(x=250, y=y_sig2) entryBox25 = tk.Entry(root, width = 6) entryBox25.insert(tk.END, "FF") entryBox25.place(x=300, y=y_sig2) entryBox26 = tk.Entry(root, width = 6) entryBox26.insert(tk.END, "FF") entryBox26.place(x=350, y=y_sig2) entryBox27 = tk.Entry(root, width = 6) entryBox27.insert(tk.END, "FF") entryBox27.place(x=400, y=y_sig2) entryBox28 = tk.Entry(root, width = 6) entryBox28.insert(tk.END, "FF") entryBox28.place(x=450, y=y_sig2) entryBox29 = tk.Entry(root, width = 6) entryBox29.insert(tk.END, "FF") entryBox29.place(x=500, y=y_sig2) #ボタンを作る button22 = tk.Button(root, text="送信", command=trans2) button22.place(x=560, y=y_sig2-5) #root.after(200, readSerial) #rootを表示し無限ループ root.mainloop()

発生している問題・エラーメッセージ

エラーはありません。

ただ、周期的に受信させようとすると、受信そのものは周期的にできるが、
その場合ほかのユーザ操作を受けて受けなくなあり、
受信終了ボタンを押すことができずにアプリを閉じないと止まらない。

補足情報(FW/ツールのバージョンなど)

Windows10、
Arduino1.8.9
Python.Python.3.7.4

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

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

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

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

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

t_obara

2019/08/19 00:54

while - readall のループを見直してみてはいかがでしょうか
guest

回答2

0

ベストアンサー

シリアル通信を行える環境にないので、通信部分は削って確認しました。
readSerial()を下記のように修正すれば動くと思います。
if True:からif figS==True:に修正。
root.after(1000, readSerial())からroot.after(1000, readSerial)に修正。
引数の関数に()がつくと即時にその関数を実行するので、1000ms後に実行してほしいはずが即時実行になったのが原因と思われます。

python

1def readSerial(): 2 global ser, figS 3 print("a") 4 ''' 5 i = 0 6 b = True 7 ser = serial.Serial('COM3', 9600, timeout=0.1, writeTimeout=0) 8 while b == True: 9 data = ser.readall() 10 print(data) 11 i = i + 1 12 if (i>100): 13 b = False 14 ser.close() 15 ''' 16 #ser = serial.Serial('COM3', 9600, timeout=0.1, writeTimeout=0) 17 if figS==True: 18 #if flgS == True: 19 while True: 20 rxData = ser.readall() 21 rxData2 = rxData.strip().decode('utf-8') 22 #print(rxData) 23 if len(rxData) > 0: 24 txt.insert('end', rxData2) 25 break 26 root.after(1000, readSerial) 27

投稿2019/08/19 10:27

編集2019/08/19 10:29
bsk

総合スコア174

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

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

HiroPokeHero

2019/08/21 22:50

ご助言ありがとうございます。 ご指摘のとおり()を外すと狙い通りの動作となりました。 ちなみに >引数の関数に()がつくと即時にその関数を実行するので この()がつくと即時に関数を実行するのはなぜでしょうか? 結構当たり前の仕組みだったりしますか? こちらももしご存知でしたら教えていただければ幸いです。
bsk

2019/08/22 09:04

pythonだと関数内で関数宣言するとそのまま実行し戻り値が関数の引数になります。これはpythonだと当たり前の動作で実際にHiroPokeHeroさんのソースコードでも利用されています。例えばfor文ではrange(int(sigDLC)):となっておりint()関数でsigDLCを整数値に変換しrange()に整数値を入力しています。 print(readSerial)などとすると<function readSerial at ***>などと出てreadSerialという関数もfunctionという型のオブジェクトだとイメージできます。
HiroPokeHero

2019/08/24 01:01

ご連絡・ご指導ありがとうございます。 root.after(1000, readSerial())とroot.after(1000, readSerial)で差があるんですね。 非常に難しい概念ですが、まずはそういうものという知識をつけて、 それから理解できるように勉強します。
guest

0

root.after(1000, readSerial())からroot.after(1000, readSerial)に修正すると
周期定な受信ができるようになりました。

readSerial()だと、1000msの待ち時間がなく、即座に関数を実行してしまうようです。
readSerialは自信を呼び出すコマンドを有しますので、結果的に無限ループに陥るようです。

投稿2019/08/24 01:04

HiroPokeHero

総合スコア45

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問