找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

帖子
查看: 5001|回復(fù): 5
打印 上一主題 下一主題
收起左側(cè)

PIC單片機(jī)USB MSC的應(yīng)用:PC 利用 MMC/SD 卡作為儲存設(shè)備進(jìn)行讀寫

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:406093 發(fā)表于 2018-10-30 18:10 | 只看該作者 |只看大圖 回帖獎勵 |倒序?yàn)g覽 |閱讀模式
本帖最后由 oldspring 于 2018-10-30 18:11 編輯

單片機(jī)的USB接口,通常用法,
1)HID  是Human Interface Device的縮寫,由其名稱可以了解HID設(shè)備是直接與人交互的設(shè)備,例如鍵盤、鼠標(biāo)與游戲桿等。不過HID設(shè)備并不一定要有人機(jī)接口,只要符合HID類別規(guī)范的設(shè)備都是HID設(shè)備。(參考百度 https://baike.baidu.com/item/USB-HID
2)CDC 虛擬串口,可與PC機(jī)直接聯(lián)機(jī)通訊,如同RS232。
3)USB MSC (Mass Storage class) MSC是一種計(jì)算機(jī)和移動設(shè)備之間的傳輸協(xié)議,它允許一個通用串行總線(USB)設(shè)備來訪問主機(jī)的計(jì)算設(shè)備,使兩者之間進(jìn)行文件傳輸。設(shè)備包括:移動硬盤,移動光驅(qū),U盤,SD、TF等儲存卡讀卡器,數(shù)碼相機(jī),手機(jī)等等。
..........

注意:
每一個USB設(shè)備,都需要一個獨(dú)立的身份編碼 (ID),它由 2 組數(shù)字組成,一個是開發(fā)商代碼(Vender ID),另一個是產(chǎn)品代碼(Product ID)。如果是PIC使用者,可以向Microchip公司申請獲得免費(fèi)的身份編碼。

USB MSC 的應(yīng)用與前面介紹的USB CDC 和 USB HID 相比較,USB MSC 的內(nèi)容比較多,需要多花一些時間。
以下介紹一個簡單的從USB接口對 MMC/SD 卡進(jìn)行讀/寫數(shù)據(jù)的簡單測試程序。希望大家能夠喜歡。

讓PC認(rèn)為 MMC/SD 卡作為儲存設(shè)備 (Storage) 進(jìn)行運(yùn)作
主程序:
  1. /*
  2. * Project name:
  3.      MassStorageDevice.vtft
  4. * Generated by:
  5.      Visual TFT
  6. * Description:
  7.      Example using EasyPIC Fusion v7 board as mass storage device. Before using it, insert microSD card
  8.      in the card slot on EasyPIC Fusion v7 board and plug usb cable to connect with PC.
  9.      After connection with PC, mikromedia is detected as mass storage device wich size is
  10.      size of microSD card inserted.
  11. * Test configuration:
  12.      MCU:             P18F87J50
  13.      Dev.Board:       MikroMMB_for_PIC18FJ_hw_rev_1.10_9A
  14.                       http://www.mikroe.com/mikromedia/pic18fj/
  15.      Oscillator:      HS-PLL, 48.000MHz
  16.      SW:              mikroC PRO for PIC
  17.                       http://www.mikroe.com/mikroc/pic/
  18. */

  19. #include "__Lib_USB_Device.h"

  20. // MMC module connections
  21. sbit Mmc_Chip_Select           at LATD0_bit;  // for writing to output pin always use latch
  22. sbit Mmc_Chip_Select_Direction at TRISD0_bit;
  23. // eof MMC module connections

  24. void interrupt(){
  25.   USBDev_IntHandler();
  26. }

  27. void main() {

  28.   PLLEN_bit = 1;
  29.   Delay_ms(150);
  30.   WDTCON.B4 = 1;
  31.   ANCON0 = 0xF0; // All pins to digital
  32.   ANCON1 = 0xFF;
  33.   WDTCON.B4 = 0;

  34.   SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH);

  35.   USBDev_MSCInit();
  36.   USBDev_Init();

  37.   IPEN_bit = 1;
  38.   USBIP_bit = 1;
  39.   USBIE_bit = 1;
  40.   GIEH_bit = 1;

  41.   while(1){
  42.     USBDev_MSCMain();
  43.   }

  44. }
