動(dòng)無FIFO版OV7670攝像頭:從接線到圖像顯示全攻略)
作為一個(gè)從標(biāo)準(zhǔn)庫一路摸到HAL庫的老玩家我必須說STM32F103驅(qū)動(dòng)OV7670攝像頭模塊這件事屬于那種“看著簡(jiǎn)單做起來全是坑”的典型項(xiàng)目。尤其是你手上拿的還是不帶FIFO的OV7670那難度直接翻倍。網(wǎng)上很多教程要么只講帶FIFO版本要么一筆帶過“用DMA讀”搞得新手連接線都理不清。這篇教程我打算從選型、接線、寄存器配置、圖像數(shù)據(jù)采集到上位機(jī)顯示把整個(gè)流程完整過一遍重點(diǎn)說說無FIFO版本怎么在F103上穩(wěn)定讀到圖像以及那些只有真正調(diào)過板子的人才會(huì)告訴你的坑。這個(gè)項(xiàng)目的核心目標(biāo)很明確用一塊STM32F103最小系統(tǒng)板接一個(gè)不帶FIFO的OV7670攝像頭模塊通過SCCB接口完成寄存器初始化再靠GPIO模擬時(shí)序把圖像數(shù)據(jù)一字節(jié)一字節(jié)讀出來最后通過串口或者SPI屏把畫面顯示出來。適合正在做畢設(shè)、電子設(shè)計(jì)競(jìng)賽或者單純想搞懂?dāng)z像頭采集原理的同學(xué)參考。只要你手里有F103開發(fā)板、一個(gè)OV7670模塊和一根USB轉(zhuǎn)串口線就可以跟著做。1. 項(xiàng)目選型與整體方案分析1.1 為什么不推薦一上來就選帶FIFO的版本OV7670在市面上的模塊分成兩種帶FIFO常見AL422B芯片和不帶FIFO。帶FIFO的模塊會(huì)多一顆緩存芯片攝像頭先把數(shù)據(jù)寫進(jìn)FIFOMCU之后慢慢讀時(shí)序壓力小很多。不帶FIFO的模塊則要求MCU在PCLK時(shí)鐘邊沿實(shí)時(shí)讀取每一個(gè)像素字節(jié)錯(cuò)過一個(gè)字節(jié)整行、整幀圖像就會(huì)錯(cuò)位輕則花屏重則完全看不出畫面。很多教程會(huì)建議新手直接買帶FIFO的版本理由是“簡(jiǎn)單”。但其實(shí)不帶FIFO的版本更能幫助你理解攝像頭時(shí)序VSYNC什么時(shí)候來、HREF什么時(shí)候拉高、PCLK每個(gè)上升沿對(duì)應(yīng)哪個(gè)字節(jié)。如果你連無FIFO版本都能穩(wěn)定出圖再回頭用帶FIFO模塊會(huì)感覺跟喝水一樣輕松。另外無FIFO模塊價(jià)格更低在一些預(yù)算有限的學(xué)生項(xiàng)目里也更常見。STM32F103本身沒有DCMI數(shù)字?jǐn)z像頭接口這是F4/F7系列才有的外設(shè)。所以在這塊芯片上我們只能用GPIO模擬采樣。好在OV7670輸出的是并行8位數(shù)據(jù)D0到D7我們只要把8根數(shù)據(jù)線接到同一組GPIO端口配合VSYNC、HREF、PCLK三根同步線就能在中斷里完成像素采集。1.2 整條數(shù)據(jù)鏈路的設(shè)計(jì)思路先捋一下從攝像頭到屏幕的完整數(shù)據(jù)流攝像頭模塊上電后必須先通過SCCB接口兼容I2C協(xié)議寫入一堆寄存器配置指定輸出RGB565格式、QVGA/QQVGA分辨率、幀率等參數(shù)。配置完成后攝像頭會(huì)持續(xù)輸出VSYNC是幀同步信號(hào)HREF是行有效信號(hào)PCLK是像素時(shí)鐘D7到D0是并行數(shù)據(jù)線。F103在收到VSYNC后開始準(zhǔn)備接收一幀圖像在HREF為高且PCLK上升沿到來時(shí)一次性讀取8位數(shù)據(jù)。數(shù)據(jù)存入內(nèi)存緩沖區(qū)等一幀采集完成后再通過串口USB轉(zhuǎn)TTL發(fā)送到上位機(jī)顯示或者直接用SPI接口刷到TFT液晶屏上。這里最關(guān)鍵的點(diǎn)是F103沒有DCMIPCLK又不慢所以必須在“分辨率、幀率、采樣方式”三者之間做權(quán)衡。我的方案是降低分辨率到QQVGA160x120降低幀率到每秒5幀左右再用GPIO外部中斷按PCLK節(jié)奏讀數(shù)。這個(gè)方案在F103上非常穩(wěn)具體原因后面會(huì)詳細(xì)展開。2. 硬件接線與開發(fā)環(huán)境準(zhǔn)備2.1 物料清單和引腳對(duì)照表我用的是一塊STM32F103ZET6最小系統(tǒng)板手里如果只有C8T6也可以跑但RAM會(huì)有點(diǎn)緊張后面會(huì)講怎么規(guī)避。OV7670模塊是普通的DIP封裝無FIFO版本沒有AL422B那顆大芯片引腳一共15個(gè)左右。接線建議按下表OV7670引腳功能STM32F103引腳VCC電源輸入 3.3V3.3VGND地GNDSIO_CSCCB時(shí)鐘PB10或任意GPIOSIO_DSCCB數(shù)據(jù)PB11或任意GPIOXCLK主時(shí)鐘輸入PA8MCO輸出12MHzPCLK像素時(shí)鐘輸出PA0EXTI0VSYNC幀同步輸出PA1EXTI1HREF行同步輸出PA2D0-D78位并行數(shù)據(jù)PB0-PB7PWDN掉電模式GND接地保持工作RESET復(fù)位3.3V接高不復(fù)位注意D0到D7必須接到同一個(gè)GPIO端口的連續(xù)引腳上例如PB0到PB7。這樣在中斷里只要讀一次GPIOB-IDR 0xFF就能拿到完整字節(jié)比分別讀8個(gè)引腳快得多。PA8作為MCO時(shí)鐘輸出也很方便只需要配置AFIO重映射和MCO引腳復(fù)用就能把HSE的12MHz時(shí)鐘直接送給攝像頭當(dāng)XCLK不用額外接有源晶振。2.2 電源濾波與電平匹配OV7670的模擬電源對(duì)紋波比較敏感如果直接用最小系統(tǒng)板上的3.3V供電啟動(dòng)瞬間或者電機(jī)、繼電器等負(fù)載切換時(shí)畫面容易出現(xiàn)橫條紋。建議在攝像頭的VCC和GND之間并聯(lián)一個(gè)10uF電解電容和一個(gè)0.1uF陶瓷電容離模塊引腳越近越好。如果手頭有10uH左右的磁珠串在供電線上再進(jìn)攝像頭效果更好。電平匹配方面OV7670是3.3V器件STM32F103的IO口也是3.3V可以直接連接不需要電平轉(zhuǎn)換。但要注意SCCB的SIO_C和SIO_D兩根線模塊內(nèi)部往往是開漏結(jié)構(gòu)最好外接兩個(gè)4.7k歐姆上拉電阻到3.3V。有些現(xiàn)成模塊上已經(jīng)做了上拉那你就不用重復(fù)加拿萬用表量一下引腳對(duì)3.3V的阻值就知道。2.3 開發(fā)環(huán)境的幾個(gè)前置準(zhǔn)備開發(fā)工具我用的是Keil MDK5配合標(biāo)準(zhǔn)外設(shè)庫StdPeriph_Lib因?yàn)榫W(wǎng)上絕大多數(shù)OV7670參考代碼都是標(biāo)準(zhǔn)庫寫的移植查閱都方便。調(diào)試器建議ST-Link V2便宜穩(wěn)定驅(qū)動(dòng)裝好之后在設(shè)備管理器里能看到ST-Link的COM口或者調(diào)試接口。需要上位機(jī)顯示圖像時(shí)還要準(zhǔn)備一根USB轉(zhuǎn)TTL串口線常見的是CH340或CP2102芯片的方案。這兩個(gè)芯片的驅(qū)動(dòng)都比較好裝CH340去官網(wǎng)下最新版就行CP2102一般系統(tǒng)能自動(dòng)識(shí)別。這里先提一句如果串口線驅(qū)動(dòng)不對(duì)上位機(jī)那邊永遠(yuǎn)收不到任何數(shù)據(jù)先別懷疑攝像頭代碼先確認(rèn)串口能自發(fā)自收。3. SCCB初始化與寄存器配置3.1 SCCB協(xié)議要點(diǎn)和軟件模擬實(shí)現(xiàn)OV7670的配置接口叫SCCB時(shí)序跟I2C非常像但讀操作有一些差異。設(shè)備寫地址是0x42讀地址是0x43。一次寫操作分三步先發(fā)設(shè)備地址寫再發(fā)寄存器地址最后發(fā)寄存器數(shù)據(jù)。一次讀操作則分兩步第一次先發(fā)設(shè)備地址寫和寄存器地址發(fā)送停止條件后重新發(fā)起一個(gè)讀起始條件再發(fā)設(shè)備地址讀然后讀取一個(gè)字節(jié)最后主控發(fā)送不應(yīng)答并停止。F103的硬件I2C模塊存在一些兼容性問題而且SCCB的讀時(shí)序和標(biāo)準(zhǔn)I2C的重復(fù)起始條件行為不完全一致很多人調(diào)試半天都卡在初始化失敗上。我的做法是直接用GPIO軟件模擬SCCB時(shí)序代碼簡(jiǎn)單可控出了問題也好定位。如果你的初始化數(shù)組里只有寫操作沒有讀校驗(yàn)?zāi)怯糜布蘒2C也能跑一旦需要讀回寄存器來驗(yàn)證軟件模擬會(huì)省很多事。模擬時(shí)序的時(shí)候注意SIO_D引腳在讀取數(shù)據(jù)前要切換成輸入模式在寫數(shù)據(jù)時(shí)要切換成輸出模式。開漏模式下拉低就寫0釋放就靠上拉電阻變成高電平天然支持雙向通信。3.2 核心寄存器配置說明OV7670寄存器很多完整初始化數(shù)組網(wǎng)上能搜到一大把基本都能用。但你不能直接復(fù)制粘貼就完事必須知道幾個(gè)關(guān)鍵寄存器的作用否則出了問題完全不知道從哪里排查。首先是0x12COM7這個(gè)寄存器控制輸出格式和分辨率。復(fù)位值寫0x80表示芯片軟復(fù)位然后寫0x04選擇RGB輸出模式如果要設(shè)置QVGA一般還會(huì)配合其他寄存器把分辨率切到320x240。其次是0x40COM15它控制RGB數(shù)據(jù)的格式。網(wǎng)上做RGB565顯示時(shí)通常寫0x15含義是啟用RGB565輸出。然后是0x11CLKRC和0x15COM10。0x11控制內(nèi)部時(shí)鐘分頻0x00表示直接用外部XCLK不分頻0x15控制像素時(shí)鐘極性、數(shù)據(jù)線極性等一般RGB565模式下寫0x00或0x02具體可以參考初始化數(shù)組。我常用的一組RGB565初始化片段大概是這樣的// 軟件復(fù)位 OV7670_WriteReg(0x12, 0x80); delay_ms(50); // 設(shè)置RGB輸出 OV7670_WriteReg(0x12, 0x04); // 設(shè)置RGB565格式 OV7670_WriteReg(0x40, 0x15); // 使用外部時(shí)鐘不分頻 OV7670_WriteReg(0x11, 0x00); // 關(guān)閉PCLK分頻 OV7670_WriteReg(0x15, 0x00);這只是最核心的幾條完整的初始化數(shù)組還要包含AEC/AGC、白平衡、色飽和度、伽馬曲線等一大堆寄存器。建議先用一個(gè)網(wǎng)上成熟的RGB565數(shù)組確認(rèn)出圖之后再根據(jù)自己的需求調(diào)整。3.3 初始化驗(yàn)證技巧很多人在這一步就翻車了寫了一堆寄存器但攝像頭根本沒工作接下來無論怎么采集都是黑屏。最直接的驗(yàn)證方法讀回OV7670的產(chǎn)品ID寄存器0x0A應(yīng)該讀到0x76寄存器0x0B應(yīng)該讀到0x73。如果能讀到這兩個(gè)值說明SCCB通信正常芯片已經(jīng)正確響應(yīng)。讀寄存器這個(gè)操作非常關(guān)鍵比用示波器看波形都快。我一般會(huì)在初始化代碼里加一個(gè)讀ID的函數(shù)如果讀不到就點(diǎn)個(gè)LED報(bào)警這樣硬件接線對(duì)不對(duì)一下就知道了。在實(shí)際調(diào)試時(shí)我還遇到過一種情況能讀到ID但讀回來全是0xFF或者0x00大概率是SIO_C和SIO_D接反了或者某個(gè)引腳虛焊。注意OV7670上電后需要等至少10ms才能開始寫寄存器寫完0x12復(fù)位命令后還要再等一段時(shí)間我習(xí)慣延時(shí)50ms。太快寫寄存器芯片可能沒準(zhǔn)備好配置會(huì)悄悄失敗。4. 無FIFO圖像數(shù)據(jù)采集的實(shí)現(xiàn)4.1 不帶FIFO到底難在哪里帶FIFO的模塊攝像頭把數(shù)據(jù)寫入FIFOMCU有空了再去讀所以對(duì)實(shí)時(shí)性要求不高。無FIFO模塊則完全不同PCLK一來數(shù)據(jù)線上就是有效的像素字節(jié)你沒讀到這個(gè)字節(jié)就永遠(yuǎn)丟掉了。PCLK不會(huì)等你攝像頭按固定節(jié)奏持續(xù)輸出整幀圖像錯(cuò)過一個(gè)字節(jié)就會(huì)導(dǎo)致后續(xù)所有數(shù)據(jù)錯(cuò)位。查一下時(shí)序參數(shù)就知道OV7670在XCLK為12MHz時(shí)PCLK最高能到6MHz左右。這個(gè)頻率下STM32F103每秒鐘要進(jìn)600萬次中斷每次中斷還要讀IO存數(shù)組CPU根本扛不住連進(jìn)中斷再返回的開銷都會(huì)把系統(tǒng)拖垮。所以必須想辦法降低PCLK頻率或者繞過中斷采用其他方式。降低PCLK的思路有兩個(gè)一是降低XCLK輸入頻率比如用定時(shí)器輸出4MHz或者8MHz給攝像頭二是修改寄存器降低幀率、拉長(zhǎng)行消隱和幀消隱時(shí)間。我實(shí)測(cè)下來的組合是XCLK給8MHz分辨率設(shè)置成QQVGA160x120幀率降到5fps左右。這樣PCLK大約在幾百KHz到1MHz之間EXTI中斷完全來得及處理。4.2 基于外部中斷的逐像素采樣方案我采用的采集方案思路并不復(fù)雜VSYNC下降沿代表一幀開始HREF高電平代表當(dāng)前處于有效像素行PCLK上升沿代表D0-D7上的數(shù)據(jù)有效。所以只要在VSYNC中斷里把行列計(jì)數(shù)器清零在PCLK中斷里判斷HREF是否高電平是的話就讀取一次GPIOB的數(shù)據(jù)存入數(shù)組。簡(jiǎn)化后的偽代碼如下void EXTI0_IRQHandler(void) // PCLK引腳中斷 { if (EXTI_GetITStatus(EXTI_Line0) ! RESET) { if (HREF_IS_HIGH frame_active) { image_buffer[row][col] GPIOB-IDR 0xFF; col; if (col IMG_W) { col 0; row; if (row IMG_H) { row 0; frame_done 1; } } } EXTI_ClearITPendingBit(EXTI_Line0); } } void EXTI1_IRQHandler(void) // VSYNC引腳中斷 { if (EXTI_GetITStatus(EXTI_Line1) ! RESET) { // 下降沿觸發(fā)開始新一幀 frame_active 1; frame_done 0; row 0; col 0; EXTI_ClearITPendingBit(EXTI_Line1); } }這里有個(gè)細(xì)節(jié)VSYNC中斷觸發(fā)后可能還要等一小段時(shí)間HREF才真正進(jìn)入有效像素區(qū)域所以直接在VSYNC里把行列清零然后等PCLK來判斷即可。READY標(biāo)志位置位后主循環(huán)就可以把圖像數(shù)據(jù)拿出去顯示。4.3 內(nèi)存規(guī)劃與緩沖區(qū)設(shè)計(jì)圖像數(shù)據(jù)存哪里、怎么存是F103上最需要?jiǎng)幽X筋的地方。以QQVGA分辨率、RGB565格式為例一幀原始數(shù)據(jù)大小是160乘以120乘以2等于38400字節(jié)。STM32F103C8T6只有20KB SRAM一整幀根本放不下。ZET6有64KB SRAM可以輕松放下。如果你用的是C8T6也有辦法一是把分辨率進(jìn)一步降低到120x80或者80x60二是改成邊采集邊發(fā)送只開一個(gè)行緩沖或者雙行緩沖。行緩沖的思路是每采完一行數(shù)據(jù)立刻通過DMA串口發(fā)給上位機(jī)同時(shí)開始采集下一行這樣內(nèi)存里最多只需要放一兩行的數(shù)據(jù)。不過邊采邊發(fā)對(duì)實(shí)時(shí)性要求很高串口波特率不夠的話發(fā)送速度跟不上采集速度數(shù)據(jù)就會(huì)堆積。我建議新手先老老實(shí)實(shí)用ZET6開一整幀大數(shù)組把采集和發(fā)送拆開功能穩(wěn)定后再優(yōu)化內(nèi)存。4.4 為什么中斷里要關(guān)掉其他無關(guān)中斷無FIFO采集最怕的就是調(diào)度延遲。如果系統(tǒng)里同時(shí)開著定時(shí)器中斷、串口中斷PCLK中斷的響應(yīng)時(shí)間就會(huì)抖動(dòng)輕則某一行少幾個(gè)像素重則整個(gè)畫面撕裂。調(diào)試這個(gè)項(xiàng)目時(shí)我把定時(shí)器中斷全部關(guān)閉串口發(fā)送也改用DMA不占用CPU保證PCLK中斷一旦觸發(fā)就立刻執(zhí)行。如果你非要在采集過程中處理其他事至少要把其他中斷的優(yōu)先級(jí)調(diào)到比PCLK中斷低并且保證處理時(shí)間極短。我在NVIC里把EXTI0PCLK設(shè)為最高優(yōu)先級(jí)其他中斷全都靠后。5. 圖像顯示與上位機(jī)調(diào)試5.1 串口上位機(jī)顯示方案最直觀的調(diào)試方法是把采集到的圖像數(shù)據(jù)通過串口發(fā)到PC再用上位機(jī)軟件顯示。我這里用的是USB轉(zhuǎn)TTL串口波特率設(shè)置460800幀頭加數(shù)據(jù)再加校驗(yàn)的私有協(xié)議。協(xié)議格式可以自定義我用的比較簡(jiǎn)單先發(fā)兩個(gè)字節(jié)幀頭0xAA 0x55再發(fā)一個(gè)字節(jié)數(shù)據(jù)類型0x01表示RGB565然后發(fā)兩個(gè)字節(jié)寬度、兩個(gè)字節(jié)高度最后是圖像數(shù)據(jù)區(qū)結(jié)尾加一個(gè)字節(jié)累加和校驗(yàn)。上位機(jī)只要識(shí)別到幀頭按固定長(zhǎng)度讀取并解析即可。發(fā)送數(shù)據(jù)時(shí)建議用DMA把緩沖區(qū)指針給串口DMA后CPU立刻去準(zhǔn)備下一幀提高吞吐量。注意必須在幀采集完成后才能啟動(dòng)DMA發(fā)送否則數(shù)據(jù)還沒采完就被發(fā)出去畫面會(huì)缺一半。5.2 RGB565到RGB888的轉(zhuǎn)換很多上位機(jī)顯示控件不支持RGB565需要轉(zhuǎn)成RGB888再顯示。轉(zhuǎn)換公式不復(fù)雜uint8_t r (rgb565 11) 0x1F; uint8_t g (rgb565 5) 0x3F; uint8_t b rgb565 0x1F; uint8_t r8 (r 3) | (r 2); uint8_t g8 (g 2) | (g 4); uint8_t b8 (b 3) | (b 2);這里有一個(gè)非常典型的坑如果顯示出來顏色明顯偏藍(lán)或者偏紅先檢查一下數(shù)據(jù)高低字節(jié)是不是反了。OV7670輸出的RGB565一字節(jié)是綠色和紅色高位混合一字節(jié)是藍(lán)色和綠色低位混合有些模塊會(huì)先發(fā)低字節(jié)再發(fā)高字節(jié)。代碼里如果直接按數(shù)組順序拼顏色通道就對(duì)不上。我調(diào)試時(shí)把兩個(gè)字節(jié)交換一下畫面顏色立刻就正常了。5.3 用SPI屏幕直接顯示的替代方案如果你手頭沒有上位機(jī)也可以把F103計(jì)算好的圖像數(shù)據(jù)直接發(fā)給SPI接口的TFT液晶屏。比如常見的1.8寸ST7735或者2.4寸ILI9341RGB565格式直接喂給屏幕驅(qū)動(dòng)即可。不過要注意屏幕刷新速度有限而且同時(shí)采集攝像頭和刷屏?xí)屨糃PU。我的做法是雙緩沖一塊緩沖區(qū)給攝像頭往里寫數(shù)據(jù)另一塊緩沖區(qū)給屏幕驅(qū)動(dòng)往外發(fā)數(shù)據(jù)采完一幀后交換指針。這種方式避免了一個(gè)緩沖區(qū)邊讀邊寫造成的撕裂感。SPI刷一整屏QQVGA圖像在F103上大概需要幾十毫秒如果幀率不高完全夠用。如果發(fā)現(xiàn)刷屏花屏優(yōu)先檢查SPI時(shí)鐘極性、相位和屏幕初始化代碼再檢查DMA配置。6. 常見問題排查與經(jīng)驗(yàn)總結(jié)6.1 故障現(xiàn)象速查表我在調(diào)試過程中一共遇到過下面這些典型問題整理成表格方便大家對(duì)照排查現(xiàn)象可能原因排查方法讀不到攝像頭IDSIO_C/SIO_D接線錯(cuò)誤或未上拉檢查接線量上拉電阻確認(rèn)設(shè)備地址0x42/0x43上位機(jī)完全無圖像串口參數(shù)不對(duì)或者USB轉(zhuǎn)TTL驅(qū)動(dòng)異常先自發(fā)自收測(cè)試串口再檢查幀頭協(xié)議圖像全黑攝像頭初始化失敗輸出全是0重新讀ID確認(rèn)配置檢查PWDN是否接地圖像全白VSYNC相位判斷反了數(shù)據(jù)采集窗口不對(duì)用示波器量VSYNC波形確認(rèn)下降沿位置圖像花屏PCLK中斷響應(yīng)不及時(shí)丟像素降低分辨率、降低幀率、關(guān)閉其他中斷顏色偏色RGB565高低字節(jié)順序反了交換兩個(gè)字節(jié)再顯示畫面上下顛倒寄存器鏡像翻轉(zhuǎn)參數(shù)不對(duì)配置0x0C寄存器VFLIP/HMIRROR屏幕顯示條紋電源紋波過大加10uF和0.1uF電容必要時(shí)加磁珠6.2 調(diào)試順序和工具使用建議調(diào)試這類項(xiàng)目強(qiáng)烈建議按下面的順序一步步驗(yàn)證不要一上來就盯著圖像看第一步確認(rèn)串口通信鏈路正常。寫一個(gè)最簡(jiǎn)單的循環(huán)發(fā)送程序電腦上能看到遞增的數(shù)據(jù)再繼續(xù)。第二步讀攝像頭ID。能讀到0x76/0x73SCCB這塊就算通過了。第三步用示波器量VSYNC、HREF、PCLK三個(gè)引腳的波形。PCLK有脈沖、VSYNC能按幀率變化說明攝像頭已經(jīng)在正常輸出了。第四步再跑圖像采集代碼看上位機(jī)畫面。沒有示波器的話可以用邏輯分析儀或者用一個(gè)笨辦法寫個(gè)程序統(tǒng)計(jì)1秒內(nèi)PCLK中斷次數(shù)如果次數(shù)基本穩(wěn)定說明時(shí)序在跑只是數(shù)據(jù)拼接的問題。比盲目改寄存器高效太多。6.3 關(guān)于寄存器初始化數(shù)組的一點(diǎn)心得網(wǎng)上流傳的OV7670初始化數(shù)組有很多版本參數(shù)略有差異但只要按RGB565、QQVGA、低幀率這三個(gè)目標(biāo)組合出來的都能用。我建議別貪心一上來就上VGA分辨率F103的GPIO中斷方案在VGA分辨率下基本很難穩(wěn)定老老實(shí)實(shí)先用QQVGA跑通全流程再去嘗試更高分辨率。另外不同批次的OV7670同一組寄存器配置出來的畫質(zhì)會(huì)有細(xì)微差別主要體現(xiàn)在亮度和色偏上。你可以把初始化數(shù)組里的自動(dòng)曝光、自動(dòng)白平衡相關(guān)寄存器保留讓攝像頭自己調(diào)節(jié)如果畫面過暗再手動(dòng)增大0x10AECH曝光值一次加幾格觀察變化。6.4 后續(xù)還能怎么擴(kuò)展圖像數(shù)據(jù)采集這種事一旦跑通了能玩的方向就很多。你可以把采集到的圖像做簡(jiǎn)單的二值化處理配合顏色識(shí)別算法做個(gè)小車巡線或者追球機(jī)器人也可以把圖像壓縮成JPEG之后存SD卡做成簡(jiǎn)易拍照設(shè)備。F103性能雖不強(qiáng)但做這些基礎(chǔ)圖像處理還是綽綽有余的。我個(gè)人折騰下來最大的體會(huì)是無FIFO攝像頭在F103上能跑通的關(guān)鍵不是代碼技巧而是對(duì)時(shí)序的理解和對(duì)工具的使用。先把示波器或者邏輯分析儀用熟把VSYNC、HREF、PCLK的波形看懂你就已經(jīng)贏了一半。剩下的一半就是耐心地一幀一幀調(diào)。等項(xiàng)目跑通第一次看著屏幕上刷出清晰圖像的那一刻相信我你會(huì)覺得前面踩的坑全都值了。