按键与中断处理

NVIC中断工作原理

cortex-m3支持256个中断,其中包含了16个内核中断,240个外部中断。stm32中断是cortex-m3中断子集。对于103系列有60个可屏蔽中断。
STM32F103xC强型产品内置嵌套的向量式中断控制器,能够处理多达60个可屏蔽中断通道(不包括16个Cortex™-M3的中断线)和16个优先级。

/*
cortex-m3内核分组方式(8组)结构体表达方式:
*/
typedef struct
{
  __IO uint32_t ISER[8];             中断使能设置寄存器          /*!< 偏移量: 0x000  Interrupt Set Enable Register           */
       uint32_t RESERVED0[24];                                   
  __IO uint32_t ICER[8];              中断清除使能寄存器         /*!<偏移量: 0x080  Interrupt Clear Enable Register        */
       uint32_t RSERVED1[24];                                    
  __IO uint32_t ISPR[8];              中断挂起设置寄存器        /*!< 偏移量: 0x100  Interrupt Set Pending Register          */
       uint32_t RESERVED2[24];                                   
  __IO uint32_t ICPR[8];              中断清除挂起寄存器        /*!<偏移量: 0x180  Interrupt Clear Pending Register        */
       uint32_t RESERVED3[24];                                   
  __IO uint32_t IABR[8];               中断激活状态位寄存器       /*!< 偏移量: 0x200  Interrupt Active bit Register           */
       uint32_t RESERVED4[56];                                   
  __IO uint8_t  IP[240];               中断优先级寄存器       /*!< 偏移量: 0x300  Interrupt Priority Register (8Bit wide) */
       uint32_t RESERVED5[644];        软件触发方式寄存器                          
  __O  uint32_t STIR;                         /*!< 偏移量: 0xE00  Software Trigger Interrupt Register     */
}  NVIC_Type;  

ISER[2]:ISER全称是:Interrupt Set-Enable Registers,这是一个中断使能寄存器组。103系列可屏蔽中断有60个,这里用了2个32位寄存器,总共可以表示64个中断,STM32F103只用了其中的前60位;ISER[0]的bit0-bit31分别对应中断0-31。ISER[1]的bit0-27对应中断32-59;这样,要使能某个中断,必须设置相应的ISER位为1,使该中断被使能(这里仅是使能,还要配合中断分组、屏蔽、IO口映射等设置才算一个完整的中断设置)。
ICER[2]:全称是Interrupt Clear-Enable Registers,是一个清除中断使能寄存器组,和ISER寄存器功能相反。这里专门设置一个ICER寄存器来清除中断位,而不是向ISER写0来擦除,是因为NVIC的这些寄存器都是写1有效的,写0是无效的。
ISPR[2]:全程是Interrupt Set-Pending Registers,是一个中断挂起控制寄存器组。每个位对应的中断和ISER是一样的,通过置1,可将正在进行中的中断挂起,而执行同级或更高级别的中断,写0无效。
ICPR[2]:Interrupt Clear-Pending Registers,解除中断挂起。写1有效,写0无效。
IABR[2]:Interrupt Active Bit Registers,中断激活标志位寄存器组,只读,可以读取当前正在执行的中断是哪一个。在中断执行完成后由硬件自动清零。对应位所代表的中断和ISER相同,如果为1,表示该位所对应的中断正在执行。
IPR[15]:Interrupt Priority Registers,中断优先级控制寄存器组。STM32的中断分组与这个寄存器密切相关。因为STM32的中断多达60多个,所以STM32采用中断分组的办法来确定中断的优先级。IPR寄存器由15个32bit的寄存器组成,每个可屏蔽中断占8bit,这样总共可以表示15x4=60个可屏蔽中断。IPR[0]的[31-24],[23-16],[15-8],[7-0]分别对应中断3-0,总共对应60个外部中断。而每个可屏蔽中断占用的8bit并没有全部使用,只用了高4位。这4位又分为抢占优先级和子优先级。这两个优先级要根据SCB->AIRCR中中断分组的设置来决定。


stm32F103外部中断.PNG
typedef struct
{
__IO uint32_t EVCR;
__IO uint32_t MAPR;
__IO uint32_t EXTICR[4];
} AFIO_TypeDef;