復(fù)制代碼
MMC/SD卡驅(qū)動程序:
  1. #include <stdint.h>

  2. // Mode sense data
  3. static const uint8_t MODE_SENSE_6_DATA[8] = {
  4.   0x00,
  5.   0x00,
  6.   0x00,
  7.   0x00,
  8.   0x00,
  9.   0x00,
  10.   0x00,
  11.   0x00
  12. };


  13. // Standard Inquiry Data
  14. static const uint8_t STD_INQUIRY_DATA[36] = {
  15.   0x00, // Direct access block device
  16.   0x80, // RMB bit set to one indicates that the medium is removable
  17.   0x00, // ISO(7..6) ECMA(5..3) ANSI(2..0) Version
  18.   0x02, // Response Data Format
  19.   0x1F, // Additional length (31)
  20.   0x00, // Reserved
  21.   0x00, // Reserved
  22.   0x00, // Reserved
  23.   'M', 'I', 'K', 'R', 'O', 'E', ' ', ' ', // Vendor Information
  24.   'm', 'i', 'c', 'r', 'o', 'S', 'D', ' ', // Product identification
  25.   'F', 'l', 'a', 's', 'h', ' ', ' ', ' ',
  26.   '1', '.', '0', '0'                      // Product Revision Level n.nn
  27. };

  28. // USB Mass storage Page 0 Inquiry Data
  29. static const uint8_t UNIT_SERIAL_NUMBER[7] = {
  30.   0x00, // Peripheral qualifier[7..5] device type[4..0]
  31.   0x80, // Page Code 80h
  32.   0x00, // Reserved
  33.   0x03, // Page Length
  34.   0x00, // Product Serial Nnumber
  35.   0x00,
  36.   0x00
  37. };

  38. static uint8_t tmpStorageBuff[36];

  39. // Storage callbacks
  40. static uint8_t StorageInit();
  41. static uint8_t StorageIsReady();
  42. static uint8_t StorageIsWriteProtected();
  43. static uint8_t StorageGetCapacity(uint32_t* blockNum, uint32_t *blockSize);
  44. static uint8_t StorageRead(uint8_t *buffer, uint32_t lba, uint16_t blockNum);
  45. static uint8_t StorageWrite(uint8_t *buffer, uint32_t lba, uint16_t blockNum);
  46. static uint8_t* StorageGetInquiryData(uint8_t vpd);
  47. static uint8_t* StorageGetStdInquiryData();
  48. static uint8_t* StorageGetModeSenseData();

  49. typedef struct {
  50.   uint8_t(*StorageInit)();
  51.   uint8_t(*StorageIsReady)();
  52.   uint8_t(*StorageIsWriteProtected)();
  53.   uint8_t(*StorageGetCapacity)(uint32_t *blockNum, uint32_t * blockSize);
  54.   uint8_t(*StorageRead) (uint8_t *buffer, uint32_t lba, uint16_t blockNum);
  55.   uint8_t(*StorageWrite)(uint8_t *buffer, uint32_t lba, uint16_t blockNum);
  56.   uint8_t * (*StorageGetInquiryData)(uint8_t vpd);
  57.   uint8_t * (*StorageGetStdInquiryData)();
  58.   uint8_t * (*StorageGetModeSenseData)();
  59. } TMSCStorageCB;

  60. TMSCStorageCB USBDev_MSCStorageCB = {
  61.   StorageInit,
  62.   StorageIsReady,
  63.   StorageIsWriteProtected,
  64.   StorageGetCapacity,
  65.   StorageRead,
  66.   StorageWrite,
  67.   StorageGetInquiryData,
  68.   StorageGetStdInquiryData,
  69.   StorageGetModeSenseData
  70. };

  71. // STORAGE IMPLEMENTATION

  72. static void StorageConstToRam(const uint8_t* fromBuffer, uint8_t* toBuffer, uint16_t len){
  73.   uint16_t i;
  74.   for(i = 0; i < len; i++){
  75.     toBuffer[i] = fromBuffer[i];
  76.   }
  77. }

  78. ////////////////////////////////////////////////////////////////////////////////
  79. // This is a wrapper for retrieving number of sector device implements.
  80. // It is used to get sector count of the device (for fat formatting purpose,
  81. // assumed sector size is 512 bytes).

  82. // MMC GetMmcSectorCount return codes
  83. static const uint8_t  MMC_OK     =   0,
  84.                       MMC_ERROR  =   255;
  85.                      
  86. static uint8_t GetMmcSectorCount(uint32_t *scCnt)
  87. {
  88.     uint8_t  csdbuf[16];
  89.     uint16_t c_size, c_size_mult, mult,
  90.            read_bl_len, block_len;
  91.     uint32_t size, blocknr;

  92.     // determine MMC/SD card size in MB
  93.     if (Mmc_Read_Csd(csdbuf) != MMC_OK)
  94.     {
  95.         return MMC_ERROR;
  96.     }

  97.     // is it version 2.0?
  98.     if (1 == ((csdbuf[0] & 0xC0) >> 6))
  99.     {
  100.         size  = 0;                  size <<= 8;
  101.         size += csdbuf[7] & 0x3F;   size <<= 8;
  102.         size += csdbuf[8];          size <<= 8;
  103.         size += csdbuf[9];          size <<= 0;

  104.         // size is in 0.5MB, get size in sectors (assumed 512 bytes sector size)
  105.         size *= 1024;
  106.     }
  107.     // if not, it's version 1.xx
  108.     else
  109.     {
  110.         c_size      = ((csdbuf[8] & 0xC0) >> 6) +
  111.                       ((unsigned) csdbuf[7] << 2) +
  112.                       (((unsigned) csdbuf[6] & 0x03) << 10);
  113.         c_size_mult = (csdbuf[10] & 0x80) +
  114.                       (((unsigned) csdbuf[9] & 0x03) << 8);
  115.         c_size_mult = c_size_mult >> 7;

  116.         read_bl_len = csdbuf[5] & 0x0f;

  117.         mult = 1;
  118.         mult = mult << (c_size_mult + 2);

  119.         blocknr = (c_size + 1) * (long) mult;
  120.         block_len = 1;
  121.         block_len = block_len << read_bl_len;

  122.         size = block_len * blocknr;

  123.         // size is in 1B, get size in sectors (assumed 512 bytes sector size)
  124.         size /= 512;
  125.     }

  126.     *scCnt = size;

  127.     return MMC_OK;
  128. }

  129. static uint8_t  storageInitStatus;   // storage initializtion status
  130. // Initializing storage
  131. static uint8_t StorageInit() {
  132.   // initialize a MMC card
  133.   storageInitStatus = Mmc_Init();
  134.   return storageInitStatus;
  135. }

  136. // Get storage capacity, number of blocks and block size
  137. static uint8_t StorageGetCapacity(uint32_t* blockNum, uint32_t *blockSize) {
  138.   GetMmcSectorCount(blockNum);
  139.   *blockSize = 512;
  140.   return 0;
  141. }

  142. // Read storage to buffer
  143. static uint8_t StorageRead(uint8_t *buffer, uint32_t lba, uint16_t blockNum) {
  144.   uint8_t status;
  145.   status = 0;
  146.   Mmc_Multi_Read_Start(lba);
  147.   while (blockNum) {
  148.     Mmc_Multi_Read_Sector(buffer);
  149.     buffer += 512;
  150.     blockNum--;
  151.   }
  152.   Mmc_Multi_Read_Stop();
  153.   return status;
  154. }

  155. // Return storage status
  156. static uint8_t StorageIsReady() {
  157.   if(storageInitStatus)
  158.     return 0; // storage is not ready
  159.   else
  160.     return 1;  // storage is ready
  161. }

  162. // Write to storage
  163. static uint8_t StorageWrite(uint8_t *buffer, uint32_t lba, uint16_t blockNum) {
  164.   uint8_t status;
  165.   status = 0;
  166.   while (blockNum) {
  167.     status |= Mmc_Write_Sector(lba, buffer);
  168.     lba++;
  169.     buffer += 512;
  170.     blockNum--;
  171.   }
  172.   return status;
  173. }

  174. // Get storage protection status
  175. static uint8_t StorageIsWriteProtected() {
  176.   return 0;
  177. }

  178. // Return storage inquiry data
  179. static uint8_t* StorageGetInquiryData(uint8_t vpd) {
  180.   StorageConstToRam(UNIT_SERIAL_NUMBER, tmpStorageBuff, 7);
  181.   return tmpStorageBuff;
  182. }

  183. // Get standard inquiry data
  184. static uint8_t* StorageGetStdInquiryData() {
  185.   StorageConstToRam(STD_INQUIRY_DATA, tmpStorageBuff, 36);
  186.   return tmpStorageBuff;
  187. }

  188. // Get mode sense data
  189. static uint8_t* StorageGetModeSenseData() {
  190.   StorageConstToRam(MODE_SENSE_6_DATA, tmpStorageBuff, 8);
  191.   return tmpStorageBuff;
  192. }

  193. // END OF STORAGE IMPLEMENTATION
