I2C虚拟项目-test3

持续更新测试用例解读。


前言

一个个对波形和代码看测试用例其实很费时间,但是我觉得有助于理解协议。坚持呀!


1. rkv_i2c_master_sda_control_cg_test

在这里插入图片描述
当DW_APB_I2C模块作为transmitter/receiver时进行保持时间设置(三种);根据波形可以看出,前三段对应读操作部分,后三段对应写操作部分,对保持时间的设置可以在master/slave模式下进行,但是对建立时间的设置只能在slave transmitter模式下进行。
在这里插入图片描述
保持时间

  1. 访问0x00寄存器(IC_CON控制寄存器),写入’h6d(110 1101),即配置IC_CON[0]为1,以启用DW_apb_i2c为master模式;配置IC_CON[2:1]为10,以设置速度模式为快速模式;配置IC_CON[3]为1,以设置作为slave地址位宽为10bit;配置IC_CON[4]为0,以设置作为master地址位宽为7bit;配置IC_CON[5]为1,打开restart;配置IC_CON[6]为1,以禁用slave模式;高位均置为0,IC_CON[7]为0表示无论是否被寻址到,都产生STOP DET中断;IC_CON[8]为0表示默认TX EMPTY中断行为;IC_CON[9]为0表示当RX_FIFO满时溢出;IC_CON[10]为0表示无论是不是master模式都产生STOP DET;
  2. 访问0x04寄存器(IC_TAR目标地址寄存器),写入’h333(11 0011 0011);
  3. 访问0x1c寄存器(IC_FS_SCL_HCNT快速高计数寄存器),写入’hc8(对应十进制200);
  4. 访问0x20寄存器(IC_FS_SCL_LCNT快速低计数寄存器),写入’hc8(对应十进制200);在这里插入图片描述完成配置;接下来以保持时间为8’d1,作为receiver进行保持时间设置为例
  5. 访问0x7c寄存器(IC_SDA_HOLD 状态寄存器),写入’h10001(1 0000 0000 0000 0001),高16位对应IC_SDA_RX_HOLD设置,表示保持时间设置为1;
  6. 访问0x6c寄存器(IC_ENABLE寄存器),写入’h1;
  7. 访问0x10寄存器(IC_DATA_CMD寄存器),写入’h100(1 0000 0000),表示进行读操作;
  8. 访问0x70寄存器(IC_STATUS状态寄存器),读取到’h2(10),TX_FIFO非空;I2C总线上出现START信号前,0x70寄存器读取均为’h2,START信号期间,0x70寄存器读取值为’h23(100011),表明master FSM处于activity状态,RX_FIFO为空,TX_FIFO非空非满;当开始地址字节传输时,0x70寄存器读取值变为’h27(100111),表明master FSM处于activity状态,RX_FIFO为空,TX_FIFO为空;地址字节为(0110 011 1+ACK),数据字节为(0101 0101+NACK),对于master recceiver,接收最后一个字节后由master发送NACK信号。随后发送RX_FULL中断,再读取0x70寄存器值变为’h2f(101111),TX_FIFO为空,RX_FIFO不为空;
  9. 访问0x10寄存器(IC_DATA_CMD寄存器),读取到’h55(0101 0101),随后I2C总线上产生STOP信号。
  10. 访问0x6c寄存器,写入’h0;
    接下来重复5-10步,将保持时间设置为8’d50和8’d150,进行相同的数据传输。 在这里插入图片描述作为transmitter时进行保持时间的设置以8’d50为例(因为在进行recevier保持时间设置时,进行了高位变化,低16位一直为1,所以当保持时间设置为8’d150时,为960001,这也是transmitter保持时间设置为8’d1时的值,因此在第一阶段没有进行再次设置,步骤不典型)
  11. 访问0x7c寄存器(IC_SDA_HOLD寄存器),写入’h960032,即IC_SDA_TX_HOLD设置为’h32(8’d50);
  12. 访问 0x6c寄存器(IC_ENABLE寄存器),写入’h1;
  13. 访问0x70寄存器,读取到’h6(110);
  14. 访问0x10寄存器(IC_CMD_DATA寄存器),写入’h55;
  15. I2C总线上产生START条件,地址字节0110 011 0+ACK,数据字节0101 0101+ACK,STOP信号;对于master transmitter,最后一个字节的ACK/NACK信号由slave发送。
  16. 访问0x6c寄存器,写入’h0;在这里插入图片描述保持时间为8’d1和8’d150的传输步骤与11-16相同。
    注释:IC_SDA_HOLD寄存器中的值以 ic_clk 周期为单位,IC_SDA_TX_HOLD 中编程的值必须大于每个模式下的最小保持时间,主模式下一个周期,从模式下七个周期,才能实现该值。

