找回密码
 立即注册
查看: 827|回复: 6

stc32g12k128 模拟SDIO四通道读取SD卡

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:6
  • 最近打卡:2024-08-27 15:25:33

1

主题

17

回帖

105

积分

注册会员

积分
105
发表于 2024-7-26 15:57:35 | 显示全部楼层 |阅读模式
本帖最后由 BFMIPBWVFP 于 2024-7-26 16:34 编辑

废话不多说直接上源码。

本例用stc32g12k128单片机,24M主频时已经过Mbyte的平均速率,如用spi,只有用24M高高速spi的DMA模式才可以达到!本人找了网上好久没有找到相关的例程,所以自已码了一个,其中参考了前辈们关于sd的知识,代码纯手敲,给各位有须要的参考,如用得到拿去用,不喜勿喷!

核心代码共四个文件:

sdio.h设置接口等,如下。

--------------------------------------------------------分割线--------------------------------------------------#ifndef __SDIO_H
#define __SDIO_H   


#include "..\sys\sys.h"
//#define MAIN_Fosc 24000000UL
//接口定义
sbit SD_D0=P7^0;
sbit SD_D1=P7^1;
sbit SD_D2=P7^2;
sbit SD_D3=P7^3;
sbit SD_da=P7^4;  //读数据指示
sbit SD_EN=P7^5;  //卡插入检测
sbit SD_CMD=P7^6;
sbit SD_SCK=P7^7;

#define SDin P7&0x0f  //用于并行读写
#define SDout P7      //用于并行读写
#define CMDdelay 15  //用于初始化命令时钟脉冲调整。使时钟速率在要求的100-400KHZ;  

void SDioinit(void);
u8 SDread(void);
void SDwrite(u8 dat);
void SDsendcmd(u8 CMD);  //低速速模式发命令
void SDHisendcmd(u8 CMD);//高速模式发命令
void watit_8CR();
u8 SDRScmd(void);
void SDRS_response(u8 dat[17]);
unsigned char crc7_mmc(unsigned char *dat,int length);


#endif

--------------------------------------------------------分割线--------------------------------------------------

sdio.c用gpio模拟sdio时序,如下::::::::::::::::::::::::

/*
此源码用于用gpoi形成基本sdio时序。支持四通道读取,写入。
由于4通道写入的CRC16计算太费资源使得写入对比SPI模式没有优势,所以此例只
使用4通道读取功能,写入没有实现。
*/
#include "sdio.h"
u8 temp=0;
void sdiodelay(void) //用于延时调节命令的时钟,初始化时时钟要在100-400KHZ。
{
    u8 us=CMDdelay;
    while(--us);
}   

void SDioinit(void)
{
  SDout=0xff;

}


u8 SDread(void) //四通道读取1byte数据
{
    SD_SCK=0;
    SD_SCK=1;
  temp=SDout&0x0f;
    SD_SCK=0;
    temp<<=4;
  SD_SCK=1;
    return(SDout&0x0f|temp);

}


void SDwrite(u8 dat) //四通道写入取1byte数据
{

    SD_SCK=0;
    SDout=SDout&0xf0|(dat>>4);
    SD_SCK=1;
    dat&=0x0f;
    SD_SCK=0;
    SDout=SDout&0xf0|dat;
  SD_SCK=1;


}

void SDsendcmd(u8 CMD)  //限速发送接收,用于初始化时使用
{

    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    sdiodelay();
    SD_SCK=1;
  sdiodelay();   
    CMD<<=1;
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    sdiodelay();
    SD_SCK=1;
  sdiodelay();   
    CMD<<=1;
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    sdiodelay();
    SD_SCK=1;
  sdiodelay();   
    CMD<<=1;
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    sdiodelay();
    SD_SCK=1;
  sdiodelay();   
    CMD<<=1;
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    sdiodelay();
    SD_SCK=1;
  sdiodelay();   
    CMD<<=1;
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    sdiodelay();
    SD_SCK=1;
  sdiodelay();   
    CMD<<=1;
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    sdiodelay();
    SD_SCK=1;
  sdiodelay();   
    CMD<<=1;
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    sdiodelay();
    SD_SCK=1;
  sdiodelay();   
    CMD<<=1;   

}
void SDHisendcmd(u8 CMD)   //全速发送命令
{
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    SD_SCK=1;
  CMD<<=1;
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    SD_SCK=1;
  CMD<<=1;
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    SD_SCK=1;
  CMD<<=1;
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    SD_SCK=1;
  CMD<<=1;
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    SD_SCK=1;
  CMD<<=1;
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    SD_SCK=1;
  CMD<<=1;
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    SD_SCK=1;
  CMD<<=1;
    SD_SCK=0;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    SD_SCK=1;
  CMD<<=1;

}


