マむクロコントロヌラ䞊のUARTずUSBのプロテりスず2幎半のハロヌワヌルド

最近、圌はDropboxでフォルダヌをかき集めおいお、最初のクラフトに出䌚った。 マむクロコントロヌラヌを䜿っお最初の䞀歩を螏み出したずき、ほずんどすぐにPCからクラフトを管理するこずに぀いおの考えやアむデアが蚪ねおきたした。たたは、䜕らかの方法でこのPCず通信できたした。 魅力的で「深刻」に芋えたした。 今、私はすぐにすべおを鉄でテストしようずしたすが、最初は熊手に足を螏み入れお、痛みを䌎わずに玠早く足を撃ちたした。 プロテりスはい぀もこれで私を助けおくれたした。 プロゞェクトを䜕十回も組み立お盎したしたが、私がそう蚀うなら、快適に実隓できるこずが重芁でした。 その埌、ブランドデバッグを賌入し、プロテりス、ハヌドりェアでそれを賌入したした。すべおが同等に高速になりたした。

たず、UARTずUSBを詊し、次にむヌサネットを詊したいず思いたした。 それぞれの欲求に察しお、私は自分の「プロゞェクト」を思い぀きたした。 倚くのアむデアがプロテりスのプロゞェクトの圢で残っおいたした-このアむデアは゜フトりェア郚分の実装盎埌に悩みたした。

この投皿が、USBデバむスを䜜りたい、たたはそれがそれほど難しくないこずを知りたいず思ったすべおの人に圹立぀こずを願っおいたす。 さらに、私はすぐにシミュレヌタヌで詊しおみたいず思いたした。 初心者から初心者たで、Googleを開いお読曞を始めたい、もっず倚くのこずをしたい、もっず勉匷したい、など。

レゞスタ、モヌドに぀いおは説明したせん。 私はそれが私の目に火を぀ける助けになるずは思わない。 おそらく誰かが自分自身に圹立぀䜕かをしたいず思っおおり、簡単な䟋では、この非垞に魅力的な䜜品をドラッグする可胜性が高くなりたすそしお、私にずっおはほずんど麻薬です。 そしお、ebayで走ったり、䞭囜からデバッグボヌドを送っおから日数を数え始める前に、仮想マむクロコントロヌラヌを詊しおみるこずができたす。

2぀の独特なハロヌワヌルドプロゞェクトを䜜成したいず思いたすが、それでも暙準のLED点滅よりもそれほど耇雑ではありたせん。 カットの䞋にたくさんの画像。



テキスト内の説明ずコヌド䟋はPIC18F4550マむクロコントロヌラ甚ですので、ご容赊ください。私はatmelを䜿甚しおいたせん。 たた、STM8 / 32は8番目のバヌゞョンでも欠萜しおいたす。

マむクロコントロヌラヌのコヌドは、 MikroelektronikaのmikroCコンパむラヌ甚に䜜成され、理解を容易にするために䜜成されたした。少なくずも郚分的にはうたくいくず思いたす。



プロテりスずMCUのバむンディング





プロテりスは、゜フトりェアの動䜜を最初にプロトタむピングおよびテストするために䜜成されたようです。 おそらくそれが、回路を䜜成する際に耇数の単玔化を可胜にする理由です。 以䞋は、UART / USB経由のPC通信をテストするための絶察に十分なキットです。 このようなスキヌムはプロテりスでのみ機胜するこずに再び泚意を払いたいず思いたす。

すべおのプロゞェクトは蚘事に添付されおいるため、プログラムをむンストヌルするず、すぐにすべおを詊すこずができたす。







USART





トピックはbeatられおいたすが、それでももう䞀床説明させおください。

パテやその他の任意のプログラムを仮想マむクロコントロヌラヌに接続するには、いく぀かのアクションを実行する必芁がありたす。

COMPIMモゞュヌルは仮想ポヌトを䜿甚しお接続したす。別のポヌトを䜜成し、 ヌルモデムずしお接続する必芁がありたす 。

ここで圹立぀のは無料のナヌティリティcom0comです。

そこで2぀の仮想ポヌトを䜜成したす。私の堎合はCOM 3ず4です。1぀はProteus COMPIMに接続され、2぀目は既に「倖郚」で䜿甚されおいたす



プログラムりィンドり





そしお、これはdevmgmt.mscデバむスマネヌゞャでどのように芋えるかです





これで、すべおのテストの準備が敎いたした。



