打印

【原创】LaunchPad的USCI实战--硬件I2C连接24LC02+MFRC522

[复制链接]
12966|41
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
yirongfu|  楼主 | 2012-6-15 00:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    这回拿到LaunchPad,除了感谢档、感谢蒸俯和CCAVTI就不用特别感谢了,用实际产品应用来回报,还得感谢21IC,特别是小跑堂的辛勤劳动!!!
    这回来点儿实用的吧,分享些自己的实际项目资料。之前曾用过2系列,最近也抽空看了看LaunchPad的资料,其实ValueLine可以当作2系列来看,再其实反正都是430,所以有些部分的移植还是比较快的。这些天使用LaunchPad做的试验,是通过MSP430G2553的硬件I2C访问挂在同一I2C接口上的EEPROMMFRC522EEPROM使用模拟I2C接口、MFRC522使用模拟SPI接口的资料网上不难得到,针对430的硬件I2C接口的可能稍微少些,至少我看TI官网上的例程好像就没有跟EEPROM连接的,MFRC522就更别说了。这回测试的难度可能在于两个器件并联挂在一个I2C接口上时的通讯,以及430USCI模块的使用。
      I2C协议就不用在这里赘述了,EEPROM选用Microchip24LC02BMFRC522接成I2C接口形式,MSP430G2553I2C口配置在USCI_B0UCB0SCLUCB0SDA)上,接线示意图如下,图中只画出I2C接口相关接线,其他接线略去,MFRC52224LC02B的用法详见芯片数据手册:

       MSP430G2553使用DCO作为CPU时钟,1MHzUSCI_B0时钟取自SMCLK11分频,SMCLK=DCOCLK。这里需要注意器件的地址,USCII2C模块有一个专门的从设备地址寄存器UCBxI2CSA,用来设置从设备的地址,这个地址可别写错,一个器件一个唯一的地址,比如24LC02B,其地址寻址控制如下所示:

MSP430G2553UCBxI2CSA寄存器构成如下所示:

在前面的电路图中,24LC02BA0A2接地,因为是7-bit寻址模式,所以其地址slave address0x50,如果A0A2不是这么接,则需要把这个地址修改为对应的值。MFRC522类似,高地址由EA固定为0101,低3位我接成010,所以地址为0x2A。这个地址的设置与模拟I2C程序中常用的一个写地址和一个读地址的方式编程方法有所不同,需要注意。
    程序思路是:采用查询相关标志位的方式,而不是中断方式,实现单个字节的收发,在此基础上接着实现若干个字节的收发,然后实现与实际器件相关的读写操作,比如24LC02B的读写,MFRC522寄存器的读、写、修改,等等。花了不少时间和眼神研究USCI模块的用法,最终还是调试出来了,感觉还不算太复杂,不像硬件SPI还有多种时序形式,没有示波器实在费劲。根据I2C器件地址和器件各自的寄存器或存储单元操作规范,分别进行访问、控制,不会冲突。这里,建议初次使用的朋友一定要好好读一下MSP430G2553User’s Guide,特别是其中的Master发送和接收模式的流程图,调试的过程需要吃透这个图,比如停止信号在何时发出、各标志位在什么时候产生、是否需要软件人为复位或置位等,要是没弄清这些细节,可能还不如使用模拟I2C方式。
    主要调试经验小结:
