天天看點

OV7620的使用

轉載請注明出處:http://blog.csdn.net/lxk7280

有人會奇怪為什麼使用OV系列的攝像頭每次都要進行SCCB的操作呢?難道它自己不會儲存上次的操作結果嗎?

原因是:OV系列的攝像頭的寄存器是EEPROM,不穩定,資料很容易丢失,是以程式每次初始化時我們都要重新寫入寄存器設定。

         PS:常見需要修改的寄存器有,PCLK速率,幀率、圖像亮度、對比度、色飽和度、鏡像等功能。

智能車攝像頭組的初期學習中,雖然有不少攝像頭優于OV7620,但是相信大部分的車友第一個接觸的都是OV7620。下面從其特性和性能等角度,剖析攝像頭的特點。

攝像頭的輸出格式有RGB565,YUY422等格式,我所接觸的第一個攝像頭OV7620的輸出格式是YUV422。下面給大家介紹一下YUV422。

什麼是YUV422?

人的眼睛對低頻信号比對高頻信号具有更高的敏感度,事實上,人的眼睛對明視度的改變比對色彩的改變要敏感的多。是以,人們将RGB三色信号改為YUV來表示,其中Y為灰階,UV為色差。如果是表示一副彩色圖像,同樣的道理,YUV444是無損的存儲方式,但是需要3個位元組,存儲空間開銷很大。由于Y分量比UV分量重要的多,是以人們用YUV422來表示。這樣一來圖像被壓縮了很多,一個位元組就可以表示其彩色的資訊。

對于OV7620,它有2 組并行的資料口Y[7..0]和UV[7..0],其中對于資料口Y[7..0],輸出的是灰階值Y,對于UV[7..0]輸出的色度信号UV。下圖給出了k 個像素(K 個位元組)輸出的格式。

OV7620的使用

OV762的控制采用SCCB(Serial Camera ControlBus)協定。SCCB的簡化的I2C協定,SIO-I是串行時鐘輸入線,SIO-O是串行雙向資料線,分别相當于I2C協定的SCL和SDA。SCCB的總線時序與I2C基本相同,他的響應信号ACK被陳偉一個傳輸單元的第9位,分别Do not care和NA.Do not care位由從機産生;NA位由主機産生,由于SCCB不支援多位元組的讀寫,NA位必須為高電平。另外SCCB沒有重複起始的概念,是以在SCCB的讀周期中,當主機發送讀指令時,從機将不能産生Do not care響應信号。

由于I2C和SCCB的一些細微差别,是以采用GPIO模拟SCCB總線的方式,SCL所連接配接的引腳始終設為輸出方式,而SDA所連接配接的引腳在資料傳輸過程中,通過設定IODIR的值,動态改變引腳的輸入/輸出方式。SCCB的寫周期直接使用I2C總線協定的寫周期時序;而SC-CB的讀周期,則增加一個總線停止條件。

OV7620的幾個優點:

第一,OV7620的電平相容3.3V和5V。目前智能車使用者用到的處理器基本上可以分為XS128和K60和KL25三種控制器,而這三種控制器的工作電平分别是5V和3.3V和3.3V。OV7620可以完全适應這兩種電平,XS128和K60和KL25可以随性切換,無需做電平比對。(要注意的是當OV7620接5v和3.3v的時候,輸出的效果是不同的,建議在5v的電壓下使用,因為在3.3v的電壓下使用比較難調,輸出的16進制資料清一色偏小。)

同樣的情況下:

3.3V下:                                                                                                       5v下:

OV7620的使用
OV7620的使用

第二,OV7620的幀率是60幀/s。新手學習攝像頭的時候,誤以為攝像頭幀率越快越好,其實不然。就拿OV7620來說,其PCLK(像素中斷)的周期是73ns,該頻率下的PCLK很容易被K60的IO捕捉,如果幀率更快的攝像頭,其PCLK的周期就會更小,該頻率下PCLK不易被K60的IO捕捉到。(但是鷹眼攝像頭不然,火哥的鷹眼攝像頭理論上宣傳的是150幀每秒,但是他并不是通過PCLK的周期減小進而獲得效果的,鷹眼攝像頭的高明之處在于它在硬體二值化之後,每一次PCLK中斷對外輸出了8個像素,而不是1個像素。鷹眼攝像頭已經買來了,以後有機會會試試效果。)

