色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > s3c2440的攝像接口拍照應用

          s3c2440的攝像接口拍照應用

          作者: 時間:2016-11-26 來源:網(wǎng)絡 收藏

          本文引用地址:http://cafeforensic.com/article/201611/321674.htm

          // SCCB 接收一個字節(jié)

          void __inline SCCB_receivebyte(unsigned char *data)

          {

          int i=0;

          int svalue=0;

          int pvalue = 0;

          rGPECON = 1<<28;// 把 GPE15 輸出改變?yōu)檩斎?/p>

          // 串行數(shù)據(jù)轉并行輸入,高位在前

          for(i=7;i>=0;i--)

          {

          CLOCK_HIGH();

          delay(10);

          svalue = rGPEDAT>>15;

          CLOCK_LOW();

          delay(10);

          pvalue |= svalue <

          }

          rGPECON =5<<28;// 再把 GPE15 改回為輸出

          // 第 9 位, N.A.

          DATA_HIGH();

          delay(10);

          CLOCK_HIGH();

          delay(10);

          CLOCK_LOW();

          delay(10);

          *data = pvalue &0xff;

          }

          // 寫操作

          void SCCB_senddata(unsigned char subaddr, unsigned char data)

          {

          //3 相寫傳輸周期

          SCCB_start();// 啟動 SCCB

          SCCB_sendbyte(0x60);//OV9650 設備從地址,寫操作

          SCCB_sendbyte(subaddr);// 設備內存地址

          SCCB_sendbyte(data);// 寫數(shù)據(jù)字節(jié)

          SCCB_end();// 結束 SCCB

          delay(20);

          }

          // 讀操作

          unsigned char SCCB_receivedata(unsigned char subaddr)

          {

          unsigned char temp;

          //2 相寫傳輸周期

          SCCB_start();// 啟動 SCCB

          SCCB_sendbyte(0x60);//OV9650 設備從地址,寫操作

          SCCB_sendbyte(subaddr);// 設備內存地址

          SCCB_end();// 結束 SCCB

          //2 相讀傳輸周期

          SCCB_start();// 啟動 SCCB

          SCCB_sendbyte(0x61);//OV9650 設備從地址,讀操作

          SCCB_receivebyte(&temp);// 讀字節(jié)

          SCCB_end();// 結束 SCCB

          return temp;

          }

          OV9650 的寄存器較多,要想配置好這些寄存器是需要花費一些精力的。下面數(shù)組給出了一個 VGA ( 640 × 480 )模式下 YUV 彩色空間的配置例子,括號內第一個元素表示寄存器地址,第二個元素表示要寫入的數(shù)據(jù)。

          const unsigned char ov9650_register[ ][2] = {

          {0x11,0x80},{0x6a,0x3e},{0x3b,0x09},{0x13,0xe0},{0x01,0x80},{0x02,0x80},{0x00,0x00},{0x10,0x00},

          {0x13,0xe5},{0x39,0x43},{0x38,0x12},{0x37,0x00},{0x35,0x91},{0x0e,0xa0},{0x1e,0x04},{0xA8,0x80},

          {0x12,0x40},{0x04,0x00},{0x0c,0x04},{0x0d,0x80},{0x18,0xc6},{0x17,0x26},{0x32,0xad},{0x03,0x00},

          {0x1a,0x3d},{0x19,0x01},{0x3f,0xa6},{0x14,0x2e},{0x15,0x10},{0x41,0x02},{0x42,0x08},{0x1b,0x00},

          {0x16,0x06},{0x33,0xe2},{0x34,0xbf},{0x96,0x04},{0x3a,0x00},{0x8e,0x00},{0x3c,0x77},{0x8B,0x06},

          {0x94,0x88},{0x95,0x88},{0x40,0xc1},{0x29,0x3f},{0x0f,0x42},{0x3d,0x92},{0x69,0x40},{0x5C,0xb9},

          {0x5D,0x96},{0x5E,0x10},{0x59,0xc0},{0x5A,0xaf},{0x5B,0x55},{0x43,0xf0},{0x44,0x10},{0x45,0x68},

          {0x46,0x96},{0x47,0x60},{0x48,0x80},{0x5F,0xe0},{0x60,0x8c},{0x61,0x20},{0xa5,0xd9},{0xa4,0x74},

          {0x8d,0x02},{0x13,0xe7},{0x4f,0x3a},{0x50,0x3d},{0x51,0x03},{0x52,0x12},{0x53,0x26},{0x54,0x38},

          {0x55,0x40},{0x56,0x40},{0x57,0x40},{0x58,0x0d},{0x8C,0x23},{0x3E,0x02},{0xa9,0xb8},{0xaa,0x92},

          {0xab,0x0a},{0x8f,0xdf},{0x90,0x00},{0x91,0x00},{0x9f,0x00},{0xa0,0x00},{0x3A,0x01},{0x24,0x70},

          {0x25,0x64},{0x26,0xc3},{0x2a,0x00},{0x2b,0x00},{0x6c,0x40},{0x6d,0x30},{0x6e,0x4b},{0x6f,0x60},

          {0x70,0x70},{0x71,0x70},{0x72,0x70},{0x73,0x70},{0x74,0x60},{0x75,0x60},{0x76,0x50},{0x77,0x48},

          {0x78,0x3a},{0x79,0x2e},{0x7a,0x28},{0x7b,0x22},{0x7c,0x04},{0x7d,0x07},{0x7e,0x10},{0x7f,0x28},

          {0x80,0x36},{0x81,0x44},{0x82,0x52},{0x83,0x60},{0x84,0x6c},{0x85,0x78},{0x86,0x8c},{0x87,0x9e},

          {0x88,0xbb},{0x89,0xd2},{0x8a,0xe6},

          };

          另外 OV9650 有兩個只讀寄存器—— 0x1C 和 0x1D ,用于存放廠家 ID ,數(shù)據(jù)分別為 0x7F 和 0xA2 ,我們可以通過讀取它們來判斷 s3c2440 是否連接了 OV9650 。當確認連接了 OV9650 后,我們就可以把上面的那個數(shù)組寫入 OV9650 內,如下所示。在這里我們總是認為 s3c2440 連接了 OV9650 。

          void config_ov9650(void)

          {

          unsigned char temp;

          int i;

          // 讀取 OV9650 廠商 ID

          i=1;

          while(i)

          {

          temp = SCCB_receivedata(0x1C);// 或 Rd_SCCB (0x1C,&temp);

          if(temp==0x7F)

          i=0;

          }

          i=1;

          while(i)

          {

          temp = SCCB_receivedata(0x1D);// 或 Rd_SCCB (0x1D,&temp);

          if(temp==0xA2)

          i=0;

          }

          // 復位所有 OV9650 寄存器

          SCCB_senddata(0x12,0x80);// 或 Wr_SCCB (0x12,0x80);

          delay(10000);

          // 配置 OV9650 寄存器

          for(i=0;i<((sizeof(ov9650_register))/2);i++)

          {

          SCCB_senddata(ov9650_register[i][0],ov9650_register[i][1]);

          // 或 Wr_SCCB (ov9650_register[i][0],ov9650_register[i][1]);

          }

          }

          上面程序中,我們是用循環(huán)語句讀取 OV9650 的寄存器 0x1C 和 0x1D 的,之所以這樣,是為了防止只讀取一次時,會有讀取不正確的現(xiàn)象發(fā)生。而一旦正確讀取了廠商 ID 信息,再讀寫 OV9650 寄存器,一般就不會發(fā)生讀寫的錯誤。

          下面就介紹 s3c2440 攝像接口的相關配置。攝像接口有兩個相互獨立的 DMA 通道—— P 通道(預覽通道)和 C 通道(編解碼通道)。 P 通道主要是存儲用于視頻顯示的 RGB 圖像數(shù)據(jù), C 通道主要是存儲用于編解碼的 YCbCr 圖像數(shù)據(jù)。在這里我們主要是把 OV9650 采集到的視頻信息實時顯示在 LCD 上,因此只介紹 P 通道的用法。

          設置 s3c2440 攝像接口一個很重要的步驟就是設置視頻尺寸大小。我們把由 OV9650 采集到的視頻尺寸稱為源,即源水平尺寸和源垂直尺寸,其中源水平尺寸必須是 8 的整數(shù)倍。這個尺寸是通過配置 OV9650 的相關寄存器實現(xiàn)的。我們把這兩個值分別放入輸入源格式寄存器 CISRCFMT 的第 16 位至第 28 位,和第 0 位至第 12 位內,例如通過 OV9650 ,采集的到的視頻尺寸為 640 × 480 ,則把 640 和 480 分別放入寄存器 CISRCFMT 中的相應位置即可。我們把實際顯示的視頻尺寸稱為目標,即目標水平尺寸和目標垂直尺寸,這里這個尺寸就是 LCD 的尺寸。我們把這兩個值分別放入預覽 DMA 目標圖像格式寄存器 CIPRTRGFMT 的第 16 位至第 28 位,和第 0 位至第 12 位內,例如 LCD 的尺寸為 320 × 240 ,則把 320 和 240 分別放入寄存器 CIPRTRGFMT 中的相應位置即可。另外還需要把這兩個值的乘積放入預覽縮放目標面積寄存器 CIPRTAREA 內。源尺寸和目標尺寸往往是不一樣大小的,那么可能還需要設置偏移量,即水平偏移量和垂直偏移量,應該把這兩個值分別放入窗口偏移寄存器 CIWDOFST 的第 16 位至第 26 位,和第 0 位至第 10 位內,其中這個寄存器的第 31 位用于控制是否需要設置偏移量,當偏移量為 0 或不需要設置偏移量時,這一位應為 0 ,否則為 1 。顯然,通過源尺寸、目標尺寸和偏移量的設置,可以實現(xiàn)被攝像物體的縮放效果。當然,要實現(xiàn)這種縮放效果,還需要配置預覽預縮放比例控制寄存器 CIPRSCPRERATIO 、預覽預縮放距離格式寄存器 CIPRSCPREDST 和預覽主縮放控制寄存器 CIPRSCCTRL ,這些寄存器的相關參數(shù)是通過計算得到的,數(shù)據(jù)手冊上有詳細的說明,而且還有標準的函數(shù)可以調用,因此在這里就不過多介紹。

          前面已經(jīng)介紹過,攝像接口都是通過 DMA 實現(xiàn)數(shù)據(jù)交換的。 s3c2440 能夠在內存中各開辟四塊乒乓存儲區(qū)域,用于實現(xiàn) P 通道和 C 通道的快速數(shù)據(jù)傳遞。在 P 通道中,寄存器 CIPRCLRSA1 、 CIPRCLRSA2 、 CIPRCLRSA3 和 CIPRCLRSA4 分別用于表示這四塊內存的首地址。另外在 DMA 數(shù)據(jù)傳遞中,還要讓 DMA 知道如何進行傳遞,即一次傳輸多少個字節(jié),這需要設置預覽 DMA 控制相關寄存器 CIPRCTRL 的主突發(fā)長度和剩余突發(fā)長度,這兩個值也可以通過調用標準函數(shù)來求得。另外在完成每一幀視頻采集后,會觸發(fā)一個視頻中斷。

          下面就給出一段具體的程序,利用 OV9650 實時地在 LCD 上顯示視頻,并通過 UART 來控制視頻,讓視頻圖像放大,縮小,以及實現(xiàn)照相的功能(讓圖像定格在 LCD 上)。

          …………

          int com;

          …………

          // 計算主突發(fā)長度和剩余突發(fā)長度,用于 CIPRCTRL 寄存器

          void CalculateBurstSize(U32 hSize,U32 *mainBurstSize,U32 *remainedBurstSize)

          {

          U32 tmp;

          tmp=(hSize/4);

          switch(tmp) {

          case 0:

          *mainBurstSize=16;

          *remainedBurstSize=16;

          break;

          case 4:

          *mainBurstSize=16;

          *remainedBurstSize=4;

          break;

          case 8:

          *mainBurstSize=16;

          *remainedBurstSize=8;

          break;

          default:

          tmp=(hSize/4)%8;

          switch(tmp) {

          case 0:

          *mainBurstSize=8;

          *remainedBurstSize=8;

          break;

          case 4:

          *mainBurstSize=8;

          *remainedBurstSize=4;

          default:

          *mainBurstSize=4;

          tmp=(hSize/4)%4;

          *remainedBurstSize= (tmp) ? tmp: 4;

          break;

          }

          break;

          }

          }

          // 計算預縮放比率及移位量,用于 CICOSCPRERATIO 寄存器

          void CalculatePrescalerRatioShift(U32 SrcSize, U32 DstSize, U32 *ratio,U32 *shift)

          {

          if(SrcSize>=64*DstSize) {

          //Uart_Printf("ERROR: out of the prescaler range: SrcSize/DstSize = %d(< 64)",SrcSize/DstSize);

          while(1);

          }

          else if(SrcSize>=32*DstSize) {

          *ratio=32;

          *shift=5;

          }

          else if(SrcSize>=16*DstSize) {

          *ratio=16;

          *shift=4;

          }

          else if(SrcSize>=8*DstSize) {

          *ratio=8;

          *shift=3;

          }

          else if(SrcSize>=4*DstSize) {

          *ratio=4;

          *shift=2;

          }

          else if(SrcSize>=2*DstSize) {

          *ratio=2;

          *shift=1;

          }

          else {

          *ratio=1;

          *shift=0;

          }

          }



          評論


          技術專區(qū)

          關閉