【OV7670】基于FPGA的OV7670摄像头介绍和使用
1.軟件版本
quartusii12.1
2.本算法理論知識
OV7670攝像頭模塊
帶384Kb FIFO? 數字攝像頭? 手動變焦
OV7670總共有656*488個像素,其中640*480個有效(即有效像素為30W)。
支持RawRGB、RGB(GBR4:2:2,RGB565/RGB555/RGB444),YUV(4:2:2)和YCbCr(4:2:2)輸出格式。
RGB565彩色模式,一個像素占兩個字節
低字節的前5位用來表示B(BLUE)
低字節的后三位+高字節的前三位用來表示G(Green)
?高字節的后5位用來表示R(RED)
VGA,即分辨率為640*480的輸出模式。VGA最早指的是顯示器640X480這種顯示模式。
QVGA,即分辨率為320*240的輸出格式,也就是本文檔我們需要用到的格式。QVGA即"Quarter VGA"。顧名思義即VGA的四分之一尺寸,亦即在液晶屏幕(LCD)上輸出的分辨率是240×320像素。
QQVGA,即分辨率為160*120的輸出格式。
數字攝像頭成像原理
數字攝像頭使用感光陣列轉換光信號,感光陣列如下圖。
??? 感光陣列將攝像頭透鏡中傳過來的光采集,轉換形成數字信號。感光陣列越密像素越大。常見感光陣列有CCD、COMS。就CCD和CMOS而言:ADC的位置和數量是最大的不同。CCD曝光結束后,進行電信號轉移,將每一行中每一個象元的電荷信號依行序依次傳入每行的“緩沖器”中,由底端線路依次將每行的電信號引導輸出至?CCD?旁的放大器進行放大,再串聯?ADC?輸出,此為線陣CCD;另外一種是每行均有放大電路,各行同時將捕捉的當前圖像信息進行ADC,既可以同時接受一幅完整的圖像信息,此為面陣CCD。CMOS?的設計中每個像素就直接連著?ADC,電信號直接放大并轉換成數字信號。
??? 比較:CCD的特色在于充分保持信號在傳輸時不失真,透過每一個像素集合至單一放大器上再做統一處理,可以保持圖像的完整性;CMOS的制程較簡單,沒有專屬通道的設計,因此必須先行放大再整合各個像素的資料。由此可見,CMOS的成像過程更加容易出現壞點,使圖像失真,但隨著他工藝的可兼容性和功耗,使得它更加適合嵌入式的需要,同時,產生的圖像失真可以通過相應的算法進行補償,但這里需要注意的是,CMOS的成像特點決定了它非常容易受到外界環境光的影響,在使用的過程中,一定要設計出符合要求的光源。
這里用的這個攝像頭,其幾個管腳的含義是:
1??? VCC 電源輸入:2.5v---3.0V
2??? GND 地
3??? SCL S 模塊內部帶上拉電阻
4??? SDA 模塊內部帶上拉電阻
5??? VSYNC 幀同步
6 ???HREF 行同步
7 ???PCLK 像素時鐘
8 ???XCLK 主時鐘輸入
9 ???D7?? DOUT9 像素數據
10 ??D6?? DOUT8 像素數據
11 ??D5?? DOUT7 像素數據
12 ??D4?? DOUT6 ?像素數據
13?? D3?? DOUT5 ?像素數據
14?? D2?? ?DOUT4 ?像素數據
16? D1?? DOUT3 ?像素數據
16? D0? DOUT2 ?像素數據
關于論文中,這個部分的書寫內容,參考我提供的文獻:
這個里面詳細介紹了OV7640的介紹,他們其實完全一樣的,你可以全面參考這個部分。
我在設計這個部分的時候,用到的技術點主要有如下幾個方面:
??? 第一,攝像頭的驅動
??? 第二,攝像頭的視頻采集
那么你寫論文的時候,參考上面論文中 這個部分,稍微改下就可以了,基本上我們這個攝像頭和這個論文中的基本完全一致的。然后我上面寫的關于這個攝像頭的介紹,你可以用進去。
2.TFT液晶屏
這個部分的時序較為復雜,具體來講,主要的內容如下所示:
這個是關于這款液晶屏的重要時序說明文檔。寫論文可以參考。
然后關于這個液晶屏,好像,寫的論文比較少,我這里主要把涉及到的一些技術點寫一下。
那么這里,主要參考的文獻是
http://www.docin.com/p-456301691.html
你可以根據這個里面的內容寫。
然后如果你要介紹這個TFT結構的話,那么參考如下的網站
http://www.go-gddq.com/html/s185/2013-05/1124316.htm
3.喇叭控制輸出音頻
??? 蜂鳴器不多解釋了,我們在設計的時候,通過一個三極管進行控制,當低電平時,三極管導通,蜂鳴器響;當高電平,三極管截止,蜂鳴器不響。通過高低電平的不同頻率的切換,輸出對應的音頻信息。這個部分比較簡單,這里不多做介紹了。
??? 然后,我們介紹一下,我們這個整個系統的設計構架:
???? 注意,你這里沒有提供SD卡,我把需要播放的音頻和視頻保存在FPGA自帶的存儲器中,這個不影響整個系統的實際原理。
??? 設計中需要對 SD 卡內音頻、視頻進行相應操作,所以需要為設計建立文件系統。雖然 Nios II IDE 集成開發環境支持 ZIP 文件系統,但它卻是針對Flash 中燒寫的 ZIP 打包文件,操作還必須通過工具燒寫 Flash。這樣不僅操作不便,而且對于音頻容量、視頻遠遠不夠。需要嵌入一個合適的文件系統。本設計中在實現 SD 卡初始化和讀寫功能的基礎上,對 Nios II 進行了文件系統的移植,使相關文件的操作問題得以解決。設計中還要實現音頻播放的快進、快退和暫停,這些功能的實現又與文件系統密切相關。
3.部分源碼
//Legal Notice: (C)2014 Altera Corporation. All rights reserved. Your //use of Altera Corporation's design tools, logic functions and other //software and tools, and its AMPP partner logic functions, and any //output files any of the foregoing (including device programming or //simulation files), and any associated documentation or information are //expressly subject to the terms and conditions of the Altera Program //License Subscription Agreement or other applicable license agreement, //including, without limitation, that your use is for the sole purpose //of programming logic devices manufactured by Altera and sold by Altera //or its authorized distributors. Please refer to the applicable //agreement for further details.// synthesis translate_off `timescale 1ns / 1ps // synthesis translate_on// turn off superfluous verilog processor warnings // altera message_level Level1 // altera message_off 10034 10035 10036 10037 10230 10240 10030 module sdram_input_efifo_module (// inputs:clk,rd,reset_n,wr,wr_data,// outputs:almost_empty,almost_full,empty,full,rd_data) ;output almost_empty;output almost_full;output empty;output full;output [ 40: 0] rd_data;input clk;input rd;input reset_n;input wr;input [ 40: 0] wr_data;wire almost_empty;wire almost_full;wire empty;reg [ 1: 0] entries;reg [ 40: 0] entry_0;reg [ 40: 0] entry_1;wire full;reg rd_address;reg [ 40: 0] rd_data;wire [ 1: 0] rdwr;reg wr_address;assign rdwr = {rd, wr};assign full = entries == 2;assign almost_full = entries >= 1;assign empty = entries == 0;assign almost_empty = entries <= 1;always @(entry_0 or entry_1 or rd_address)begincase (rd_address) // synthesis parallel_case full_case1'd0: beginrd_data = entry_0;end // 1'd0 1'd1: beginrd_data = entry_1;end // 1'd1 default: beginend // defaultendcase // rd_addressendalways @(posedge clk or negedge reset_n)beginif (reset_n == 0)beginwr_address <= 0;rd_address <= 0;entries <= 0;endelse case (rdwr) // synthesis parallel_case full_case2'd1: begin// Write dataif (!full)beginentries <= entries + 1;wr_address <= (wr_address == 1) ? 0 : (wr_address + 1);endend // 2'd1 2'd2: begin// Read dataif (!empty)beginentries <= entries - 1;rd_address <= (rd_address == 1) ? 0 : (rd_address + 1);endend // 2'd2 2'd3: beginwr_address <= (wr_address == 1) ? 0 : (wr_address + 1);rd_address <= (rd_address == 1) ? 0 : (rd_address + 1);end // 2'd3 default: beginend // defaultendcase // rdwrendalways @(posedge clk)begin//Write dataif (wr & !full)case (wr_address) // synthesis parallel_case full_case1'd0: beginentry_0 <= wr_data;end // 1'd0 1'd1: beginentry_1 <= wr_data;end // 1'd1 default: beginend // defaultendcase // wr_addressendendmodule// synthesis translate_off `timescale 1ns / 1ps // synthesis translate_on// turn off superfluous verilog processor warnings // altera message_level Level1 // altera message_off 10034 10035 10036 10037 10230 10240 10030 module sdram (// inputs:az_addr,az_be_n,az_cs,az_data,az_rd_n,az_wr_n,clk,reset_n,// outputs:za_data,za_valid,za_waitrequest,zs_addr,zs_ba,zs_cas_n,zs_cke,zs_cs_n,zs_dq,zs_dqm,zs_ras_n,zs_we_n) ;output [ 15: 0] za_data;output za_valid;output za_waitrequest;output [ 11: 0] zs_addr;output [ 1: 0] zs_ba;output zs_cas_n;output zs_cke;output zs_cs_n;inout [ 15: 0] zs_dq;output [ 1: 0] zs_dqm;output zs_ras_n;output zs_we_n;input [ 21: 0] az_addr;input [ 1: 0] az_be_n;input az_cs;input [ 15: 0] az_data;input az_rd_n;input az_wr_n;input clk;input reset_n;wire [ 23: 0] CODE;reg ack_refresh_request;reg [ 21: 0] active_addr;wire [ 1: 0] active_bank;reg active_cs_n;reg [ 15: 0] active_data;reg [ 1: 0] active_dqm;reg active_rnw;wire almost_empty;wire almost_full;wire bank_match;wire [ 7: 0] cas_addr;wire clk_en;wire [ 3: 0] cmd_all;wire [ 2: 0] cmd_code;wire cs_n;wire csn_decode;wire csn_match;wire [ 21: 0] f_addr;wire [ 1: 0] f_bank;wire f_cs_n;wire [ 15: 0] f_data;wire [ 1: 0] f_dqm;wire f_empty;reg f_pop;wire f_rnw;wire f_select;wire [ 40: 0] fifo_read_data;reg [ 11: 0] i_addr;reg [ 3: 0] i_cmd;reg [ 2: 0] i_count;reg [ 2: 0] i_next;reg [ 2: 0] i_refs;reg [ 2: 0] i_state;reg init_done;reg [ 11: 0] m_addr /* synthesis ALTERA_ATTRIBUTE = "FAST_OUTPUT_REGISTER=ON" */;reg [ 1: 0] m_bank /* synthesis ALTERA_ATTRIBUTE = "FAST_OUTPUT_REGISTER=ON" */;reg [ 3: 0] m_cmd /* synthesis ALTERA_ATTRIBUTE = "FAST_OUTPUT_REGISTER=ON" */;reg [ 2: 0] m_count;reg [ 15: 0] m_data /* synthesis ALTERA_ATTRIBUTE = "FAST_OUTPUT_REGISTER=ON ; FAST_OUTPUT_ENABLE_REGISTER=ON" */;reg [ 1: 0] m_dqm /* synthesis ALTERA_ATTRIBUTE = "FAST_OUTPUT_REGISTER=ON" */;reg [ 8: 0] m_next;reg [ 8: 0] m_state;reg oe /* synthesis ALTERA_ATTRIBUTE = "FAST_OUTPUT_ENABLE_REGISTER=ON" */;wire pending;wire rd_strobe;reg [ 2: 0] rd_valid;reg [ 13: 0] refresh_counter;reg refresh_request;wire rnw_match;wire row_match;wire [ 23: 0] txt_code;reg za_cannotrefresh;reg [ 15: 0] za_data /* synthesis ALTERA_ATTRIBUTE = "FAST_INPUT_REGISTER=ON" */;reg za_valid;wire za_waitrequest;wire [ 11: 0] zs_addr;wire [ 1: 0] zs_ba;wire zs_cas_n;wire zs_cke;wire zs_cs_n;wire [ 15: 0] zs_dq;wire [ 1: 0] zs_dqm;wire zs_ras_n;wire zs_we_n;assign clk_en = 1;//s1, which is an e_avalon_slaveassign {zs_cs_n, zs_ras_n, zs_cas_n, zs_we_n} = m_cmd;assign zs_addr = m_addr;assign zs_cke = clk_en;assign zs_dq = oe?m_data:{16{1'bz}};assign zs_dqm = m_dqm;assign zs_ba = m_bank;assign f_select = f_pop & pending;assign f_cs_n = 1'b0;assign cs_n = f_select ? f_cs_n : active_cs_n;assign csn_decode = cs_n;assign {f_rnw, f_addr, f_dqm, f_data} = fifo_read_data;sdram_input_efifo_module the_sdram_input_efifo_module(.almost_empty (almost_empty),.almost_full (almost_full),.clk (clk),.empty (f_empty),.full (za_waitrequest),.rd (f_select),.rd_data (fifo_read_data),.reset_n (reset_n),.wr ((~az_wr_n | ~az_rd_n) & !za_waitrequest),.wr_data ({az_wr_n, az_addr, az_wr_n ? 2'b0 : az_be_n, az_data}));assign f_bank = {f_addr[21],f_addr[8]};// Refresh/init counter.always @(posedge clk or negedge reset_n)beginif (reset_n == 0)refresh_counter <= 10000;else if (refresh_counter == 0)refresh_counter <= 1562;else refresh_counter <= refresh_counter - 1'b1;end// Refresh request signal.always @(posedge clk or negedge reset_n)beginif (reset_n == 0)refresh_request <= 0;else if (1)refresh_request <= ((refresh_counter == 0) | refresh_request) & ~ack_refresh_request & init_done;end// Generate an Interrupt if two ref_reqs occur before one ack_refresh_requestalways @(posedge clk or negedge reset_n)beginif (reset_n == 0)za_cannotrefresh <= 0;else if (1)za_cannotrefresh <= (refresh_counter == 0) & refresh_request;end// Initialization-done flag.always @(posedge clk or negedge reset_n)beginif (reset_n == 0)init_done <= 0;else if (1)init_done <= init_done | (i_state == 3'b101);end// **** Init FSM ****always @(posedge clk or negedge reset_n)beginif (reset_n == 0)begini_state <= 3'b000;i_next <= 3'b000;i_cmd <= 4'b1111;i_addr <= {12{1'b1}};i_count <= {3{1'b0}};endelse begini_addr <= {12{1'b1}};case (i_state) // synthesis parallel_case full_case3'b000: begini_cmd <= 4'b1111;i_refs <= 3'b0;//Wait for refresh count-down after resetif (refresh_counter == 0)i_state <= 3'b001;end // 3'b000 3'b001: begini_state <= 3'b011;i_cmd <= {{1{1'b0}},3'h2};i_count <= 1;i_next <= 3'b010;end // 3'b001 3'b010: begini_cmd <= {{1{1'b0}},3'h1};i_refs <= i_refs + 1'b1;i_state <= 3'b011;i_count <= 7;// Count up init_refresh_commandsif (i_refs == 3'h1)i_next <= 3'b111;else i_next <= 3'b010;end // 3'b010 3'b011: begini_cmd <= {{1{1'b0}},3'h7};//WAIT til safe to Proceed...if (i_count > 1)i_count <= i_count - 1'b1;else i_state <= i_next;end // 3'b011 3'b101: begini_state <= 3'b101;end // 3'b101 3'b111: begini_state <= 3'b011;i_cmd <= {{1{1'b0}},3'h0};i_addr <= {{2{1'b0}},1'b0,2'b00,3'h3,4'h0};i_count <= 4;i_next <= 3'b101;end // 3'b111 default: begini_state <= 3'b000;end // defaultendcase // i_stateendendassign active_bank = {active_addr[21],active_addr[8]};assign csn_match = active_cs_n == f_cs_n;assign rnw_match = active_rnw == f_rnw;assign bank_match = active_bank == f_bank;assign row_match = {active_addr[20 : 9]} == {f_addr[20 : 9]};assign pending = csn_match && rnw_match && bank_match && row_match && !f_empty;assign cas_addr = f_select ? { {4{1'b0}},f_addr[7 : 0] } : { {4{1'b0}},active_addr[7 : 0] };// **** Main FSM ****always @(posedge clk or negedge reset_n)beginif (reset_n == 0)beginm_state <= 9'b000000001;m_next <= 9'b000000001;m_cmd <= 4'b1111;m_bank <= 2'b00;m_addr <= 12'b000000000000;m_data <= 16'b0000000000000000;m_dqm <= 2'b00;m_count <= 3'b000;ack_refresh_request <= 1'b0;f_pop <= 1'b0;oe <= 1'b0;endelse beginf_pop <= 1'b0;oe <= 1'b0;case (m_state) // synthesis parallel_case full_case9'b000000001: begin//Wait for init-fsm to be done...if (init_done)begin//Hold bus if another cycle ended to arf.if (refresh_request)m_cmd <= {{1{1'b0}},3'h7};else m_cmd <= 4'b1111;ack_refresh_request <= 1'b0;//Wait for a read/write request.if (refresh_request)beginm_state <= 9'b001000000;m_next <= 9'b010000000;m_count <= 1;active_cs_n <= 1'b1;endelse if (!f_empty)beginf_pop <= 1'b1;active_cs_n <= f_cs_n;active_rnw <= f_rnw;active_addr <= f_addr;active_data <= f_data;active_dqm <= f_dqm;m_state <= 9'b000000010;endendelse beginm_addr <= i_addr;m_state <= 9'b000000001;m_next <= 9'b000000001;m_cmd <= i_cmd;endend // 9'b000000001 9'b000000010: beginm_state <= 9'b000000100;m_cmd <= {csn_decode,3'h3};m_bank <= active_bank;m_addr <= active_addr[20 : 9];m_data <= active_data;m_dqm <= active_dqm;m_count <= 2;m_next <= active_rnw ? 9'b000001000 : 9'b000010000;end // 9'b000000010 9'b000000100: begin// precharge all if arf, else precharge csn_decodeif (m_next == 9'b010000000)m_cmd <= {{1{1'b0}},3'h7};else m_cmd <= {csn_decode,3'h7};//Count down til safe to Proceed...if (m_count > 1)m_count <= m_count - 1'b1;else m_state <= m_next;end // 9'b000000100 9'b000001000: beginm_cmd <= {csn_decode,3'h5};m_bank <= f_select ? f_bank : active_bank;m_dqm <= f_select ? f_dqm : active_dqm;m_addr <= cas_addr;//Do we have a transaction pending?if (pending)begin//if we need to ARF, bail, else spinif (refresh_request)beginm_state <= 9'b000000100;m_next <= 9'b000000001;m_count <= 2;endelse beginf_pop <= 1'b1;active_cs_n <= f_cs_n;active_rnw <= f_rnw;active_addr <= f_addr;active_data <= f_data;active_dqm <= f_dqm;endendelse begin//correctly end RD spin cycle if fifo mtif (~pending & f_pop)m_cmd <= {csn_decode,3'h7};m_state <= 9'b100000000;endend // 9'b000001000 9'b000010000: beginm_cmd <= {csn_decode,3'h4};oe <= 1'b1;m_data <= f_select ? f_data : active_data;m_dqm <= f_select ? f_dqm : active_dqm;m_bank <= f_select ? f_bank : active_bank;m_addr <= cas_addr;//Do we have a transaction pending?if (pending)begin//if we need to ARF, bail, else spinif (refresh_request)beginm_state <= 9'b000000100;m_next <= 9'b000000001;m_count <= 2;endelse beginf_pop <= 1'b1;active_cs_n <= f_cs_n;active_rnw <= f_rnw;active_addr <= f_addr;active_data <= f_data;active_dqm <= f_dqm;endendelse begin//correctly end WR spin cycle if fifo emptyif (~pending & f_pop)beginm_cmd <= {csn_decode,3'h7};oe <= 1'b0;endm_state <= 9'b100000000;endend // 9'b000010000 9'b000100000: beginm_cmd <= {csn_decode,3'h7};//Count down til safe to Proceed...if (m_count > 1)m_count <= m_count - 1'b1;else beginm_state <= 9'b001000000;m_count <= 1;endend // 9'b000100000 9'b001000000: beginm_state <= 9'b000000100;m_addr <= {12{1'b1}};// precharge all if arf, else precharge csn_decodeif (refresh_request)m_cmd <= {{1{1'b0}},3'h2};else m_cmd <= {csn_decode,3'h2};end // 9'b001000000 9'b010000000: beginack_refresh_request <= 1'b1;m_state <= 9'b000000100;m_cmd <= {{1{1'b0}},3'h1};m_count <= 7;m_next <= 9'b000000001;end // 9'b010000000 9'b100000000: beginm_cmd <= {csn_decode,3'h7};//if we need to ARF, bail, else spinif (refresh_request)beginm_state <= 9'b000000100;m_next <= 9'b000000001;m_count <= 1;endelse //wait for fifo to have contentsif (!f_empty)//Are we 'pending' yet?if (csn_match && rnw_match && bank_match && row_match)beginm_state <= f_rnw ? 9'b000001000 : 9'b000010000;f_pop <= 1'b1;active_cs_n <= f_cs_n;active_rnw <= f_rnw;active_addr <= f_addr;active_data <= f_data;active_dqm <= f_dqm;endelse beginm_state <= 9'b000100000;m_next <= 9'b000000001;m_count <= 1;endend // 9'b100000000 // synthesis translate_offdefault: beginm_state <= m_state;m_cmd <= 4'b1111;f_pop <= 1'b0;oe <= 1'b0;end // default// synthesis translate_onendcase // m_stateendendassign rd_strobe = m_cmd[2 : 0] == 3'h5;//Track RD Req's based on cas_latency w/shift regalways @(posedge clk or negedge reset_n)beginif (reset_n == 0)rd_valid <= {3{1'b0}};else rd_valid <= (rd_valid << 1) | { {2{1'b0}}, rd_strobe };end// Register dq data.always @(posedge clk or negedge reset_n)beginif (reset_n == 0)za_data <= 0;else za_data <= zs_dq;end// Delay za_valid to match registered data.always @(posedge clk or negedge reset_n)beginif (reset_n == 0)za_valid <= 0;else if (1)za_valid <= rd_valid[2];endassign cmd_code = m_cmd[2 : 0];assign cmd_all = m_cmd;//synthesis translate_offSIMULATION-ONLY CONTENTSassign txt_code = (cmd_code == 3'h0)? 24'h4c4d52 :(cmd_code == 3'h1)? 24'h415246 :(cmd_code == 3'h2)? 24'h505245 :(cmd_code == 3'h3)? 24'h414354 :(cmd_code == 3'h4)? 24'h205752 :(cmd_code == 3'h5)? 24'h205244 :(cmd_code == 3'h6)? 24'h425354 :(cmd_code == 3'h7)? 24'h4e4f50 :24'h424144;assign CODE = &(cmd_all|4'h7) ? 24'h494e48 : txt_code;END SIMULATION-ONLY CONTENTS//synthesis translate_onendmoduleA13-12總結
以上是生活随笔為你收集整理的【OV7670】基于FPGA的OV7670摄像头介绍和使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql 分钟_MySQL如何获取一个
- 下一篇: OV代码签名数字证书