第三:OV7620的分辨率也是非常合适的,在第三篇也提到OV7620是隔行掃描,采集VSYN的話,其輸出分辨率是640*240。如果改為QVGA格式,預設輸出分辨率是320*120,該分辨率下非常适合采集賽道,資料容量有限又不會失真圖像。(OV7620的分辨率可以通過SCCB修改,有興趣修改的可以去檢視OV7620的寄存器配置,然後通過SCCB修改。)

隻有掌握了OV7620的時序,才能靈活得使用OV7620。下面開始本篇的重點:OV7620時序分析。

對于OV7620,我們隻關心場中斷信号VSYN、行中斷信号HREF、像素中斷信号PCLK的波形。用示波器去監控這三個波形,可以看到一下關系。

OV7620的使用

VSYN 的周期是16.64ms,高電平時間為換場時間,約80us;低電平時間内像素輸出。我們在采集VSYN脈沖時,既可以采集上升沿,也可以采集下降沿,采集下降沿更準确些,這也是一場的開始。從VSYN的周期可以算出,1s/16.64ms=60幀,OV7620的幀率是60幀/s。

HREF的周期63.6us,高電平時間為像素輸出時間,約47us;低電平時間為換行時間,是以采集HREF一定要采集其上升沿,下降沿後的資料是無效的。從HREF的周期可以算出,16.64ms/63.6us≈261,除去期間的間隙時間,可以算出每場圖像有240行。

PCLK的周期是73ns,高電平輸出像素,低電平像素無效。PCLK是一直輸出的,是以一定要在觸發VSYN并且觸發HREF以後,再去捕捉PCLK才能捕捉到像素資料。從PCLK的周期可以算出,47us/73ns≈640,可以算出每行圖像中有640個像素點。

介紹完基本知識之後,下面開始寫程式了(Keil--K60--C語言):

在這我分成兩部分着重介紹7620的時序程式和貼上SCCB的協定程式(其實原理和處理情況和I2C差不多):

First :

首先要對使用到的一些IO口進行初始化處理,四個部分的初始化,

A.像素中斷PCLK 

B.行中斷HREF

C.場中斷VSYNC

D.DMA

程式如下:

//初始化OV7620子產品
void OV7620_Init()
{
	//像素中斷 PCLK
	GPIO_InitStruct1.GPIO_Pin = OV7620_PCLK_PIN;
	GPIO_InitStruct1.GPIO_InitState = Bit_SET;
	GPIO_InitStruct1.GPIO_IRQMode = GPIO_IT_DMA_RISING;
	GPIO_InitStruct1.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_InitStruct1.GPIOx = OV7620_PCLK_PORT;
	GPIO_Init(&GPIO_InitStruct1);

	//行中斷 HREF
	GPIO_InitStruct1.GPIO_Pin = OV7620_HREF_PIN;
	GPIO_InitStruct1.GPIO_InitState = Bit_SET;
	GPIO_InitStruct1.GPIO_IRQMode = GPIO_IT_RISING;
	GPIO_InitStruct1.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_InitStruct1.GPIOx = OV7620_HREF_PORT;
	GPIO_Init(&GPIO_InitStruct1);

	// 場中斷 VSYNC
	GPIO_InitStruct1.GPIO_Pin = OV7620_VSYNC_PIN;
	GPIO_InitStruct1.GPIO_InitState = Bit_SET;
	GPIO_InitStruct1.GPIO_IRQMode = GPIO_IT_RISING;   //GPIO_IT_RISING
	GPIO_InitStruct1.GPIO_Mode = GPIO_Mode_IPD;   //GPIO_Mode_IPD
	GPIO_InitStruct1.GPIOx = OV7620_VSYNC_PORT;
	GPIO_Init(&GPIO_InitStruct1);

  //配置DMA
  DMA_InitStruct1.Channelx          = DMA_CH1;         //DMA 1通道
  DMA_InitStruct1.PeripheralDMAReq   =PORTC_DMAREQ;    //C端口(PCLK) 上升呀觸發    
  DMA_InitStruct1.MinorLoopLength = 170;               //傳輸次數 超過攝像頭每行像素數即可
	DMA_InitStruct1.TransferBytes = 1;                   //每次傳輸1個位元組       
	DMA_InitStruct1.DMAAutoClose  = ENABLE;              //連續采集
	DMA_InitStruct1.EnableState = ENABLE;                //初始化後立即采集
	 
  DMA_InitStruct1.SourceBaseAddr =(uint32_t)&PTD->PDIR;//攝像頭端口接D0-D7
	DMA_InitStruct1.SourceMajorInc = 0;                  //位址不增加
	DMA_InitStruct1.SourceDataSize = DMA_SRC_8BIT;       //8BIT資料
	DMA_InitStruct1.SourceMinorInc = 0;

	
  DMA_InitStruct1.DestBaseAddr =(uint32_t)DMABuffer;  //DMA 記憶體  //uint8_t DMABuffer[400]; 
	DMA_InitStruct1.DestMajorInc = 0;
	DMA_InitStruct1.DestDataSize = DMA_DST_8BIT;
	DMA_InitStruct1.DestMinorInc = 1;                   //每次傳輸 +1個位元組
	DMA_Init(&DMA_InitStruct1);
}
           

