搜索
bottom↓
回复: 21

Proteus 仿真MMC成功,将图和全部程序贴上

[复制链接]

出0入0汤圆

发表于 2011-6-17 18:04:16 | 显示全部楼层 |阅读模式
刚刚学ARM7,正好想一下SD卡,用的是Proteus里面的MMC卡,使用的只是单一的对扇区的读写操作,还不懂得文件系统
驱动用的SPI,好奇怪,刚开始的时候用SPI根本就行,然后转用软件模拟的SPI却又行,最后再做一些调整后和参考别人的一些程序,硬件的SPI也就可以了
看看图片

(原文件名:液晶显示.jpg)


由于不知道里面的MMC文件要怎么生成,所以是用的记事本“另存为……”的方法做的


(原文件名:MMC.jpg)
仿真时的效果

(原文件名:效果.jpg)

下面是SPI方式操作MMC卡的程序:
#include        "INCLUDES.h"
/*****************************************************

                                SPI方式读取MMC(SD)卡

*****************************************************/
typedef struct
{
        uint16        size_m;
        uint8        sector_multiply;
        uint16        sector_count;
        uint8        mmcname[6];                       
} MMC_INFO;

#define                MMC_CMD_ERROR        'A'
#define                MMC_DATA_ERROR        'B'
#define         DELAY                        500

#define                SCK_1                        IO0SET=( 1<<4 )
#define                SCK_0                        IO0CLR=( 1<<4 )

#define                MOSI_1                        IO0SET=( 1<<6 )
#define                MOSI_0                        IO0CLR=( 1<<6 )

#define                CS_1                          IO0SET=( 1<<8 )
#define                CS_0                          IO0CLR=( 1<<8 )

#define                MISO                        5

