历史上的今天
返回首页

历史上的今天

今天是:2024年11月06日(星期三)

正在发生

2019年11月06日 | PIC单片机USB MSC的应用:用 MMC/SD 卡作为储存设备进行读写

2019-11-06 来源:51hei

单片机的USB接口,通常用法,


1)HID  是Human Interface Device的缩写,由其名称可以了解HID设备是直接与人交互的设备,例如键盘、鼠标与游戏杆等。不过HID设备并不一定要有人机接口,只要符合HID类别规范的设备都是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 卡进行读/写数据的简单测试程序。希望大家能够喜欢。

USB MSC.jpg?imageView2/2/w/550 

让PC认为 MMC/SD 卡作为储存设备 (Storage) 进行运作

主程序:

/*

* Project name:

     MassStorageDevice.vtft

* Generated by:

     Visual TFT

* Description:

     Example using EasyPIC Fusion v7 board as mass storage device. Before using it, insert microSD card

     in the card slot on EasyPIC Fusion v7 board and plug usb cable to connect with PC.

     After connection with PC, mikromedia is detected as mass storage device wich size is

     size of microSD card inserted.

* Test configuration:

     MCU:             P18F87J50

     Dev.Board:       MikroMMB_for_PIC18FJ_hw_rev_1.10_9A

                      http://www.mikroe.com/mikromedia/pic18fj/

     Oscillator:      HS-PLL, 48.000MHz

     SW:              mikroC PRO for PIC

                      http://www.mikroe.com/mikroc/pic/

*/


#include "__Lib_USB_Device.h"


// MMC module connections

sbit Mmc_Chip_Select           at LATD0_bit;  // for writing to output pin always use latch

sbit Mmc_Chip_Select_Direction at TRISD0_bit;

// eof MMC module connections


void interrupt(){

  USBDev_IntHandler();

}


void main() {


  PLLEN_bit = 1;

  Delay_ms(150);

  WDTCON.B4 = 1;

  ANCON0 = 0xF0; // All pins to digital

  ANCON1 = 0xFF;

  WDTCON.B4 = 0;


  SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH);


  USBDev_MSCInit();

  USBDev_Init();


  IPEN_bit = 1;

  USBIP_bit = 1;

  USBIE_bit = 1;

  GIEH_bit = 1;


  while(1){

    USBDev_MSCMain();

  }


}

复制代码

MMC/SD卡驱动程序:

#include


// Mode sense data

static const uint8_t MODE_SENSE_6_DATA[8] = {

  0x00,

  0x00,

  0x00,

  0x00,

  0x00,

  0x00,

  0x00,

  0x00

};



// Standard Inquiry Data

static const uint8_t STD_INQUIRY_DATA[36] = {

  0x00, // Direct access block device

  0x80, // RMB bit set to one indicates that the medium is removable

  0x00, // ISO(7..6) ECMA(5..3) ANSI(2..0) Version

  0x02, // Response Data Format

  0x1F, // Additional length (31)

  0x00, // Reserved

  0x00, // Reserved

  0x00, // Reserved

  'M', 'I', 'K', 'R', 'O', 'E', ' ', ' ', // Vendor Information

  'm', 'i', 'c', 'r', 'o', 'S', 'D', ' ', // Product identification

  'F', 'l', 'a', 's', 'h', ' ', ' ', ' ',

  '1', '.', '0', '0'                      // Product Revision Level n.nn

};


// USB Mass storage Page 0 Inquiry Data

static const uint8_t UNIT_SERIAL_NUMBER[7] = {

  0x00, // Peripheral qualifier[7..5] device type[4..0]

  0x80, // Page Code 80h

  0x00, // Reserved

  0x03, // Page Length

  0x00, // Product Serial Nnumber

  0x00,

  0x00

};


static uint8_t tmpStorageBuff[36];


// Storage callbacks

static uint8_t StorageInit();

static uint8_t StorageIsReady();

static uint8_t StorageIsWriteProtected();