STM32 任何一个 IO 口都可以配置成中断输入口,但是 IO 口的数目远大于中断线数(16 个)。于是 STM32 就这样设计,GPIOA~GPIOG 的[15:0]分别对应中断线 15~0。这样每个中断线对应了最多 7 个 IO 口,以线 0为例:它对应了 GPIOA.0、GPIOB.0、GPIOC.0、GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0。中断线每次只能连接到1个IO口上,这样就需要EXTICR来决定对应的中断线配置到哪个GPIO上了。EXTICR 寄存器组,总共有 4 个,因为编译器的寄存器组都是从 0 开始编号的,所以EXTICR[0]~ EXTICR[3],每个EXTICR 只用了其低 16 位。比如如我要设置 GPIOB.1 映射到中断线 1,则只要设置 EXTICR[0]的 bit[7:4]为 0001 即可。默认都是 0000 即映射到 GPIOA。

typedef struct
{
__IO uint32_t IMR;
__IO uint32_t EMR;
__IO uint32_t RTSR;
__IO uint32_t FTSR;
__IO uint32_t SWIER;
__IO uint32_t PR;
} EXTI_TypeDef;

通过这些寄存器的设置,就可以对外部中断进行详细设置了。IMR:中断屏蔽寄存器。这是一个 32 寄存器。但是只有前 19 位有效。当位 x 设置为 1 时,则开启这个线上的中断,否则关闭该线上的中断。
EMR:事件屏蔽寄存器,同 IMR,只是该寄存器是针对事件的屏蔽和开启。
RTSR:上升沿触发选择寄存器。该寄存器同 IMR,也是一个 32 为的寄存器,只有前 19位有效。位 x 对应线 x 上的上升沿触发,如果设置为 1,则是允许上升沿触发中断/事件。否则,不允许。
FTSR:下降沿触发选择寄存器。同 RTSR,不过这个寄存器是设置下降沿的。下降沿和上升沿可以被同时设置,这样就变成了任意电平触发了。
SWIER:软件中断事件寄存器。通过向该寄存器的位 x 写入 1,在未设置 IMR 和 EMR 的时候,将设置 PR 中相应位挂起。如果设置了 IMR 和 EMR 时将产生一次中断。被设置的 SWIER位,将会在 PR 中的对应位清除后清除。
PR:挂起寄存器。当外部中断线上发生了选择的边沿事件,该寄存器的对应位会被置为 1。0,表示对应线上没有发生触发请求。通过向该寄存器的对应位写入 1 可以清除该位。在中断服务函数里面经常会要向该寄存器的对应位写 1 来清除中断请求。

GPIO外部输入中断实验

与按键输入实验相同,通过中断实现。KEY0 控制 DS0,按一次亮,再按一次,就灭。KEY1 控制 DS1,效果同 KEY0。WK_UP 按键则同时控制 DS0 和 DS1,按一次,他们的状态就翻转一次。KEY0为PC5KEY1为PA15WK_UP位PA0。
1 ) 初始化 IO 口为输入。
这一步设置你要作为外部中断输入的 IO 口的状态,可以设置为上拉/下拉输入,也可以设
置为浮空输入,但浮空的时候外部一定要带上拉,或者下拉电阻。否则可能导致中断不停的触
发。在干扰较大的地方,就算使用了上拉/下拉,也建议使用外部上拉/下拉电阻,这样可以一
定程度防止外部干扰带来的影响。
2 ) 开启 IO 口复用时钟,设置 IO 口与中断线的映射关系。
STM32 的 IO 口与中断线的对应关系需要配置外部中断配置寄存器 EXTICR,这样我们要
先开启复用时钟,然后配置 IO 口与中断线的对应关系。才能把外部中断与中断线连接起来。
3 ) 开启与该 IO 口相对的线上中断/ 事件,设置触发条件。
这一步,我们要配置中断产生的条件,STM32 可以配置成上升沿触发,下降沿触发,或者
任意电平变化触发,但是不能配置成高电平触发和低电平触发。这里根据自己的实际情况来配
置,同时要开启中断线上的中断。这里需要注意的是:如果使用外部中断,并设置该中断的 EMR
位的话,会引起软件仿真不能跳到中断,而硬件上是可以的。而不设置 EMR,软件仿真就可以
进入中断服务函数,并且硬件上也是可以的。建议不要配置 EMR 位。
4 ) 配置中断分组(NVIC ),并使能中断。
这一步,我们就是配置中断的分组,以及使能,对 STM32 的中断来说,只有配置了 NVIC
的设置,并开启才能被执行,否则是不会执行到中断服务函数里面去的。关于 NVIC 的详细介
绍。
5 ) 编写中断服务函数。
这是中断设置的最后一步,中断服务函数,是必不可少的,如果在代码里面开启了中断,
但是没编写中断服务函数,就可能引起硬件错误,从而导致程序崩溃!所以在开启了某个中断
后,一定要记得为该中断编写服务函数。在中断服务函数里面编写你要执行的中断后的操作。