/*
**SPI初始化
*/
void SPIInit( void )
{
        PINSEL0                &=                0xFFFF00FF;
        PINSEL0                |=                ( 1<<(4*2) )                         //P0.4设为SPI 时钟引脚
                                           |( 1<<(5*2) )                        //P0.5设为SPI 数据输入引脚
                                           |( 1<<(6*2) )                        //P0.6设为SPI 数据输出引脚
                                           |( 1<<(7*2) );
        PINSEL0                &=                0xFFFCFFFF;

        IO0DIR                |=                ( 1<<8 );
        IO0DIR                &=           ~( 1<<5 );
        IO0SET                =                ( 1<<8 );
        CS_1;
        S0SPCCR         =                 254;
        S0SPCR                 =                0x20;        
}
/*
**SPI读取数据
*/
uint8 SPI_WR( uint8 data )
{
        S0SPDR        =        data;
        while ( 0 == ( S0SPSR & 0x80 ) );
        return ( S0SPDR );
}
/*
**SPI发送串数据
*/
void SPI_Send( const uint8 *pdata,
                           uint16 Length )
{
        uint16 i;
        for ( i = 0; i < Length; i++ )
        {
                SPI_WR( *pdata++ );
        }
}
/*
**SPI接收串数据
*/
void SPI_Receive( uint8 *buffer,
                                  uint16 Length )
{
        uint16 i;
        for ( i = 0; i < Length; i++ )
        {
                *buffer        =  SPI_WR( 0xff );
                buffer++;
        }
        return ;
}
/*
**SPI接收一个字节的数据
*/
uint8 SPI_ReceiveByte( void )
{
        uint8 data;
        data        =         SPI_WR( 0xff );
        return ( data );
}
/*
**MMC应答
*/
uint8 MMC_Response( uint8 response )
{
        uint16 count;
        count        =         0xff;
        while ( (SPI_ReceiveByte() != response) && count )
        {
                count--;
        }
        if ( count )
        {
                return 0;
        }
        else
        {
                return 1;
        }
}
/*
**MMC等待写完成
*/
uint8 MMC_Wait_Finish( void )
{
        uint16 count;
        uint8  temp;

        count        =        0xffff;
        temp        =        0;
        while ( (temp == 0) && count )
        {
                temp        =         SPI_ReceiveByte();
                count--;
        }
        if ( count )
        {
                return 0;
        }
        else
        {
                return 1;
        }
}
/*
**MMC初始化
*/
uint8 MMCInit( void )
{
        uint16 i;
        uint8  mmccmd[6];
        uint8  MMCStatus;
        MMCStatus = 0;                                                  //初始化状态为0
        CS_1;                                                                //禁止MMC卡
        for ( i = 0; i < 512; i++ )
        {
                MMCWRData = i;
                MMCRDData = ~i;
        }

        for ( i = 0; i < 10; i++ )
        {
                MMCRDData = 0xff;
        }

        SPI_Send( MMCRDData, 10 );                        //80个时钟信号

        mmccmd[0] = 0x40;                                        //复位命令
        mmccmd[1] = 0x00;
        mmccmd[2] = 0x00;
        mmccmd[3] = 0x00;
        mmccmd[4] = 0x00;
        mmccmd[5] = 0x95;
        CS_0;                                                                //使能MMC卡
        SPI_Send( mmccmd, 6 );                                //发送复位命令
        if ( MMC_Response( 0x01 ) )                        //判断是否超时
        {
                MMCStatus        =        1;
                CS_1;
                return MMCStatus;                                  //返回错误代码
        }
        CS_1;                                                                  //禁止MMC卡
        SPI_ReceiveByte();                                        //八个时钟信号
        LCDDisCharStr( 0,0,"Reset Succeed" );

        mmccmd[0] = 0x41;                                        //进入SPI模式命令
        mmccmd[1] = 0x00;
        mmccmd[2] = 0x00;
        mmccmd[3] = 0x00;
        mmccmd[4] = 0x00;
        mmccmd[5] = 0xff;
        i = 0xff;
        CS_0;                                                                //使能MMC卡
        do{
                SPI_Send( mmccmd, 6 );                        //走入SPI模式的命令
                i--;
        }while( MMC_Response( 0x00 ) && i );
        if ( i == 0 )                                                  //判断进入SPI是否成功
        {
                MMCStatus        =         1;
                CS_1;
                return MMCStatus;                                  //返回错误代码
        }
        CS_1;
        SPI_ReceiveByte();                                        //八个时钟信号
        LCDDisCharStr( 1,0,"SPI Mode Succeed" );

        mmccmd[0] = 0x41;                                        //设置块大小的命令
        mmccmd[1] = 0x00;
        mmccmd[2] = 0x00;
        mmccmd[3] = 0x02;                                        //设置为512 bytes
        mmccmd[4] = 0x00;
        mmccmd[5] = 0xff;
        CS_0;
        SPI_Send( mmccmd, 6 );                                //发送命令,设置块大小为512字节
        if ( MMC_Response( 0x00 ) )
        {
                MMCStatus        =        1;
                CS_1;
                return MMCStatus;               
        }
        CS_1;
        SPI_ReceiveByte();
        LCDDisCharStr( 2, 0, "Block Set 512 Bytes Succeed" );
        S0SPCCR         =          8;                                        //让SPI走入高速模式
        return 0;                                                         //返回0,操作成功
}
/*
**读取MMC卡上CID信息
*/
uint8 MMC_Read_CID( uint8 *RegData )
{
        uint8 temp;
        uint8 mmccmd[]={0x4a,0x00,0x00,
                                    0x00,0x00,0xff};
        temp        =         MMC_Read_Register( mmccmd, RegData, 16 );
        return temp;               
}
/*
**读取MMC卡的CSD信息
*/
uint8 MMC_Read_CSD( uint8 *RegData )
{
        uint8 temp;
        uint8 mmccmd[]={0x49,0x00,0x00,
                                    0x00,0x00,0xff};
        temp        =         MMC_Read_Register( mmccmd, RegData, 16 );
        return temp;       
}
/*
**读取MMC卡寄存器的信息
*/
uint8 MMC_Read_Register( uint8 *pcmd,        //读取相应寄存器的命令
                                                 uint8 *data,        //寄存器信息的存放
                                                 uint8 Length )        //要读取的信息的字节长度
{
        uint8 MMCStatus;
        MMCStatus        =        0;
        CS_0;
        SPI_Send( pcmd, 6 );                                //发送读取的命令
        if ( MMC_Response( 0x00 ) )
        {
                MMCStatus        =        1;                                 //命令写入失败
                CS_1;
                return MMCStatus;       
        }
        if ( MMC_Response( 0xfe ) )                         //判断是否返回令牌0xfe
        {
                MMCStatus        =        1;
                CS_1;
                return MMCStatus;
        }
        SPI_Receive( data, Length );
        CS_1;
        SPI_ReceiveByte();
        return 0;                                                        //返回0,说明读取成功       
}
/*
**读取MMC卡的信息
*/
void MMC_Information( void )
{
        uint8 temp;
        uint8 buffer[17];
        uint8 table[6];
        MMC_INFO mmc_information;
        MMC_INFO *mmc;

        mmc         =         &mmc_information;
        temp        =         MMC_Read_CSD( buffer );
        if ( temp )
        {
                LCDDisCharStr( 3, 0 , "Read MMC Information Fail" );
                return ;
        }
        mmc->sector_count        =        buffer[6] & 0x03;                                  //获取扇区的总数
        mmc->sector_count  <<=        8;
        mmc->sector_count        +=        buffer[7];
        mmc->sector_count  <<=        2;
        mmc->sector_count   +=        (buffer[8] & 0xc0) >> 6;
       
        table[5]        =         '\0';
        table[4]        =         mmc->sector_count % 10 + 1 + '0';
        table[3]        =         mmc->sector_count / 10  % 10 + '0';
        table[2]        =         mmc->sector_count /100 % 10 + '0';
        table[1]        =         mmc->sector_count / 1000 % 10 + '0';
        table[0]        =         mmc->sector_count / 10000 % 10 + '0';
        LCDDisCharStr( 3, 0, "Section:" );
        LCDDisCharStr( 3, 8, table );       
       
        mmc->sector_multiply        =         buffer[9] & 0x03;                        //获取层数
        mmc->sector_multiply   <<=         1;
        mmc->sector_multiply        +=         ( buffer[10] & 0x80 ) >> 7;
                                                                                                                        //获取MMC的容量
        mmc->size_m                                =         mmc->sector_count >> ( 9 - mmc->sector_multiply );

        table[5]        =         '\0';
        table[4]        =         mmc->size_m % 10 + 1 + '0';
        table[3]        =         mmc->size_m / 10  % 10 + '0';
        table[2]        =         mmc->size_m /100 % 10 + '0';
        table[1]        =         mmc->size_m / 1000 % 10 + '0';
        table[0]        =         mmc->size_m / 10000 % 10 + '0';
        LCDDisCharStr( 4, 0, "MMC Size:" );
        LCDDisCharStr( 4, 9, table );
        LCDDisCharStr( 4, 14, "M" );
}
/*
**读取一个扇区的内容
*/
uint8 MMC_Read_Block( uint16 Address )
{
        uint16 CheckSum;
        uint16 addh;
        uint16 addl;
        uint8  MMCStatus;
        uint8  mmccmd[6];
        addl        =        ( (Address & 0x003F) << 9 );
        addh        =        ( (Address & 0xFFC0) >> 7 );
        mmccmd[0]        =         0x51;
        mmccmd[1]        =         addh >> 8;
        mmccmd[2]        =         addh;
        mmccmd[3]        =         addl >> 8;
        mmccmd[4]        =         addl;
        mmccmd[5]        =         0xff;

        CS_0;
        SPI_Send( mmccmd, 6 );

        if ( MMC_Response( 0x00 ) )                                                        //等待MMC的回应
        {
                MMCStatus        =        1;
                CS_1;
                return MMCStatus;
        }

        if ( MMC_Response( 0xfe ) )                                                        //等待令牌信息
        {
                MMCStatus        =        1;
                CS_1;
                return MMCStatus;
        }

        SPI_Receive( MMCRDData, 512 );                                                 //读取512字节的数据

        CheckSum        =        SPI_ReceiveByte();
        CheckSum        =        (CheckSum<<8) | SPI_ReceiveByte();

        CS_1;
        SPI_ReceiveByte();
        return 0;
}
/*
**写一个扇区的内容
*/
uint8 MMC_Write_Block( uint16 Address )
{
        uint16 addh;
        uint16 addl;
        uint8  MMCStatus;
        uint8  mmccmd[6];

        addl=( (Address & 0x003F) << 9 );
        addh=( (Address & 0xFFC0) >> 7 );

        mmccmd[0]        =         0x58;
        mmccmd[1]        =         addh >> 8;
        mmccmd[2]        =         addh;
        mmccmd[3]        =         addl >> 8;
        mmccmd[4]        =         addl;
        mmccmd[5]        =         0xff;

        CS_0;
        SPI_Send( mmccmd, 6 );                                                //写命令
        if ( MMC_Response( 0x00 ) )                                          //等待回应
        {       
                MMCStatus        =        1;
                CS_1;
                return MMCStatus;
        }
        mmccmd[0]        =        0xfe;
        SPI_Send( mmccmd, 1 );                                                //写令牌
        SPI_Send( MMCWRData, 512 );                                          //写512字节到MMC

        mmccmd[0]        =        0xff;                                                  //CRC7用
        mmccmd[0]        =        0xff;
        SPI_Send( mmccmd, 2 );

        MMCStatus        =        SPI_ReceiveByte();

        if ( ( MMCStatus & 0x0f ) != 0x05 )
        {
                MMCStatus        =        1;
                CS_1;
                return MMCStatus;
        }

        if ( MMC_Wait_Finish() )
        {
                MMCStatus        =        1;
                CS_1;
                return MMCStatus;
        }

        CS_1;
        SPI_ReceiveByte();
        return 0;
}
这个是串口程序
#include        "INCLUDES.h"