static uint8_t StorageGetCapacity(uint32_t* blockNum, uint32_t *blockSize);

static uint8_t StorageRead(uint8_t *buffer, uint32_t lba, uint16_t blockNum);

static uint8_t StorageWrite(uint8_t *buffer, uint32_t lba, uint16_t blockNum);

static uint8_t* StorageGetInquiryData(uint8_t vpd);

static uint8_t* StorageGetStdInquiryData();

static uint8_t* StorageGetModeSenseData();


typedef struct {

  uint8_t(*StorageInit)();

  uint8_t(*StorageIsReady)();

  uint8_t(*StorageIsWriteProtected)();

  uint8_t(*StorageGetCapacity)(uint32_t *blockNum, uint32_t * blockSize);

  uint8_t(*StorageRead) (uint8_t *buffer, uint32_t lba, uint16_t blockNum);

  uint8_t(*StorageWrite)(uint8_t *buffer, uint32_t lba, uint16_t blockNum);

  uint8_t * (*StorageGetInquiryData)(uint8_t vpd);

  uint8_t * (*StorageGetStdInquiryData)();

  uint8_t * (*StorageGetModeSenseData)();

} TMSCStorageCB;


TMSCStorageCB USBDev_MSCStorageCB = {

  StorageInit,

  StorageIsReady,

  StorageIsWriteProtected,

  StorageGetCapacity,

  StorageRead,

  StorageWrite,

  StorageGetInquiryData,

  StorageGetStdInquiryData,

  StorageGetModeSenseData

};


// STORAGE IMPLEMENTATION


static void StorageConstToRam(const uint8_t* fromBuffer, uint8_t* toBuffer, uint16_t len){

  uint16_t i;

  for(i = 0; i < len; i++){

    toBuffer[i] = fromBuffer[i];

  }

}


////////////////////////////////////////////////////////////////////////////////

// This is a wrapper for retrieving number of sector device implements.

// It is used to get sector count of the device (for fat formatting purpose,

// assumed sector size is 512 bytes).


// MMC GetMmcSectorCount return codes

static const uint8_t  MMC_OK     =   0,

                      MMC_ERROR  =   255;

                      

static uint8_t GetMmcSectorCount(uint32_t *scCnt)

{

    uint8_t  csdbuf[16];

    uint16_t c_size, c_size_mult, mult,

           read_bl_len, block_len;

    uint32_t size, blocknr;


    // determine MMC/SD card size in MB

    if (Mmc_Read_Csd(csdbuf) != MMC_OK)

    {

        return MMC_ERROR;

    }


    // is it version 2.0?

    if (1 == ((csdbuf[0] & 0xC0) >> 6))

    {

        size  = 0;                  size <<= 8;

        size += csdbuf[7] & 0x3F;   size <<= 8;

        size += csdbuf[8];          size <<= 8;

        size += csdbuf[9];          size <<= 0;


        // size is in 0.5MB, get size in sectors (assumed 512 bytes sector size)

        size *= 1024;

    }

    // if not, it's version 1.xx

    else

    {

        c_size      = ((csdbuf[8] & 0xC0) >> 6) +

                      ((unsigned) csdbuf[7] << 2) +

                      (((unsigned) csdbuf[6] & 0x03) << 10);

        c_size_mult = (csdbuf[10] & 0x80) +

                      (((unsigned) csdbuf[9] & 0x03) << 8);

        c_size_mult = c_size_mult >> 7;


        read_bl_len = csdbuf[5] & 0x0f;


        mult = 1;

        mult = mult << (c_size_mult + 2);


        blocknr = (c_size + 1) * (long) mult;

        block_len = 1;

        block_len = block_len << read_bl_len;


        size = block_len * blocknr;


        // size is in 1B, get size in sectors (assumed 512 bytes sector size)

        size /= 512;

    }


    *scCnt = size;


    return MMC_OK;

}


static uint8_t  storageInitStatus;   // storage initializtion status

// Initializing storage