void watit_8CR()  //等待8个时钟周期。
{
  u8 temp=0xff,CMD=0xff,i=8;

    while(i--)
    {
    SD_SCK=1;
  (CMD&0x80)?SD_CMD=1:SD_CMD=0;
    temp<<=1;   
    sdiodelay();
    SD_SCK=0;   
    sdiodelay();
    temp|=SD_CMD;
    CMD<<=1;   

    }


}
u8 SDRScmd(void)  //接收回复,用于初始化时和设置卡。


{
  u8 temp;

    SD_SCK=0;   
  sdiodelay();   
  temp<<=1;
    SD_SCK=1;
  sdiodelay();
    temp|=SD_CMD;
    SD_SCK=0;   
  sdiodelay();   
  temp<<=1;
    SD_SCK=1;
  sdiodelay();
    temp|=SD_CMD;
    SD_SCK=0;   
  sdiodelay();   
  temp<<=1;
    SD_SCK=1;
  sdiodelay();
    temp|=SD_CMD;
    SD_SCK=0;   
  sdiodelay();   
  temp<<=1;
    SD_SCK=1;
  sdiodelay();
    temp|=SD_CMD;
    SD_SCK=0;   
  sdiodelay();   
  temp<<=1;
    SD_SCK=1;
  sdiodelay();
    temp|=SD_CMD;
    SD_SCK=0;   
  sdiodelay();   
  temp<<=1;
    SD_SCK=1;
  sdiodelay();
    temp|=SD_CMD;
    SD_SCK=0;   
  sdiodelay();   
  temp<<=1;
    SD_SCK=1;
  sdiodelay();
    temp|=SD_CMD;
    SD_SCK=0;   
  sdiodelay();   
  temp<<=1;
    SD_SCK=1;
  sdiodelay();
    temp|=SD_CMD;

    return temp;

}


void SDRS_response(u8 dat[17]) //接收回复
{u8 i=500,j=8;

    while(i--)
    {
  SD_SCK=0;   
  sdiodelay();   
    SD_SCK=1;
    sdiodelay();
        if(SD_CMD==0)//返回开始
            {  
              dat[0]<<=1;
                    dat[0]|=SD_CMD;
                    SD_SCK=0;
                    sdiodelay();

                    SD_SCK=1;
                    sdiodelay();
                  dat[0]<<=1;
                    dat[0]|=SD_CMD;
                                    SD_SCK=0;
                    sdiodelay();
                    SD_SCK=1;
                    sdiodelay();
                  dat[0]<<=1;
                    dat[0]|=SD_CMD;
                                    SD_SCK=0;
                    sdiodelay();
                    SD_SCK=1;
                    sdiodelay();
                  dat[0]<<=1;
                    dat[0]|=SD_CMD;
                                    SD_SCK=0;
                    sdiodelay();
                    SD_SCK=1;
                    sdiodelay();
                  dat[0]<<=1;
                    dat[0]|=SD_CMD;
                                        SD_SCK=0;
                    sdiodelay();
                    SD_SCK=1;
                    sdiodelay();
                  dat[0]<<=1;
                    dat[0]|=SD_CMD;
                                        SD_SCK=0;
                    sdiodelay();
                    SD_SCK=1;
                    sdiodelay();
                  dat[0]<<=1;
                    dat[0]|=SD_CMD;
                                        SD_SCK=0;
                    sdiodelay();
                    SD_SCK=1;
                    sdiodelay();
                  dat[0]<<=1;
                    dat[0]|=SD_CMD;


                for(j=1;j<17;j++)dat[j]=SDRScmd();
                break;
            }

    }


}   

unsigned char crc7_mmc(unsigned char *dat,int length) //用于计算发送命令时的CRC7
{
    u8 i;
    u8 crc = 0;        // Initial value
    while (length--)
    {
        crc ^= *dat++;        // crc ^= *data; data++;
        for (i = 0; i < 8; i++)
        {
            if (crc & 0x80)
                crc = (crc << 1) ^ 0x12;        // 0x12 = 0x09<<(8-7) 多项式 x7+x3+1 0x85
            else
                crc <<= 1;
        }
    }

    return crc >> 1;
}   


u16 crc16_ccitt(u8 *dat, u16 length)  //CRC-16/CCITT        x16+x12+x5+1
{
    u8 i;
    u16 crc = 0;        // Initial value
    while(length--)
    {
        crc ^= *dat++;        // crc ^= *dat; dat++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0x8408;        // 0x8408 = reverse 0x1021
            else
                crc = (crc >> 1);
        }
    }
    return crc;
}