1. 在调试中曾遇到一个问题,写完24LC02B的一个Page后,需要做适当的延时再接着下一个Page的写,否则有可能出错或进行不下去。一般停在循环判断某个标志位的地方,后面所附的源代码中也可以看到,等待标志位的过程我是采用一直while查询的方式,没有作超时退出处理,这种处理方式当然最好进行改进,目前之所以这么处理,是因为一般调试好后成品的线路板只要器件不坏,不会在这里出问题,因此简化处理了。
2. 硬件I2C的操作采用了查询的方式,而不是中断的方式,这是基于保证通讯优先级最高的考虑,在通讯期间不处理其他事件,因为我的应用中通讯的数据很重要。采用查询的方式,也便于编程。当然,具体情况具体分析,大家可以根据自己的情况进行选择。我个人认为查询稳妥些,并且在操作期间将中断暂时关闭,确保时序不出错。
3. 多个I2C器件挂同一总线上,是为了节约I/O口的开支,这也体现Value的精神,目前来看,硬件USCI使用起来还是不难的。多年以前曾经尝试将PCF856324LC02挂同一总线进行操作,模拟I2C方式,结果不行,后来的解决措施是共用SCL,但分开SDA,这也是种思路。
4. 调试MFRC522时,可以对照上面的MSP430G2553的流程图和MFRC522的寄存器读、写流程进行,使程序符合MFRC522的要求,再结合下面的NXP示例代码,一般都能成功,除非硬件有问题。
    因为涉及正在使用的产品,不便完全分享,只摘出与MSP430G2553硬件相关的代码和公用的底层代码供大家参考,请见谅。不过,这样也有好处,因为照搬源代码不利于自己的进步:)。好在而分享的这些代码都是接口的关键代码,已经节约了这部分的调试过程。MFRC522的接口协议程序我附上NXP的一个示例代码供大家参考,它的单片机使用的是NXPLPC9401,其中RC522的硬件初始化函数SysInit(void)的开头部分需要对芯片进行复位操作,涉及MSP430G2553I/O口对MFRC522NRSTPD引脚的操作,大家在实际应用编程时注意不要遗忘。基本上,这些资料对于使用24LC02BMFRC522的软件开发和原理图设计已经够用了。

    最后,2楼上代码,因为网站提示字数超限了。
评分
参与人数 2威望 +6 收起 理由
永远的不知 + 4 原创好文
tianm + 2

相关帖子

沙发
yirongfu|  楼主 | 2012-6-15 00:45 | 只看该作者
首先是NXP的示例代码: MFRC52x SampleCode_LPC9401.rar (30.1 KB)

最后,上酸菜:

#include "msp430g2553.h"
#include <intrinsics.h>
#include "Rc522Reg.h"                        //见NXP的代码
#include "ErrCode.h"                            //见NXP的代码
#include "OpCtrl.h"                                //见NXP的代码
#include "Mifare.h"                                //见NXP的代码

#define txbeforerx 0x01                 //bitflag
#define i2ctxend 0x02                   //bitflag
#define i2crxend 0x04                   //bitflag
#define tx1byte 0x08                    //bitflag

#define epr24_addr  0x50                //24LC02B器件地址
#define rc522_addr  0x2A                //MFRC522器件地址

unsigned char TxData[9];
unsigned char RxBuffer[8];
unsigned char cachedata[40];
unsigned char *PTxData,*PRxData;
unsigned char bitflag;


/*----------------------------------------------------------------------------
功能:USCI_B0的I2C功能初始化
输入:
输出:
说明:SMCLK=DCOCLK
----------------------------------------------------------------------------*/
void I2C_init(void)
{
  UCB0CTL1 |= UCSWRST;                                      // Enable SW reset
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;        // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_2 + UCSWRST;                    // Use SMCLK, keep SW reset, receiver
  UCB0BR0 = 11;                                                     // fSCL = SMCLK/11
  UCB0BR1 = 0;

  UCB0CTL1 &= ~UCSWRST;                                 // Clear SW reset, resume operation
  bitflag &= 0xF0;
}

/*----------------------------------------------------------------------------
功能:从I2C接口接收n个字节数据
输入:待接收字节个数 num,7-bit从机地址slave_addr
输出:接收的数据存放在RxBuffer数组
说明:接收之前需要发送的数据放在TxData[0],比如源数据内存地址;适合接收2个以上字节
----------------------------------------------------------------------------*/
void I2CRxnbyte(unsigned char slave_addr, unsigned char num)
{
  UCB0I2CSA = slave_addr;
  IE2 |= UCB0TXIE + UCB0RXIE;                 // Enable TX RX interrupt
  
  PRxData = (unsigned char *)RxBuffer;        // Start of RX buffer
  PTxData = (unsigned char *)TxData;          // TX array start address

  TxByteCount = 1;
  RxByteCount = num;                                 // Load RX byte counter
  bitflag |= txbeforerx;
  UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition

  __bis_SR_register( GIE );                           // Enable general interrupt
  while( bitflag & txbeforerx )                       //TxByteCount != 1
  {
    __no_operation();
  }
  IFG2 &= ~UCB0TXIFG;

  IE2 &= ~UCB0TXIE;

  while( !(bitflag & i2crxend) )                    // Wait until all data is RX'd
  {
    __no_operation();
  }
  IE2 &= ~UCB0RXIE;                                    // Disable RX interrupt
  bitflag &= ~i2crxend;
}