復(fù)制代碼

USB MSC 驅(qū)動程序:
  1. #include <stdint.h>

  2. const uint8_t  _USB_MSC_MANUFACTURER_STRING[]  = "MikroElektronika";
  3. const uint8_t  _USB_MSC_PRODUCT_STRING[]       = "Mass Storage by Mikroe";
  4. const uint8_t  _USB_MSC_SERIALNUMBER_STRING[]  = "0x00000002";
  5. const uint8_t  _USB_MSC_CONFIGURATION_STRING[] = "Mass Storage Config Desc string";
  6. const uint8_t  _USB_MSC_INTERFACE_STRING[]     = "Mass Storage mscInterface Desc string";

  7. const uint8_t  _USB_MSC_STR_DESC_SIZE          = 4;
  8. const uint16_t _USB_MSC_STR_DESC_LANGID        = 0x409;

  9. const uint8_t _USB_MSC_CONFIG_DESC_SIZ  = 32;   // Configuration descriptor size
  10. const uint8_t _USB_MSC_PACKET_MAX_SIZE  = 64;   // Max packet size for endpoint
  11. const uint8_t _USB_MSC_IN_EP_NUM  = 1;          // IN endpoint number
  12. const uint8_t _USB_MSC_OUT_EP_NUM = 1;          // OUT endpoint number

  13. //String Descriptor Zero, Specifying Languages Supported by the Device
  14. const uint8_t USB_MSC_LangIDDesc[_USB_MSC_STR_DESC_SIZE] = {
  15.   _USB_MSC_STR_DESC_SIZE,
  16.   _USB_DEV_DESCRIPTOR_TYPE_STRING,
  17.   _USB_MSC_STR_DESC_LANGID & 0xFF,
  18.   _USB_MSC_STR_DESC_LANGID >> 8,
  19. };


  20. // device descriptor
  21. const uint8_t USB_MSC_device_descriptor[] = {
  22.   0x12, // bLength
  23.   0x01, // bDescriptorType
  24.   0x00, // bcdUSB
  25.   0x02,
  26.   0x00, // bDeviceClass
  27.   0x00, // bDeviceSubClass
  28.   0x00, // bDeviceProtocol
  29.   0x40, // bMaxPacketSize0
  30.   0x00, // idVendor
  31.   0x00,
  32.   0x02, // idProduct
  33.   0x00,
  34.   0x00, // bcdDevice
  35.   0x02,
  36.   0x01, // iManufacturer
  37.   0x02, // iProduct
  38.   0x03, // iSerialNumber
  39.   0x01  // bNumConfigurations

  40. };

  41. // Configuration descriptor with all interfaces and endpoints
  42. // descriptors for all of the interfaces
  43. const uint8_t USB_MSC_cfg_descriptor[_USB_MSC_CONFIG_DESC_SIZ] = {
  44.   // Configuration descriptor
  45.   0x09,                                   // bLength: Configuration Descriptor size
  46.   _USB_DEV_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType: Configuration
  47.   _USB_MSC_CONFIG_DESC_SIZ & 0xFF,        // wTotalLength: Bytes returned
  48.   _USB_MSC_CONFIG_DESC_SIZ >> 8,
  49.   0x01,                                   // bNumInterfaces: 1 interface
  50.   0x01,                                   // bConfigurationValue: Configuration value
  51.   0x04,                                   // iConfiguration: Index of string descriptor describing the configuration
  52.   0xC0,                                   // bmAttributes: self powered
  53.   0x32,                                   // MaxPower 100 mA: maximum power consuption of the device

  54.   // Mass Storage interface
  55.   0x09,                                   // bLength: interface descriptor size
  56.   0x04,                                   // bDescriptorType: interface descriptor type
  57.   0x00,                                   // bInterfaceNumber: Number of Interface
  58.   0x00,                                   // bAlternateSetting: Alternate setting
  59.   0x02,                                   // bNumEndpoints: Number of endpoints
  60.   0x08,                                   // bInterfaceClass: MSC
  61.   0x06,                                   // bInterfaceSubClass : SCSI transparent
  62.   0x50,                                   // nInterfaceProtocol
  63.   0x05,                                   // iInterface: Index of string descriptor

  64.   // Mass Storage Endpoints
  65.   0x07,                                   // bLength: Endpoint Descriptor size
  66.   _USB_DEV_DESCRIPTOR_TYPE_ENDPOINT,      // bDescriptorType: endpoint descriptor type

  67.   0x80 | _USB_MSC_IN_EP_NUM,              // bEndpointAddress: Endpoint Address (IN)
  68.   0x02,                                   // bmAttributes: Bulk endpoint
  69.   _USB_MSC_PACKET_MAX_SIZE,               // wMaxPacketSize: maximum packet size for endpoint
  70.   0x00,
  71.   0x00,                                   // bInterval: Polling Interval

  72.   0x07,                                   // bLength: Endpoint Descriptor size
  73.   _USB_DEV_DESCRIPTOR_TYPE_ENDPOINT,      // bDescriptorType: endpoint descriptor type
  74.   _USB_MSC_OUT_EP_NUM,                    // bEndpointAddress: Endpoint Address (OUT)
  75.   0x02,                                   // bmAttributes: Bulk endpoint
  76.   _USB_MSC_PACKET_MAX_SIZE,               // wMaxPacketSize: maximum packet size for endpoint
  77.   0x00,
  78.   0x00                                    // bInterval
  79. };