sd.h为sd卡的基本设置:

#ifndef __SD_H
#define __SD_H
#include "sdio.h"

extern u8 SD_Type;//SD卡的类型
extern u8 Response[17];//命令返回数组

//错误码定义
//-------------------------------------------------------------
#define INIT_CMD0_ERROR     0x01 //CMD0错误
#define INIT_CMD1_ERROR     0x02 //CMD1错误
#define WRITE_BLOCK_ERROR   0x03 //写块错误
#define READ_BLOCK_ERROR    0x04 //读块错误
//-------------------------------------------------------------


// SD卡类型定义  
#define SD_TYPE_ERR     0X00
#define SD_TYPE_V2      0X04
#define SD_TYPE_V2HC    0X06

//SD传输数据结束后是否释放总线宏定义  
#define NO_RELEASE      0
#define RELEASE         1   


//SD卡回应标记字
#define MSD_RESPONSE_NO_ERROR      0x00
#define MSD_IN_IDLE_STATE          0x01
#define MSD_ERASE_RESET            0x02
#define MSD_ILLEGAL_COMMAND        0x04
#define MSD_COM_CRC_ERROR          0x08
#define MSD_ERASE_SEQUENCE_ERROR   0x10
#define MSD_ADDRESS_ERROR          0x20
#define MSD_PARAMETER_ERROR        0x40
#define MSD_RESPONSE_FAILURE       0xFF     

// SD卡指令表         
#define CMD0    0       //卡复位
#define CMD1    1
#define CMD2    2       //获取CID寄存器
#define CMD3    3       //获取CID寄存器
#define CMD7    7       //获取CID寄存器
#define CMD8    8       //命令8 ,SEND_IF_COND
#define CMD9    9       //命令9 ,读CSD数据
#define CMD10   10      //命令10,读CID数据
#define CMD12   12      //命令12,停止数据传输
#define CMD16   16      //命令16,设置SectorSize 应返回0x00
#define CMD17   17      //命令17,读sector
#define CMD18   18      //命令18,读Multi sector
#define CMD23   23      //命令23,设置多sector写入前预先擦除N个block
#define CMD24   24      //命令24,写sector
#define CMD25   25      //命令25,写Multi sector
#define CMD41   41      //命令41,应返回0x00
#define CMD55   55      //命令55,应返回0x01
#define CMD58   58      //命令58,读OCR信息
#define CMD59   59      //命令59,使能/禁止CRC,应返回0x00
#define TRY_TIME 10    //向SD卡写入命令之后,读取SD卡的回应次数,即读TRY_TIME次,如果在TRY_TIME次中读不到回应,产生超时错误,命令写入失败


u8 SD_WaitReady(void);                        //等待SD卡准备
u8 SD_Init(void);                            //初始化
u8 SD_SendCmd(u8 cmd, u32 arg);        //写命令
u8 SDRScmd(void);
void SD_readsent(u32 add);
void SD_readblock(u8 buf[],u32 add);
void SD_readMblock(u8 buf[],u32 add,u32 num);//读多个扇区
#endif

--------------------------------------------------------分割线--------------------------------------------------

sd.c为sd卡的初始化和读取函数实现。

/*
此源码用于用gpoi模拟sdio实现sd卡使用4通道读取功能,写入没有实现(CRC16校检太费时,没有优势)。
由于现市面上的卡都是2.0以上的大容量卡,所以本例只支持2.0版以上SD卡。
*/
#include "sd.h"
//#include ".\src\uart1.h"
//#include "delay.h"

u8 SD_Type=0;//SD卡的类型
u8 Response[17]={0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};//命令返回数组
u16 SD_RCA;  //卡自荐的地址,host 需要保存下来以便后续使用 CMD7 来选中此卡。

///


//等待卡准备好
//返回值:0,准备好了;其他,错误代码
u8 SD_WaitReady(void)
{
    u32 t=500;
  while(t--)SDsendcmd(0xff);
    return 1;
}


