Mạch điều khiển vô lăng USB

ngochoangimsat

Administrator
Hướng dẫn điều khiển vô lăng trên ô tô qua đường USB

1. Phương án sử dụng vô lăng analog (vô lăng kỹ thuật tương tự):

Phần hay nhất của việc kết nối trên xe chính là tự tạo được một hệ thống cho phép nhận các nút điều khiển trên vô lăng nguyên bản của xe mà không phải chế lại hoặc điều chỉnh. Hệ thống của chúng ta sẽ trở thành một chiếc đầu đúng nghĩa của nó với sự hỗ trợ tối đa các tính năng vốn có trên hệ thống giải trí của xe.

Mục này chỉ đề cập vô lăng analog (là vô lăng dùng điện trở chia cấp điện áp để phân biệt các nút). Vô lăng của các xe Toyota và đa số các xe đời cũ của các hãng khác dùng kiểu vô lăng này. Các xe hiện đại hơn như Mec, Audi, KIA đời mới... hiện nay đều dùng vô lăng kỹ thuật số (hòa tín hiệu điều khiển vào mạng CANBUS) sẽ được đề cập trong một chuyên mục khác (mục 2 sẽ cập nhật sau).

Sơ đồ khối mạch chuyển đổi tín hiệu vô lăng sang usb joystick. Chúng ta tạm quy ước gọi nó với cái tên USB SWC để tiện thảo luận. Việc dùng vô lăng như một Joystick sẽ có cách làm cho một nút trên vô lăng đạt 6 tác dụng khác nhau, đây là một tính năng cực kỳ cao cấp mà chỉ có các điện thoại, máy tính bảng hoặc đầu android Carpad III trên ô tô mới có thể làm được (Chỉ các đầu android carpad 3 có mã NRxxxx như NR3001, NR9001). Các đầu android khác không có.



Thực tế và lý thuyết luôn có khoảng cách :D sản phẩm thử nghiệm làm ra nó xấu hơn trên thiết kế là hiển nhiên rồi :D. Chúng tôi sử dụng đế cắm để tháo lắp IC cho tiện. 2 dây màu đỏ là dây Key1 và Key 2 , dây màu đen là dây mát của Key 1 và Key 2. 3 dây này nối vào vô lăng. Cổng USB của DVD cắm vào cổng USB của bo mạch.
Mã nguồn được viết trên phần mềm chuyên dụng để lập trình vi điều khiển có tên MikroC for PIC, các bạn muốn sửa và biên dịch lại thành firmware cho riêng mình thì cài phần mềm đó nhé. Firmware đã biên dịch sẵn ở đây thì phải lắp đúng thạch anh tần số như mạch đã thiết kế, lắp khác thạch anh sẽ không chạy được. Để lắp thạch anh khác các bạn phải dùng mã nguồn của tại đây rồi biên dịch lại.

+ Firmware đã biên dịch (File usbswc.hex) các bạn chép file này rồi đi mua con IC vi xử lý PIC 18F4550 nhờ người bán người ta nạp luôn cho, về chỉ việc nối mạch dùng.

Đây là 2 firmware, trong đó có một file để dùng cho mạch lắp thạch anh 20MHz và 1 file để dùng cho mạch lắp thạch anh 16MHz. Dùng thạch anh loại nào thì nạp firmware tương ứng
https://drive.google.com/drive/folders/0B3qhdJuRuw4HVGZ0aXhVVlc4aXc?usp=sharing
+ Mã nguồn cho phần chính (file Main.c khi sử dụng MikroC for Pic sẽ có file này)

Mã:
//
unsigned char readbuff[1] absolute 0x500;
unsigned char writebuff[1] absolute 0x540;
unsigned int pov;
unsigned int buttons;
//
void interrupt()
{
USB_Interrupt_Proc(); // USB servicing is done inside the interrupt
}

void main()
{
HID_Enable(&readbuff,&writebuff); // Enable HID communication
ADC_init();
while(1)
{
pov = ADC_Get_Sample(0);
if(pov >= 10 && pov <= 128) buttons = 1; //bam nut 1
else if(pov >= 129 && pov <= 256) buttons = 2; //bam nut 2
else if(pov >= 257 && pov <= 384) buttons = 4; //bam nut 3
else if(pov >= 385 && pov <= 512) buttons = 8; //bam nut 4
else if(pov >= 513 && pov <= 640) buttons = 16; //bam nut 5
else if(pov >= 641 && pov <= 768) buttons = 32; //bam nut 6
else if(pov >= 769 && pov <= 896) buttons = 64; //bam nut 7
else if(pov >= 897 && pov <= 1015) buttons = 128; //bam nut 8
else    {buttons = 0;} //khong bam nut
writebuff[0] = buttons;
while(!HID_Write(&writebuff,1));
}
}
+ Mã nguồn cho file USB Hid Report Descriptor để mô tả máy hiểu là đang cắm Joystick (USB_DSC.c):

Mã:
const unsigned int USB_VENDOR_ID = 0x1234;
const unsigned int USB_PRODUCT_ID = 0x0001;
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 = 1;
//const char HID_OUTPUT_REPORT_BYTES = 1;
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 = 23;

/* 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[USB_HID_RPT_SIZE];
}hid_rpt_desc =
  {
    0x05, 0x01,             // USAGE_PAGE (Generic Desktop)
    0x09, 0x04,             // USAGE (Joystick)
    0xa1, 0x01,             // COLLECTION (Application)
    //0xa1, 0x00,             // COLLECTION (Physical)
    0x05, 0x09,             // USAGE_PAGE (Button)
    0x19, 0x01,             // USAGE_MINIMUM (Button 1)
    0x29, 0x08,             // USAGE_MAXIMUM (Button 8)
    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)
    //0xc0,                    // END_COLLECTION
    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[16];
  }strd2={
    34,           //sizeof this descriptor string
    0x03,
    {'M','i','k','r','o','e','l','e','k','t','r','o','n','i','k','a'}
  };

//Product string descriptor
const struct{
  char bLength;
  char bDscType;
  unsigned int string[15];
}strd3={
    32,          //sizeof this descriptor string
    0x03,
    {'U','S','B',' ','H','I','D',' ','L','i','b','r','a','r','y'}
};

//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;
}





2. Phương án sử dụng vô lăng kỹ thuật số:

Vô lăng kỹ thuật số được sử dụng trên hầu hết các xe đời mới hiện nay. Trong đó tín hiệu từ vô lăng được mã hóa và hòa vào mạng cục bộ CANBUS trên xe (Mạng CANBUS đã có bài viết ở đây, các bạn có thể qua đó tham khảo).


Giao tiếp ODROID với mạng canbus có thể thực hiện dễ dàng với bộ đôi sử dụng PIC 18F4550 + chíp MPC2551 hoặc kết nối chân GPIO của ODROID với MPC2551. Các kết nối cực kỳ đơn giản, nhỏ gọn và thu mọi tín hiệu canbus của xe. Với người hiểu lập trình android thì có thể thu mọi tín hiệu của xe để sử dụng vào một mục đích nào đó .
Bài viết này sẽ cập nhật sau

 
Top