/*----------------------------------------------------------------------------
功能:从I2C接口的当前地址接收1个字节数据
输入:7-bit从机地址slave_addr
输出:接收的数据存放在RxBuffer数组
说明:在接收第1个字节过程中需要置位停止位,接收数据放在RxBuffer[0]
----------------------------------------------------------------------------*/
void I2CRx1byte(unsigned char slave_addr)
{
  UCB0I2CSA = slave_addr;
  IE2 |= UCB0RXIE;                                         // Enable TX RX interrupt
  
  PRxData = (unsigned char *)RxBuffer;            // Start of RX buffer

  RxByteCount = 1;                                          // Load RX byte counter

  UCB0CTL1 &= ~UCTR;                                    // I2C RX
  UCB0CTL1 |= UCTXSTT;


  while( UCB0CTL1 & UCTXSTT )
  {
    __no_operation();
  }
  __no_operation();
  UCB0CTL1 |= UCTXSTP;
  while( !(bitflag & i2crxend) )                        // Wait until all data is RX'd
  {
    __no_operation();
  }
  IE2 &= ~UCB0RXIE;                                        // Disable RX interrupt
  bitflag &= ~i2crxend;
  __no_operation();
}

/*----------------------------------------------------------------------------
功能:向I2C接口发送n个字节数据
输入:待发送字节个数 num,7-bit从机地址slave_addr
输出:
说明:待发送数据存放在TxData数组中;适合发送2个以上字节
----------------------------------------------------------------------------*/
void I2CTxnbyte(unsigned char slave_addr, unsigned char num)
{

  UCB0I2CSA = slave_addr;                         // 24C02 Write Address is 0a0h

  IE2 |= UCB0TXIE;                                      // Enable TX interrupt

  PTxData = (unsigned char *)TxData;              // TX array start address
  TxByteCount = num;                                      // Load TX byte counter
  UCB0CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition
  __bis_SR_register( GIE );                                // Enter LPM0 w/ interrupts

  while( !(bitflag & i2ctxend) )                        // Wait until all data is RX'd
  {
    __no_operation();
  }
  
  IE2 &= ~UCB0TXIE;                                      // Disable TX interrupt
  IFG2 &= ~UCB0TXIFG;
  bitflag &= ~i2ctxend;
}

/*----------------------------------------------------------------------------
功能:向I2C接口发送1个字节数据
输入:待发送字节个数 num,7-bit从机地址slave_addr
输出:
说明:在发送第1个字节过程中需要置位停止位,待发送数据放在TxData[0]
----------------------------------------------------------------------------*/
void I2CTx1byte(unsigned char slave_addr)
{
  UCB0I2CSA = slave_addr;                         // 24C02 Write Address is 0a0h
  bitflag |= tx1byte;

  IE2 |= UCB0TXIE;                                      // Enable TX interrupt

  PTxData = (unsigned char *)TxData;              // TX array start address
  TxByteCount = 1;                                          // Load TX byte counter
  UCB0CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition
  __bis_SR_register( GIE );                                // Enter LPM0 w/ interrupts

  while( UCB0CTL1 & UCTXSTT )
  {
    __no_operation();
  }
  __no_operation();
  UCB0CTL1 |= UCTXSTP;
  while( !(bitflag & i2ctxend) )                        // Wait until all data is RX'd
  {
    __no_operation();
  }
  
  IE2 &= ~UCB0TXIE;                                      // Disable TX interrupt
  bitflag &= ~tx1byte;
  IFG2 &= ~UCB0TXIFG;
  bitflag &= ~i2ctxend;
  __no_operation();
}