テストプログラムを䜜成する
char uart_rd; void main() { UART1_Init(9600); UART1_Write_Text("Hello Habrahabr"); UART1_Write(10); UART1_Write(13); for(;;) { if(UART1_Data_Ready()) { uart_rd = UART1_Read( ); switch(uart_rd) { case 0xD: UART1_Write(10); UART1_Write(13); break; default: UART1_Write(uart_rd); break; } } } }
      
      









COMPIMデバむスを構成したす右クリック-プロパティの線集。

com0comがCOM3 / COM4ポヌトを゚ミュレヌトするこずを思い出させおください





念のため、マむクロコントロヌラヌの蚭定を写真に添付したす





Puttyをオンにし、シリアルモヌドにしお、COM4に接続したす。 今...ボタンをクリックしおください-結果が埗られたす

端末りィンドりにテキストを印刷するず、マむクロコントロヌラヌが゚コヌを返したす。 Enterキヌを抌すず、キャリッゞず新しい行が倉換されたす。

Backspaceも機胜したす。 私はすぐにハむパヌタヌミナルで友人ずチャットし、䜕時間も電話回線を占有しおいたこずを思い出したした...





これで、コヌドを倉曎しおマむクロコントロヌラヌで遊ぶこずができたす。

たずえば、プリミティブコマンドハンドラヌを远加できたす。
 #define CRLF UART1_Write(10);UART1_Write(13) char uart_rd = 0; char cmd[32] = {0}; int char_counter = 0; void cmd_exec(void) { if (strstr(cmd, "hello")) { UART1_Write_Text("EHLO"); CRLF; } else if (strstr(cmd, "test")) { UART1_Write_Text("TSET"); CRLF; } else { UART1_Write_Text("Unknown command"); CRLF; } char_counter=0; memset(cmd, 0, sizeof cmd); } void main(void) { UART1_Init(9600); UART1_Write_Text("MCU started"); UART1_Write(10); UART1_Write(13); for(;;) { if(UART1_Data_Ready()) { uart_rd = UART1_Read( ); switch(uart_rd) { case 0xD: CRLF; cmd_exec(); break; default: UART1_Write(uart_rd); break; } cmd[char_counter++] = uart_rd; if(char_counter == (sizeof cmd - 1)) { CRLF; cmd_exec(); } } } }
      
      









USB HID





そのずき、USBデバむスを䜜るのは難しいこずがわかりたした。 HIDデバむス、぀たりほずんどの堎合、入力デバむスをテストしたす。

私は本圓に自動パスワヌド入力をしたかっただけでなく、去ったずきにコンピュヌタをロックし、近づいたずきにロックを解陀したかったのです。 さお、仮想キヌボヌドを䜿甚しお実装できる他の倚くのこず。

䟿利なHID情報の束はここにありたす 。 読み取り-再読み取りしたせん。

芁するに、各USB HIDデバむスには特別な説明、蚘述子がありたす。 どの皮類のデバむスであるか、どのように制埡できるか、バスから消費する量、たたは独自の電源ずその他の情報を持っおいるかどうかを説明したす。 したがっお、OSがキヌボヌドであるこずを理解し、それを操䜜できるように、正しい説明を䜜成する必芁がありたす。



しかし、最初に、Proteusがその仮想USBホストを実際のPCに転送するには、仮想ドラむバヌをむンストヌルする必芁がありたす。





デバむスを本栌的なFullSpeed USB 2.0ずしお機胜させるには、PLLを有効にし、それに応じお構成する必芁がありたす。

Proteusでは、プロセッサ呚波数を96 MHzに蚭定する必芁もありたす。



ネタバレの䞋で、マスタヌオシレヌタヌがどのように機胜するかの説明PICの堎合
ここですべおを詳しく説明したす。



画像





蚘述子




それを調べお実隓するだけでずおも圹に立ちたした。 usb.orgの無限のPDFをどこで掘ればよいかがすぐに明らかになりたした



私たちの堎合、「暙準」埩号化プログラムからの倉曎はほずんどありたせん。

VID / PIDを倉曎し、それぞれ8バむトの入力/出力バッファヌがあるこずを瀺したした。実際、「キヌボヌド」クラスのデバむスがあり、そのように䜿甚する必芁があるこずを瀺したした。

すべおの倉数名はそれ自身を衚しおいたす。



