Arduiono や Raspberry Pi Pico を操作して I2C 通信などを実行する Windows アプリを作成したのですが、この記事ではその Windows アプリの基礎となる USB-Serial 通信の制御部分を紹介します。
前の記事ですでに Visual Studio で作ったアプリで Raspberry pi pico との通信を達成していますが、この記事では通信を利用してアプリから Raspberry pi pico の GPIO を制御してみます。
どんなアプリを作るか
この記事で作成するアプリは以下のファームを書き込んだ Raspberry pi pico の制御を目的とします。このファームを書き込むと Raspberry pi pico の GP3-0 が Output, GP7-4 が Input になり、USB-Serial 通信で GP3-0 の出力を制御し、GP7-0 の High/Low 状態を取得することができます。
Raspberry pi pico には 1 byte 以上のデータを送信すると同じ数のデータが返ってきます。
送信データのフォーマットは以下の通りです。
Bit 7/6/5/4: 0000 (固定)
Bit 3/2/1/0: GP3/2/1/0 の出力の指示 / 0 = Low, 1 = High
返信データのフォーマットは以下の通りです。
Bit 7/6/5/4/3/2/1/0: GP7/6/5/4/3/2/1/0 の出力状態 / 0 = Low, 1 = High
送信データで GP3-0 の出力の High/Low を指示します。複数 Byte を送信すると各 Byte の指示に従って 1 ms 間隔で GP3-0 の出力が High/Low 遷移します。
返信データは GP7-0 の High/Low 状態を示します。Raspberry pi pico は送信データを受け取ると上記の通りそのデータの指示に従って GP3-0 の High/Low 状態を変更し、1 ms 経過後に GP7-0 の High/Low 状態を読み取ってデータにして返信します。送信データが複数 Byte の場合も各 byte ごとに同じ処理を行って データを返信します。
Raspberry pi pico に 0x01, 0x02 を送信した際の処理は以下の通りです。
- Raspberry pi pico に 0x01, 0x02 を送信する
- Raspberry pi pico が 0x01 に従って GP3/2/1/0 = Low/Low/Low/High を出力する
- 1 ms 経過
- Raspberry pi pico が GP7-0 の High/Low 状態を読み取って 1 byte のデータにして返信する
- Raspberry pi pico が 0x02 に従って GP3/2/1/0 = Low/Low/High/Low を出力する
- 1 ms 経過
- Raspberry pi pico が GP7-0 の High/Low 状態を読み取って 1 byte のデータにして返信する
フォームを改造する
Visual Studio に戻ってアプリのフォームを作ります。前回の L チカのフォームを元に改造することにします。まずは不要になった NumericUpDown を削除して、左のツールボックスから代わりに送信データを入力するための「TextBox」を追加します。ついでに「Label」も追加します。
ちなみに Label のテキストは Label を選択した状態で右下のプロパティの中の「Text」の項目を変更します。
Label を追加したのは、今回は入力用の TextBox を 4個置くからです。各TextBox の前に名札代わりに Label を置きます。また、TextBox の名前が Default のままだと 4 個の入力のどれがどれか分からなくなりそうなので名前を変更します。TextBox の名前は、対象の TextBox を選択した状態にして右下のプロパティの中の「Name」の項目を変更します。名前は何でも良いのですが、ここでは TB_IN1/2/3/4 にしています。
この 4個の TextBox に入力した値が Raspberry pi pico への送信データになります。TextBox には GP3/2/1/0 の High/Low の指示を4桁の 0/1 で記入します。例えば 0101 と記入した場合は GP3/2/1/0 = Low/High/Low/High を意味します。TextBox を 4 個用意したのは送信データを 4 byte にするためです。
関数を作成する
関数を作成します。書き込む場所は前回と同じく、作成中のフォームの button1 をクリックすると開く button1_Click 関数の中です。前回の記述をばっさり削除して書き直します。
namespace RPP_CTRL_CS { using System.IO.Ports; public partial class Form1 : Form { static SerialPort SP1; public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { int i; int j; int intTO; byte[] byteDATA = {0,0,0,0}; string strDATA = ""; TextBox[] TB_IN = {TB_IN1,TB_IN2,TB_IN3,TB_IN4}; SP1 = new SerialPort(); SP1.PortName = textBox2.Text; SP1.BaudRate = 115200; SP1.Parity = Parity.None; SP1.DataBits = 8; SP1.StopBits = StopBits.One; SP1.DtrEnable = true; SP1.RtsEnable = true; SP1.Open(); for (j = 0; j < 4; j++) { strDATA = TB_IN[j].Text; for (i = 0; i < 4; i++) { if (strDATA.Substring(i, 1) == "1") { byteDATA[j] |= (byte)(0x01 << (3 - i)); } } } SP1.Write(byteDATA, 0, 4); for (j = 0; j < 4; j++) { intTO = 0; while (SP1.BytesToRead == 0) { System.Threading.Thread.Sleep(1); intTO++; if (intTO == 100) break; } if (intTO != 100) { SP1.Read(byteDATA, 0, 1); for (i = 0; i < 8; i++) { if ((byteDATA[0] & (((byte)0x01) << (7 - i))) > 0) { textBox1.AppendText("1"); } else { textBox1.AppendText("0"); } } textBox1.AppendText("\r\n"); } else { textBox1.AppendText("failed.\r\n"); } } SP1.Close(); } } }
SerialPort 関連の記述に関しては前回の記事をご参照ください。
for (j = 0; j < 4; j++) { strDATA = TB_IN[j].Text; for (i = 0; i < 4; i++) { if (strDATA.Substring(i, 1) == "1") { byteDATA[j] |= (byte)(0x01 << (3 - i)); } } }
TextBox の入力を Raspberry pi pico への送信データに変換します。
TextBox への入力は 4 桁の 0/1 で GP3/2/1/0 の出力の High/Low を指示します。例えば TextBox への入力が 0101 の場合は Byte型の 0x05 に変換します。
ここでは 4個の TextBox (TB_IN1/2/3/4) の入力データを Byte に変換して byteDATA[0]/[1]/[2]/[3] に代入しています。
for (i = 0; i < 8; i++) { if ((byteDATA[0] & (((byte)0x01) << (7 - i))) > 0) { textBox1.AppendText("1"); } else { textBox1.AppendText("0"); } } textBox1.AppendText("\r\n");
Raspberry pi pico からの返信データを textBox1 に出力します。
Byte型のデータを 0/1 の 8 桁の文字列に変換しています。返信データが 0xA5 だった場合、8桁の文字列は 10100101 になり、GP8/7/6/5/4/3/2/1/0 = High/Low/High/Low/Low/High/Low/High であったことを示します。
動作確認
作成したアプリの動作確認を行います。
Raspberry pi pico を PC に接続して、Visual Studio で作成したアプリの立ち上げます。アプリの立ち上げ方は Visual Studio の上のメニューの「Debug」「Any CPU」と並んだ先の 「(緑三角) (プロジェクト名: ここでは RPP_CTRL_CS)」をクリックです。
立ち上がったアプリのフォームの右上の TextBox には Raspberry pi pico の COM番号を記入します。COM 番号の確認方法は前回の記事をご参照ください。
次にアプリのフォームの Step 1/2/3/4 の TextBox に GP3-0 への指示を入力します。例えば Step 1/2/3/4 = 0001/0010/0100/1000 を記入すると Raspberry pi pico の GP3/2/1/0 の出力は Low/Low/Low/High -> Low/Low/High/Low -> Low/High/Low/Low -> High/Low/Low/Low と遷移します。
最後に button1 をクリックすると Step 1/2/3/4 に入力した通りに Raspberry pi pico の GP3-0 が遷移し、その時の GP7-0 の状態が下の TextBox に出力されます。
下図の例は Step1/2/3/4 = 0001/0010/0100/1000 を記入して button1 をクリックし、続いて Step1/2/3/4 = 1110/1101/1011/0111 を記入して button1 をクリックした結果です。出力された GP7-0 の状態において、GP3-0 の状態は Step 1/2/3/4 で指示した通りになっています。また、Raspberry pi pico 側では GP0 - GP7 と GP2 - GP6 を短絡しているので GP0 が High を出力している時には GP7 も High, GP2 が High を出力している時には GP6 も High になっています。GP5/4 は Open のままなので状態は常に Low です。
以上のように、Visual Studio を使って Raspberry pi pico の GPIO の制御することができました。GPIO だけでなく I2C や SPI も基本的な制御は同様です。また、Arduino でも Teensy でも、USB-Serial 通信が成立すれば同様に制御することができます。
これらを積み重ねて出来たのがこの自作アプリとなります。