UMEHOSHI ITA TOP PAGE    COMPUTER SHIEN LAB

[UMEHOSHI ITA]の制御で使っているIC「PIC32MX270F256B-I/SO」のフラッシュメモリには、テスト用プログラムが書き込まれいています。
以降では、このプログラムを「テスト・ウメ・フラッシュ」と呼ぶことにして解説します。
また、「テスト・ウメ・フラッシュ」を利用したユーザー用のプログラムを 「ウメ・エディットプログラム」と呼ぶことにします。
「ウメ・エディットプログラム」の開発では「umehoshiEditツール」が必要で、 その取得や最初の操作情報は、こちらを参照してください。
(「PICKit3などの書き込みツール」をお持ちの方で、「テスト・ウメ・フラッシュ」を利用しないで、 「MPLAB X IDE」の開発環境ですべてをプログラミングする場合の情報ではありません。)
「テスト・ウメ・フラッシュ」をどのように利用して、「ウメ・エディットプログラム」を 作るかの解説で、「umehoshiEditツール」の使用例を示しています。
各サンプルは、このWebページ上でドラック&コピーして、貼り付けしてご利用ください。

各種確認プログラム左記に必要な部品の追加例

USBで接続されるホストにメッセージ(文字列)を送信する。

とくに必要ありません。
(D1のLEDは、あるとよい)

モータ制御、PWM (Timer2利用)

PWM対応の部品追加例

ADC(A/Dコンバータ)を使う(Timer3利用)

ADC 対応の部品追加例

BEEP(ブザー音で、デフォルトのCORE Timer、Timer1を利用)

BEEP SWITCH 対応の部品追加例

[UMEHOSHI ITA]単体で動作させる

Reset SW, Type-A, CN2 部品追加例

赤外線制御

U20,D4,D5,NPN, D3 部品追加例

UART を介して、Bluetoothで制御

CN11,CN-12 部品追加例

UART を介して、ESP32-WROOM-32DをBASIC制御

U19 部品追加例

UART を介して、RN4020(BLE)で制御

U17にRN4020の部品を追加する例

[UMEHOSHI ITA]をUART を介して、Bluetoothで制御する

[UMEHOSHI ITA]で動作させる時に必要な部品の追加とペアリングの確認するまでのリンクで、ペアリング済みにしてからこのページを始めてください。

上記リンクで示したWindowsで「AE-RN-42-XB」のBluetoothモージュールとペアリングを行った後から始めている内容です。
目標は、PC側で作成したPythonのBluetoothのクライアントソフトで、遠隔操作により16進のブザー音を鳴らすことです。
(応用すれば他のOSでも可能で、例えば『Bluetoothによる赤外線のリモコン操作』などへと、発展することも可能でしょう)

また下記電池駆動状態で、このBluetoothを介して、プログラムファイルを転送して実行させる方法も紹介しています。


PC側のPythonを使った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の名前で作成した場合の実行例を、以下で示しています。


[UMEHOSHI ITA]側のプログラミング

「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;//受信で実行する関数を定義
}
このプログラムを転送して0x80005000のstart実行させます。
その後、次のように別途の電池電源などを、microUSB で供給します。



このようにして、、USB-TYpeAの方を抜けば、 [UMEHOSHI ITA]を遠隔操作できる訳です。

以下に、離れているPCにおいて上記のPyhonのプログラムにより、遠隔動作させているイメージを示します。
(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のプログラムだけを起動すれば、再び制御できるでしょう。




Bluetoothを介して、プログラムファイルを転送して実行させる方法

上記では、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>

以上のように、bluetoothモジュールを付ければ、少し離れたPCからプログラムファイルの転送や実行が可能です。
(なおUSB接続と違って、デフォルトのADCのサンプリングデータはbluetoothに送出されません。)




UART1受信デフォルトルーチン

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](受信データ));