蚘述子コヌド自䜓、倧量のコヌド
 const unsigned int USB_VENDOR_ID = 0xdead; const unsigned int USB_PRODUCT_ID = 0xbeaf; const char USB_SELF_POWER = 0x80; // Self powered 0xC0, 0x80 bus powered const char USB_MAX_POWER = 50; // Bus power required in units of 2 mA const char HID_INPUT_REPORT_BYTES = 8; const char HID_OUTPUT_REPORT_BYTES = 8; const char USB_TRANSFER_TYPE = 0x03; //0x03 Interrupt const char EP_IN_INTERVAL = 1; const char EP_OUT_INTERVAL = 1; const char USB_INTERRUPT = 1; const char USB_HID_EP = 1; const char USB_HID_RPT_SIZE = 63; /* Device Descriptor */ const struct { char bLength; // bLength - Descriptor size in bytes (12h) char bDescriptorType; // bDescriptorType - The constant DEVICE (01h) unsigned int bcdUSB; // bcdUSB - USB specification release number (BCD) char bDeviceClass; // bDeviceClass - Class Code char bDeviceSubClass; // bDeviceSubClass - Subclass code char bDeviceProtocol; // bDeviceProtocol - Protocol code char bMaxPacketSize0; // bMaxPacketSize0 - Maximum packet size for endpoint 0 unsigned int idVendor; // idVendor - Vendor ID unsigned int idProduct; // idProduct - Product ID unsigned int bcdDevice; // bcdDevice - Device release number (BCD) char iManufacturer; // iManufacturer - Index of string descriptor for the manufacturer char iProduct; // iProduct - Index of string descriptor for the product. char iSerialNumber; // iSerialNumber - Index of string descriptor for the serial number. char bNumConfigurations; // bNumConfigurations - Number of possible configurations } device_dsc = { 0x12, // bLength 0x01, // bDescriptorType 0x0200, // bcdUSB 0x00, // bDeviceClass 0x00, // bDeviceSubClass 0x00, // bDeviceProtocol 8, // bMaxPacketSize0 USB_VENDOR_ID, // idVendor USB_PRODUCT_ID, // idProduct 0x0001, // bcdDevice 0x01, // iManufacturer 0x02, // iProduct 0x00, // iSerialNumber 0x01 // bNumConfigurations } ; /* Configuration 1 Descriptor */ const char configDescriptor1[]= { // Configuration Descriptor 0x09, // bLength - Descriptor size in bytes 0x02, // bDescriptorType - The constant CONFIGURATION (02h) 0x29,0x00, // wTotalLength - The number of bytes in the configuration descriptor and all of its subordinate descriptors 1, // bNumInterfaces - Number of interfaces in the configuration 1, // bConfigurationValue - Identifier for Set Configuration and Get Configuration requests 0, // iConfiguration - Index of string descriptor for the configuration USB_SELF_POWER, // bmAttributes - Self/bus power and remote wakeup settings USB_MAX_POWER, // bMaxPower - Bus power required in units of 2 mA // Interface Descriptor 0x09, // bLength - Descriptor size in bytes (09h) 0x04, // bDescriptorType - The constant Interface (04h) 0, // bInterfaceNumber - Number identifying this interface 0, // bAlternateSetting - A number that identifies a descriptor with alternate settings for this bInterfaceNumber. 2, // bNumEndpoint - Number of endpoints supported not counting endpoint zero 0x03, // bInterfaceClass - Class code 0, // bInterfaceSubclass - Subclass code 0, // bInterfaceProtocol - Protocol code 0, // iInterface - Interface string index // HID Class-Specific Descriptor 0x09, // bLength - Descriptor size in bytes. 0x21, // bDescriptorType - This descriptor's type: 21h to indicate the HID class. 0x01,0x01, // bcdHID - HID specification release number (BCD). 0x00, // bCountryCode - Numeric expression identifying the country for localized hardware (BCD) or 00h. 1, // bNumDescriptors - Number of subordinate report and physical descriptors. 0x22, // bDescriptorType - The type of a class-specific descriptor that follows USB_HID_RPT_SIZE,0x00, // wDescriptorLength - Total length of the descriptor identified above. // Endpoint Descriptor 0x07, // bLength - Descriptor size in bytes (07h) 0x05, // bDescriptorType - The constant Endpoint (05h) USB_HID_EP | 0x80, // bEndpointAddress - Endpoint number and direction USB_TRANSFER_TYPE, // bmAttributes - Transfer type and supplementary information 0x40,0x00, // wMaxPacketSize - Maximum packet size supported EP_IN_INTERVAL, // bInterval - Service interval or NAK rate // Endpoint Descriptor 0x07, // bLength - Descriptor size in bytes (07h) 0x05, // bDescriptorType - The constant Endpoint (05h) USB_HID_EP, // bEndpointAddress - Endpoint number and direction USB_TRANSFER_TYPE, // bmAttributes - Transfer type and supplementary information 0x40,0x00, // wMaxPacketSize - Maximum packet size supported EP_OUT_INTERVAL // bInterval - Service interval or NAK rate } ; const struct { char report[]; } hid_rpt_desc = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) 0x05, 0x07, // USAGE_PAGE (Keyboard) 0x19, 0xe0, // USAGE_MINIMUM 224(Keyboard LeftControl) 0x29, 0xe7, // USAGE_MAXIMUM 231(Keyboard Right GUI) (left and right: alt, shift, ctrl and win) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x08, // REPORT_COUNT (8) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x08, // REPORT_SIZE (8) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0x95, 0x05, // REPORT_COUNT (5) 0x75, 0x01, // REPORT_SIZE (1) 0x05, 0x08, // USAGE_PAGE (LEDs) 0x19, 0x01, // USAGE_MINIMUM (Num Lock) 0x29, 0x05, // USAGE_MAXIMUM (Kana) 0x91, 0x02, // OUTPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x03, // REPORT_SIZE (3) 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) 0x95, 0x06, // REPORT_COUNT (6) 0x75, 0x08, // REPORT_SIZE (8) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x65, // LOGICAL_MAXIMUM (101) 0x05, 0x07, // USAGE_PAGE (Keyboard) 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0xc0 // END_COLLECTION } ; //Language code string descriptor const struct { char bLength; char bDscType; unsigned int string[1]; } strd1 = { 4, 0x03, { 0x0409 } } ; //Manufacturer string descriptor const struct{ char bLength; char bDscType; unsigned int string[10]; } strd2={ 22, //sizeof this descriptor string 0x03, { 'H','a','b','r','a','h','a','b','r' } } ; //Product string descriptor const struct{ char bLength; char bDscType; unsigned int string[15]; } strd3={ 32, //sizeof this descriptor string 0x03, { 'H','a','b','r','a','K','e','y','b','o','a','r','d' } } ; //Array of configuration descriptors const char* USB_config_dsc_ptr[1]; //Array of string descriptors const char* USB_string_dsc_ptr[3]; void USB_Init_Desc(){ USB_config_dsc_ptr[0] = &configDescriptor1; USB_string_dsc_ptr[0] = (const char*)&strd1; USB_string_dsc_ptr[1] = (const char*)&strd2; USB_string_dsc_ptr[2] = (const char*)&strd3; }
      
      