寄存器

1)初始化IO口

void KEYInit(void)
{
    RCC->APB2ENR|=1<<2; //使能 PORTA 时钟
    RCC->APB2ENR|=1<<4; //使能 PORTC 时钟
    JTAG_Set(SWD_ENABLE); //关闭 JTAG,开启 SWD
    GPIOA->CRL&=0XFFFFFFF0; //PA0 设置成输入
    GPIOA->CRL|=0X00000008;
    GPIOA->CRH&=0X0FFFFFFF; //PA15 设置成输入
    GPIOA->CRH|=0X80000000;
    GPIOA->ODR|=1<<15; //PA15 上拉,PA0 默认下拉
    GPIOC->CRL&=0XFF0FFFFF; //PC5 设置成输入
    GPIOC->CRL|=0X00800000;
    GPIOC->ODR|=1<<5; //PC5 上拉
}

2)开启IO复用时钟,配置IO口和中断线的映射关系,以及触发条件

void EXTtInit(u8 GPIOx, u8 BITx, u8 TRIM)
{
    U8 EXTADDR;
    u8 EXTOFFSET;
    EXTADDR=BITx/4; //得到中断寄存器组的编号
    EXTOFFSET=(BITx%4)*4;
    RCC->APB2ENR|=0x01; //使能 io 复用时钟
    AFIO->EXTICR[EXTADDR]&=~(0x000F<<EXTOFFSET);//清除原来设置!!!
    AFIO->EXTICR[EXTADDR]|=GPIOx<<EXTOFFSET;//EXTI.BITx 映射到 GPIOx.BITx
    //自动设置
    EXTI->IMR|=1<<BITx; //开启 line BITx 上的中断
    if(TRIM&0x01)EXTI->FTSR|=1<<BITx; //line BITx 上事件下降沿触发
    if(TRIM&0x02)EXTI->RTSR|=1<<BITx; //line BITx 上事件上升降沿触发
}

3)配置中断分组,设置中断优先级,使能中断
设置中断分组

void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)
{
    u32 temp,temp1;
    temp1=(~NVIC_Group)&0x07;//取后三位
    temp1<<=8;
    temp=SCB->AIRCR; //读取先前的设置
    temp&=0X0000F8FF; //清空先前分组
    temp|=0X05FA0000; //写入钥匙
    temp|=temp1;
    SCB->AIRCR=temp; //设置分组
}

配置中断优先级(包括抢占优先级和子优先级)

void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,
u8 NVIC_Group)
{
u32 temp;
MY_NVIC_PriorityGroupConfig(NVIC_Group);//设置分组
temp=NVIC_PreemptionPriority<<(4-NVIC_Group);
temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
temp&=0xf; //取低四位
NVIC->ISER[NVIC_Channel/32]|=(1<<NVIC_Channel%32);
//使能中断位(要清除的话,相反操作就 OK)
NVIC->IP[NVIC_Channel]|=temp<<4; //设置响应优先级和抢断优先级
}

4)写中断服务函数