然後開始編寫場中斷函數,編寫之前我們需要在心裡理一下思緒,在場中斷函數裡我們要按照順序,做以下幾件事情:

A.确認是否是場中斷,确認之後進入處理。

B.清除标志位Flag。(Flag是用來觀察是否處理完一場圖像的标志)

C.清除中斷标志。

D.計數全部清零。(因為新的一場已經開始)

E.打開行中斷,關閉場中斷。

void PORTB_IRQHandler(void)//功  能:PORTB 外部中斷服務 //V 
{
    u8 i=9;
	  if((PORTB->ISFR>>i)==1)
		{
			Flag = 0;
			PORTB->ISFR|=(1<<9);   
			Row = 0;
			Row_Num = 0;
			NVIC_EnableIRQ(PORTA_IRQn);//行
			NVIC_DisableIRQ(PORTB_IRQn);//場
		}
           

接着編寫行中斷函數,在行中斷中,我們要做以下幾件事情:

A.确認是否是行中斷。

B.關閉DMA中斷,防止提前進入PCLK的采集。

C.跳過消隐區。(消隐區:消隐區的出現,在電視機原理上,是因為電子束結束一行掃描,從一行尾換到另一行頭,期間的空閑期,這叫做行消隐信号;同理,從一場尾換到另一場尾,期間也會有空閑期,這叫做場消隐信号。)

D.進入行采集處理。

E.配置DMA,并且打開DMA中斷。

F.行計數加1,表示已經采集完了一行。(因為PCLK的中斷周期遠遠小于HREF的中斷周期,是以不需要杞人憂天,擔心中斷搞得混亂。)

G.當采集完了自己的目标行數之後,标志位Flag修改。并關閉行中斷,打開場中斷,等待下一次的場中斷。

void PORTA_IRQHandler(void)//功  能:PORTA 外部中斷服務//Herf
{
   u8 i=14;
	 DMA_SetEnableReq(DMA_CH1,DISABLE);		//close DMA ISr			
	 if((PORTA->ISFR>>i)==1);
	 {
		 PORTA->ISFR|=(1<<14);   
		 if(Row_Num++ > 15)  //消隐區啦
		 {
				if(Row_Num%5)   //進入行采集
				{
					//配置DMA
					DMA_InitStruct1.Channelx          = DMA_CH1;         //DMA 1通道
					DMA_InitStruct1.PeripheralDMAReq   =PORTC_DMAREQ;    //C端口(PCLK) 上升呀觸發    
					DMA_InitStruct1.MinorLoopLength = 170;               //傳輸次數 超過攝像頭每行像素數即可
					DMA_InitStruct1.TransferBytes = 1;                   //每次傳輸1個位元組       
					DMA_InitStruct1.DMAAutoClose  = ENABLE;              //連續采集
					DMA_InitStruct1.EnableState = ENABLE;                //初始化後立即采集
					 
					DMA_InitStruct1.SourceBaseAddr =(uint32_t)&PTD->PDIR;//攝像頭端口接D0-D7
					DMA_InitStruct1.SourceMajorInc = 0;                  //位址不增加
					DMA_InitStruct1.SourceDataSize = DMA_SRC_8BIT;       //8BIT資料
					DMA_InitStruct1.SourceMinorInc = 0;

					DMA_InitStruct1.DestBaseAddr =(uint32_t)Image[Row];  //DMA 記憶體  //uint8_t DMABuffer[400]; 
					DMA_InitStruct1.DestMajorInc = 0;
					DMA_InitStruct1.DestDataSize = DMA_DST_8BIT;
					DMA_InitStruct1.DestMinorInc = 1;                   //每次傳輸 +1個位元組
					DMA_Init(&DMA_InitStruct1);
		///			
					Row ++; 
					if(Row==MAX_ROW)
					{
						Flag = 1;
						NVIC_DisableIRQ(PORTA_IRQn);//行
						NVIC_EnableIRQ(PORTB_IRQn);//場		
					}
				}
			} 
	 }       
}
           

最後給大家看一下,DMA的初始化函數,這個函數是超核的庫裡面的,不是我寫的,但是上面的解釋很詳細了,相信都能看懂。

void DMA_Init(DMA_InitTypeDef *DMA_InitStruct)
{
	//參數檢查
	assert_param(IS_DMA_REQ(DMA_InitStruct->PeripheralDMAReq));
	assert_param(IS_DMA_ATTR_SSIZE(DMA_InitStruct->SourceDataSize));
	assert_param(IS_DMA_ATTR_DSIZE(DMA_InitStruct->DestDataSize));
	assert_param(IS_DMA_CH(DMA_InitStruct->Channelx));
	assert_param(IS_DMA_MINOR_LOOP(DMA_InitStruct->MinorLoopLength));
	
	//打開DMA0和DMAMUX時鐘源
	SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK;    
	SIM->SCGC7 |= SIM_SCGC7_DMA_MASK;
	//配置DMA觸發源
	DMAMUX->CHCFG[DMA_InitStruct->Channelx] = DMAMUX_CHCFG_SOURCE(DMA_InitStruct->PeripheralDMAReq);
	//設定源位址資訊	
	DMA0->TCD[DMA_InitStruct->Channelx].SADDR = DMA_InitStruct->SourceBaseAddr;
	//執行完源位址操作後,是否在源位址基礎上累加
	DMA0->TCD[DMA_InitStruct->Channelx].SOFF = DMA_SOFF_SOFF(DMA_InitStruct->SourceMinorInc);
	//設定源位址傳輸寬度
	DMA0->TCD[DMA_InitStruct->Channelx].ATTR  = 0;
	DMA0->TCD[DMA_InitStruct->Channelx].ATTR |= DMA_ATTR_SSIZE(DMA_InitStruct->SourceDataSize);
	//主循環進行完後 是否更改源位址
	DMA0->TCD[DMA_InitStruct->Channelx].SLAST = DMA_InitStruct->SourceMajorInc;
	
	//設定目的位址資訊
	DMA0->TCD[DMA_InitStruct->Channelx].DADDR = DMA_InitStruct->DestBaseAddr;
	//執行完源位址操作後,是否在源位址基礎上累加
	DMA0->TCD[DMA_InitStruct->Channelx].DOFF = DMA_DOFF_DOFF(DMA_InitStruct->DestMinorInc);
	//設定目的位址傳輸寬度
	DMA0->TCD[DMA_InitStruct->Channelx].ATTR |= DMA_ATTR_DSIZE(DMA_InitStruct->DestDataSize);
	//主循環進行完後 是否更改源位址
	DMA0->TCD[DMA_InitStruct->Channelx].DLAST_SGA = DMA_InitStruct->DestMajorInc;
	
	//設定計數器長度 循環次數
	//設定資料長度 長度每次遞減 也被稱作目前主循環計數 current major loop count
	DMA0->TCD[DMA_InitStruct->Channelx].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(DMA_InitStruct->MinorLoopLength );
	//起始循環計數器 當主循環計數器為0 時候 将裝載起始循環計數器的值
	DMA0->TCD[DMA_InitStruct->Channelx].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(DMA_InitStruct->MinorLoopLength);
	//設定每一次傳輸位元組的個數  個數到達上限時 DMA便将資料存入RAM 
	DMA0->TCD[DMA_InitStruct->Channelx].NBYTES_MLNO = DMA_NBYTES_MLNO_NBYTES(DMA_InitStruct->TransferBytes);
//設定DMA TCD控制寄存器
	DMA0->TCD[DMA_InitStruct->Channelx].CSR = 0;
	if(DMA_InitStruct->DMAAutoClose == ENABLE)
	{
		 DMA0->TCD[DMA_InitStruct->Channelx].CSR  |=DMA_CSR_DREQ_MASK; 
	}
	else
	{
		 DMA0->TCD[DMA_InitStruct->Channelx].CSR  &=(~DMA_CSR_DREQ_MASK); 
	}
	//使能此寄存器DMA開始工作
	DMA_SetEnableReq(DMA_InitStruct->Channelx,DMA_InitStruct->EnableState);
	//DMA 通道使能
	DMAMUX->CHCFG[DMA_InitStruct->Channelx] |= DMAMUX_CHCFG_ENBL_MASK;
}
           

Second:

講完OV7620的一些中斷處理函數之後,我們來看看SCCB的庫程式,這個庫可以通用,需要的車友可以直接添加,隻需要對照自己使用的庫,在IO口初始化裡面做出相應的修改即可。

#ifndef __SCCB_H
#define __SCCB_H


#define SCL_HIGH         PEout(1) = 1    //設定為輸出後輸出1
#define SCL_LOW         PEout(1) = 0    //設定為輸出後輸出0
#define	SCL_OUT 	PTE->PDDR|=(1<<1)   //設定為輸出
//#define	SCL_DDR_IN() 	  PTE->PDDR&=~(1<<1)//輸入

#define SDA_HIGH         PEout(0)= 1    //設定為輸出後輸出1
#define SDA_LOW         PEout(0)= 0    //設定為輸出後輸出0
#define SDA_DATA      	PEin(0)
#define SDA_OUT	  PTE->PDDR|=(1<<0)  //設定為輸出
#define SDA_IN	  PTE->PDDR&=~(1<<0) //設定為輸入
#define u8 unsigned char
#define u16 unsigned short 

//#define ADDR_OV7725   0x42

void sccb_init(void);                           //初始化SCCB端口為GPIO
void sccb_wait(void);                           //SCCB時序延時
void sccb_start(void);                          //起始标志
void sccb_stop(void);                           //停止标志
u8 sccb_sendByte(u8 data);
void sccb_regWrite(u8 device,u8 address,u8 data);
#endif 
#include "sys.h"
#include "gpio.h"
#include "sccb.h"
#include "delay.h"
#include "stdio.h"

/*************************************************************************
*  函數名稱:sccb_init
*  功能說明:初始化SCCB  其中SCL接PE1 SDA接PTE0
*************************************************************************/
void sccb_init(void)
{
			int i ;
			GPIO_InitTypeDef GPIO_InitStruct1;	
			for(i=0;i<8;i++)
			{
				GPIO_InitStruct1.GPIO_Pin = i;
				GPIO_InitStruct1.GPIO_InitState = Bit_RESET; //change as Bit_Set , it will shut.
				GPIO_InitStruct1.GPIO_IRQMode = GPIO_IT_DISABLE;
				GPIO_InitStruct1.GPIO_Mode = GPIO_Mode_IN_FLOATING;
				GPIO_InitStruct1.GPIOx = PTD;
				GPIO_Init(&GPIO_InitStruct1);
			}
			
			 GPIO_InitStruct1.GPIO_Pin = 0;
			 GPIO_InitStruct1.GPIO_InitState = Bit_RESET;
			 GPIO_InitStruct1.GPIO_IRQMode = GPIO_IT_DISABLE;
			 GPIO_InitStruct1.GPIO_Mode = GPIO_Mode_OPP;
			 GPIO_InitStruct1.GPIOx = PTE;
			 GPIO_Init(&GPIO_InitStruct1);	
			
			GPIO_InitStruct1.GPIO_Pin = 1;
			GPIO_InitStruct1.GPIO_InitState = Bit_RESET;
			GPIO_InitStruct1.GPIO_IRQMode = GPIO_IT_DISABLE;
			GPIO_InitStruct1.GPIO_Mode = GPIO_Mode_OPP;
			GPIO_InitStruct1.GPIOx = PTE;
			GPIO_Init(&GPIO_InitStruct1);
}
/************************************************************************
*  函數名稱:sccb_wait
*  功能說明:SCCB延時,不應太小
*************************************************************************/
void sccb_wait(void)
{
  u8 i;
  u16 j;
  for( i=0; i<100; i++)
  {
    j++;
  }
}
/************************************************************************
*  函數名稱:sccb_start
*  功能說明:SCCB啟動位
*************************************************************************/
void sccb_start(void)
{
  SCL_OUT;
  SDA_OUT;
 
  SDA_HIGH;
  //sccb_wait();
  SCL_HIGH;
  sccb_wait();
  SDA_LOW;
  sccb_wait();
  SCL_LOW;
}

/************************************************************************
*  函數名稱:sccb_stop
*  功能說明:SCCB停止位
*************************************************************************/
void sccb_stop(void)
{
  SCL_OUT;
  SDA_OUT;
  
  SDA_LOW;
  sccb_wait();
  SCL_HIGH;
  sccb_wait();
  SDA_HIGH;
  sccb_wait();
}

/************************************************************************
*  函數名稱:sccb_sendByte
*  功能說明:在SCCB總線上發送一個位元組
*  參數說明:data 要發送的位元組内容
*************************************************************************/
u8 sccb_sendByte(u8 data)
{
  u8 i;
   u8 ack;
  SDA_OUT;
  for( i=0; i<8; i++)
  {
    if(data & 0x80)
      SDA_HIGH;
    else 
      SDA_LOW;
    data <<= 1;
    sccb_wait();
    SCL_HIGH;
    sccb_wait();
    SCL_LOW;
    sccb_wait();
  }
  SDA_HIGH;
  SDA_IN;
  sccb_wait();
  SCL_HIGH;
  sccb_wait();
  ack = SDA_DATA;
  SCL_LOW;
  sccb_wait();
  return ack;
}


/************************************************************************
*  函數名稱:sccb_regWrite
*  功能說明:通過SCCB總線向指定裝置的指定位址發送指定内容
*  參數說明:device---裝置号  讀寫有差別  42是寫,43是寫
*            address---寫資料的寄存器
*            data---寫的内容
*  函數傳回:ack=1未收到應答(失敗)    ack=0收到應答(成功)
*************************************************************************/
void sccb_regWrite(u8 device,u8 address,u8 data)
{
 // u8 i;
  u8 ack;
//  for( i=0; i<20; i++)
//  {
    sccb_start();
    ack = sccb_sendByte(device);
    while( ack )
    {
      ack = sccb_sendByte(device);
	//		printf("device\n\r");
    }   
    ack = sccb_sendByte(address);
    while( ack )
    {
      ack = sccb_sendByte(address);;
  //    printf("address\n\r");
    }
    ack = sccb_sendByte(data);
    while( ack  )
    {
     ack = sccb_sendByte(data);
  //    printf("data\n\r");
    }   
    sccb_stop();
//    if( ack == 0 ) break;
//  }
}
           

貼上使用的SCCB的庫之後,給大家看一下對SCCB的一段執行個體操作程式。程式上有詳細的解釋,我就不贅述了。

sccb_init();
	sccb_regWrite(0x42,0x11,0x01);    //位址0X11-中斷四分頻(1280*480)           PCLK:166ns   HREF:254.6us   VSYN:133.6ms
	sccb_regWrite(0x42,0x14,0x24);    //位址0X14-QVGA(320*240)                  PCLK:332ns   HREF:509.6us   VSYN:133.6ms
	sccb_regWrite(0x42,0x28,0x40);    //位址0X28-黑白模式(320*240               PCLK:332ns   HREF:127us   VSYN:33.6ms  
	sccb_wait();
           

以上就是關于OV7620的使用了,看完之後大家是不是會使用了呢。關于後期圖像的處理和調試,我目前正在使用一款智能車調試助手,感覺非常好用,完全免費,并且可以配合Visual Studio,在Visual Studio裡面用C#編寫一些圖像處理的算法,生成dll檔案,然後在調試助手的界面裡面直接觀察。非常好非常好。給大家看看圖。

OV7620的使用

如果有需要關于OV7620資料或者調試軟體或者有什麼賜教,請留言共同探讨。.

End。2014、03、26

繼續閱讀