復(fù)制代碼

詳細(xì)內(nèi)容,請參考:http://www.torrancerestoration.com/bbs/dpj-138111-1.html


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:419199 發(fā)表于 2018-11-1 16:15 | 只看該作者
樓主有完整的代碼分享嗎?我點(diǎn)了詳細(xì)內(nèi)容轉(zhuǎn)成另一個帖子了。
回復(fù)

使用道具 舉報(bào)

板凳
ID:419199 發(fā)表于 2018-11-1 16:16 | 只看該作者
樓主,求完整代碼
回復(fù)

使用道具 舉報(bào)

地板
ID:406093 發(fā)表于 2018-11-4 20:11 | 只看該作者
這個就是詳細(xì)代碼,連接的內(nèi)容你仔細(xì)再看看。不知道你是用哪一種PIC單片機(jī)。8 位?16位?或者32位?
回復(fù)

使用道具 舉報(bào)

5#
ID:419199 發(fā)表于 2018-11-5 13:46 | 只看該作者
oldspring 發(fā)表于 2018-11-4 20:11
這個就是詳細(xì)代碼,連接的內(nèi)容你仔細(xì)再看看。不知道你是用哪一種PIC單片機(jī)。8 位?16位?或者32位?

我用的是pic18f67j94,就是在主程序里面的所調(diào)用的USB函數(shù)只有函數(shù)名,求樓主分享函數(shù)內(nèi)容,USBDev_IntHandler()、USBDev_MSCMain();
回復(fù)

使用道具 舉報(bào)

6#
ID:419199 發(fā)表于 2018-11-5 13:50 | 只看該作者
oldspring 發(fā)表于 2018-11-4 20:11
這個就是詳細(xì)代碼,連接的內(nèi)容你仔細(xì)再看看。不知道你是用哪一種PIC單片機(jī)。8 位?16位?或者32位?

點(diǎn)擊詳細(xì)內(nèi)容就會轉(zhuǎn)到:推薦一款PIC單片機(jī)編譯器
回復(fù)

使用道具 舉報(bào)

7#
ID:406093 發(fā)表于 2018-11-6 09:38 | 只看該作者
如果你使用的是8位單片機(jī),仔細(xì)看MikroE公司的8位編譯器,在該軟件的Help里面有詳細(xì)說明。MikroE的函數(shù)只支持他們的編譯器。函數(shù)的內(nèi)部Code也是不公開的。Microchip單片機(jī)的USB模塊技術(shù)是非常成熟的,如果你希望寫自己的USB函數(shù),無論是CDC,HID或者M(jìn)SC,都可以參考Microchip的相關(guān)Datasheet,應(yīng)該不是很困難的,只是很費(fèi)時間。
回復(fù)

使用道具 舉報(bào)

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表