void EXTI0_IRQHandler(void)
{
delay_ms(10); //消抖
if(WK_UP==1) //WK_UP 按键
{
LED0=!LED0;
LED1=!LED1;
}
EXTI->PR=1<<0; //清除 LINE0 上的中断标志位
}
//外部中断 9~5 服务程序
void EXTI9_5_IRQHandler(void)
{
delay_ms(10); //消抖
if(KEY0==0) LED0=!LED0; //按键 0
EXTI->PR=1<<5; //清除 LINE5 上的中断标志位
}
//外部中断 15~10 服务程序
void EXTI15_10_IRQHandler(void)
{
delay_ms(10); //消抖
if(KEY1==0) LED1=!LED1; //按键 1
EXTI->PR=1<<15; //清除 LINE15 上的中断标志位
}

库函数

1)配置IO口

GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,
ENABLE);//使能 PORTA,PORTC 时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
//关闭 jtag,使能 SWD,可以用 SWD 模式调试
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//PA15
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化 GPIOA15
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//PC5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化 GPIOC5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//PA0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 设置成输入,默认下拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化 GPIOA.0

2)开启IO复用时钟,配置IO口和中断线的映射关系,以及触发条件

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)//GPIO与中断线的映射
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)//中断线上的参数配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能 AFIO 时钟

//GPIOC.5 中断线以及中断初始化配置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line5;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);//根据 EXTI_InitStruct 中指定的参数初始化外设 EXTI 寄存器

//GPIOA.15 中断线以及中断初始化配置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15);
EXTI_InitStructure.EXTI_Line=EXTI_Line15;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);//根据 EXTI_InitStruct 中指定的参数初始化外设 EXTI 寄存器

//GPIOA.0 中断线以及中断初始化配置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
//根据 EXTI_InitStruct 中指定的参数初始化外设 EXTI 寄存器

3)设置中断分组,设置中断优先级

void NVIC_Init(NVIC_InitTypeDef * NVIC_InitStructure)//中断优先级配置
NVIC_InitTypeDef NVIC_InitStructure;

NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
//使能按键所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级 1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);//根据 NVIC_InitStruct 中指定的参数初始化外设 NVIC 寄存器

NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
//使能按键所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级 1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
//使能按键所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级 1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);

4)中断服务函数

void EXTI0_IRQHandler(void)
{
delay_ms(10); //消抖
if(WK_UP==1)
{
LED0=!LED0;
LED1=!LED1;
}
EXTI_ClearITPendingBit(EXTI_Line0); //清除 EXTI0 线路挂起位
}
void EXTI9_5_IRQHandler(void)
{
delay_ms(10); //消抖
if(KEY0==0) {
LED0=!LED0;
}
EXTI_ClearITPendingBit(EXTI_Line5); //清除 LINE5 上的中断标志位
}
void EXTI15_10_IRQHandler(void)
{
delay_ms(10); //消抖
if(KEY1==0) {
LED1=!LED1;
}
EXTI_ClearITPendingBit(EXTI_Line15); //清除 LINE15 线路挂起位
}

常用中断服务函数格式为:

void EXTI2_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line2)!=RESET)//判断某个线上的中断是否发生
{
中断逻辑…
EXTI_ClearITPendingBit(EXTI_Line2); //清除 LINE 上的中断标志位
}
}

STM32Cube

配置端口后,软件自动生成配置函数,只需要写回调函数即可。(清除中断标志位在void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);函数中)

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{ 
    if (GPIO_Pin & WK_UP_Pin){
    HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8);
    HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_2);
    
        
    }
    
    if (GPIO_Pin & KEY0_Pin){
        
    HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8);   
    }
    if (GPIO_Pin & KEY1_Pin){
        
    HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_2);   
    }
    
} 
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容

  • uboot step 12 按键玩中断-S3C6410中断介绍 向量中断控制器相关寄存器 中断处理流程 中断源-外...
    2625K阅读 1,242评论 0 1
  • 一,外部中断简介 1.1 CM4 内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断,...
    三文五略阅读 3,306评论 0 0
  • feisky云计算、虚拟化与Linux技术笔记posts - 1014, comments - 298, trac...
    不排版阅读 3,800评论 0 5
  • 姓名:周崇杰 学号:16140120059 专业:机械设计制造及其自动化 转载自:http://blog.csd...
    CJbaby阅读 11,918评论 0 7
  • 大家好,我们是一群流浪猫!愿被这个世界温柔相待 ! 我们想爸爸,想妈妈,想要有个自己的家,想要一个暖心的主人!所以...
    居幽形愁阅读 426评论 3 0