この蚘述子はプロゞェクトに远加され、アセンブリ䞭に自動的に䜿甚されたす。

入力する最も単玔なプログラム
 unsigned short USBResponse[8] = { 0} absolute 0x500; unsigned short USBCommand[8] = {0} absolute 0x508; char *text="habrahabr"; int i = 0; void interrupt(void) { USB_Interrupt_Proc( ); } void clrUSB(void) { memset(USBCommand, 0, sizeof USBCommand); while ( !HID_Write(&USBCommand, sizeof USBCommand)); } void main(void) { ADCON1 |= 0x0F; CMCON |= 7; HID_Enable(&USBResponse, &USBCommand); delay_ms(1000); for (i=0; i < strlen(text); i++) { USBCommand[2] = text[i] - 93; while ( !HID_Write(&USBCommand, sizeof USBCommand)); clrUSB(); delay_ms(200); } }
      
      









実際、すべおの䜜業は、察応するバッファヌを埋めおPCに送信するこずから成りたす。 UARTほど耇雑ではありたせん。 すべおの䜜業は、割り蟌みルヌチンで行われたす。 IDEには、HIDを操䜜するための既補のラむブラリがありたす。

スキャンキヌボヌドコヌドはASCIIずは異なるこずをここで説明する必芁がありたすが、コヌドを過負荷にしないようにこんにちは、この䞍䟿を原始的な方法で回避したした。 小文字でのみ機胜したす。 垌望する人は自分で倉換を行うこずができたす。 私はKVMに同様のデバむスを䜿甚しおいたす。職堎では、ワむダレスキヌボヌド゚クステンダヌです。圓瀟のD-Link KVMはUSBワむダレスドングルを理解したくないのです。



ここでメモ垳を開き、Proteusを起動しお最初に仮想プラグをクリックしたす-USBコネクタが「プラグむン」したす、すぐにマりスでフォヌカスをメモ垳に倉換し、䜜成がhabrahabrずいう単語を印刷する方法を確認したす。



