PICでUSBを!(知識ゼロからのスタートです)
PIC18F14K50のUSB機能を100%自前のソフトで制御する試みです。しかもアセンブラで!
当記事は2009年12月から「TTLでCPUをつくろう!」というタイトルの もとにほとんど毎日連載をしてきたものを再編集したものです。 |
2011.7.11 前へ 次へ 目次へ戻る ホームページトップへ戻る |
☆C++でUSB(HID)アクセスプログラムを作成 PIC側のプログラムはC18コンパイラを使わずPICアセンブラで作成しますが、パソコン側のUSB(HID)アクセスプログラムはBorland C++コンパイラで作成します。 しかしこれがまた難物で悪戦苦闘の連続でありました。 |
[第52回]
●HID送信テスト
いままで説明してきましたHIDテストプログラムに送信部分を付け加えて実行してみました。
HID送信はWriteFile関数を使います。送信はWindowsマシンからUSBケーブルで接続したPIC18F4550基板に対して行い、PIC18F4550からはRS485で当社のBASICボードZB25Kに対して行います。
その簡単な接続図と写真は[第29回]でお見せしたものと同じです。
[第29回]では、64バイト固定長のデータを送信するテストでしたが、今回は任意の長さのデータを送ってみました。
まずは今回のテストプログラムを実行したときの画面のコピーをお見せします。
右側が送信側です。
左側の画面はBASICボードZB25KがRS485経由でPIC18F4550から受信したデータをパラレルポート経由でWindowsマシンのDOS窓に表示させているところです。
RS485(RS232C)のボーレートは9600ボーです。
HID通信の概略については、[第29回]から以後の何回かにわたって説明をしていますから、HIDについて忘れてしまったよ、というお方はもう一度お読みくださいませ。
そこでも説明しましたようにHID送信(もちろん受信も同じ)では、一度に64バイトしか送ることができません。
右側の送信画面に見えておりますように、データが無い部分は全て00にしてしまえば、送信データ部分だけが認識できるようにも思われますが、そういうわけにはいきません。
今回は見やすさも考えて、ASCII文字コードで送りましたが、メモリデータやプログラムなどをバイナリ(2進数)データのまま送信することも考慮すると、その場合には00〜FFの全てがデータになる可能性がありますから、00とかFFをデータがないことを示す記号にすることはできません。
同様の理由で改行コード0D・0Aも、データエンドマークとしては使うことができません。
ではどうするか。
これはもう、64バイトのうちの1バイトを使って、送信文字数を示すことしかないのではありませんか?
画面右のDOS窓では、送信する文字列データをそのまま表示させたあと、そのデータコードを16進数で表示させています。
最初のバイトが[00]ですが、これはWriteFile関数、ReadFile関数の約束事です。
送信、受信するデータは64バイトですが、送受信バッファは65バイト必要です。
そして最初のバイトには00を入れます。
実際に送受信されるデータは2バイト目からになります。
今回の送信プログラムでは、その2バイト目に、送信バイト数を入れています。
これを受信したPIC18F4550は、この先頭の文字数情報によって、送られてきた64バイトのうち、真の送信データが何バイトかを知ることができますから、必要なデータのみを取り出すことができます。
●HID送信プログラムリストです
今回の送信テスト(上の画面)で使ったHID送信プログラムです。
//HID TEST from hidtest8 // //10/4/13 4/15 4/16 // #include <windows.h> #include <setupapi.h> extern "C" { #include "hidsdi.h" } #include <iostream.h> #pragma comment(lib, "hid.lib") void main( void ) { cout << hex; GUID hidGuid; HidD_GetHidGuid(&hidGuid); HDEVINFO devinf; devinf = SetupDiGetClassDevs(&hidGuid, NULL, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); SP_DEVICE_INTERFACE_DATA spid; spid.cbSize = sizeof(spid); // int getmk=0; HANDLE handle; for( int index = 0; ; index++ ) { if(!SetupDiEnumDeviceInterfaces(devinf, NULL, &hidGuid, index, &spid))break; unsigned long size; SetupDiGetDeviceInterfaceDetail( devinf, &spid, NULL, 0, &size, 0 ); PSP_INTERFACE_DEVICE_DETAIL_DATA dev_det =new SP_INTERFACE_DEVICE_DETAIL_DATA[size]; dev_det->cbSize=sizeof(*dev_det); SetupDiGetDeviceInterfaceDetail( devinf, &spid, dev_det, size, &size, 0 ); // handle = CreateFile( dev_det->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if(handle==INVALID_HANDLE_VALUE){cout<<"INVALID_HADLE"<<endl;continue;} HIDD_ATTRIBUTES attr; HidD_GetAttributes( handle, &attr ) ; if (attr.VendorID==0x4d8 && attr.ProductID==0xa){cout << "GET!" <<endl;getmk=1;break;} CloseHandle(handle); } if (getmk==0){cout <<"not found" <<endl;return;} // //write file test DWORD nwrite=65;//not 64! DWORD nwritn=0; unsigned char wbf[65]="\0"; char *wdata1="samidareo/atsumetehayashi/mogamigawa"; int n=strlen(wdata1); wbf[1]=n+2;//with CR+LF int i; int j=0; for (i=2;i<=n+1;i++){wbf[i]=wdata1[j];j++;} wbf[i]=0x0d; wbf[i+1]=0x0a; cout << wdata1 << endl; int d; for (i=0;i<=0x40;i++) { d=wbf[i]; printf("[%x]",d); } cout << endl; if(!WriteFile(handle,&wbf,nwrite,&nwritn,NULL))cout<<"write error"<<endl; else cout<< "write ok"<<endl; CloseHandle(handle); } |
//HID WRITE TEST from hidtest8n // //10/4/13 4/15 4/16 // #include <windows.h> #include <setupapi.h> extern "C" { #include "hidsdi.h" } #include <iostream.h> #pragma comment(lib, "hid.lib") // void hidwrite(char *wdata); HANDLE handle; // void main( void ) { cout << hex; GUID hidGuid; HidD_GetHidGuid(&hidGuid); HDEVINFO devinf; devinf = SetupDiGetClassDevs(&hidGuid, NULL, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); SP_DEVICE_INTERFACE_DATA spid; spid.cbSize = sizeof(spid); // int getmk=0; for( int index = 0; ; index++ ) { if(!SetupDiEnumDeviceInterfaces(devinf, NULL, &hidGuid, index, &spid))break; unsigned long size; SetupDiGetDeviceInterfaceDetail( devinf, &spid, NULL, 0, &size, 0 ); PSP_INTERFACE_DEVICE_DETAIL_DATA dev_det =new SP_INTERFACE_DEVICE_DETAIL_DATA[size]; dev_det->cbSize=sizeof(*dev_det); SetupDiGetDeviceInterfaceDetail( devinf, &spid, dev_det, size, &size, 0 ); // handle = CreateFile( dev_det->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if(handle==INVALID_HANDLE_VALUE){cout<<"INVALID_HADLE"<<endl;continue;} HIDD_ATTRIBUTES attr; HidD_GetAttributes( handle, &attr ) ; if (attr.VendorID==0x4d8 && attr.ProductID==0xa){cout << "GET!" <<endl;getmk=1;break;} CloseHandle(handle); } if (getmk==0){cout <<"not found" <<endl;return;} // //write file test char *wdata1="samidareo/atsumetehayashi/mogamigawa"; char *wdata2="natsukusaya/tsuwamonodomoga/yumenoato"; char *wdata3="shizukasaya/iwanishimiiru/seminokoe"; char *wdata4="yukuharuya/torinakiuono/mewanamida"; char *wdata5="araumiya/sadoniyokotou/amanogawa"; hidwrite(wdata1); hidwrite(wdata2); hidwrite(wdata3); hidwrite(wdata4); hidwrite(wdata5); CloseHandle(handle); } // void hidwrite(char *wdata) { DWORD nwrite=65;//not 64! DWORD nwritn=0; unsigned char wbf[65]="\0"; int n=strlen(wdata); wbf[1]=n+2;//with CR+LF int i; int j=0; for (i=2;i<=n+1;i++){wbf[i]=wdata[j];j++;} wbf[i]=0x0d; wbf[i+1]=0x0a; cout << wdata << endl; int d; if(!WriteFile(handle,&wbf,nwrite,&nwritn,NULL))cout<<"write error"<<endl; else cout<< "write ok"<<endl; return; } // |