单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 778|回复: 5
打印 上一主题 下一主题
收起左侧

PIC单片机USB MSC的应用:PC 利用 MMC/SD 卡作为储存设备进行读写

[复制链接]
跳转到指定楼层
楼主
本帖最后由 oldspring 于 2018-10-30 18:11 编辑

单片机的USB接口,通常用法,
1)HID  是Human Interface Device的缩写,由其名称可以了解HID设备是直接与人交互的设备,例如键盘、鼠标与游戏杆等。不过HID设备并不一定要有人机接口,只要符合HID类别规范的设备都是HID设备。(参考百度 https://baike.baidu.com/item/USB-HID
2)CDC 虚拟串口,可与PC机直接联机通讯,如同RS232。
3)USB MSC (Mass Storage class) MSC是一种计算机和移动设备之间的传输协议,它允许一个通用串行总线(USB)设备来访问主机的计算设备,使两者之间进行文件传输。设备包括:移动硬盘,移动光驱,U盘,SD、TF等储存卡读卡器,数码相机,手机等等。
..........

注意:
每一个USB设备,都需要一个独立的身份编码 (ID),它由 2 组数字组成,一个是开发商代码(Vender ID),另一个是产品代码(Product ID)。如果是PIC使用者,可以向Microchip公司申请获得免费的身份编码。

USB MSC 的应用与前面介绍的USB CDC 和 USB HID 相比较,USB MSC 的内容比较多,需要多花一些时间。
以下介绍一个简单的从USB接口对 MMC/SD 卡进行读/写数据的简单测试程序。希望大家能够喜欢。

让PC认为 MMC/SD 卡作为储存设备 (Storage) 进行运作
主程序:
  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. }
复制代码
MMC/SD卡驱动程序:
  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
复制代码

USB MSC 驱动程序:
  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. };
复制代码

详细内容,请参考:http://www.51hei.com/bbs/dpj-138111-1.html


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 转播转播 分享分享 分享淘帖 顶 踩
回复

使用道具 举报

沙发
Cathychen 发表于 2018-11-1 16:15 | 只看该作者
楼主有完整的代码分享吗?我点了详细内容转成另一个帖子了。
回复

使用道具 举报

板凳
Cathychen 发表于 2018-11-1 16:16 | 只看该作者
楼主,求完整代码
回复

使用道具 举报

地板
 楼主| oldspring 发表于 2018-11-4 20:11 | 只看该作者
这个就是详细代码,连接的内容你仔细再看看。不知道你是用哪一种PIC单片机。8 位?16位?或者32位?
回复

使用道具 举报

5#
Cathychen 发表于 2018-11-5 13:46 | 只看该作者
oldspring 发表于 2018-11-4 20:11
这个就是详细代码,连接的内容你仔细再看看。不知道你是用哪一种PIC单片机。8 位?16位?或者32位?

我用的是pic18f67j94,就是在主程序里面的所调用的USB函数只有函数名,求楼主分享函数内容,USBDev_IntHandler()、USBDev_MSCMain();
回复

使用道具 举报

6#
Cathychen 发表于 2018-11-5 13:50 | 只看该作者
oldspring 发表于 2018-11-4 20:11
这个就是详细代码,连接的内容你仔细再看看。不知道你是用哪一种PIC单片机。8 位?16位?或者32位?

点击详细内容就会转到:推荐一款PIC单片机编译器
回复

使用道具 举报

7#
 楼主| oldspring 发表于 2018-11-6 09:38 | 只看该作者
如果你使用的是8位单片机,仔细看MikroE公司的8位编译器,在该软件的Help里面有详细说明。MikroE的函数只支持他们的编译器。函数的内部Code也是不公开的。Microchip单片机的USB模块技术是非常成熟的,如果你希望写自己的USB函数,无论是CDC,HID或者MSC,都可以参考Microchip的相关Datasheet,应该不是很困难的,只是很费时间。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|单片机论坛 |51Hei单片机16群 联系QQ:125739409;技术交流QQ群7344883

Powered by 单片机教程网

快速回复 返回顶部 返回列表