建立时间
在建立时间分别设置为8’d1, 8’d50, 8’d150;由于 I2C SDA Setup寄存器只会在当DW_APB_I2C作为salve transmitter时被使用,所以没有在I2C总线上体现相关设置。在这里插入图片描述

  1. 访问0x94寄存器(IC_SDA_SETUP寄存器),写入’h1(8’d1),即将建立时间设置为8’d1;

  2. 访问 0x6c寄存器(IC_ENABLE寄存器),写入’h1;

  3. 访问0x6c寄存器,写入’h0;
    至此完成一次建立时间的设置,建立时间为8’d50和8’d150的设置步骤与1-3相同。对应下面代码
    在这里插入图片描述

  4. 最后访问0x70寄存器(IC_STATUS状态寄存器),I2C处于禁用状态,对应apb_wait_empty_seq的操作。

2. rkv_i2c_master_timeout_cg_test

在这里插入图片描述
对timeout的设置在波形上体现为pready拉低时间的变化(pslverr拉高时间始终为4000ps),最终编程值确定寄存器超时计数器从哪个值开始倒计时。 此计数器上的零将通过pslverr为高中断等待的事务。

  1. 访问0x00寄存器(IC_CON控制寄存器),写入’h6d(110 1101),即配置IC_CON[0]为1,以启用DW_apb_i2c为master模式;配置IC_CON[2:1]为10,以设置速度模式为快速模式;配置IC_CON[3]为1,以设置作为slave地址位宽为10bit;配置IC_CON[4]为0,以设置作为master地址位宽为7bit;配置IC_CON[5]为1,打开restart;配置IC_CON[6]为1,以禁用slave模式;高位均置为0,IC_CON[7]为0表示无论是否被寻址到,都产生STOP DET中断;IC_CON[8]为0表示默认TX EMPTY中断行为;IC_CON[9]为0表示当RX_FIFO满时溢出;IC_CON[10]为0表示无论是不是master模式都产生STOP DET;

  2. 访问0x04寄存器(IC_TAR目标地址寄存器),写入’h333(11 0011 0011);7bit模式下对应地址为011 0011;

  3. 访问0x1c寄存器(IC_FS_SCL_HCNT快速高计数寄存器),写入’hc8(对应十进制200);

  4. 访问0x20寄存器(IC_FS_SCL_LCNT快速低计数寄存器),写入’hc8(对应十进制200);
    完成基本配置在这里插入图片描述

  5. 访问0xf0寄存器(REG_TIMEOUT_RST寄存器),写入’h1,对应timeout[0] (4’b0001);

  6. 访问0x6c寄存器(IC_ENABLE寄存器),写入’h1;

  7. 访问0x10寄存器(IC_DATA_CMD寄存器),写入’h0;接着依次写入’h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7,在将要写入’h8时,pready信号拉低(318000ps-322000ps),共计4000ps,占整个penable有效时间的1/2,其中penable信号拉高时间为318000ps-326000ps,共计8000ps,待pready信号拉高后,pslverr信号接着拉低(4000ps),表示传输异常,'h8写入失败(因为在IC_COMP_PARAM_1 寄存器中设置的TX BUFFER DEPTH为7,即深度为8,所以不能存入第9个数据,引起pready拉低);

  8. 随后观测到I2C总线出现(地址字节)0110 011 0(write)+ACK,(数据字节)0000 0000+ACK,0000 0001+ACK,0000 0010+ACK,0000 0011+ACK,0000 0100+ACK,0000 0101+ACK,0000 0110+ACK,0000 0111+ACK,STOP信号,开始最后一个字节的发送后,出现TX_EMPTY中断,出现STOP信号后中断消失;

  9. 访问0x6c寄存器(IC_ENABLE寄存器),写入’h0;
    至此完成timeout[0]的测试;timeout[1]为4’b0111,pready拉低时间343354000ps-343382000ps,共计28000ps, pslverr拉高时间为4000ps,占整个penable有效时间的7/8,其中penable拉高时间343354000ps-343386000ps,共计32000ps;
    timeout[2]为4’b1100,pready拉低时间686434000ps-686482000ps,共计48000ps,占整个penable有效时间的12/13,pslverr拉高时间为4000ps,其中penable 拉高时间为686434000ps-686486000ps,共计52000ps。
    对应代码为在这里插入图片描述

