STM32F4_V1.25.0韌體庫應用於STM32F407ZGT6(二)- 除錯攝像頭OV3640的IIC通路
1、軟體、硬體
接著上一篇部落格的工程基礎
STM32F4_V1.25.0韌體庫應用於STM32F407ZGT6(一)
2、硬體連線
嘮叨幾句,購買了一個在卡片電腦上專用的攝像頭模組,排針和我的板子camara卡槽匹配不上,只能飛線。長下面這個樣子,CAMERA是卡槽介面,背面有個CAMERB是插針。
商家只管賣,連個原理圖都沒有,板子上引腳名稱也沒有,詢問商家的回覆是這攝像頭為某某板子專用,他們也沒有原理圖。網上查了那些板子camera介面的原理圖,才知道攝像頭上的三角符號一端要板子上三角符號對應。好吧,原理圖上也沒有標註三角符號那一端是地線還是排線頂端。
好不容易找到在Android系統上使用過該模組的人,給出的說明書如下。
2.1、CAMERA介面圖
下圖EINT19其實就是PWDN引腳
對應模組來看,CAMERA介面應該是下面這樣的,和上圖左右對應匹配
2.2、CAMERB介面圖
看模組背面的CAMERB介面,實際上插針對應左右兩邊和上圖相反。只要保證CAMERA介面認識正確,用萬用表探CAMERA和CAMERB即可找到引腳。
為啥這麼設計呢?帶著疑問,我去看板子的硬體,也是這樣的,板子上卡槽是按原理圖的左右順序預留的,那麼插針只有左右順序對調才能匹配板子。或者板子做預留的卡槽和攝像頭插針左右相反,總之這是需要留意的點。
用公對公的杜邦線一個一個和板子引腳連線,這裡先測試IIC通路,把5V、3.3V、GND、RST、PWDN、I2C_SCL、I2C_SDA對應連線到板子上。
板子camera介面原理圖如下:
3、程式碼實現
OV3640的IIC裝置地址是0x78,寫資料時是0x78,讀資料時是0x79。STM32的i2c驅動對於裝置地址是直接傳入0x78,根據讀寫再與或讀寫位(無需左移)。
從標準IIC波形上看攝像頭的資料,裝置地址的高7位是0X3C,那種需要左移或上讀寫位的驅動,傳入的是0X3C,左移或上讀寫位即為0x78(寫)、0x79(讀)。
3.1、i2c.h檔案
#ifndef __BSP_I2C_H__
#define __BSP_I2C_H__
/****************************** Includes *****************************/
#include "stm32f4xx.h"
#include "stm32f4xx_hal.h"
#include "bsp_debug_usart.h"
/****************************** Defines *******************************/
#define OV3640_DEVICE_ADDRESS 0x78 //0x78 & 1 = 0x78 寫
//0x78 | 1 = 0x79 讀
/*引腳定義*/
#define SENSORS_I2C_SCL_GPIO_PORT GPIOB
#define SENSORS_I2C_SCL_GPIO_CLK_ENABLE() __GPIOB_CLK_ENABLE()
#define SENSORS_I2C_SCL_GPIO_PIN GPIO_PIN_8
#define SENSORS_I2C_SDA_GPIO_PORT GPIOB
#define SENSORS_I2C_SDA_GPIO_CLK_ENABLE() __GPIOB_CLK_ENABLE()
#define SENSORS_I2C_SDA_GPIO_PIN GPIO_PIN_9
#define SENSORS_I2C_AF GPIO_AF4_I2C1
#define SENSORS_I2C I2C1
#define SENSORS_I2C_RCC_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE()
#define SENSORS_I2C_FORCE_RESET() __HAL_RCC_I2C1_FORCE_RESET()
#define SENSORS_I2C_RELEASE_RESET() __HAL_RCC_I2C1_RELEASE_RESET()
void I2CMaster_Init(void);
uint8_t OV3640_WriteReg(uint16_t Addr, uint8_t Data);
uint8_t OV3640_ReadReg(uint16_t Addr);
#endif // __BSP_I2C_H__
3.2、i2c.c檔案
OV3640的暫存器地址是16位,所以直接呼叫 HAL_I2C_Mem_Write、HAL_I2C_Mem_Read函式操作暫存器,第4個引數傳入I2C_MEMADD_SIZE_16BIT即可。
#include "bsp_i2c.h"
#include <stdio.h>
I2C_HandleTypeDef I2C_Handle;
/******************************* Function ************************************/
void I2CMaster_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 使能I2Cx時鐘 */
SENSORS_I2C_RCC_CLK_ENABLE();
/* 使能I2C GPIO 時鐘 */
SENSORS_I2C_SCL_GPIO_CLK_ENABLE();
SENSORS_I2C_SDA_GPIO_CLK_ENABLE();
/* 配置I2Cx引腳: SCL ----------------------------------------*/
GPIO_InitStructure.Pin = SENSORS_I2C_SCL_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = SENSORS_I2C_AF;
HAL_GPIO_Init(SENSORS_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
/* 配置I2Cx引腳: SDA ----------------------------------------*/
GPIO_InitStructure.Pin = SENSORS_I2C_SDA_GPIO_PIN;
HAL_GPIO_Init(SENSORS_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
if(HAL_I2C_GetState(&I2C_Handle) == HAL_I2C_STATE_RESET)
{
/* 強制復位I2C外設時鐘 */
SENSORS_I2C_FORCE_RESET();
/* 釋放I2C外設時鐘復位 */
SENSORS_I2C_RELEASE_RESET();
/* I2C 配置 */
I2C_Handle.Instance = SENSORS_I2C;
I2C_Handle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
I2C_Handle.Init.ClockSpeed = 40000; //40K,低速率
I2C_Handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
I2C_Handle.Init.DutyCycle = I2C_DUTYCYCLE_2;
I2C_Handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
I2C_Handle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
I2C_Handle.Init.OwnAddress1 = 0xFE ;
I2C_Handle.Init.OwnAddress2 = 0;
/* 初始化I2C */
HAL_I2C_Init(&I2C_Handle);
}
}
/**
* @brief Manages error callback by re-initializing I2C.
* @param Addr: I2C Address
* @retval None
*/
static void I2Cx_Error(void)
{
/* 恢復I2C暫存器為預設值 */
HAL_I2C_DeInit(&I2C_Handle);
/* 重新初始化I2C外設 */
I2CMaster_Init();
}
/**
* @brief 寫一位元組資料到OV3640暫存器
* @param Addr: OV3640 的暫存器地址
* @param Data: 要寫入的資料
* @retval 返回0表示寫入正常,0xFF表示錯誤
*/
uint8_t OV3640_WriteReg(uint16_t Addr, uint8_t Data)
{
HAL_StatusTypeDef status = HAL_OK;
status = HAL_I2C_Mem_Write(&I2C_Handle, OV3640_DEVICE_ADDRESS, (uint16_t)Addr, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&Data, 1, 1000);
/* Check the communication status */
if(status != HAL_OK)
{
/* Re-Initiaize the I2C Bus */
printf("ERR write status[%d]\r\n",status);
I2Cx_Error();
}
return status;
}
/**
* @brief 從OV3640暫存器中讀取一個位元組的資料
* @param Addr: 暫存器地址ַ
* @retval 返回讀取得的資料
*/
uint8_t OV3640_ReadReg(uint16_t Addr)
{
uint8_t Data = 0;
HAL_StatusTypeDef status = HAL_OK;
status = HAL_I2C_Mem_Read(&I2C_Handle, OV3640_DEVICE_ADDRESS, (uint16_t)Addr, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&Data, 1, 1000);
/* Check the communication status */
if(status != HAL_OK)
{
/* I2C error occurred */
printf("ERR read status[%d]\r\n",status);
I2Cx_Error();
}
/* return the read data */
return Data;
}
3.3、ov3640.h檔案
定義了攝像頭所需的所有引腳
#include "stm32f4xx.h"
#include "stm32f4xx_hal.h"
// VSYNC
#define DCMI_VSYNC_GPIO_PORT GPIOB
#define DCMI_VSYNC_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define DCMI_VSYNC_GPIO_PIN GPIO_PIN_7
#define DCMI_VSYNC_AF GPIO_AF13_DCMI
// HSYNC
#define DCMI_HSYNC_GPIO_PORT GPIOA
#define DCMI_HSYNC_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define DCMI_HSYNC_GPIO_PIN GPIO_PIN_4
#define DCMI_HSYNC_AF GPIO_AF13_DCMI
// PIXCLK
#define DCMI_PIXCLK_GPIO_PORT GPIOA
#define DCMI_PIXCLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define DCMI_PIXCLK_GPIO_PIN GPIO_PIN_6
#define DCMI_PIXCLK_AF GPIO_AF13_DCMI
// PWDN
#define DCMI_PWDN_GPIO_PORT GPIOC
#define DCMI_PWDN_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
#define DCMI_PWDN_GPIO_PIN GPIO_PIN_0
// RST
#define DCMI_RST_GPIO_PORT GPIOF
#define DCMI_RST_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE()
#define DCMI_RST_GPIO_PIN GPIO_PIN_10
// D0-D7
#define DCMI_D0_GPIO_PORT GPIOC
#define DCMI_D0_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
#define DCMI_D0_GPIO_PIN GPIO_PIN_6
#define DCMI_D0_AF GPIO_AF13_DCMI
#define DCMI_D1_GPIO_PORT GPIOC
#define DCMI_D1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
#define DCMI_D1_GPIO_PIN GPIO_PIN_7
#define DCMI_D1_AF GPIO_AF13_DCMI
#define DCMI_D2_GPIO_PORT GPIOC
#define DCMI_D2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
#define DCMI_D2_GPIO_PIN GPIO_PIN_8
#define DCMI_D2_AF GPIO_AF13_DCMI
#define DCMI_D3_GPIO_PORT GPIOC
#define DCMI_D3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
#define DCMI_D3_GPIO_PIN GPIO_PIN_9
#define DCMI_D3_AF GPIO_AF13_DCMI
#define DCMI_D4_GPIO_PORT GPIOE
#define DCMI_D4_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
#define DCMI_D4_GPIO_PIN GPIO_PIN_4
#define DCMI_D4_AF GPIO_AF13_DCMI
#define DCMI_D5_GPIO_PORT GPIOB
#define DCMI_D5_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define DCMI_D5_GPIO_PIN GPIO_PIN_6
#define DCMI_D5_AF GPIO_AF13_DCMI
#define DCMI_D6_GPIO_PORT GPIOE
#define DCMI_D6_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
#define DCMI_D6_GPIO_PIN GPIO_PIN_5
#define DCMI_D6_AF GPIO_AF13_DCMI
#define DCMI_D7_GPIO_PORT GPIOE
#define DCMI_D7_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
#define DCMI_D7_GPIO_PIN GPIO_PIN_6
#define DCMI_D7_AF GPIO_AF13_DCMI
#define OV3640_PIDH 0x300A //產品ID高8位
#define OV3640_PIDL 0x300B //產品ID低8位
//產品ID結構體
typedef struct
{
uint8_t PIDH;
uint8_t PIDL;
}OV3640_IDTypeDef;
3.4、ov3640.c檔案
初始化控制攝像頭使用的GPIO
/**
* @brief 初始化控制攝像頭使用的GPIO
* @param None
* @retval None
*/
void OV3640_HW_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/***DCMI引腳配置***/
/* 使能DCMI時鐘 */
DCMI_RST_GPIO_CLK_ENABLE();
DCMI_PWDN_GPIO_CLK_ENABLE();
DCMI_VSYNC_GPIO_CLK_ENABLE();
DCMI_HSYNC_GPIO_CLK_ENABLE();
DCMI_PIXCLK_GPIO_CLK_ENABLE();
DCMI_D0_GPIO_CLK_ENABLE();
DCMI_D1_GPIO_CLK_ENABLE();
DCMI_D2_GPIO_CLK_ENABLE();
DCMI_D3_GPIO_CLK_ENABLE();
DCMI_D4_GPIO_CLK_ENABLE();
DCMI_D5_GPIO_CLK_ENABLE();
DCMI_D6_GPIO_CLK_ENABLE();
DCMI_D7_GPIO_CLK_ENABLE();
/*控制/同步訊號線*/
GPIO_InitStructure.Pin = DCMI_VSYNC_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.Pull = GPIO_PULLUP ;
GPIO_InitStructure.Alternate = DCMI_VSYNC_AF;
HAL_GPIO_Init(DCMI_VSYNC_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_HSYNC_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_HSYNC_AF;
HAL_GPIO_Init(DCMI_HSYNC_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_PIXCLK_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_PIXCLK_AF;
HAL_GPIO_Init(DCMI_PIXCLK_GPIO_PORT, &GPIO_InitStructure);
/*資料訊號*/
GPIO_InitStructure.Pin = DCMI_D0_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D0_AF;
HAL_GPIO_Init(DCMI_D0_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_D1_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D1_AF;
HAL_GPIO_Init(DCMI_D1_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_D2_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D2_AF;
HAL_GPIO_Init(DCMI_D2_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_D3_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D3_AF;
HAL_GPIO_Init(DCMI_D3_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_D4_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D4_AF;
HAL_GPIO_Init(DCMI_D4_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_D5_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D5_AF;
HAL_GPIO_Init(DCMI_D5_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_D6_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D6_AF;
HAL_GPIO_Init(DCMI_D6_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_D7_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D7_AF;
HAL_GPIO_Init(DCMI_D7_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.Pull = GPIO_PULLUP ;
GPIO_InitStructure.Pin = DCMI_PWDN_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(DCMI_PWDN_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_RST_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(DCMI_RST_GPIO_PORT, &GPIO_InitStructure);
/*PWDN引腳,高電平關閉電源,低電平供電,GPIO_PIN_RESET是0*/
HAL_GPIO_WritePin(DCMI_PWDN_GPIO_PORT,DCMI_PWDN_GPIO_PIN,GPIO_PIN_RESET);
}
/**
* @brief 讀取攝像頭的ID
* @param OV3640ID:儲存ID的結構體
* @retval None
*/
void OV3640_ReadID(OV3640_IDTypeDef *OV3640ID)
{
/*讀取寄存晶片ID*/
OV3640ID->PIDH = OV3640_ReadReg(OV3640_PIDH);
OV3640ID->PIDL = OV3640_ReadReg(OV3640_PIDL);
}
3.5、main函式
int main(void)
{
HAL_Init();
/* Configure the system clock to 168 MHz */
SystemClock_Config();
DEBUG_USART_Config();
HAL_Delay(1000);
//camera ID 結構體初始化
OV3640_IDTypeDef OV3640_Camera_ID;
//I2C初始化
I2CMaster_Init();
//攝像頭硬體初始化
OV3640_HW_Init();
HAL_Delay(100);
//讀取攝像頭ID
OV3640_ReadID(&OV3640_Camera_ID);
printf("ID = %x%x\r\n",OV3640_Camera_ID.PIDH ,OV3640_Camera_ID.PIDL);
if(OV3640_Camera_ID.PIDH == 0x36)
{
printf("Right\r\n");
while(1);
}
else
{
printf("ERR\r\n");
while(1);
}
}
4、除錯通路
4.1、抓取IIC波形失敗
用邏輯分析儀抓取波形,發現在裝置地址0x78後,收到攝像頭回復的NACK,隨後跟著Stop。懷疑是IIC驅動不對,因為有的OV攝像頭預設回覆的是NACK,而STM32F4的V1.25.0驅動在收到NACK後會報錯退出。OV家的攝像頭,使用SCCB協議,類似IIC,但和IIC還是有點區別,對第9位不關心。
查閱資料,這篇部落格給出瞭解釋,OV3640會回覆ACK,所以不是驅動的問題。
Wince6.0 上增加ov3640攝像頭
4.2、查詢原因,解決問題
可能壓根攝像頭就沒有工作,因為程式起來後,攝像頭一點溫度都沒有,查閱資料發現別的模組外部都有一個24M的晶振,而我購買這一塊攝像頭沒有外部時鐘,草率了以為有來著,原來晶振是長那個樣子。
好吧!查閱資料,尋求幫助,瞭解到攝像頭的時鐘可以由外部晶振提供,或者由主控晶片提供,這裡使用PA8引腳(MCO1)直接將板子外部晶振的時鐘輸出給攝像頭。
我手上的板子外部晶振是25M,剛好符合攝像頭工作時鐘(6-27M)
void ov3640_input_clk()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_PIN_8;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
//時鐘源輸出到MCO1引腳(PA8),選擇HSE時鐘作為MCO1源,1分頻,那麼輸出25M時鐘給攝像頭
HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE,RCC_MCODIV_1);
}
用示波器探測PA8引腳,可以觀察到25M穩定時鐘輸出,將PA8引腳接到攝像頭的CAMCLK腳
提供時鐘後,攝像頭髮燙了,但是IIC依然沒有資料,害怕因為短路攝像頭才發燙。
在同事幫助下,看晶片手冊文件,上電要滿足一定的時序,攝像頭才會正常工作。對於硬體小白的我來說,以為晶片只要供電就能工作,沒想到還有一定的時序要求。
(哎呦喂,一定要仔細看手冊啊!!!!!!!)
如果1.8V用於I/O電源,則首選使用內部DVDD。 如果2.8V用於I/O電源,由於內部DVDD調節器的高壓下降,存在潛在的熱問題。 因此,對於2.8V的I/O電源,OmniVision建議使用外部DVDD源。
用萬用表探測攝像頭模組的電壓,供電是5V,電源轉換後DOVDD是2.79V,DVDD是1.53V,AVDD是2.79V,這也分不清該用啥電源啊?
隨便試試哪種時序吧!
這個上電後,需要延時5ms再將PWDN腳拉低,加了延時也沒有效果,依然IIC通訊沒有成功。
看到一篇部落格,說OV5640和OV3640差不多,所以參照OV5640的初始化流程,發現OV5640的上電時序還對復位腳有操作。
檢視OV5640的datasheet,無論外部電源還是內部電源,時序都差不多,在PWDN拉低後還有拉高RESET腳才能操作IIC,且保證時鐘穩定輸入。
修改程式碼
void OV3640_HW_Init(void)
{
/***省略程式碼部分***/
/*POWER 低*/
HAL_GPIO_WritePin(DCMI_PWDN_GPIO_PORT,DCMI_PWDN_GPIO_PIN,(GPIO_PinState)0);
/*RESET 高*/
HAL_GPIO_WritePin(DCMI_RST_GPIO_PORT,DCMI_RST_GPIO_PIN,(GPIO_PinState)1);
}
再次抓波形,成功讀取到OV3640的產品ID,我的天哪!終於可以了,忙活了幾天。
該產品ID和0V5640這些不一樣,並不是型號ID,而是0X364C
5、總結
5.1、攝像頭要麼使用外部晶振時鐘,要麼使用主控板提供時鐘,必須有時鐘才能工作。
5.2、一定要仔細看手冊,這裡寫了要把復位腳拉高後才能操作IIC,只看圖的我忽略了那句話。
5.3、遇到問題,冷靜分析。
別急,別急,別急
查硬體、查軟體、查文件
相關文章
- 搭建一個攝像頭應用程式 應用程式內部攝像頭
- DIY工程寶,網路診斷,攝像頭除錯除錯
- 攝像頭 ISP 除錯的入門之談(經驗總結)除錯
- UVC 攝像頭在 RK3399 上的應用
- 攝像頭操作指南
- 【音影片】攝像頭
- Android提供的攝像頭拍照Android
- ToDesk勾上攝像頭會看到我嗎?如何關閉攝像頭
- 基於人工智慧的摔倒識別攝像頭人工智慧
- iOS應用自動撥打電話,開啟攝像頭缺陷iOS
- 啟明雲端ESP32-S2 攝像頭 WIFI方案應用於智慧貓眼WiFi
- 如何在SAP UI5應用裡新增使用攝像頭拍照的功能UI
- android 開啟攝像頭Android
- android opencv 前置攝像頭AndroidOpenCV
- Android呼叫攝像頭拍照Android
- .NET 攝像頭採集
- [譯]Android的多攝像頭支援Android
- [譯] Android 的多攝像頭支援Android
- Win10攝像頭如何開啟_WIN10攝像頭在哪裡Win10
- JavaCV的攝像頭實戰之二:本地視窗預覽Java
- jQuery webcam plugin呼叫攝像頭jQueryWebPlugin
- 如何使用PYTHON操作攝像頭Python
- 某CCTV攝像頭漏洞分析
- 安卓呼叫攝像頭拍照安卓
- 大華攝像頭 ZLMediaKit JavaJava
- WebRTC開啟本地攝像頭Web
- 人工智慧"眼睛"——攝像頭人工智慧
- 筆記本攝像頭怎麼開啟 筆記本設定攝像頭教程筆記
- Win10系統如何開啟網路攝像頭應用設定Win10
- 用樹莓派USB攝像頭做個監控樹莓派
- windows10攝像頭怎麼開啟_window10怎麼開啟攝像頭的方法Windows
- win10如何開啟電腦攝像頭錄影_win10用電腦自帶攝像頭錄影的方法Win10
- win10攝像裝置被佔用怎麼辦_win10攝像頭被佔用的解決方法Win10
- Web呼叫網路攝像頭及各類錯誤處理Web
- win10 怎麼檢測攝像頭_win10怎麼設定攝像頭Win10
- Win10專業版攝像頭在哪裡開啟 windows10攝像頭開啟的方法Win10Windows
- 基於 GD 庫生成圓形頭像
- html5呼叫攝像頭功能HTML