/*----------------------------------------------------------------------------
功能:软件延时
输入:u16Val,延时长度,ms
输出:
说明:参数范围0-65535,延时单位约为1ms@1MHz MCLK
----------------------------------------------------------------------------*/
void soft_delay_ms(unsigned int u16Val)
{
  unsigned int i;
  while(u16Val--)
  {
    i = 1000;
    while(i--)
    {
      __no_operation();
//      _nop_();
//      _nop_();
    }
  }
}

/*----------------------------------------------------------------------------
功能:向24LC02B发送n个字节数据
输入:待发送字节个数 num(包括地址字节),写入的目的地址d_addr
输出:
说明:待发送数据存放在TxData数组中,地址存放TxData[0],数据从TxData[1]开始存放
----------------------------------------------------------------------------*/
void Write_24c02_nbyte(unsigned char num,unsigned char d_addr)
{
  TxData[0] = d_addr;
  I2CTxnbyte(epr24_addr, num);
}

/*----------------------------------------------------------------------------
功能:从24LC02B接收n个字节数据
输入:待接收字节个数 num,待读取的源数据地址s_addr
输出:接收的数据存放在RxBuffer数组
说明:接收之前需要发送的数据放在TxData[0],比如源数据内存地址,待接收字节数应大于2
----------------------------------------------------------------------------*/
void Read_24c02_nbyte(unsigned char num,unsigned char s_addr)
{
  TxData[0] = s_addr;
  I2CRxnbyte(epr24_addr,num);
}

/*----------------------------------------------------------------------------
功能:向24LC02B更新所有数据
输入:
输出:
说明:cachedata[]是被保存的数据,只是个示例
----------------------------------------------------------------------------*/
void renew_24c02(void)
{
  TxData[1] = cachedata[0];
  TxData[2] = cachedata[1];
  TxData[3] = cachedata[2];
  TxData[4] = cachedata[3];
  TxData[5] = cachedata[4];
  TxData[6] = cachedata[5];
  TxData[7] = cachedata[6];
  TxData[8] = cachedata[7];
  Write_24c02_nbyte(9,0);     //page1
  
  soft_delay_ms(2);

  TxData[1] = cachedata[8];
  TxData[2] = cachedata[9];
  TxData[3] = cachedata[10];
  TxData[4] = cachedata[11];
  TxData[5] = cachedata[12];
  TxData[6] = cachedata[13];
  TxData[7] = cachedata[14];
  TxData[8] = cachedata[15];
  Write_24c02_nbyte(9,8);     //page2
  
  soft_delay_ms(2);
  
  TxData[1] = cachedata[16];
  TxData[2] = cachedata[17];
  TxData[3] = cachedata[18];
  TxData[4] = cachedata[19];
  TxData[5] = cachedata[20];
  TxData[6] = cachedata[21];
  TxData[7] = cachedata[22];
  TxData[8] = cachedata[23];
  Write_24c02_nbyte(9,0x10);     //page3
  
  soft_delay_ms(2);
  
  TxData[1] = cachedata[24];
  TxData[2] = cachedata[25];
  TxData[3] = cachedata[26];
  TxData[4] = cachedata[27];
  TxData[5] = cachedata[28];
  TxData[6] = cachedata[29];
  TxData[7] = cachedata[30];
  TxData[8] = cachedata[31];
  Write_24c02_nbyte(9,0x18);     //page4
  
  soft_delay_ms(2);
  
  TxData[1] = cachedata[32];
  TxData[2] = cachedata[33];
  TxData[3] = cachedata[34];
  TxData[4] = cachedata[35];
  TxData[5] = cachedata[36];
  TxData[6] = cachedata[37];
  TxData[7] = cachedata[38];
  TxData[8] = cachedata[39];
  Write_24c02_nbyte(9,0x20);     //page5
}

