こんにちは、なりなりです(^ ^)
【PSoC入門】プロジェクト生成からLチカまで - なりなり日記
PSoCによるプログラミング勉強の続きです。
今回は、USBポートを経由してWindows PCとPSoCを通信させます。
PSoCにはUSBUARTというUSBポートを使ってUART通信するコンポーネントが有ることは、本にも書いてあります。
CypressのサイトでUSBUARTの情報を調べてみると
http://www.cypress.com/file/53431/downloadhttp://www.cypress.com/file/53431/download
こちらが見つかって、サンプルプログラムが載っているため試してみようとすると、ビルド以前に、エディタ上で幾つかのワーニングが出て来てしまいます。そんな関数無いよ的な。どうやら、この資料のコンポーネントは古いようです。
Support: Live Chat Online, Tech Support & FAQ - Infineon Technologies
使っているのは、こちらのPSoC1などのUSBUARTと同じコンポーネントっぽいです。
ということで、更に自力...
実は、Create Project -> Code exampleでUSBFS_UARTというサンプルコードが生成出来ることに、後から気付きました…
まず、USBUART(CDC Interface)を回路図に置きます。USBポートは固定であるため、ピンアサインをする必要はありません。CDCって何かというと、
USBの通信規格には, CDC (Communication Device Class)というデバイス・クラスが定義されており、USB経由でUARTのように簡単にシリアル通信(送受信)することができます。CDCはWindowsパソコンで標準的にサポートされており、USB上でCDCに準拠したデバイスが認識されると、仮想的にCOMポートが生成され、一般的な通信ターミナル・ソフトウェア(TeraTermなど)で通信できるようになります。
なのだそうです。
僕自身、パソコンの細かいところには疎いので知らなかったのですが、こういったところは共通規格として定義されているんですね。プログラミングをやってみると、こういった勉強にもなります。
逆に、プログラミングをしない場合は、こういったことを知っていても仕方ないから知ろうとしないのですが。
PSoC Creatorの回路図上のブロックをダブルクリックするとプロパティ画面が開き、更にDatasheetボタンを押すとPDFが開きます。開くのはUSBFSのデータシートなので、更に、USBUART(CDC)のリンクをクリックします。詳細を理解したい場合はじっくり読む必要が有りますが、まずは軽く進みます。
Full Speed USB (USBFS) - Infineon Technologies
USBFSについては、こちらにも資料有り。
USBを使うとクロックレートに制限が生じるので注意ですが、PSoC Creatorが許してくれないので、間違った設定にはしようが有りません。
もっと言えば、勝手に設定してくれればと思いますけど(^◇^;)
USBUARTのサンプルプログラムの関数をひとつひとつ置き換えてmain.cを編集してみます。
変更前 | 変更後 |
---|---|
USBUART_1_bGetConfiguration | USBUART_1_GetConfiguration |
USBUART_1_bGetRxCount() | USBUART_1_GetCount() |
USBUART_1_ReadAll(Buffer) | USBUART_1_GetAll(Buffer) |
USBUART_1_Write(Buffer, Count) | USBUART_1_PutData(Buffer, Count) |
USBUART_1_bTxIsReady() | USBUART_1_CDCIIsReady() |
関数がことごとく変更されている...
※対応表はUSB FSのデータシートに記載されていました。
UDBで自由に出来る分、主要コンポーネントの作りも結構変わるのかもしれませんね。めんどくさい気もしますが、技術の変化に適応しやすいとも言えます。
結局、main.cは以下の様にしました。
#include "project.h" //#include <device.h> uint8 Count; uint8 Buffer[128]; uint8 Hello[20] = 'Hello , I'm PSoc!"; uint8 Count2 = 17; int main(void) { CyGlobalIntEnable; /* Enable global interrupts. */ USBUART_1_Start(0, USBUART_1_3V_OPERATION); while(!USBUART_1_GetConfiguration()); USBUART_1_CDC_Init(); /* Place your initialization/startup code here (e.g. MyInst_Start()) */ for(;;) { /* Place your application code here. */ Count = USBUART_1_GetCount(); // the number of bytes from PC if(Count != 0) /* Check for input data from PC */ { USBUART_1_GetAll(Buffer); // Input data from PC if(Buffer[0] == '?') // Echo data back to PC USBUART_1_PutData(Hello, Count2); else USBUART_1_PutData(Buffer, Count);// Echo data back to PC while(!USBUART_1_CDCIIsReady()){} // Wait for Tx to finish } } }
USBUART_1_Start()の第1引数(Device Number)はUSBUART_1コンポーネントのDevice Descriptionで確認出来ます。
PSoCを5Vで使っているなら、第2引数をUSBUART_1_5V_OPERATIONに変更します。
基本はPSoCが受信したテキストをそのまま返信するだけですが、「?」を受信すると「Hello , I'm PSoc!」と返します。
Programming後にPCのUSBケーブルを基板の右側のポートに挿し直すとデバイスとして認識されますが、実際にUART通信させるには専用ドライバのインストールが必要となります。
ドライバはPSoC Creatorが用意していてくれるので、作成したPSoCのプロジェクトが入っているディレクトリを指定してやれば、後は検索してインストールしてくれます。
マイクロソフトはCypressのドライバを知らないため警告が出ますが、無視してインストールします。すると「デバイスは正常に動作しています」と表示されるはずです。
これで、デバイスマネージャの「ポート(COMとLPT)」に「Cypress USB UART(COM6)」と表示されるはずです。うまく認識しない場合は、一度、抜き差ししてみます。COMナンバーは環境によって違うかもしれません。
動作検証にはTera Termなどを使っても良いのですが、せっかくなのでPythonを使います。
Pythonでシリアル通信するにはPyserialモジュールを使います。
Short introduction — pySerial 3.0 documentation
PyserialのOPEN/CLOSEの仕方などはこちらを参考に。
大したことはしないので、インタラクティブモードでコマンドを打ち込みます。
Pyserialモジュールですが、インポートするのはserialです。
importでエラーが出たら、モジュールがインストールされていないということなので、
コマンドラインで「pip install pyserial」としてインストールしてください。
>>> import serial >>> ser = serial.Serial(port = 'COM6', baudrate = 19200, timeout = 1) >>> ser Serial<id=0x1ec5bb0, open=True>(port='COM6', baudrate=19200, bytesize=8, parity='N', stopbits=1, timeout=1, xonxoff=False, rtscts=False, dsrdtr=False) >>> ser.open() >>> ser.write(b'?') 1 >>> ser.readline() b"Hello , I'm PSoc!" >>> ser.write(b'abc') 3 >>> ser.readline() b'abc'
ばっちり動きました。やっぱ、Pythonは便利ですね!
次は、割り込みの勉強する予定です。
実用的なプログラムを組むには、通常はmainのforループで回しておいて、タイマー割り込みやUART割り込みが入ったら何か別の処置をするとい処理が必要ですから。
また、大抵の場合、forループは常にフルスピードで回しておく必要は無いので、waitをかけて休ませたりもしますよね。これには、CyDelay(100)(100ms休ませる)を1行追加すると良さそう。