static uint8_t StorageInit() {

  // initialize a MMC card

  storageInitStatus = Mmc_Init();

  return storageInitStatus;

}


// Get storage capacity, number of blocks and block size

static uint8_t StorageGetCapacity(uint32_t* blockNum, uint32_t *blockSize) {

  GetMmcSectorCount(blockNum);

  *blockSize = 512;

  return 0;

}


// Read storage to buffer

static uint8_t StorageRead(uint8_t *buffer, uint32_t lba, uint16_t blockNum) {

  uint8_t status;

  status = 0;

  Mmc_Multi_Read_Start(lba);

  while (blockNum) {

    Mmc_Multi_Read_Sector(buffer);

    buffer += 512;

    blockNum--;

  }

  Mmc_Multi_Read_Stop();

  return status;

}


// Return storage status

static uint8_t StorageIsReady() {

  if(storageInitStatus)

    return 0; // storage is not ready

  else

    return 1;  // storage is ready

}


// Write to storage

static uint8_t StorageWrite(uint8_t *buffer, uint32_t lba, uint16_t blockNum) {

  uint8_t status;

  status = 0;

  while (blockNum) {

    status |= Mmc_Write_Sector(lba, buffer);

    lba++;

    buffer += 512;

    blockNum--;

  }

  return status;

}


// Get storage protection status

static uint8_t StorageIsWriteProtected() {

  return 0;

}


// Return storage inquiry data

static uint8_t* StorageGetInquiryData(uint8_t vpd) {

  StorageConstToRam(UNIT_SERIAL_NUMBER, tmpStorageBuff, 7);

  return tmpStorageBuff;

}


// Get standard inquiry data

