UMEHOSHI ITA TOP PAGE COMPUTER SHIEN LAB
[UMEHOSHI ITA]の制御で使っているIC「PIC32MX270F256B-I/SO」のフラッシュメモリには、テスト用プログラムが書き込まれいています。
以降では、このプログラムを「テスト・ウメ・フラッシュ」と呼ぶことにして解説します。
また、「テスト・ウメ・フラッシュ」を利用したユーザー用のプログラムを
「ウメ・エディットプログラム」と呼ぶことにします。
「ウメ・エディットプログラム」の開発では「umehoshiEditツール」が必要で、
その取得や最初の操作情報は、こちらを参照してください。
(「PICKit3などの書き込みツール」をお持ちの方で、「テスト・ウメ・フラッシュ」を利用しないで、
「MPLAB X IDE」の開発環境ですべてをプログラミングする場合の情報ではありません。)
「テスト・ウメ・フラッシュ」をどのように利用して、「ウメ・エディットプログラム」を
作るかの解説で、「umehoshiEditツール」の使用例を示しています。
各サンプルは、このWebページ上でドラック&コピーして、貼り付けしてご利用ください。
各種確認プログラム | 左記に必要な部品の追加例 |
---|---|
とくに必要ありません。 (D1のLEDは、あるとよい) | |
PWM対応の部品追加例 | |
ADC 対応の部品追加例 | |
BEEP SWITCH 対応の部品追加例 | |
Reset SW, Type-A, CN2 部品追加例 | |
U20,D4,D5,NPN, D3 部品追加例 | |
CN11,CN-12 部品追加例 | |
U19 部品追加例 | |
U17にRN4020の部品を追加する例 |
[UMEHOSHI ITA]で動作させる時に必要な部品の追加とペアリングの確認するまでのリンクで、ペアリング済みにしてからこのページを始めてください。
上記リンクで示したWindowsで「AE-RN-42-XB」のBluetoothモージュールとペアリングを行った後から始めている内容です。
目標は、PC側で作成したPythonのBluetoothのクライアントソフトで、遠隔操作により16進のブザー音を鳴らすことです。
(応用すれば他のOSでも可能で、例えば『Bluetoothによる赤外線のリモコン操作』などへと、発展することも可能でしょう)
また下記電池駆動状態で、このBluetoothを介して、プログラムファイルを転送して実行させる方法も紹介しています。
これは、PC側より、キー入力した文字列をBluetoothモジュールに送信するためのプログラムです。
このプログラムは、次のように進行して進みます。
● まずペアリング済みのデバイスを列挙し、そのリストから接続するデバイスを番号のキー入力させます。
● 上記で入力したデバイスのサービスが見つかるまで繰り返す。
見つかれば、そのデバイス情報を表示して、その後に接続します。
● 接続後に受信スレッドを起動し、そこで1byte受信データがあればそれをコンソールに表示する繰り返しを開始します。
● キーボード入力のループで、入力した1行の文字列をbluetoothで送信する繰り返しです。
このキーボード入力で、文字を入力せずに[Enter]キーだけ押した場合にプログラムを終了します。
以下にこのプログラムを示しますが、Bluetooth用の追加モジュールが必要です。
追加モジュールは「pip install PyBluez-win10」の操作などで、予めインストールしてください。
import sys # btc.py import time import threading # https://pybluez.readthedocs.io/en/latest/install.html import bluetooth devices = bluetooth.discover_devices(lookup_names=True) print("Found {} devices.".format(len(devices))) n=0 for addr, name in devices: # ペアリングデバイスリストアップ print("No={} {} - {}".format(n, addr, name)) n+=1 no=input("Device No=>>") addr, name = devices[int(no)] # 上記選択デバイスをメモ sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) # ソケット生成 uuid = '00001101-0000-1000-8000-00805F9B34FB' # SPP (シリアルポートプロファイル) の UUID service = [] retry = 1 while len(service) == 0: # 接続予定のデバイスのサービスが存在するか?のチェックで、見つかるまで繰り返す。 print( "Looking for service on {0}, try {1}".format(addr, retry) ) service = bluetooth.find_service(address=addr, uuid=uuid) retry = retry + 1 time.sleep(1) if len(service) != 1: print("not find service.") exit(1) # print(service) service = service[0] for k in service: # 見つかったデバイス情報を表示 print("\t", k, ":" , service[k]) print( "Service found. Name={0}".format(service["name"]) ) print( "Connecting to service." ) sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) try: sock.connect((addr, service["port"])) # 接続!! print( "Connected to service on {0} on port {1}".format(addr, service["port"]) ) except bluetooth.btcommon.BluetoothError as e: print( "Connection failed: {0}".format(e) ) exit(0) loop_flag=True def read_loop(): # 受信スレッド用の関数 global loop_flag while loop_flag: try: b=sock.recv(1) # binaryで1byte入力 #print(type(b), b) print( chr(b[0]), end="") # 文字に変換して表示 except: print("End Thread") loop_flag = False return # スレッドに read_loop 関数を渡す t_id = threading.Thread(target=read_loop) t_id.start() # スレッドスタート while True: # 送信用のループ s = input("input>") # 送信文字列のキー入力 if s == "": break # Enterだけすると、終了 s += "\r\n" sock.send(s.encode('ascii')) # byteに変換して送信 sock.close()
bluetoothデバイス側の実行をしないで実行すると、デバイスが見つからないために023行のループが終了しません。
(Ctrl+C のキー操作で、強制終了することができます。)
上記プログラムのソースファイルをbtc.pyの名前で作成した場合の実行例を、以下で示しています。
「umehoshiEditツール」を起動して、次のように、USBを接続して
対応するCOMポートへの接続を行います。
USBのもう一方はPCと接続します。
この状態(プログラム転送前)で、上記で作成したPythonのコードを動かして、Bluetoothの動作を確認できます。
以下でその実行のイメージを示します。
(win36) Z:\ai2>python btc.py Found 3 devices. No=0 00:1B:41:95:4C:E9 - LBT-HS310 No=1 00:1B:10:60:32:A2 - Makeblock No=2 00:06:66:7D:BE:FE - RNBT-BEFE Device No=>>2 Looking for service on 00:06:66:7D:BE:FE, try 1 host : 00:06:66:7D:BE:FE name : b'RNI-SPP' description : port : 1 protocol : RFCOMM rawrecord : b'6\x00;\t\x00\x00\n\x00\x01\x00\x00\t\x00\x015\x03\x19\x11\x01\t\x00\x045\x0c5\x03\x19\x01\x005\x05\x19\x00\x03\x08\x01\t\x00\x065\t\ten\t\x00j\t\x01\x00\t\x01\x00%\x07RNI-SPP' service-classes : [b'1101'] profiles : [] provider : None service-id : None handle : 65536 Service found. Name=b'RNI-SPP' Connecting to service. Connected to service on 00:06:66:7D:BE:FE on port 1 input>hello input>abc input>123 input>test 0123456789 input> End Thread (win36) Z:\ai2> |
右上のPythonプログラムでは、 [UMEHOSHI ITA]に乗せたBluetoothのモジュールの[RNBT-BEFE]を、
2を入力して選択していま。
赤の部分がキーボードの入力部です。
Pythonプログラムでは、このモジュール接続後、[hello]、
[abc]、
[123]
[test 0123456789]のキー入力をBluetoothで送信しています。
Bluetoothモジュール(RN-42)では受信データを接続しているUART1に送信しています。
左上では、このデータを [UMEHOSHI ITA]のUART1とUSBを介して、
「umehoshiEditツール」の[Communication]タブ内に表示されています。
このように、特にプログラムを作らなくてもUART1からの受信データをUSBへ送る処理がデフォルトで動作しています。
(このUART1受信デフォルトルーチンの関数のプログラムイメージをこのリンクで示します。)
この関数が、_HANDLES[_IDX_RECV_UART1] に記憶されて、それが受信割り込みから呼びだされています。
よって_HANDLES[_IDX_RECV_UART1] を、受信時に実行させたい関数に置き換えることができ、
以下のソースの027行で、その例を示しています。
下記ソースでは、UART1の受信(RN-42からの受信)データをbufに記憶し、改行の受信で数値に変換し、
その数値の4ビット(0から15)の16進ビープパターンでブザーを鳴らす関数を、recive_bluetoothの名前で定義しています。
そしてこの関数を、_HANDLES[_IDX_RECV_UART1]に記憶しています。
それにより、Bluetoothからの受信でrecive_bluetoothが呼び出されて、対応する音を鳴らすようにしています。
#include <xc.h> #include "common.h" #include <stdlib.h> char buf[15] = {0};//Bluetooth受信バッファア int count = 0;//上記バッファへの記憶数 int recive_bluetooth(uint8_t data){ _send_uart1(data); // Bluetoothへのエコー送信 //_send_char(data); // USBへの出力 _set_break_buffer(); //USBバッファFlash buf[count]=data; if(buf[count++] == '\n'){//改行 buf[count] = 0; int numb = atoi(buf);//数値へ変換 count=0; _clear_beep_code();//これまで鳴っていたビープを止める(初期化) _set_beep_code( numb << 4 & 0x0f0 | 0x4);//4bitのビープ再生 } return 1; } __attribute__((address( 0x80005000 ))) void start (void); void start() { _send_string("START\r\n"); _HANDLES[_IDX_RECV_UART1] = (void *) recive_bluetooth;//受信で実行する関数を定義 }
(win36) Z:\ai2>python btc.py Found 3 devices. No=0 00:1B:41:95:4C:E9 - LBT-HS310 No=1 00:1B:10:60:32:A2 - Makeblock No=2 00:06:66:7D:BE:FE - RNBT-BEFE Device No=>>2 Looking for service on 00:06:66:7D:BE:FE, try 1 host : 00:06:66:7D:BE:FE name : b'RNI-SPP' description : port : 1 protocol : RFCOMM rawrecord : b'6\x00;\t\x00\x00\n\x00\x01\x00\x00\t\x00\x015\x03\x19\x11\x01\t\x00\x045\x0c5\x03\x19\x01\x005\x05\x19\x00\x03\x08\x01\t\x00\x065\t\ten\t\x00j\t\x01\x00\t\x01\x00%\x07RNI-SPP' service-classes : [b'1101'] profiles : [] provider : None service-id : None handle : 65536 Service found. Name=b'RNI-SPP' Connecting to service. Connected to service on 00:06:66:7D:BE:FE on port 1 input>5 input>5 10 input>10 15 input>15 0 input>0 End Thread (win36) Z:\ai2>
上記の赤の部分が入力です。
(『_send_uart1(data); // Bluetoothへのエコー送信』によるエコー文字列表示のために赤入力位置がずれています。
このエコー送信を無しにした方が動作が分かり易いかもしれません。)
5の入力で、「ト・ツー・ト・ツー」
10の入力で、「ツー・ト・ツー・ト」
15の入力で、「ツー・ツー・ツー・ツー」
0の入力で、「ト・ト・ト・ト」
と鳴ります。最後は[Enterで終わっています。
電源の供給を止めなければ、後でPyhonのプログラムだけを起動すれば、再び制御できるでしょう。
上記では、USB TypeAの接続も使ってプログラムを転送しました。
ですが電池などで「micro B」に電源供給すれるだけで、Bluetoothを介した遠隔的プログラム転送や実行が可能です。
そのためには、[UMEHOSHI ITA ]をUART1コマンドモードで
起動する必要があります。
このUART1コマンドモードは、UARTで'S'や'R'から始まる「UME専用Hexコマンド」を受け付ける状態です。
UARTにRN-42(Bluetooth)に接続されていれば、RN-42(Bluetooth)にコマンド文字列を送ると
UARTを介してコマンドを送れるという訳です。
UART1コマンドモードにするには、SW1とSW2を押して、SW1を離してから4秒以上後にSW2を離します。
(SW1とSW2を押して、SW1を離すと、LED D1が点灯した後に消灯し、その後に再び点灯しますが、
その点灯タイミングでSW1を離すとよいでしょう。(この2度目の点灯が4秒です。)
この状態の[UMEHOSHI ITA ]の[RNBT-BEFE]に対して、PCからBluetoothで接続して、キー入力したコマンド文字列や
指定ファイルの転送するpythonのプログラム例を、以下に紹介します。(Windowsプログラムです。)
import sys # btc2.py
import os
import time
import threading
# https://pybluez.readthedocs.io/en/latest/install.html
import bluetooth
devices = bluetooth.discover_devices(lookup_names=True)
print("Found {} devices.".format(len(devices)))
addr=None
addr, name ="00:06:66:7D:BE:FE","RNBT-BEFE" # 接続対象のBluetooth機器が分かればここで設定する
if addr is None:
n=0
for addr, name in devices: # ペアリングデバイスリストアップ
print("No={} {} - {}".format(n, addr, name))
n+=1
#
no=input("Device No=>>")
addr, name = devices[int(no)] # 上記選択デバイスをメモ
sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) # ソケット生成
uuid = '00001101-0000-1000-8000-00805F9B34FB' # SPP (シリアルポートプロファイル) の UUID
service = []
retry = 1
while len(service) == 0: # 接続予定のデバイスのサービスが存在するか?のチェックで、見つかるまで繰り返す。
print( "Looking for service on {0}, try {1}".format(addr, retry) )
service = bluetooth.find_service(address=addr, uuid=uuid)
retry = retry + 1
time.sleep(0.5)
if len(service) != 1:
print("not find service.")
exit(1)
# print(service)
service = service[0]
for k in service: # 見つかったデバイス情報を表示
print("\t", k, ":" , service[k])
print( "Service found. Name={0}".format(service["name"]) )
print( "Connecting to service." )
sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
try:
sock.connect((addr, service["port"])) # 接続!!
print( "Connected to service on {0} on port {1}".format(addr, service["port"]) )
except bluetooth.btcommon.BluetoothError as e:
print( "Connection failed: {0}".format(e) )
exit(0)
loop_flag=True
def read_loop(): # 受信スレッド用の関数
global loop_flag
while loop_flag:
try:
b=sock.recv(1) # binaryで1byte入力
#print(type(b), b)
print( chr(b[0]), end="") # 文字に変換して表示
except:
print("End Thread")
loop_flag = False
return
# スレッドに read_loop 関数を渡す
t_id = threading.Thread(target=read_loop)
t_id.start() # スレッドスタート
def send_file( ): # hexファイルをbluetoothで転送して実行
print(os.listdir("."))
file = input("file name>")
if not os.path.isfile( file ) : return
with open ( file ) as f:
datas = f.readlines()
if file.endswith(".umh"): datas = datas[1:]
for s in datas:
s = s.strip() + "\r\n"
print(s, end="")
s = s.encode('ascii')
sock.send(s) # byteに変換して送信
time.sleep(0.1)
def get_check_sum(s): # チェックサム用2文字を取得
''' ck = get_check_sum("G108000900000") で"67"が取得
'''
ck = 0
for c in s: ck += ord(c)
ck &= 0x0ff
return f"{ 0x100-ck :02X}" # check sum の16進2文字
def get_memory( ): # メモリ内容の表示
try:
adr=int(input("memory hex address>"), 16)
size=int(input("get memory hex size>"), 16)
cmd = f"G{size:02X}{adr:08X}00"
cmd += get_check_sum( cmd ) + "\r\n"
s = cmd.encode('ascii')
#print(cmd, end="")
sock.send(s) # byteに変換して送信
time.sleep(0.5)
#
except Excption as e:
print(e)
def run_from_address( ): # 指定アドレスからの実行
try:
adr=int(input("memory hex address>"), 16)
cmd = f"R00{adr:08X}00"
cmd += get_check_sum( cmd ) + "\r\n"
s = cmd.encode('ascii')
#print(cmd, end="")
sock.send(s) # byteに変換して送信
time.sleep(0.5)
#
except Excption as e:
print(e)
while True: # 送信用のループ
s = input("[quit|S|G|R|f|g|r]input>") .strip() # 送信文字列のキー入力
if s == "quit": break # quit入力で、終了
elif s == 'f': send_file( )
elif s == 'g': get_memory( )
elif s == 'r': run_from_address( )
elif s=="" or not s[0] in "SGR":
s += "\r\n"
sock.send(s.encode('ascii')) # byteに変換して送信
time.sleep(0.1)
sock.close()
上記の で示すアドレスや名前が以前に接続した機器で、これに接続するプログラムです。
(この行は、接続する機器のアドレスと名前に変更してください。)
この行をコメントにするとbluetooth機器をサーチして接続先をキー入力で選ぶ挙動となります。
接続終了のキー入力のプロンプトは、[quit|S|G|R|f|g|r]input>で、ここでキー入力します。
ここで、'S'や'G'や'R'から始まる「UME専用Hexコマンド」文字列を入力して実行できます。
そして 'f'を入力すると、ファイル入力に進み、そのファイル内容を送って実行できます。
'g'を入力すると、アドレス入力に進み、、[UMEHOSHI ITA ]のメモリ内容が確認できます。
また'r'を入力すると、アドレス入力に進み、、[UMEHOSHI ITA ]の指定アドレスから実行できます。
以下の実行例では、赤の部分がキー入力部分で、'f'入力で、カレントディレクトリのファイルがリストアップされ、
'beep1.hex'のファイル名をキー入力して、ファイルを転送しています。
次に、'80005000'のアドレスから16byteの情報を確認し、'80005000'のアドレスから実行させています。
最後にquitで終了させています。
R:\bt>python btc.py Found 5 devices. Looking for service on 00:06:66:7D:BE:FE, try 1 Looking for service on 00:06:66:7D:BE:FE, try 2 host : 00:06:66:7D:BE:FE name : b'RNI-SPP' ・・・・省略・・・ Service found. Name=b'RNI-SPP' Connecting to service. Connected to service on 00:06:66:7D:BE:FE on port 1 [quit|S|G|R|E|f|g|r]input>f ['beep1.hex', 'beep2.hex', 'btc.py', '_python36 .bat', '_python36_btc.bat'] file name>beep1.hex S108000500000E8FFBD271400BFAF1000BEAF21F0A00317 S108000500000E8FFBD271400BFAF1000BEAF21F0A00317 SET:80005000 S10800050100000A0023CF44142340000428C09F84000BD S10800050100000A0023CF44142340000428C09F84000BD SET:80005010 S1080005020000000000000A0023CF04142340000428CEB S1080005020000000000000A0023CF04142340000428CEB SET:80005020 S1080005030001200042409F840000000000000A0023CFB S1080005030001200042409F840000000000000A0023CFB SET:80005030 S108000504000FC414234000040AC21E8C0031400BF8F77 S108000504000FC414234000040AC21E8C0031400BF8F77 SET:80005040 S1080005050001000BE8F1800BD270800E00300000000BC S1080005050001000BE8F1800BD270800E00300000000BC SET:80005050 S1080005060000000000022222222222222222222222229 S1080005060000000000022222222222222222222222229 SET:80005060 [quit|S|G|R|E|f|g|r]input>g memory hex address>80005000 get memory hex size>10 G1080005000006B :108000500000E8FFBD271400BFAF1000BEAF21F0A00330 [quit|S|G|R|E|f|g|r]input>r memory hex address>80005000 R00800050000061 START:80005000 [quit|S|G|R|E|f|g|r]input>quit End Thread R:\bt> |
UART1からの受信割り込みで呼び出されるルーチンは、次のように作られています。
int recv_uart1(uint8_t data) { UART1からの1byte受信すると呼び出される。(実際のコードはこちらを参照してください) 引数 data がUART1から受信した1byteをUSBへ出力する。 処理した場合は1、処理しない場合は0を返す。 }これは、次のように記憶されています。(上記ではこの設定をrecive_bluetoothに変更しています)
_HANDLES[_IDX_RECV_UART1] = (void *)recv_uart1;この関数が、UART1からの受信割り込みで次のように呼びだされています。
(((int (**)(uint8_t) )_HANDLES)[_IDX_SEND_UART1](受信データ));