//向SD卡发送一个命令
//输入: u8 cmd   命令
//      u32 arg  命令参数
//      u8 crc   crc校验值      
//返回值:SD卡返回的响应                                                              
u8 SD_SendCmd(u8 cmd, u32 arg)
{

    u8 Retry=0;
    u8 crc;
  u8 dat[5];
        Response[0]=0xff;
        dat[0]=(u8)(cmd | 0x40);
        dat[1]=(u8)(arg>>24);
        dat[2]=(u8)(arg>>16);
        dat[3]=(u8)(arg>>8);
        dat[4]=(u8)(arg);
      crc=(crc7_mmc(dat,5)<<1)+1;
    SDsendcmd(dat[0]);       //分别写入命令    最高2位固定为1  
    SDsendcmd(dat[1]);        //命令参数 2-5字节  4个字节 32位
    SDsendcmd(dat[2]);
    SDsendcmd(dat[3]);
    SDsendcmd(dat[4]);      
    SDsendcmd(crc);
                                     //停止传数据命令
    //if(cmd==CMD12)SDsendcmd(0xff);//Skip a stuff byte when stop reading
      SDRS_response(Response);
      watit_8CR();
    return Response[0];
}

//初始化SD卡
u8 SD_Init(void)
{
  u8 r1;      // 存放SD卡的返回值
  u16 retry;  // 用来进行超时计数


     SD_WaitReady();
    r1=SD_SendCmd(CMD0,0);//进入IDLE状态      即复位sd卡 空闲状态
  watit_8CR();



     SD_Type=0;//默认无卡


        SD_SendCmd(CMD8,0x1AA);//SD V2.0      发送接口状态命令                                          
                                          //如果返回值为1 则是 SDV2.0版本

            if(Response[3]==0x01&&Response[4]==0xaa)//卡是否支持2.7~3.6V
            {  

                retry=64;
         do
                        {
                            SD_SendCmd(55,0x00000000);
                            Response[1]=0x00;
                          SD_SendCmd(41,0x403c0000);
                        }while(((Response[1]&0x80)!=0x80)&& retry--);//OCR[31]=1 时上电操作是否完成

                        //OCR[31]=1 时,OCR[30] (CCS) 指示了卡是否为大容量卡。
                        //CMD8 无响应,ACMD41 响应的 OCR[30]=0 :SD 1.X 卡。
                        //CMD8 有响应,ACMD41 响应的 OCR[30]=0 :SD 2.0 非大容量卡。
                        //CMD8 有响应,ACMD41 响应的 OCR[30]=1 :SDHC 2.0 大容量卡。

                        if(Response[1]&0x40)SD_Type=SD_TYPE_V2HC;//CMD8 有响应,ACMD41 响应的 OCR[30]=1 :SDHC 2.0 大容量卡。   
                        else SD_Type=SD_TYPE_V2;

                    r1=SD_SendCmd(CMD2,0x00000000); //获取CID寄存器   
                                       //R2 类响应136BIT,其中包含了 CID 寄存器 (如图13) ,是该卡的识别号,host 可以忽略 CID 的内容。

                    r1=SD_SendCmd(CMD3,0x00000000);//进入数据传输模式。

                    SD_RCA=((u16)Response[1]<<8)|Response[2]; // 获取RCA (16bit) ,这是卡自荐的地址,host 需要保存下来以便后续使用 CMD7 来选中此卡。

          r1=SD_SendCmd(CMD7,(u32)(SD_RCA)<<16);    //选中卡   

                    r1=SD_SendCmd(55,(u32)(SD_RCA)<<16);  //CMD55,参数必须是RCA
                    r1=SD_SendCmd(6, 0x00000002);    //ACMD6,打开4bit传输模式选中卡
          r1=SD_SendCmd(CMD16,0x00000200);    //设置块为512byte,不能设为其它。
                     //SD_WaitReady();   

            }



    SDout=0xff;
    if(SD_Type)return 0;    //如果没有采集到SD卡版本 返回0成功。
    else if(r1)return r1; //初始化失败。      
    return 0xaa;//其他错误
}


void SD_readblock(u8 buf[],u32 add)//读取一个扇区数据
{
      int i=0,j=-1,cn=0;
        u8 CRC=0;
      u8 dat[5];
    if(SD_Type!=SD_TYPE_V2HC)add <<= 9;//转换为字节地址
        dat[0]=(u8)(17 | 0x40);
        dat[1]=(u8)(add>>24);
        dat[2]=(u8)(add>>16);
        dat[3]=(u8)(add>>8);
        dat[4]=(u8)(add);
      CRC=(crc7_mmc(dat,5)<<1)+1;

    SDHisendcmd(dat[0]);//发送读命令
    SDHisendcmd(dat[1]);
  SDHisendcmd(dat[2]);
  SDHisendcmd(dat[3]);
  SDHisendcmd(dat[4]);
  SDHisendcmd(CRC);
    P7=0xff;
    for(i=0;i<1024;i++) // 接收数据
     {

        SD_SCK=0;
        SD_SCK=1;   
        if(!SD_D0)
            {   
                  P74=0;
            for(j=0;j<512;j++)
                {
                    SD_SCK=0;
                    SD_SCK=1;
                    buf[j]=SDout;
                    SD_SCK=0;
                    buf[j]<<=4;
                    SD_SCK=1;
                    buf[j]|=(SDout&0x0f);               
                }
                P74=1;
                SDread();
                SDread();//接收crc16,丢弃。
                SDread();
                SDread();

                SDread();
                SDread();
                SDread();
                SDread();

                SDread();                        
                break;
            }
    }

}