static uint8_t* StorageGetStdInquiryData() {

  StorageConstToRam(STD_INQUIRY_DATA, tmpStorageBuff, 36);

  return tmpStorageBuff;

推荐阅读

史海拾趣

Cressall Power Resistors公司的发展小趣事

随着全球环保意识的提高,Cressall积极响应绿色生产的号召。公司投入资金研发环保型功率电阻器,采用环保材料和生产工艺,减少了对环境的污染。同时,公司还加强了对废弃物的处理和回收利用,实现了资源的循环利用。这些环保措施不仅提升了公司的社会形象,还为公司带来了更多的商机。

Connector City公司的发展小趣事

随着国内市场的饱和,Connector City公司开始寻求海外市场的发展机遇。公司制定了详细的国际化战略,积极开拓海外市场,加强与国外客户的合作与交流。同时,公司还注重本土化运营,根据不同国家和地区的市场需求和文化差异,灵活调整产品设计和营销策略。通过不断拓展海外市场,公司的销售业绩实现了快速增长。

European Crystal Org公司的发展小趣事

ECO始终将产品质量视为公司发展的生命线。公司建立了严格的质量管理体系,对生产过程中的每一个环节进行严格把关。此外,ECO还注重品牌形象的塑造,通过广告宣传、客户案例分享等方式提升品牌知名度和美誉度。这些努力使ECO在行业内树立了良好的口碑,吸引了越来越多的优质客户。

Honda Tsushin Kogyo Co Ltd公司的发展小趣事

Honda Tsushin Kogyo在发展的过程中,可能形成了独特的企业文化和社会责任感。公司注重员工培训和团队建设,为员工提供良好的工作环境和发展机会。同时,公司还积极参与社会公益事业,通过捐赠、志愿服务等方式回馈社会。这些举措不仅提升了企业的社会形象,还增强了员工的归属感和凝聚力。在企业文化和社会责任的引领下,Honda Tsushin Kogyo实现了经济效益和社会效益的双赢。

需要注意的是,由于Honda Tsushin Kogyo的具体发展历程和详细故事可能并不完全公开,以上内容主要基于一般性的电子行业发展趋势和企业发展规律进行推测和整理。

Esico-Triton公司的发展小趣事

Esico-Triton公司成立于XXXX年,起初是一个小型的电子设备研发团队。当时,创始人[XXXXX]和[XXXXX]看到了电子设备市场的巨大潜力,于是决定合作创办一家公司。他们的初衷是开发一款能够简化工作流程的电子设备。在公司创立初期,资金紧张,研发条件有限,但团队成员凭借着对技术的热情和专业知识,成功研发出了第一款产品——一款便携式数据处理器。这款产品因其便携性和高效性受到了市场的欢迎,为Esico-Triton的后续发展奠定了坚实的基础。

Azoteq公司的发展小趣事

随着触控技术的兴起,Azoteq在2004年增加了第二条产品线,以应对新兴的电容式触摸和接近感应产品市场。这一举措使得Azoteq能够紧跟市场趋势,为客户提供更多样化的产品选择。通过不断的技术创新和市场拓展,Azoteq在这一领域逐渐取得了领先地位。

问答坊 | AI 解惑

监视电视系统防雷防护技术方案简介

一、 闭路监视电视系统简介:     CCTV系统结构:     电视监控系统(Closed Circuit Television,简称CCTV),一般由以下三部分组成:     前端部分:     主要由黑白(彩色)摄像机、镜头、云台、防 ...…

查看全部问答>

高人可以帮我看下我的这个拨码开关程序老有点小我问题,,十万火急

process(clk_a) VARIABLE cnt_a : std_logic_vector(7 downto 0):=\"11111111\"; begin   if (clk_a\'event and clk_a=\'1\') then    if cnt_a=\"11111111\" then     cnt_a:=d;     full_a…

查看全部问答>

Altium Designer 使用

Altium Designer 使用 —— 快速制作原理图封装当制作引脚数比较多的器件的原理图封装时,可以使用AD提供的“smart grid insert”功能快速制作原理图封装库。本文以制作K9F1G08为例,进行简单说明。K9F1G08的引脚分布如图1所示:1. 打开 excel ,按 ...…

查看全部问答>

新建一个wince 的mfc exe,怎么在对话框中添加一个ie控件,浏览一个url(本地页面),thanks

新建的时候,选择,WCE MFC appWizard[exe] ,然后再选择Dialog base, 怎么样在该Dialog上添加一个ie控件,然后去浏览一个本地url? thanks…

查看全部问答>

最新cadence(allegro)视频教程

本人从朋友那里得到一份cadence(allegro)视频教程15.5板本,是一个培训班的内部视频讲义,清晰度很高,很具体详细,是自学的好资料。如果您没时间看书或者想很快学会allegro的话就请联系:13783696474   或者QQ:20247125    ...…

查看全部问答>

新人报道

我是刚刚来到的新人,刚刚接触WINCE。现在跟老师做着一个项目,需要将一个PC上的一个写好的软件移植到wince6.0下面,平台在mini的6410上搭建,还需要搞好一个ccd摄像头的驱动(有可二次开发的开发包),想问问,如果要入门,那么我应该先看拿些书籍 ...…

查看全部问答>

f2812 SCI RS485 调试

1.最近我用sci调试RS485的时候遇到一个怪现象: 有时候(不是全部,重新加载程序的时候一般都是)cpu明明有数据发出来,SCIRX,SCITX波形正常,可是485驱动芯片出来的两线信号发不出来,示波器只能看到负半波.只要我把与其通信的人机界面的通讯口拔出来 ...…

查看全部问答>

proteus仿真出现问题

proteus仿真出现问题,如下图,不知怎么回事?…

查看全部问答>

时钟的触发时序执行时间?

最近在学习FPGA方面知识,对时钟触发有了了解,但有好多问题有些不明白。希望大虾解释 如: always(posedge CLK) begin //执行任务块 end 假如时钟的周期为50nS,占空比50%;所执行的任务块比较耗时间,超过50nS,而此时任务块尚未完全执行完 ...…

查看全部问答>

在PCB中设计WIFI时候注意事项

各位大神,在PCB中设计WIFI时候注意事项有哪些?你们有什么经验?…

查看全部问答>