/*----------------------------------------------------------------------------
功能:从24LC02B还原所有数据
输入:
输出:
说明:cachedata[]是被还原的数据,只是个示例
----------------------------------------------------------------------------*/
void recover_24c02(void)
{
  Read_24c02_nbyte(8,0);
  cachedata[0] = RxBuffer[0];
  cachedata[1] = RxBuffer[1];
  cachedata[2] = RxBuffer[2];
  cachedata[3] = RxBuffer[3];
  cachedata[4] = RxBuffer[4];
  cachedata[5] = RxBuffer[5];
  cachedata[6] = RxBuffer[6];
  cachedata[7] = RxBuffer[7];
  
  Read_24c02_nbyte(8,8);
  cachedata[8] = RxBuffer[0];
  cachedata[9] = RxBuffer[1];
  cachedata[10] = RxBuffer[2];
  cachedata[11] = RxBuffer[3];
  cachedata[12] = RxBuffer[4];
  cachedata[13] = RxBuffer[5];
  cachedata[14] = RxBuffer[6];
  cachedata[15] = RxBuffer[7];
  
  Read_24c02_nbyte(8,0x10);
  cachedata[16] = RxBuffer[0];
  cachedata[17] = RxBuffer[1];
  cachedata[18] = RxBuffer[2];
  cachedata[19] = RxBuffer[3];
  cachedata[20] = RxBuffer[4];
  cachedata[21] = RxBuffer[5];
  cachedata[22] = RxBuffer[6];
  cachedata[23] = RxBuffer[7];
  
  Read_24c02_nbyte(8,0x18);
  cachedata[24] = RxBuffer[0];
  cachedata[25] = RxBuffer[1];
  cachedata[26] = RxBuffer[2];
  cachedata[27] = RxBuffer[3];
  cachedata[28] = RxBuffer[4];
  cachedata[29] = RxBuffer[5];
  cachedata[30] = RxBuffer[6];
  cachedata[31] = RxBuffer[7];
  
  Read_24c02_nbyte(8,0x20);
  cachedata[32] = RxBuffer[0];
  cachedata[33] = RxBuffer[1];
  cachedata[34] = RxBuffer[2];
  cachedata[35] = RxBuffer[3];
  cachedata[36] = RxBuffer[4];
  cachedata[37] = RxBuffer[5];
  cachedata[38] = RxBuffer[6];
  cachedata[39] = RxBuffer[7];
}

/*----------------------------------------------------------------------------
功能:Write data to register of RC522
输入:RegAddr-The address of the register;RegVal-The value to be written
输出:
说明:
----------------------------------------------------------------------------*/
void RcSetReg(unsigned char RegAddr, unsigned char RegVal)
{
  TxData[0] = RegAddr;

  TxData[1] = RegVal;
  I2CTxnbyte(rc522_addr, 2);
}

/*----------------------------------------------------------------------------
功能:read data from register of RC522
输入:RegAddr-The address of the register to be read
输出:The value of the specified register
说明:
----------------------------------------------------------------------------*/
unsigned char RcGetReg(unsigned char RegAddr)
{
  unsigned char RegVal;
  short status;

  TxData[0] = RegAddr;

  I2CTx1byte(rc522_addr);

  I2CRx1byte(rc522_addr);
  status = STATUS_SUCCESS;                //实际调试已经成功
  RegVal = RxBuffer[0];

  return RegVal;
}

/*----------------------------------------------------------------------------
功能:Change some bits of the register
输入:RegAddr-The address of the register;ModifyVal-The value to change to, set or clr;MaskByte-Only the corresponding bit '1' is valid
输出:
说明:
----------------------------------------------------------------------------*/
void RcModifyReg(unsigned char RegAddr, unsigned char ModifyVal, unsigned char MaskByte)
{
    unsigned char RegVal;
    RegVal = RcGetReg(RegAddr);
    if(ModifyVal)
    {
        RegVal |= MaskByte;
    }
    else
    {
        RegVal &= (~MaskByte);
    }
    RcSetReg(RegAddr, RegVal);
}

使用特权

评论回复
评分
参与人数 1威望 +3 收起 理由
21小跑堂 + 3
板凳
杰式4231| | 2012-6-15 07:48 | 只看该作者
坐沙发

使用特权

评论回复
地板
QQ3986| | 2012-6-15 08:23 | 只看该作者
坐板凳。学习学习。。。。。。

使用特权

评论回复
5
tianm| | 2012-6-15 11:51 | 只看该作者
谢谢LZ分享  希望能看到更多更精彩的设计

使用特权

评论回复
6
yirongfu|  楼主 | 2012-6-15 18:26 | 只看该作者
:handshake

使用特权