/************************************************

                                串口0初始化
                                波特率:57600

************************************************/
void UARTInit( void )
{
        PINSEL0    &=        0xfffffff5;
        PINSEL0           |=        0x00000005;
//        IO0DIR           &=        0xfffffffe;                       
        U0LCR                =        0x83;
//        U0DLM                =        ( ( 44236800/16 ) / 57600 )        / 256;
//        U0DLL                =        ( ( 44236800/16 ) / 57600 )        % 256;
//        U0DLM                =        0x00;
        U0DLL                =        60;
        U0LCR                =        0x03;
}

/************************************************

                                串口发送数据给PC

************************************************/
void UartSend( const uint8 *pchar )
{
        while ( *pchar != '\0' )
        {
                U0THR        =        *pchar++;
                while ( ( U0LSR & 0x40 ) == 0 )
                {
               
                }
        }
}
/************************************************

                                串口发送非常量

************************************************/
void UartPrintf( uint8 *pchar,
                                 uint16 Length )
{
        while ( Length-- )
        {
                U0THR        =        *pchar++;
                while ( ( U0LSR & 0x40 ) == 0 )
                {
               
                }
        }
}
单片机用的是LPC2124

(原文件名:接口.jpg)

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2011-6-17 23:17:43 | 显示全部楼层
MMC。。用 winimage 弄。我发过一个帖子的。