void SD_readMblock(u8 buf[],u32 add,s32 num)//读取num个扇区数据
{

      u32 i,j,k=0;
        u8 CRC=0;
      u8 dat[5];
    if(SD_Type!=SD_TYPE_V2HC)add <<= 9;//转换为字节地址
        dat[0]=(u8)(18 | 0x40);
        dat[1]=(u8)(add>>24);
        dat[2]=(u8)(add>>16);
        dat[3]=(u8)(add>>8);
        dat[4]=(u8)(add);
      CRC=(crc7_mmc(dat,5)<<1)+1;

    SDHisendcmd(dat[0]);//发送读命令
    SDHisendcmd(dat[1]);
  SDHisendcmd(dat[2]);
  SDHisendcmd(dat[3]);
  SDHisendcmd(dat[4]);
  SDHisendcmd(CRC);
    SDout=0xff;
    num--;   
    for(i=0;i<10240;i++) // 接收数据
     {

        SD_SCK=0;
        SD_SCK=1;   
        if(!SD_D0)
            {   
                  P74=0;
            for(j=0;j<512;j++)
                {
                    SD_SCK=0;
                    SD_SCK=1;
                    buf[k]=SDout;
                    SD_SCK=0;
                    buf[k]<<=4;
                    SD_SCK=1;
                    buf[k]|=(SDout&0x0f);   
                    k++;
                }
                P74=1;
                SDread();
                SDread();//接收crc16,丢弃。
                SDread();
                SDread();

                SDread();
                SDread();
                SDread();
                SDread();

                SDread();                        
                if(num<1)break;
                num--;
            }
    }

        SDHisendcmd(0x4c);//发送读命令CMD12
        SDHisendcmd(0);
        SDHisendcmd(0);
        SDHisendcmd(0);
        SDHisendcmd(0);
        SDHisendcmd(0x61);

    for(i=0;i<1024;i++) // 接收数据
     {

        SD_SCK=0;
        SD_SCK=1;   
        if(SD_CMD==0)
            {   

             for(j=0;j<64;j++)
                {
                    SD_SCK=0;
                    SD_SCK=1;

                }

                break;

            }
    }

}
————————————————


原文链接:https://blog.csdn.net/bfmipbwvfp/article/details/140374767,也是本人发的,上面有附件。

回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:391
  • 最近打卡:2025-04-30 00:26:42

0

主题

336

回帖

1490

积分

金牌会员

积分
1490
发表于 2024-7-27 17:21:23 | 显示全部楼层
谢谢分享
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:422
  • 最近打卡:2025-05-01 09:54:52
已绑定手机

19

主题

3190

回帖

4866

积分

论坛元老

积分
4866
发表于 2024-7-27 18:20:42 来自手机 | 显示全部楼层
这是qspi接口的程序
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看II
  • 打卡总天数:21
  • 最近打卡:2025-04-04 22:11:37
已绑定手机

36

主题

287

回帖

824

积分

高级会员

积分
824
发表于 2024-7-29 07:09:02 来自手机 | 显示全部楼层
SD卡模拟qspi比spi硬件dma快多少?
如果flash也用qspi了话能快很多吗?
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:502
  • 最近打卡:2025-05-01 08:01:38
已绑定手机

1

主题

833

回帖

1441

积分

金牌会员

积分
1441
发表于 2024-7-29 07:58:31 | 显示全部楼层
感谢分享
靡不有初,鲜克有终
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:6
  • 最近打卡:2024-08-27 15:25:33

1

主题

17

回帖

105

积分

注册会员

积分
105
发表于 2024-7-29 08:14:57 | 显示全部楼层
so*** 发表于 2024-7-27 18:20
这是qspi接口的程序

并不是,QSPI比sdio少一条CMD命令线路。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2025-03-13 15:49:42

1

主题

0

回帖

24

积分

新手上路

积分
24
发表于 2025-3-13 15:49:42 | 显示全部楼层
感谢分享
回复

使用道具 举报 送花

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

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-2 02:09 , Processed in 0.155020 second(s), 92 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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