评论回复
7
wudayongnb| | 2012-7-7 21:25 | 只看该作者
我怎么看不懂你的程序是怎么实现发送和接收的呢,连UCB0TXBUF和UCB0RXBUF寄存器也没用到

使用特权

评论回复
8
Rancho13502| | 2012-7-8 08:14 | 只看该作者
正在搞IIC的,学习

使用特权

评论回复
9
u880| | 2012-7-8 08:47 | 只看该作者
大牛,向你学习

使用特权

评论回复
10
huigoushang| | 2012-7-8 09:04 | 只看该作者
太详细了

使用特权

评论回复
11
G21372| | 2012-7-8 09:24 | 只看该作者
好棒的资料 顶

使用特权

评论回复
12
yangguangaisha| | 2012-7-8 09:36 | 只看该作者
强帖留名

使用特权

评论回复
13
gexingyouxian| | 2012-7-8 09:45 | 只看该作者
很有参考价值

使用特权

评论回复
14
acer4736| | 2012-7-8 09:51 | 只看该作者
果然和厉害啊

使用特权

评论回复
15
xiaojian1227| | 2012-7-13 21:49 | 只看该作者
楼主的数据时如何进行收发的呢?没有写中断函数啊,或者是根本没有看到UCB0RXBUF或者UCB0TXBUF,不通过这两个寄存器,怎么进行数据的收发呢?希望耐心赐教!

使用特权

评论回复
16
yirongfu|  楼主 | 2012-7-13 23:02 | 只看该作者
感谢7楼和15楼朋友的格外关注:handshake

再进一步说明一下,帖子里提到的查询相关标志位的方式是指在处理具体的应用层面的通讯时的方式,而不是最底层的单个字节bit流传输的处理方式,最底层的bit流传输方式正是上面两位朋友关注的,采用的是中断方式,现将这部分代码也贡献出来,这部分代码大家还可以参考官方例程:


/*----------------------------------------------------------------------------
The USCIAB0TX_ISR is structured such that it can be used to transmit any
number of bytes by pre-loading TXByteCtr with the byte count. Also, TXData points to the next byte to transmit.
----------------------------------------------------------------------------*/
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
  if ( IFG2 & UCB0RXIFG )
  {
    RxByteCount--;                            // Decrement RX byte counter
    if ( RxByteCount )
    {
      *PRxData++ = UCB0RXBUF;                 // Move RX data to address PRxData
      if ( RxByteCount == 1 )                   // Only one byte left?
        UCB0CTL1 |= UCTXSTP;   // Generate I2C stop condition before the final byte has been Rx'd
    }
    else
    {
      *PRxData = UCB0RXBUF;                   // Move final RX data to PRxData
      bitflag |= i2crxend;
    }
  }
  if ( IFG2 & UCB0TXIFG )
  {
    if (TxByteCount)                            // Check TX byte counter
    {
      UCB0TXBUF = *PTxData++;                 // Load TX buffer
      TxByteCount--;                            // Decrement TX byte counter
      if((TxByteCount == 0) && (bitflag & tx1byte))
        bitflag |= i2ctxend;
    }
    else
    {
      if ( bitflag & txbeforerx )
      {
        UCB0CTL1 &= ~UCTR;            //set as RX
        UCB0CTL1 |= UCTXSTT;          //generate Start
        IFG2 &= ~UCB0TXIFG;
        bitflag &= ~txbeforerx;
      }
      else
      {
        UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
        IFG2 &= ~UCB0TXIFG;                     // Clear USCI_B0 TX int flag
        bitflag |= i2ctxend;
      }
    }
  }
}

使用特权

评论回复
17
whzy3j| | 2012-8-1 16:34 | 只看该作者
:handshake

使用特权

评论回复
18
hnhdzzc| | 2012-8-2 10:30 | 只看该作者
感谢楼主

使用特权

评论回复
19
冰岛海盗| | 2012-8-6 21:04 | 只看该作者
楼主给力啊

使用特权

评论回复
20
yuyishifeng| | 2012-8-7 11:39 | 只看该作者
楼主,看不太懂,能给我讲解一下吗,QQ977594253

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:生活将我们磨圆,是为了让我们滚得更远。。。 我来到这个世上就没打算活着回去!

99

主题

901

帖子

2

粉丝