出0入0汤圆

发表于 2011-6-17 23:21:05 | 显示全部楼层
好资料

出0入0汤圆

发表于 2011-6-17 23:30:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-20 10:03:00 | 显示全部楼层
ding

出0入0汤圆

发表于 2011-6-20 15:01:20 | 显示全部楼层
回复【楼主位】ijlc1314  夜猫
-----------------------------------------------------------------------

mark

出0入0汤圆

 楼主| 发表于 2011-8-16 16:54:39 | 显示全部楼层
现在自己想做个小东西,不知道放到实际可行不?

出0入0汤圆

发表于 2011-8-26 21:05:16 | 显示全部楼层
没入门,认为很强大

出0入0汤圆

发表于 2011-10-19 11:53:02 | 显示全部楼层
哪位大侠可以帮帮忙,用PROTEUS仿真,对MMC写入CMD25命令后,卡返回的值中不是0X00,但CMD24命令的返回却是正确的。两天没的搞定。
是MMC不支持CMD25吗?还是我的程序有问题?还是PROTEUS不支持?
点击此处下载 ourdev_686303SY4DX6.rar(文件大小:189K) (原文件名:lpc2131 proteus.rar)

-----------------------------------------------------------------------

出0入0汤圆

发表于 2011-10-24 21:03:37 | 显示全部楼层
mark,我也不知道,帮顶!