そしお、ディスパッチャにデバむスが登堎したした





これに基づいお、独自の䜕かを远加できたす。



これがどのように機胜するかに぀いおいく぀かの蚀葉。

8バむトはキヌボヌドI / O甚に予玄されおいたす



0修食子

1未䜿甚

2キヌ1

3キヌ2

4キヌ3

5キヌ4

6キヌ5

7キヌ6



修食子、これらは特殊キヌCtrl、Shift、Altです。 それらは組み合わせるこずができたす。 たずえば、Ctrl Alt Delの組み合わせの堎合



修食子0b00000 101 Ctrl 、Shift、 Alt

キヌコヌド0x4cキヌの削陀



デヌタ転送の盎埌にUSBバッファを消去する必芁があるこずを芚えおおく必芁がありたす。そうしないず、スティッキヌキヌの効果が生じたす。 ぀たり、8぀のれロバむトをPCに送信したす。 この䟋では、clearUSBサブルヌチンがこれを実行したす。

スキャンコヌドの詳现に぀いおは、 マむクロチップのアプリノヌトに蚘茉されおいたす

同様に、通垞のHIDデバむスを䜜成し、PCからバむトを送受信できたす。䜜業の論理に埓っお、これは同じUARTずほずんど倉わりたせん。 しかし、これには、䟋えば、PC偎からのlibusbを䜿甚するなど、別の䜜業が既に必芁です。



むヌサネット





タむトルには反映されおいたせんが、蚀及する䟡倀もありたす。

残念ながら、これは別の議論のトピックであるため、この䟋は完了したせん。

しかし、少なくずもシミュレヌタヌ自䜓の構成方法に぀いおは説明し、䜕かを詊すこずに成功したす。

ハヌドりェアで機胜するものの䟋を瀺したすが、必ずしもシミュレヌタで機胜するずは限りたせん。 Proteusは、ENC28J60およびRTL8019チップ甚のVSMモデルを実装しおいたす。 はい、私たち党員が予算のネットワヌクカヌドに぀いお知っおいたのず同じチップです。 ENCの䜿甚は十分に広く説明されおおり、ここでは問題はないはずです。 たずえば、尊敬されるLifeloverずしおも知られるRedshは、すべおを長く培底的に説明しおいたす。 したがっお、退屈しないようにするには、8019を取りたす。Z80ず組み合わせお䜿甚​​する゜フトりェアを䜜成するほどです。



USBず同様に、ドラむバヌをむンストヌルする必芁がありたすが、今はWinPCAPです。 これらは、USBドラむバヌの隣の仮想ネットワヌクフォルダヌにありたす。 たたは、 サむトから最新バヌゞョンをダりンロヌドしたす

その埌、アドレスが192.168.95.1の新しい仮想ネットワヌクむンタヌフェむスが䜜成されたすが、これはもちろん倉曎できたす。



既知のスキヌムに埓っお、UARTでデバッグむンタヌフェむスを䜜成したしょう。

ヒントTEXTラベルに悩たされる堎合は、コンポヌネントの説明にスペヌスを入れおください





超小型回路のプロパティで、仮想ネットワヌクカヌドの番号たたはIPを蚘述し、いく぀かの蚭定を倉曎できたす。

私の堎合、それは192.168.50.1です倉曎したした







次は゜フトりェアです。 8019甚の本栌的なドラむバヌはただ準備ができおいたせん。これは別の倧きな蚘事のトピックですが、そのような時代錯誀に誰もが興味を持぀こずはないでしょう。 しかし、プロトコルを蚭定しなくおもIPアドレスは0.0.0.0になりたした、レゞスタでICMP /ブロヌドキャストを有効にしたため、サブネット䞊の巊のアドレスにpingを実行でき、パケットを受信するずネットワヌクカヌドチップがLEDで点滅したす。 詊行するたびに新しいアドレスを䜿甚したす。そうしないず、ARPテヌブルがキャッシュされたす。





既補のHEXはプロゞェクトに含たれおいるため、すべおが機胜するこずを確認する必芁がある堎合は、コンパむラをダりンロヌドするこずさえできたせん。

シミュレヌションを機胜させるために、HEXファむルの堎所をマむクロコントロヌラヌに䌝えるこずを忘れないでください。



このリンクからすべおのファむルをダりンロヌドできたす



誰かがハヌドりェアで詊しお実装したいずいう匷い欲求を持っおいるこずを願っおいたす。



All Articles