波形图如下:在这里插入图片描述

总结

虽然秋招艰难,但也还是要继续学呀!

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
C++面试题 参考:http://blog.csdn.net/Ghost90/archive/2009/04/22/4099672.aspx 整理:松鼠 时间:2009-5-8 1、const 有什么用途?(请至少说明两种) 答: (1)可以定义 const 常量 (2)const可以修饰函数的参数、返回值,甚至函数的定义体。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。 2、在C++ 程序中调用被 C编译器编译后的函数,为什么要加 extern “C”? 答:C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为: void foo(int x, int y); 该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。 C++提供了C连接交换指定符号extern“C”来解决名字匹配问题。 3、请简述以下两个for循环的优缺点(5分) for (i=0; i<N; i++) { if (condition) DoSomething(); else DoOtherthing(); } if (condition) { for (i=0; i<N; i++) DoSomething(); } else { for (i=0; i<N; i++) DoOtherthing(); } 优点:程序简洁 缺点:多执行了N-1次逻辑判断,并且打断了循环“流水线”作业,使得编译器不能对循环进行优化处理,降低了效率。 优点:循环的效率高 缺点:程序不简洁 4、有关内存的思考题 void GetMemory(char *p) { p = (char *)malloc(100); } void Test(void) { char *str = NULL; GetMemory(str); strcpy(str, "hello world"); printf(str); } 请问运行Test函数会有什么样的结果? 答:程序崩溃。 因为GetMemory并不能传递动态内存, Test函数中的 str一直都是 NULL。 strcpy(str, "hello world");将使程序崩溃。 char *GetMemory(void) { char p[] = "hello world"; return p; } void Test(void) { char *str = NULL; str = GetMemory(); printf(str); } 请问运行Test函数会有什么样的结果? 答:可能是乱码。 因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是 NULL,但其原现的内容已经被清除,新内容不可知。 void GetMemory2(char **p, int num) { *p = (char *)malloc(num); } void Test(void) { char *str = NULL; GetMemory(&str, 100); strcpy(str, "hello"); printf(str); } 请问运行Test函数会有什么样的结果? 答: (1)能够输出hello (2)内存泄漏 void Test(void) { char *str = (char *) malloc(100); strcpy(str, “hello”); free(str); if(str != NULL) { strcpy(str, “world”); printf(str); } } 请问运行Test函数会有什么样的结果? 答:篡改动态内存区的内容,后果难以预料,非常危险。 因为free(str);之后,str成为野指针, if(str != NULL)语句不起作用。 5、编写strcpy函数(10分) 已知strcpy函数的原型是 char *strcpy(char *strDest, const char *strSrc); 其中strDest是目的字符串,strSrc是源字符串。 (1)不调用C++/C的字符串库函数,请编写函数 strcpy char *strcpy(char* strDest, const char* strSrc) { assert((strDest!=NULL) && (strSrc !=NULL));//2分 char *address = strDest;//2分 while( (*strDest++ = * strSrc++) != ‘\0’ )//2分 NULL; return address;// 2分 } 5.1 strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值? 答:为了实现链式表达式。 // 2分 例如int length = strlen( strcpy( strDest, "hello world") ); 6、编写类String的构造函数、析构函数和赋值函数(25分) 已知类String的原型为: class String { public: String(const char *str = NULL);//普通构造函数 String(const String &other);//拷贝构造函数 ~ String(void);// 析构函数 String & operate =(const String &other);// 赋值函数 private: char* m_data;// 用于保存字符串 }; 请编写String的上述4个函数。 标准答案: // String的析构函数 String::~String(void) // 3分 { delete [] m_data; // 由于m_data是内部数据类型,也可以写成delete m_data; } // String的普通构造函数 String::String(const char *str) // 6分 { if(str==NULL) { m_data = new char[1]; // 若能加NULL 判断则更好 *m_data = ‘\0’; } else { int length = strlen(str); m_data = new char[length+1]; // 若能加NULL 判断则更好 strcpy(m_data, str); } } // 拷贝构造函数 String::String(const String &other) // 3分 { int length = strlen(other.m_data); m_data = new char[length+1]; // 若能加NULL 判断则更好 strcpy(m_data, other.m_data); } // 赋值函数 String & String::operate =(const String &other) // 13分 { // (1) 检查自赋值 // 4分 if(this == &other) return *this; // (2) 释放原有的内存资源 // 3分 delete [] m_data; // ()分配新的内存资源,并复制内容// 3分 int length = strlen(other.m_data); m_data = new char[length+1]; // 若能加NULL 判断则更好 strcpy(m_data, other.m_data); // ()返回本对象的引用 // 3分 return *this; } 7、实现双向链表删除一个节点P,在节点P后插入一个节点,写出这两个函数。 void DeleteNode(DuNode *p) { p->prior->next=p->next; p->next->prior=p->prior; } void InsertNode(DuNode *p, DuNode *s)//Node "s" is inserted after "p" { s->next=p->next; p->next->prior=s; p->next=s; s->prior=p; } 8、Windows程序的入口是哪里?写出Windows消息机制的流程。 WINDOWS入口是WinMain函数 消息机制的流程: 系统中发生了某个事件 Windows把这个事件翻译为消息,然后把它放到消息队列中 1. 应用程序从消息队列中接收到这个消息,把它存放在TMsg记录中 2. 应用程序把消息传递给一个适当的窗口的窗口过程 3. 窗口过程响应这个消息并进行处理 9.写一个函数,将其中的\t都转换成4个空格。 #include<iostream> using namespace std; char* Convert_t(char *des,char *src) { char *temp; des=new char[100]; temp=des; while(*src!='\0') { if(*src=='\t') { src++; *des++=' '; *des++=' '; *des++=' '; *des++=' '; continue; } *des++=*src++; } *des='\0'; des=temp; return des; } int main() { char *t="asdf\tasd\tasasddas\\tdfasdf",*d; cout<<t<<endl; cout<<Convert_t(d,t); getchar(); } 10.如何定义和实现一个类的成员函数为回调函数? 如果类的成员函数是一个callback函数, 必须宣告它为"static",才能把C++ 编译器加诸于函数的一个隐藏参数this去掉。 11.C++里面是不是所有的动作都是main()引起的?如果不是,请举例。 不是的,C++里面有些动作不是引起的,比如,全局对象的实例化、全局变量的动态空间申请,等等 下面是一个例子: #include<iostream> using namespace std; char *des=new char[100]; //全局变量的动态空间申请在程序运行之后,main运行之前完成。所以不是所有的动作都是main引起的。 int main() { char *des="abc"; cout<<des<<endl; getchar(); } 12.C++里面如何声明const void f(void)函数为C程序中的库函数? extern "C" const void f(void); 这样声明之后,相当于告诉C, 函数const void f(void)是在C++语言的文件中声明或者实现的,c程序可以使用这个C++中的函数了,从而实现C++和c的混合编程。 13、编写一个函数,作用是把一个char组成的字符串循环右移n个。比如原来是“abcdefghi”如果n=2,移位后应该是“hiabcdefgh” 正确解答1: void LoopMove(char* pStr, int steps) { int n = strlen( pStr ) - steps; char tmp[MAX_LEN]; strcpy ( tmp, pStr + n ); strcpy ( tmp + steps, pStr); *( tmp + strlen ( pStr ) ) = '\0'; strcpy( pStr, tmp ); } 正确解答2: void LoopMove(char* pStr,int steps ) { int n = strlen( pStr ) - steps; char tmp[MAX_LEN]; memcpy( tmp, pStr + n, steps ); memcpy(pStr + steps, pStr, n ); memcpy(pStr, tmp, steps ); } 14、写出输出结果 void fun(char s[10]) { char a[10]; cout<<"a:"<<sizeof(a)<<endl; cout<<"s:"<<sizeof(s)<<endl; } 输出: a:10 s:4 15、内存的分配方式的分配方式有几种? 答: 1. 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量。 2. 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。 3. 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。 16.是不是一个父类写了一个virtual 函数,如果子类覆盖它的函数不加virtual ,也能实现多态? 答:virtual修饰符会被隐形继承的。private 也被集成,只事派生类没有访问权限而已。virtual可加可不加。子类的空间里有父类的所有变量(static除外)。同一个函数只存在一个实体(inline除外)。子类覆盖它的函数不加virtual ,也能实现多态。在子类的空间里,有父类的私有变量。私有变量不能直接访问。 17.进程间通信的方式有? 进程间通信的方式有 共享内存, 管道 ,Socket ,消息队列 , DDE等 18.C++中什么数据分配在栈或堆中,New分配数据是在近堆还是远堆中? 答:栈: 存放局部变量,函数调用参数,函数返回值,函数返回地址。由系统管理 堆: 程序运行时动态申请,new 和 malloc申请的内存就在堆上 (Google搜):DOS下程序是独占方式,堆分为近堆和远堆,近堆和栈是在数据段开辟的同一块内存地址,栈从下往上增长,堆从上向下分配,中间没有规定分界线,所以程序控制不当,如深层次的递归,大量的动态地址分配很容易造成堆栈冲突,即堆栈地址重叠,从而造成死机和程序运行异常。堆和栈连在一起说的原因就是如此。至于远堆则是指在数据段和代码段以外计算机所有没有使用的剩余基本内存。Windows采用的是虚拟地址,内存分配方式就不一样了 补充:DOS下堆栈的分配是由程序而不是操作系统自己控制的,具体分配大小、方式随编译系统、程序模式不同而异。C语言的堆栈分配代码在启动代码中. 19.全局变量和局部变量在内存中是否有区别?如果有,是什么区别? 全局变量储存在静态数据库,局部变量在堆栈。 20.TCP/IP 建立连接的过程?(3-way shake) 答:在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认; 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。 21.winsock建立连接的主要实现步骤? 答:服务器端:socker()建立套接字,绑定(bind)并监听(listen),用accept()等待客户端连接。 客户端:socker()建立套接字,连接(connect)服务器,连接上后使用send()和recv(),在套接字上写读数据,直至数据交换完毕,closesocket()关闭套接字。 服务器端:accept()发现有客户端连接,建立一个新的套接字,自身重新开始等待连接。该新产生的套接字使用send()和recv()写读数据,直至数据交换完毕,closesocket()关闭套接字。 22.static有什么用途?(请至少说明两种) 1) 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。 2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。 3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用 23.引用与指针有什么区别? 1) 引用必须被初始化,指针不必。 2) 引用初始化以后不能被改变,指针可以改变所指的对象。 3) 不存在指向空值的引用,但是存在指向空值的指针。 24、请写出下列代码的输出内容 #include<stdio.h> main() { int a,b,c,d; a=10; b=a++; c=++a; d=10*a++; printf("b,c,d:%d,%d,%d",b,c,d); return 0; } 答:10,12,120 main() { int a[5]={1,2,3,4,5}; int *ptr=(int *)(&a+1); printf("%d,%d",*(a+1),*(ptr-1)); } 输出:2,5 *(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5 &a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int) int *ptr=(int *)(&a+1); 则ptr实际是&(a[5]),也就是a+5 原因如下: &a是数组指针,其类型为 int (*)[5]; 而指针加1要根据指针类型加上一定的值, 不同类型的指针+1之后增加的大小不同 a是长度为5的int数组指针,所以要加 5*sizeof(int) 所以ptr实际是a[5] 但是prt与(&a+1)类型是不一样的(这点很重要) 所以prt-1只会减去sizeof(int*) a,&a的地址是一样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5]
根据你提供的代码,我看到你正在进行线性回归分析,并使用残差抽样方法进行模拟。以下是对你提供的代码的解释: 1. `dim(src)[1]`:这段代码返回数据框 `src` 的行数。 2. `lm.test1 <- lm(RM000006~mkt+smb+hml+rmw+cma,data=src)`:这段代码使用线性回归模型,以 `RM000006` 作为因变量,`mkt`、`smb`、`hml`、`rmw`、`cma` 作为自变量,拟合了一个线性回归模型,并将结果保存在 `lm.test1` 中。 3. `summary(lm.test1)`:这段代码返回线性回归模型 `lm.test1` 的摘要统计信息,包括回归系数、截距、残差等。 4. `resid <- residuals(lm.test1)`:这段代码计算线性回归模型 `lm.test1` 的残差,并将结果保存在 `resid` 中。 5. `install.packages("sampling")` 和 `library("sampling")`:这两段代码用于安装和加载名为 "sampling" 的 R 包,该包提供了抽样方法的函数。 6. `results <- c()` 和 `resultst <- c()`:这两段代码创建了两个空的向量 `results` 和 `resultst`,用于存储模拟结果。 7. `for (i in 1:1000)`:这段代码表示进行1000次模拟。 8. `n <- sample(resid, 485, replace = TRUE, prob = NULL)`:这段代码使用 `sample` 函数从 `resid` 中有放回地抽取485个样本,并将结果保存在 `n` 中。 9. `r <- 0.9844538*mkt + 0.01333323*smb - 0.4016015*hml - 0.3710315*rmw - 0.1699253*cma + n`:这段代码根据给定的线性方程和从残差中抽取的样本,计算虚拟收益序列 `r`。 10. 模拟过程将重复进行1000次,并将每次模拟的结果分别存储在 `results` 和 `resultst` 中。 希望以上解释对你有帮助!如果你有更多问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ann_xia66

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值