出0入0汤圆

 楼主| 发表于 2011-10-25 09:14:09 | 显示全部楼层
回复【8楼】hubaixdl  
-----------------------------------------------------------------------

比较久了,我也忘了,不过MMC和SD记得是有个命令不一样的,你查查就知道了,可以参考上面的程序

出0入0汤圆

发表于 2011-11-1 18:01:15 | 显示全部楼层
回复【10楼】ijlc1314 夜猫
-----------------------------------------------------------------------

我查过楼主的程序,里面没有关于CM25的内容,后来只好用CMD24进行多次写。有兴趣的朋友可以看一下我的程序,点击此处下载 ourdev_690787Q353C2.rar(文件大小:1.20M) (原文件名:08B5.rar)

当我用硬件进行仿真时,可以对卡进行初始化,读0扇区的内容,前面部分只是00,后面的64个才可以读到正确的数,但是用PROTEUS进行仿真却没有问题。软件仿真用的是PROTEUS7.8,KEIL4.12.

出0入0汤圆

 楼主| 发表于 2011-11-2 13:37:24 | 显示全部楼层
回复【11楼】hubaixdl  
-----------------------------------------------------------------------


仿真与实际应用总是有那么些差别,随着自己买的东西越来越多,也越来越不用仿真了

出0入0汤圆

发表于 2012-1-9 21:55:30 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-1-11 09:41:39 | 显示全部楼层
Mark

出0入0汤圆

发表于 2012-8-1 11:56:27 | 显示全部楼层
不错 谢谢

出0入0汤圆

发表于 2012-8-17 01:47:25 | 显示全部楼层
PROTEUS仿真,对MMC写入CMD25命令后,卡返回的值中不是0X00,我也遇到了这个问题,求解

出0入0汤圆

发表于 2014-5-11 13:32:37 | 显示全部楼层
hubaixdl 发表于 2011-10-19 11:53
哪位大侠可以帮帮忙,用PROTEUS仿真,对MMC写入CMD25命令后,卡返回的值中不是0X00,但CMD24命令的返回却是 ...

Proteus
多块写用CMD25 返回0x05不对呀,怎么都是0xFF

请教您怎么解决的?

出0入0汤圆

发表于 2014-5-11 18:40:10 | 显示全部楼层
Protwus 的MMC仿真到底能不能用CMD25多快写呀

出0入0汤圆

发表于 2014-5-11 18:41:21 | 显示全部楼层
楼主多快写CMD25 能不能用?

出0入0汤圆

发表于 2015-1-12 22:30:07 | 显示全部楼层
不错  很是受启发

出0入0汤圆

发表于 2015-2-26 09:10:43 | 显示全部楼层
学习了,不错。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-26 07:58

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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