-
使用单片机采集130W串口摄像头的方法
2020-08-27 20:06:51本文介绍使用单片机控制采集130W像素摄像头的方法。本章使用的摄像头为青青子木ZM系列,被动型130W像素,防雨广角型摄像头 -
基于单片机的串口摄像头模块的读写C语言源程序.rar
2011-12-09 11:27:20基于单片机的串口摄像头模块的读写C语言源程序 -
M32S 串口摄像头的技术应用
2020-10-28 13:39:02本串口摄像机,采用《标准串口摄像机协议》(见附录),并提供单片机C语言读取图像的程序例程及VC6.0的主要函数例程,以方便用户移值,快速上手;提供PC端测试程序。 产品特点 1、具有较低照度(月光级、星光级、...M32S 串口摄像机普遍应用于水利、油田、电力、环保、森林防火、边境安全、野外监测、仓库防盗防火等;具有超低照度,高可靠性的特点。
本串口摄像机,采用《标准串口摄像机协议》(见附录),并提供单片机C语言读取图像的程序例程及VC6.0的主要函数例程,以方便用户移值,快速上手;提供PC端测试程序。产品特点
1、具有较低照度(月光级、星光级、星光+),在光线较暗或晚上的环境,仍然拍照得较为理想的效果;城市环境无需补光,夜视距离高达2000米;
2、通讯端口具有防浪涌保护,提高产品可靠性;
3、宽电压电源输入9~28V;
4、电源防反接保护;
-
平时杂技,串口摄像头+portmon.exe
2013-05-31 06:18:52PORTMON.EXE 你个可以监视已经被别的软件打开的串口数据分析软件。 如果你希望捕获自己串口程序发送的数据以及问题。 如果你希望分析别的软件利用串口发送的数据命令格式。...串口摄像头: typePORTMON.EXE 你个可以监视已经被别的软件打开的串口数据分析软件。
如果你希望捕获自己串口程序发送的数据以及问题。
如果你希望分析别的软件利用串口发送的数据命令格式。这个工具可以帮你。SSCOM.EXE 串口发送和调试工具,做单片机/嵌入式系统的应该要知道,除非你有更好的。当然WINDOWS带的超级终端也是不错的。
串口摄像头:
typedef struct{
unsigned char Len;
unsigned char Buff[10];
}CMD_BUFFER;
CMD_BUFFER Cmd;
bool SendCommand(void)
{
unsigned char CmdHeader[4] = {0x55, 0x41, 0x52, 0x54}; //'UART'
UART_SendData(CmdHeader,4);
UART_SendData(Cmd.Buff,Cmd.Len);
UART_RdReady();
return true;
}
void ClrCmdBuff(void)
{
int i;
for(i=0;i<7;i++) Cmd.Buff[i]=0x0;
}
//停止更新Frame buffer
void CmdStopFBuf(void)
{
ClrCmdBuff();
Cmd.Buff[0] = 0xcA;
Cmd.Len = 7;
SendCommand();
}
//启动更新Frame buffer
void CmdResumeFBuf(void)
{
ClrCmdBuff();
Cmd.Buff[0] = 0xCB;
Cmd.Len = 7;
SendCommand();
//获取Frame buffer大小
long CmdGetFBufLen(void)
{
long dwFrameLen;
ClrCmdBuff();
Cmd.Buff[0] = 0xc9;
Cmd.Len = 7;
SendCommand();
if(UART_GetData(RecBuff,3))
{
dwFrameLen = ( ((DWORD)(RecBuff[0]) & 0xFF) << 16 ) +
( ((DWORD)(RecBuff[1]) & 0xFF) << 8 ) +
( ((DWORD)(RecBuff[2]) & 0xFF) );
return dwFrameLen;
}
else
return false;
}
//读取Frame buffer指定偏移量开始的指定大小,如果您的系统RAM足够大,也可以一次读取完。
bool CmdReadFBuf(long offset, unsigned int rd_len)
{
Cmd.Buff[0] = 0xc7;
Cmd.Buff[1] = (BYTE)( offset >> 16 );
Cmd.Buff[2] = (BYTE)( offset >> 8 );
Cmd.Buff[3] = (BYTE)( offset );
Cmd.Buff[4] = (BYTE)0x00;
Cmd.Buff[5] = (BYTE)( rd_len >> 8 );
Cmd.Buff[6] = (BYTE)( rd_len );
Cmd.Len = 7;
SendCommand();
if(UART_GetData(RecBuff,rd_len)==0)
return false;
return true;
}
功能介绍:
1. CMOS SENSOR,分辨率:VGA 640X480
2. 图像压缩格式:JPG, 通过串口数据通讯读取
3. 3种工作模式:实时图像模式、运动图像监测模式和省电模式
4. 通讯方式:RS232, RS488;最高波特率:115200
5. 视频复合(CVBS)信号输出:http://blog.sina.com.cn/ezant
-
摄像头+串口+上位机显示图像
2021-01-19 21:38:34使用stm32f103zet6单片机驱动摄像头,通过串口将图像实时传输到上位机进行显示,内含上位机和整个工程源码,实测可用 -
单片机之串口数据处理
2018-05-17 18:08:53例如:GPRS模块、GPS模块、语音模块、热敏微型打印机、串口摄像头等等。在与这些模块进行数据通信都离不开串口,而对于串口的操作,由于串口本身没有标准的通信协议,所以很难做到非常统一的操作过程。一般来说,...随着硬件系统的模块化发展,很多电子产品都做出模块并采用串口进行数据通信。例如:GPRS模块、GPS模块、语音模块、热敏微型打印机、串口摄像头等等。在与这些模块进行数据通信都离不开串口,而对于串口的操作,由于串口本身没有标准的通信协议,所以很难做到非常统一的操作过程。一般来说,不同的模块其有着特殊的通信协议,我们只能根据其协议进行数据解码。
虽然说串口没有标准协议,但是我们却可以把它们的相似部分提取出来,做成模块化的程序,方便代码的移植和理解。下面我们简单谈到串口数据的处理方法。。。。。
串口数据处理流程:
一般来说,串口数据的接收都是采用中断方式,中断中只复制把串口发送的数据放入数据缓冲区中。而发送一般都是采用查询方式比较方便。不管是与什么设备通信,这一点完全是一致的。所以,我们完全可以把这部分代码独立起来。
定义数据结构如下:
typedef struct
{
u16 WtCnt; // 写指针
u16 RdCnt;// 读指针
u16 BufLen;缓冲尺寸
u8 *RwBuf;// 读写缓冲} DF_RCV;
复制代码
对于这个结构来说非常简单,参数1是用于结束数据计数,参数2为处理数据计数,参数3为缓冲的大小,参数4为缓冲区指针,这里用指针是为了保证这个结构的独立,否则无法满足各种需求。实现函数:
初始化函数
本函数用于对串口结构体中的各种数据进行初始化。
/****************************************************************************- FunctionName : DFInit()
- Description : 初始化
- EntryParameter : None
- ReturnValue : None
****************************************************************************/
void DFInit(DF_RCV *pRcv)
{
u16 i;
pRcv->WtCnt = 0x0000;
pRcv->RdCnt = 0x0000;for (i=0; iBufLen; i++)
{
pRcv->RwBuf[i] = 0x00;
}
}
复制代码接收一字节数据
本函数用于把串口中断接收的数据放入数据缓冲区中,并且接收计数器加1.
/****************************************************************************- FunctionName : DFWriteByte()
- Description : 数据接收(接收中断调用)
- EntryParameter : None
- ReturnValue : None
****************************************************************************/
void DFWriteByte(u8 dat, DF_RCV *pRcv)
{
pRcv->RwBuf[pRcv->WtCnt] = dat; // 数据存入
if (++(pRcv->WtCnt) >= pRcv->BufLen) // 缓冲判断
{
pRcv->WtCnt = 0;
}
}
复制代码读取一字节数据
本函数用于从接收缓冲区中读取未处理的一字节数据,读计数器加1.
/****************************************************************************- FunctionName : DFReadByte()
- Description : 从接受缓冲中读取一字节数据
- EntryParameter : None
- ReturnValue : 返回读取数据
****************************************************************************/
u8 DFReadByte(DF_RCV *pRcv)
{
u8 val = 0x00;
val = pRcv->RwBuf[pRcv->RdCnt]; // 读取一字节
if (++(pRcv->RdCnt) >= pRcv->BufLen)
{
pRcv->RdCnt = 0; // 清零
}return val; // 返回数据
}
复制代码获取缓冲区中未处理数据的长度
本函数用于读取串口缓冲区中还未处理的数据的大小。
/****************************************************************************- FunctionName : DFGetLen()
- Description : 获取缓冲区中未读数据长度
- EntryParameter : None
- ReturnValue : 返回数据长度
****************************************************************************/
u16 DFGetLen(DF_RCV *pRcv)
{
return ((pRcv->WtCnt >= pRcv->RdCnt) ? ((pRcv->WtCnt - pRcv->RdCnt)) :
((pRcv->WtCnt + pRcv->BufLen) - pRcv->RdCnt));
}
复制代码
有了以上几个函数,串口的处理就非常简单了。这几个函数可以应用到任何串口中,也可以应用到任务微处理器上,一致非常简单,应用也非常方便。下面我们说说实际的应用。
这部分代码为应用代码
为了保证数据的相对独立和模块化,下面代码将写入应用代码中,和上面的程序不能放在相同的文件中。
数据定义
首先需要定义一个缓冲区,这个缓冲区的大小根据实际应用定义,其大小一般为数据帧的最大值的2倍。之后需要定义一个DF_RCV数据,在这个数据中需要初始化这个结构图的参数。特别需要注意,缓冲的大小,和缓冲区指针赋值。
u8 AU_Buf[AU_BUF_ZISE] = {0};
DF_RCV AU_Rvc = {0, 0, AU_BUF_ZISE, AU_Buf};
复制代码编写数据接收函数
本函数把串口数据放入缓冲区中,此函数必须在串口中断中调用。
/****************************************************************************- FunctionName : AURcvDat()
- Description : 串口数据接收(串口中断服务调用)
- EntryParameter : None
- ReturnValue : None
****************************************************************************/
void AURcvDat(u8 dat)
{
DFWriteByte(dat, &AU_Rvc);
}
复制代码
数据处理函数
本函数判断缓冲区中是否有数据,如果有,逐个读取并处理。
/****************************************************************************- FunctionName : AUTaskCtrl()
- Description : 通信数据处理
- EntryParameter : None
- ReturnValue : None
****************************************************************************/
void AUTaskCtrl(void)
{
u8 tmpDat;
u16 i, len = 0;
static u8 sendMark = 0;
len = DFGetLen(&AU_Rvc); // 获取未读数据长度
for (i=0; i < len; i++)
{
tmpDat = DFReadByte(&AU_Rvc); // 读一字节数据
AU_PrcRcvDat(tmpDat);
}
}
复制代码
函数AU_PrcRcvDat(tmpDat)是数据处理函数,首先是数据帧判断,如果是一帧数据,就进行相应操作,并把操作结果返回。了解了这个过程,串口的编程就变得非常简单。而且我们在读程序时,只要看懂一个串口处理过程,其他串口的程序就自然懂了,非常方便吧。
关键字:单片机 串口数据处理
编辑:什么鱼 引用地址:http://www.eeworld.com.cn/mcu/article_2016071427571.html -
VSwin32命令控制台与单片机串口数据传输
2017-08-11 00:37:54例程1:摄像头识别小圆,然后通过串口输出小圆的xy坐标。单片机可以直接接受,具体串口配置自己配置。 例程2:VSwin32命令控制台程序 调用串口,可以根据自己需要配置串口,完成windows与单片机的数据传输。可作为... -
【程序】STM32F103RE单片机利用外部中断和DMA获取OV2640摄像头拍摄的照片,并通过串口发送到电脑上
2018-03-14 20:08:54PC端程序:在port.txt里面写好串口号,然后运行Release里面的程序接收图像,该程序是用Visual Studio 2012编译的单片机端程序:dcmi_ov2640.h和dcmi_ov2640.c是从STM32F4官方标准库里面的OV2640 DCMI例程里面找到的...PC端程序:在port.txt里面写好串口号,然后运行Release里面的程序接收图像,该程序是用Visual Studio 2012编译的
单片机端程序:dcmi_ov2640.h和dcmi_ov2640.c是从STM32F4官方标准库里面的OV2640 DCMI例程里面找到的,经过了修改后移植到了STM32F1单片机上程序下载地址:https://pan.baidu.com/s/1zhG3V1egXW9NBl9Pu6Bekw
【开发板】
这个开发板上的摄像头自带了一个贴片与非门,HREF和PCLK进行与非后连接到单片机的PB9端口上。该摄像头上还自带有一个24MHz的晶振给OV2640提供时钟。
微雪(WaveShare)OV2640摄像头没有与非门和晶振。如果使用这种摄像头,那么就必须外接一个74HC00的与非门(1A接HREF,1B接PCLK,1Y接PB9,不用的输入端要接高电平,不用的输出端悬空),然后选择一个单片机的定时器输出比较通道(如TIM3_CH2),输出24MHz的时钟信号到摄像头的XCLK引脚上,给摄像头提供时钟。代码如下:
// 利用TIM3_CH2在PB5上为摄像头XCLK提供24MHz的时钟 void OV2640_EnableClock(void) { RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; AFIO->MAPR |= AFIO_MAPR_TIM3_REMAP_1; GPIOB->CRL = (GPIOB->CRL & 0xff0fffff) | 0xb00000; // PB5设为复用推挽输出 TIM3->ARR = 2; // 72MHz/(2+1)=24MHz TIM3->PSC = 0; // 不分频 TIM3->EGR = TIM_EGR_UG; TIM3->CCR2 = 1; // 决定占空比 TIM3->CCMR1 = TIM_CCMR1_OC2M; // PWM2模式 TIM3->CCER = TIM_CCER_CC2E; // 打开输出比较 TIM3->CR1 = TIM_CR1_CEN; // 打开定时器 }
以上这段代码在调用OV2640_Init前调用就可以了。微雪OV2640摄像头的SIOC、SIOD分别是I2C的SCL和SDA。D2~D9接到PC0~PC7上,RET和PWDN引脚可以悬空。不过RET引脚默认是没有接到摄像头上的。根据微雪OV2640摄像头的原理图,必须要将背面左边从下往上数第三个跳线(R2)用焊锡丝接通之后,才能使用RET引脚。此外,原理图上RET引脚还通过R3接了一个4.7kΩ电阻和104电容组成的上电复位电路。
接与非门可以方便DMA捕获数据,不受HREF的干扰。虽然OV2640的手册上说,将COM10寄存器的Bit[5]置1也可以实现与非门的功能,但是笔者试了一下不行,置1后PCLK引脚上就完全没有时钟信号输出了。
【拍摄的图像】
[1600x1200]
[800x600]
采集到的JPEG图像,前面几十字节内容一般都是固定不变的。比如开头四个字节通常为FFD8FFE0。根据这一点,可以检查采集过程中是否有字节丢失的情况。
【截图】
PC端程序运行结果:
采集到的图像:
【采集原理】
PB0(VSYNC)为图像的开始/结束信号。OV2640的时序规定,当HREF=1时PCLK出现上升沿可采集一次数据(一字节)。HREF和PCLK是通过一个与非门接到PB9上的。如图所示,只要与非门的输出端PB9出现下降沿就可以采集数据。PB9对应定时器4的输入捕获通道4,但该通道不能触发DMA请求,只有通道3可以,所以通过TIM_CCMR2_CC3S位的设置把TIM4_CH4映射到TIM4_CH3上。TIM_CCER_CC3P=1表示下降沿触发,然后将TIM_DIER_CC3DE置1就可以产生DMA请求了。每产生一次DMA请求,DMA就自动复制一次PC0~7上的1字节数据。
【程序】
[PC端程序:接收图像]
#include <stdio.h> #include <Windows.h> #include <Shlwapi.h> #pragma comment(lib, "Shlwapi.lib") char buffer[131072]; // 接收缓冲区 int buffer_size = 0; // 缓冲区已用空间 HANDLE hPort; // 打开的串口 int convert_data(char *data, int len); void save_file(const void *data, int len); // 对数据进行CRC校验, len包括CRC校验码的长度 int check_data(const void *data, int len) { DWORD crc = 0xffffffff; DWORD temp; int i, j; for (i = 0; i < len; i += 4) { if (i <= len - 8 || i == len - 4) temp = *(LPDWORD)((LPBYTE)data + i); else { temp = 0; memcpy(&temp, (LPBYTE)data + i, len - i - 4); i = len - 8; } crc ^= temp; for (j = 0; j < 32; j++) { if (crc & 0x80000000) crc = (crc << 1) ^ 0x4c11db7; else crc <<= 1; } } return crc == 0; } void convert_all(void) { char *pbuf = buffer; char *pend; int remaining_size = buffer_size; int section_size; while ((pend = (char *)memchr(pbuf, '\r', remaining_size)) != NULL) // 按换行符分割收到的数据 { section_size = (int)(pend - pbuf); // 数据大小 if (convert_data(pbuf, section_size)) // 如果数据内容为标准的十六进制字符串 { if (check_data(pbuf, section_size / 2)) // 检验CRC save_file(pbuf, section_size / 2 - 4); // 保存文件 } // 跳过\r\n, 继续往后搜索 remaining_size -= section_size + 2; if (remaining_size <= 0) // 若\r\n后没有数据了, 或只有\r, 或没有\r\n, 则停止搜索 break; pbuf = pend + 2; } if (remaining_size > 0) { // 未处理的数据前移, 为新收到的数据腾出空间 buffer_size = remaining_size; memmove(buffer, pbuf, remaining_size); } else buffer_size = 0; } // 将十六进制字符串格式转换成二进制数据 int convert_data(char *data, int len) { char ch; int i; for (i = 0; i < len; i++) { if (data[i] >= '0' && data[i] <= '9') ch = data[i] - '0'; else if (data[i] >= 'A' && data[i] <= 'F') ch = data[i] - 'A' + 10; else return 0; if (i % 2 == 0) data[i / 2] = ch << 4; else data[i / 2] |= ch; } return 1; } // 根据port.txt写的串口号打开串口 int open_comm(void) { char name[30]; COMMTIMEOUTS timeouts = {0}; DCB dcb = {0}; FILE *fp; int port_id; // 获取串口号 fopen_s(&fp, "port.txt", "r"); if (fp == NULL) { printf("Cannot open port.txt!\n"); return 0; } fscanf_s(fp, "COM%d", &port_id); sprintf_s(name, sizeof(name), "\\\\.\\COM%d", port_id); fclose(fp); // 打开串口 hPort = CreateFileA(name, GENERIC_READ | GENERIC_WRITE, (DWORD)NULL, NULL, OPEN_EXISTING, (DWORD)NULL, NULL); if (hPort == INVALID_HANDLE_VALUE) { printf("Cannot open COM%d!\n", port_id); return 0; } // 设置波特率 dcb.BaudRate = CBR_115200; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; dcb.DCBlength = sizeof(DCB); if (!SetCommState(hPort, &dcb)) { CloseHandle(hPort); printf("Cannot setup COM%d!\n", port_id); return 0; } // 设置超时时间 timeouts.ReadTotalTimeoutConstant = 20000; if (!SetCommTimeouts(hPort, &timeouts)) { CloseHandle(hPort); printf("Cannot setup the timeouts of COM%d!\n", port_id); return 0; } return 1; } void save_file(const void *data, int len) { char name[100]; FILE *fp; size_t folder_len; SYSTEMTIME systime; // 根据当前日期创建文件夹 GetLocalTime(&systime); sprintf_s(name, sizeof(name), "images/%d-%02d-%02d", systime.wYear, systime.wMonth, systime.wDay); if (!PathFileExistsA("images")) CreateDirectoryA("images", NULL); if (!PathFileExistsA(name)) CreateDirectoryA(name, NULL); // 根据当前时间生成文件名 folder_len = strlen(name); sprintf_s(name + folder_len, sizeof(name) - folder_len, "/%d-%02d-%02d_%02d%02d%02d_%d.jpg", systime.wYear, systime.wMonth, systime.wDay, systime.wHour, systime.wMinute, systime.wSecond, systime.wMilliseconds); folder_len++; // 保存图像数据 fopen_s(&fp, name, "wb"); if (fp == NULL) { printf("Cannot open file %s!\n", name + folder_len); return; } fwrite(data, 1, len, fp); fclose(fp); printf("%s (%d bytes)\n", name + folder_len, len); } int main(void) { DWORD size; if (!open_comm()) return 0; while (1) { WriteFile(hPort, "RECV", 4, &size, NULL); // 向串口发送数据 ReadFile(hPort, buffer + buffer_size, sizeof(buffer) - buffer_size, &size, NULL); // 从串口接收数据 if (size == 0) break; buffer_size += size; convert_all(); // 提取有效数据并保存 if (buffer_size == sizeof(buffer)) { printf("Buffer is full! Drop!\n"); buffer_size = 0; } } CloseHandle(hPort); return 0; }
[单片机程序:采集并通过串口发送图像]
main.c:(使用DMA方式采集——强烈推荐)
#include <stdio.h> #include <stm32f10x.h> #include <string.h> #include "dcmi_ov2640.h" #define STATE_START 0x01 #define STATE_STOP 0x02 uint8_t image_buffer[64480]; // 如果存储空间不够了, 把这个数组改小就行了 uint8_t image_state = 0; // 图像捕获状态 uint32_t image_size; // 图像的大小 // 精确延时n毫秒 void delay(uint16_t nms) { TIM6->ARR = 10 * nms - 1; TIM6->PSC = 7199; TIM6->EGR = TIM_EGR_UG; TIM6->SR &= ~TIM_SR_UIF; TIM6->CR1 = TIM_CR1_OPM | TIM_CR1_CEN; while ((TIM6->SR & TIM_SR_UIF) == 0); } // 向串口发送图像数据, 并在末尾附上CRC校验码 void dump(const void *data, uint32_t size) { uint8_t value; uint32_t i; uint32_t temp; CRC->CR = CRC_CR_RESET; for (i = 0; i < size; i++) { // 输出图像数据 value = *((uint8_t *)data + i); printf("%02X", value); // 每4字节计算一次CRC if ((i & 3) == 0) { if (i + 4 <= size) CRC->DR = *(uint32_t *)((uint8_t *)data + i); else { temp = 0; memcpy(&temp, (uint8_t *)data + i, size - i); CRC->DR = temp; } } } // 输出CRC temp = CRC->DR; temp = (temp >> 24) | ((temp >> 8) & 0xff00) | ((temp & 0xff00) << 8) | ((temp & 0x00ff) << 24); printf("%08X\n", temp); } int fputc(int ch, FILE *fp) { if (fp == stdout) { if (ch == '\n') { while ((USART1->SR & USART_SR_TXE) == 0); USART1->DR = '\r'; } while ((USART1->SR & USART_SR_TXE) == 0); USART1->DR = ch; } return ch; } int main(void) { RCC->AHBENR |= RCC_AHBENR_CRCEN | RCC_AHBENR_DMA1EN; RCC->APB1ENR = RCC_APB1ENR_I2C1EN | RCC_APB1ENR_TIM4EN | RCC_APB1ENR_TIM6EN; RCC->APB2ENR = RCC_APB2ENR_AFIOEN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_USART1EN; GPIOA->CRH = (GPIOA->CRH & 0xfffff00f) | 0x4b0; // 串口发送引脚PA9设为复用推挽输出 GPIOB->CRL = (GPIOB->CRL & 0x00ffffff) | 0xff000000; // PB6~7连接摄像头的I2C接口, 设为复用开漏输出 // PB0(VSYNC)和PB9(=~(HREF & PCLK))为浮空输入 // PC0~7是摄像头的8位数据引脚, 为浮空输入 USART1->BRR = SystemCoreClock / 115200; USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; I2C1->CR2 = 36; // APB1总线频率: 36MHz I2C1->CCR = 1800; // 速率: 10kHz (不可太高, 否则会导致Ack Failure; 计算公式为PCLK1/nf, 标准模式下n=2) I2C1->TRISE = 37; // 标准模式下为PCLK+1 I2C1->CR1 = I2C_CR1_PE; // 打开I2C总线 // 每当PB9上出现下降沿时, 就发送一次DMA请求, 采集GPIOC低8位的数据 TIM4->CCMR2 = TIM_CCMR2_CC3S_1; // PB9(TIM4_CH4)映射到TIM4_CH3上 TIM4->CCER = TIM_CCER_CC3P; // 下降沿触发 TIM4->CCER |= TIM_CCER_CC3E; // 打开TIM4_CH3的输入捕获 // 无需让定时器4开始计时, 这里只使用该定时器的一个输入捕获通道 // 配置TIM4_CH3对应的DMA通道 DMA1_Channel5->CMAR = (uint32_t)image_buffer; DMA1_Channel5->CPAR = (uint32_t)&GPIOC->IDR; DMA1_Channel5->CNDTR = sizeof(image_buffer); // 超出部分会被自动丢弃!! 所以图像不能大于64480字节 DMA1_Channel5->CCR = DMA_CCR5_PL | DMA_CCR5_MINC | DMA_CCR5_EN; OV2640_Init(JPEG_800x600); // 打开PB0外部中断 AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI0_PB; EXTI->IMR = EXTI_IMR_MR0; EXTI->RTSR = EXTI_RTSR_TR0; // PB0上的上升沿能触发中断 EXTI->FTSR = EXTI_FTSR_TR0; // PB0上的下降沿也能触发中断 NVIC_EnableIRQ(EXTI0_IRQn); // 允许执行中断服务函数 while (1) { if (image_state == (STATE_START | STATE_STOP)) { printf("size=%d\n", image_size); dump(image_buffer, image_size); // 通过串口发送图像, 然后附上CRC校验值 // 让DMA内部指针回到数组的开头 DMA1_Channel5->CCR &= ~DMA_CCR5_EN; DMA1_Channel5->CNDTR = sizeof(image_buffer); DMA1_Channel5->CCR |= DMA_CCR5_EN; image_state = 0; // 允许采集新图像 (这条语句一次性把START和STOP都清0了) } } } void EXTI0_IRQHandler(void) { EXTI->PR = EXTI_PR_PR0; // 清除中断标志位 if (GPIOB->IDR & GPIO_IDR_IDR0) { // PB0上升沿表示图像数据传输开始 if (image_state != 0) return; // 如果图像已经开始采集了, 就忽略这个开始信号 image_state = STATE_START; // 打开TIM4_CH3对应的DMA通道, 开始采集数据 TIM4->DIER = TIM_DIER_CC3DE; // 允许PB9上的下降沿触发DMA请求 } else { // PB0下降沿表示图像数据传输结束 if ((image_state & STATE_START) == 0 || (image_state & STATE_STOP)) return; // 忽略没有开始信号的结束信号, 以及重复的结束信号 image_state |= STATE_STOP; TIM4->DIER &= ~TIM_DIER_CC3DE; // 停止采集 image_size = sizeof(image_buffer) - DMA1_Channel5->CNDTR; // 总量-剩余数据量=图像大小 } }
main.c:(只用外部中断采集——不推荐,因为中断频率太高,中断处理函数稍微多写几行代码就会出问题)
#include <stdio.h> #include <stm32f10x.h> #include <string.h> #include "dcmi_ov2640.h" #define STATE_START 0x01 #define STATE_STOP 0x02 uint8_t image_buffer[64480]; // 如果存储空间不够了, 把这个数组改小就行了 uint8_t image_state = 0; // 图像捕获状态 uint32_t image_size; // 图像的大小 // 精确延时n毫秒 void delay(uint16_t nms) { TIM6->ARR = 10 * nms - 1; TIM6->PSC = 7199; TIM6->EGR = TIM_EGR_UG; TIM6->SR &= ~TIM_SR_UIF; TIM6->CR1 = TIM_CR1_OPM | TIM_CR1_CEN; while ((TIM6->SR & TIM_SR_UIF) == 0); } // 向串口发送图像数据, 并在末尾附上CRC校验码 void dump(const void *data, uint32_t size) { uint8_t value; uint32_t i; uint32_t temp; CRC->CR = CRC_CR_RESET; for (i = 0; i < size; i++) { // 输出图像数据 value = *((uint8_t *)data + i); printf("%02X", value); // 每4字节计算一次CRC if ((i & 3) == 0) { if (i + 4 <= size) CRC->DR = *(uint32_t *)((uint8_t *)data + i); else { temp = 0; memcpy(&temp, (uint8_t *)data + i, size - i); CRC->DR = temp; } } } // 输出CRC temp = CRC->DR; temp = (temp >> 24) | ((temp >> 8) & 0xff00) | ((temp & 0xff00) << 8) | ((temp & 0x00ff) << 24); printf("%08X\n", temp); } int fputc(int ch, FILE *fp) { if (fp == stdout) { if (ch == '\n') { while ((USART1->SR & USART_SR_TXE) == 0); USART1->DR = '\r'; } while ((USART1->SR & USART_SR_TXE) == 0); USART1->DR = ch; } return ch; } int main(void) { RCC->AHBENR |= RCC_AHBENR_CRCEN; RCC->APB1ENR = RCC_APB1ENR_I2C1EN | RCC_APB1ENR_TIM6EN; RCC->APB2ENR = RCC_APB2ENR_AFIOEN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_USART1EN; GPIOA->CRH = (GPIOA->CRH & 0xfffff00f) | 0x4b0; // 串口发送引脚PA9设为复用推挽输出 GPIOB->CRL = (GPIOB->CRL & 0x00ffffff) | 0xff000000; // PB6~7连接摄像头的I2C接口, 设为复用开漏输出 // PB0(VSYNC)和PB9(=~(HREF & PCLK))为浮空输入 // PC0~7是摄像头的8位数据引脚, 为浮空输入 USART1->BRR = SystemCoreClock / 115200; USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; I2C1->CR2 = 36; // APB1总线频率: 36MHz I2C1->CCR = 1800; // 速率: 10kHz (不可太高, 否则会导致Ack Failure; 计算公式为PCLK1/nf, 标准模式下n=2) I2C1->TRISE = 37; // 标准模式下为PCLK+1 I2C1->CR1 = I2C_CR1_PE; // 打开I2C总线 OV2640_Init(JPEG_800x600); // 打开PB0和PB9外部中断 AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI0_PB; AFIO->EXTICR[2] = AFIO_EXTICR3_EXTI9_PB; EXTI->IMR = EXTI_IMR_MR0; EXTI->RTSR = EXTI_RTSR_TR0; // PB0上的上升沿能触发中断 EXTI->FTSR = EXTI_FTSR_TR0 | EXTI_FTSR_TR9; // PB0和PB9上的下降沿能触发中断 NVIC_EnableIRQ(EXTI0_IRQn); // 允许执行中断服务函数 NVIC_EnableIRQ(EXTI9_5_IRQn); while (1) { if (image_state == (STATE_START | STATE_STOP)) { printf("size=%d\n", image_size); dump(image_buffer, image_size); // 通过串口发送图像, 然后附上CRC校验值 image_state = 0; // 允许采集新图像 (这条语句一次性把START和STOP都清0了) } } } void EXTI0_IRQHandler(void) { EXTI->PR = EXTI_PR_PR0; // 清除中断标志位 if (GPIOB->IDR & GPIO_IDR_IDR0) { // PB0上升沿表示图像数据传输开始 if (image_state != 0) return; // 如果图像已经开始采集了, 就忽略这个开始信号 image_state = STATE_START; image_size = 0; EXTI->IMR |= EXTI_IMR_MR9; // 开始采集 } else { // PB0下降沿表示图像数据传输结束 if ((image_state & STATE_START) == 0 || (image_state & STATE_STOP)) return; // 忽略没有开始信号的结束信号, 以及重复的结束信号 image_state |= STATE_STOP; EXTI->IMR &= ~EXTI_IMR_MR9; // 停止采集 } } void EXTI9_5_IRQHandler(void) { uint8_t data; EXTI->PR = EXTI_PR_PR9; data = GPIOC->IDR & 0xff; if ((image_state & (STATE_START | STATE_STOP)) == STATE_START && image_size < sizeof(image_buffer)) image_buffer[image_size++] = data; }
dcmi_ov2640.h:
/** ****************************************************************************** * @file DCMI/DCMI_CameraExample/dcmi_ov2640.h * @author MCD Application Team * @version V1.8.0 * @date 04-November-2016 * @brief Header for dcmi_ov2640.c module ****************************************************************************** * @attention * * <h2><center>© COPYRIGHT 2016 STMicroelectronics</center></h2> * * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.st.com/software_license_agreement_liberty_v2 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ****************************************************************************** */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __DCMI_OV2640_H #define __DCMI_OV2640_H /* Exported types ------------------------------------------------------------*/ typedef struct { uint8_t Manufacturer_ID1; uint8_t Manufacturer_ID2; uint8_t PIDH; uint8_t PIDL; } OV2640_IDTypeDef; /* Image Sizes enumeration */ typedef enum { BMP_QQVGA = 0x00, /* BMP Image QQVGA 160x120 Size */ BMP_QVGA = 0x01, /* BMP Image QVGA 320x240 Size */ JPEG_160x120 = 0x02, /* JPEG Image 160x120 Size */ JPEG_176x144 = 0x03, /* JPEG Image 176x144 Size */ JPEG_320x240 = 0x04, /* JPEG Image 320x240 Size */ JPEG_352x288 = 0x05, /* JPEG Image 352x288 Size */ JPEG_800x600 = 0x06, /* JPEG Image 800x600 Size */ JPEG_1600x1200 = 0x07 /* JPEG Image 1600x1200 Size */ } ImageFormat_TypeDef; /* Exported constants --------------------------------------------------------*/ #define OV2640_DEVICE_WRITE_ADDRESS 0x60 #define OV2640_DEVICE_READ_ADDRESS 0x61 /* OV2640 Registers definition when DSP bank selected (0xFF = 0x00) */ /* OV2640 Registers definition when DSP bank selected (0xFF = 0x00) */ #define OV2640_DSP_R_BYPASS 0x05 #define OV2640_DSP_Qs 0x44 #define OV2640_DSP_CTRL 0x50 #define OV2640_DSP_HSIZE1 0x51 #define OV2640_DSP_VSIZE1 0x52 #define OV2640_DSP_XOFFL 0x53 #define OV2640_DSP_YOFFL 0x54 #define OV2640_DSP_VHYX 0x55 #define OV2640_DSP_DPRP 0x56 #define OV2640_DSP_TEST 0x57 #define OV2640_DSP_ZMOW 0x5A #define OV2640_DSP_ZMOH 0x5B #define OV2640_DSP_ZMHH 0x5C #define OV2640_DSP_BPADDR 0x7C #define OV2640_DSP_BPDATA 0x7D #define OV2640_DSP_CTRL2 0x86 #define OV2640_DSP_CTRL3 0x87 #define OV2640_DSP_SIZEL 0x8C #define OV2640_DSP_HSIZE2 0xC0 #define OV2640_DSP_VSIZE2 0xC1 #define OV2640_DSP_CTRL0 0xC2 #define OV2640_DSP_CTRL1 0xC3 #define OV2640_DSP_R_DVP_SP 0xD3 #define OV2640_DSP_IMAGE_MODE 0xDA #define OV2640_DSP_RESET 0xE0 #define OV2640_DSP_MS_SP 0xF0 #define OV2640_DSP_SS_ID 0x7F #define OV2640_DSP_SS_CTRL 0xF8 #define OV2640_DSP_MC_BIST 0xF9 #define OV2640_DSP_MC_AL 0xFA #define OV2640_DSP_MC_AH 0xFB #define OV2640_DSP_MC_D 0xFC #define OV2640_DSP_P_STATUS 0xFE #define OV2640_DSP_RA_DLMT 0xFF /* OV2640 Registers definition when sensor bank selected (0xFF = 0x01) */ #define OV2640_SENSOR_GAIN 0x00 #define OV2640_SENSOR_COM1 0x03 #define OV2640_SENSOR_REG04 0x04 #define OV2640_SENSOR_REG08 0x08 #define OV2640_SENSOR_COM2 0x09 #define OV2640_SENSOR_PIDH 0x0A #define OV2640_SENSOR_PIDL 0x0B #define OV2640_SENSOR_COM3 0x0C #define OV2640_SENSOR_COM4 0x0D #define OV2640_SENSOR_AEC 0x10 #define OV2640_SENSOR_CLKRC 0x11 #define OV2640_SENSOR_COM7 0x12 #define OV2640_SENSOR_COM8 0x13 #define OV2640_SENSOR_COM9 0x14 #define OV2640_SENSOR_COM10 0x15 #define OV2640_SENSOR_HREFST 0x17 #define OV2640_SENSOR_HREFEND 0x18 #define OV2640_SENSOR_VSTART 0x19 #define OV2640_SENSOR_VEND 0x1A #define OV2640_SENSOR_MIDH 0x1C #define OV2640_SENSOR_MIDL 0x1D #define OV2640_SENSOR_AEW 0x24 #define OV2640_SENSOR_AEB 0x25 #define OV2640_SENSOR_W 0x26 #define OV2640_SENSOR_REG2A 0x2A #define OV2640_SENSOR_FRARL 0x2B #define OV2640_SENSOR_ADDVSL 0x2D #define OV2640_SENSOR_ADDVHS 0x2E #define OV2640_SENSOR_YAVG 0x2F #define OV2640_SENSOR_REG32 0x32 #define OV2640_SENSOR_ARCOM2 0x34 #define OV2640_SENSOR_REG45 0x45 #define OV2640_SENSOR_FLL 0x46 #define OV2640_SENSOR_FLH 0x47 #define OV2640_SENSOR_COM19 0x48 #define OV2640_SENSOR_ZOOMS 0x49 #define OV2640_SENSOR_COM22 0x4B #define OV2640_SENSOR_COM25 0x4E #define OV2640_SENSOR_BD50 0x4F #define OV2640_SENSOR_BD60 0x50 #define OV2640_SENSOR_REG5D 0x5D #define OV2640_SENSOR_REG5E 0x5E #define OV2640_SENSOR_REG5F 0x5F #define OV2640_SENSOR_REG60 0x60 #define OV2640_SENSOR_HISTO_LOW 0x61 #define OV2640_SENSOR_HISTO_HIGH 0x62 /* Exported macro ------------------------------------------------------------*/ /* Exported functions ------------------------------------------------------- */ void OV2640_Reset(void); void OV2640_ReadID(OV2640_IDTypeDef *OV2640ID); void OV2640_Init(ImageFormat_TypeDef ImageFormat); void OV2640_QQVGAConfig(void); void OV2640_QVGAConfig(void); void OV2640_JPEGConfig(ImageFormat_TypeDef ImageFormat); void OV2640_BrightnessConfig(uint8_t Brightness); void OV2640_ContrastConfig(uint8_t value1, uint8_t value2); void OV2640_BandWConfig(uint8_t BlackWhite); void OV2640_ColorEffectsConfig(uint8_t value1, uint8_t value2); void OV2640_WriteReg(uint8_t addr, uint8_t data); uint8_t OV2640_ReadReg(uint8_t addr); #endif /* __DCMI_OV2640_H */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
dcmi_ov2640.c:
/** ****************************************************************************** * @file DCMI/DCMI_CameraExample/dcmi_ov2640.c * @author MCD Application Team * @version V1.8.0 * @date 04-November-2016 * @brief This file includes the driver for OV2640 Camera module mounted on * STM324xG-EVAL and STM32437I-EVAL evaluation boards. ****************************************************************************** * @attention * * <h2><center>© COPYRIGHT 2016 STMicroelectronics</center></h2> * * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.st.com/software_license_agreement_liberty_v2 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include <stdio.h> #include <stm32f10x.h> #include "dcmi_ov2640.h" void delay(uint16_t nms); /** @addtogroup STM32F4xx_StdPeriph_Examples * @{ */ /** @addtogroup DCMI_CameraExample * @{ */ /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* QQVGA 160x120 */ const char OV2640_QQVGA[][2] = { 0xff, 0x00, 0x2c, 0xff, 0x2e, 0xdf, 0xff, 0x01, 0x3c, 0x32, 0x11, 0x00, 0x09, 0x02, 0x03, 0xcf, 0x04, 0x08, 0x13, 0xe5, 0x14, 0x48, 0x2c, 0x0c, 0x33, 0x78, 0x3a, 0x33, 0x3b, 0xfb, 0x3e, 0x00, 0x43, 0x11, 0x16, 0x10, 0x39, 0x02, 0x35, 0x88, 0x22, 0x0a, 0x37, 0x40, 0x23, 0x00, 0x34, 0xa0, 0x36, 0x1a, 0x06, 0x02, 0x07, 0xc0, 0x0d, 0xb7, 0x0e, 0x01, 0x4c, 0x00, 0x4a, 0x81, 0x21, 0x99, 0x24, 0x3a, 0x25, 0x32, 0x26, 0x82, 0x5c, 0x00, 0x63, 0x00, 0x5d, 0x55, 0x5e, 0x7d, 0x5f, 0x7d, 0x60, 0x55, 0x61, 0x70, 0x62, 0x80, 0x7c, 0x05, 0x20, 0x80, 0x28, 0x30, 0x6c, 0x00, 0x6d, 0x80, 0x6e, 0x00, 0x70, 0x02, 0x71, 0x96, 0x73, 0xe1, 0x3d, 0x34, 0x5a, 0x57, 0x4f, 0xbb, 0x50, 0x9c, 0x0f, 0x43, 0xff, 0x00, 0xe5, 0x7f, 0xf9, 0xc0, 0x41, 0x24, 0xe0, 0x14, 0x76, 0xff, 0x33, 0xa0, 0x42, 0x20, 0x43, 0x18, 0x4c, 0x00, 0x87, 0xd0, 0x88, 0x3f, 0xd7, 0x03, 0xd9, 0x10, 0xd3, 0x82, 0xc8, 0x08, 0xc9, 0x80, 0x7c, 0x00, 0x7d, 0x02, 0x7c, 0x03, 0x7d, 0x48, 0x7d, 0x48, 0x7c, 0x08, 0x7d, 0x20, 0x7d, 0x10, 0x7d, 0x0e, 0x90, 0x00, 0x91, 0x0e, 0x91, 0x1a, 0x91, 0x31, 0x91, 0x5a, 0x91, 0x69, 0x91, 0x75, 0x91, 0x7e, 0x91, 0x88, 0x91, 0x8f, 0x91, 0x96, 0x91, 0xa3, 0x91, 0xaf, 0x91, 0xc4, 0x91, 0xd7, 0x91, 0xe8, 0x91, 0x20, 0x92, 0x00, 0x93, 0x06, 0x93, 0xe3, 0x93, 0x05, 0x93, 0x05, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x08, 0x97, 0x19, 0x97, 0x02, 0x97, 0x0c, 0x97, 0x24, 0x97, 0x30, 0x97, 0x28, 0x97, 0x26, 0x97, 0x02, 0x97, 0x98, 0x97, 0x80, 0x97, 0x00, 0x97, 0x00, 0xc3, 0xed, 0xa4, 0x00, 0xa8, 0x00, 0xbf, 0x00, 0xba, 0xf0, 0xbc, 0x64, 0xbb, 0x02, 0xb6, 0x3d, 0xb8, 0x57, 0xb7, 0x38, 0xb9, 0x4e, 0xb3, 0xe8, 0xb4, 0xe1, 0xb5, 0x66, 0xb0, 0x67, 0xb1, 0x5e, 0xb2, 0x04, 0xc7, 0x00, 0xc6, 0x51, 0xc5, 0x11, 0xc4, 0x9c, 0xcf, 0x02, 0xa6, 0x00, 0xa7, 0xe0, 0xa7, 0x10, 0xa7, 0x1e, 0xa7, 0x21, 0xa7, 0x00, 0xa7, 0x28, 0xa7, 0xd0, 0xa7, 0x10, 0xa7, 0x16, 0xa7, 0x21, 0xa7, 0x00, 0xa7, 0x28, 0xa7, 0xd0, 0xa7, 0x10, 0xa7, 0x17, 0xa7, 0x21, 0xa7, 0x00, 0xa7, 0x28, 0xc0, 0xc8, 0xc1, 0x96, 0x86, 0x1d, 0x50, 0x00, 0x51, 0x90, 0x52, 0x18, 0x53, 0x00, 0x54, 0x00, 0x55, 0x88, 0x57, 0x00, 0x5a, 0x90, 0x5b, 0x18, 0x5c, 0x05, 0xc3, 0xef, 0x7f, 0x00, 0xda, 0x00, 0xe5, 0x1f, 0xe1, 0x67, 0xe0, 0x00, 0xdd, 0xff, 0x05, 0x00, 0xff, 0x01, 0xff, 0x01, 0x12, 0x00, 0x17, 0x11, 0x18, 0x75, 0x19, 0x01, 0x1a, 0x97, 0x32, 0x36, 0x4f, 0xbb, 0x6d, 0x80, 0x3d, 0x34, 0x39, 0x02, 0x35, 0x88, 0x22, 0x0a, 0x37, 0x40, 0x23, 0x00, 0x34, 0xa0, 0x36, 0x1a, 0x06, 0x02, 0x07, 0xc0, 0x0d, 0xb7, 0x0e, 0x01, 0x4c, 0x00, 0xff, 0x00, 0xe0, 0x04, 0x8c, 0x00, 0x87, 0xd0, 0xe0, 0x00, 0xff, 0x00, 0xe0, 0x14, 0xe1, 0x77, 0xe5, 0x1f, 0xd7, 0x03, 0xda, 0x10, 0xe0, 0x00, 0xff, 0x00, 0xe0, 0x04, 0xc0, 0xc8, 0xc1, 0x96, 0x86, 0x1d, 0x50, 0x00, 0x51, 0x90, 0x52, 0x2c, 0x53, 0x00, 0x54, 0x00, 0x55, 0x88, 0x57, 0x00, 0x5a, 0x90, 0x5b, 0x2c, 0x5c, 0x05, 0xe0, 0x00, 0xd3, 0x04, 0xff, 0x00, 0xc3, 0xef, 0xa6, 0x00, 0xa7, 0xdd, 0xa7, 0x78, 0xa7, 0x7e, 0xa7, 0x24, 0xa7, 0x00, 0xa7, 0x25, 0xa6, 0x06, 0xa7, 0x20, 0xa7, 0x58, 0xa7, 0x73, 0xa7, 0x34, 0xa7, 0x00, 0xa7, 0x25, 0xa6, 0x0c, 0xa7, 0x28, 0xa7, 0x58, 0xa7, 0x6d, 0xa7, 0x34, 0xa7, 0x00, 0xa7, 0x25, 0xff, 0x00, 0xe0, 0x04, 0xe1, 0x67, 0xe5, 0x1f, 0xd7, 0x01, 0xda, 0x08, 0xda, 0x09, 0xe0, 0x00, 0x98, 0x00, 0x99, 0x00, 0xff, 0x01, 0x04, 0x28, 0xff, 0x01, 0x12, 0x40, 0x17, 0x11, 0x18, 0x43, 0x19, 0x00, 0x1a, 0x4b, 0x32, 0x09, 0x4f, 0xca, 0x50, 0xa8, 0x5a, 0x23, 0x6d, 0x00, 0x39, 0x12, 0x35, 0xda, 0x22, 0x1a, 0x37, 0xc3, 0x23, 0x00, 0x34, 0xc0, 0x36, 0x1a, 0x06, 0x88, 0x07, 0xc0, 0x0d, 0x87, 0x0e, 0x41, 0x4c, 0x00, 0xff, 0x00, 0xe0, 0x04, 0xc0, 0x64, 0xc1, 0x4b, 0x86, 0x35, 0x50, 0x92, 0x51, 0xc8, 0x52, 0x96, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x57, 0x00, 0x5a, 0x28, 0x5b, 0x1e, 0x5c, 0x00, 0xe0, 0x00, 0xff, 0x01, 0x11, 0x00, 0x3d, 0x38, 0x2d, 0x00, 0x50, 0x65, 0xff, 0x00, 0xd3, 0x04, 0x7c, 0x00, 0x7d, 0x04, 0x7c, 0x09, 0x7d, 0x28, 0x7d, 0x00, }; /* QVGA 320x240 */ const unsigned char OV2640_QVGA[][2] = { 0xff, 0x00, 0x2c, 0xff, 0x2e, 0xdf, 0xff, 0x01, 0x3c, 0x32, 0x11, 0x00, 0x09, 0x02, 0x04, 0x28, 0x13, 0xe5, 0x14, 0x48, 0x2c, 0x0c, 0x33, 0x78, 0x3a, 0x33, 0x3b, 0xfB, 0x3e, 0x00, 0x43, 0x11, 0x16, 0x10, 0x4a, 0x81, 0x21, 0x99, 0x24, 0x40, 0x25, 0x38, 0x26, 0x82, 0x5c, 0x00, 0x63, 0x00, 0x46, 0x3f, 0x0c, 0x3c, 0x61, 0x70, 0x62, 0x80, 0x7c, 0x05, 0x20, 0x80, 0x28, 0x30, 0x6c, 0x00, 0x6d, 0x80, 0x6e, 0x00, 0x70, 0x02, 0x71, 0x94, 0x73, 0xc1, 0x3d, 0x34, 0x5a, 0x57, 0x12, 0x00, 0x11, 0x00, 0x17, 0x11, 0x18, 0x75, 0x19, 0x01, 0x1a, 0x97, 0x32, 0x36, 0x03, 0x0f, 0x37, 0x40, 0x4f, 0xbb, 0x50, 0x9c, 0x5a, 0x57, 0x6d, 0x80, 0x6d, 0x38, 0x39, 0x02, 0x35, 0x88, 0x22, 0x0a, 0x37, 0x40, 0x23, 0x00, 0x34, 0xa0, 0x36, 0x1a, 0x06, 0x02, 0x07, 0xc0, 0x0d, 0xb7, 0x0e, 0x01, 0x4c, 0x00, 0xff, 0x00, 0xe5, 0x7f, 0xf9, 0xc0, 0x41, 0x24, 0xe0, 0x14, 0x76, 0xff, 0x33, 0xa0, 0x42, 0x20, 0x43, 0x18, 0x4c, 0x00, 0x87, 0xd0, 0x88, 0x3f, 0xd7, 0x03, 0xd9, 0x10, 0xd3, 0x82, 0xc8, 0x08, 0xc9, 0x80, 0x7d, 0x00, 0x7c, 0x03, 0x7d, 0x48, 0x7c, 0x08, 0x7d, 0x20, 0x7d, 0x10, 0x7d, 0x0e, 0x90, 0x00, 0x91, 0x0e, 0x91, 0x1a, 0x91, 0x31, 0x91, 0x5a, 0x91, 0x69, 0x91, 0x75, 0x91, 0x7e, 0x91, 0x88, 0x91, 0x8f, 0x91, 0x96, 0x91, 0xa3, 0x91, 0xaf, 0x91, 0xc4, 0x91, 0xd7, 0x91, 0xe8, 0x91, 0x20, 0x92, 0x00, 0x93, 0x06, 0x93, 0xe3, 0x93, 0x02, 0x93, 0x02, 0x93, 0x00, 0x93, 0x04, 0x93, 0x00, 0x93, 0x03, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x08, 0x97, 0x19, 0x97, 0x02, 0x97, 0x0c, 0x97, 0x24, 0x97, 0x30, 0x97, 0x28, 0x97, 0x26, 0x97, 0x02, 0x97, 0x98, 0x97, 0x80, 0x97, 0x00, 0x97, 0x00, 0xc3, 0xef, 0xff, 0x00, 0xba, 0xdc, 0xbb, 0x08, 0xb6, 0x24, 0xb8, 0x33, 0xb7, 0x20, 0xb9, 0x30, 0xb3, 0xb4, 0xb4, 0xca, 0xb5, 0x43, 0xb0, 0x5c, 0xb1, 0x4f, 0xb2, 0x06, 0xc7, 0x00, 0xc6, 0x51, 0xc5, 0x11, 0xc4, 0x9c, 0xbf, 0x00, 0xbc, 0x64, 0xa6, 0x00, 0xa7, 0x1e, 0xa7, 0x6b, 0xa7, 0x47, 0xa7, 0x33, 0xa7, 0x00, 0xa7, 0x23, 0xa7, 0x2e, 0xa7, 0x85, 0xa7, 0x42, 0xa7, 0x33, 0xa7, 0x00, 0xa7, 0x23, 0xa7, 0x1b, 0xa7, 0x74, 0xa7, 0x42, 0xa7, 0x33, 0xa7, 0x00, 0xa7, 0x23, 0xc0, 0xc8, 0xc1, 0x96, 0x8c, 0x00, 0x86, 0x3d, 0x50, 0x92, 0x51, 0x90, 0x52, 0x2c, 0x53, 0x00, 0x54, 0x00, 0x55, 0x88, 0x5a, 0x50, 0x5b, 0x3c, 0x5c, 0x00, 0xd3, 0x04, 0x7f, 0x00, 0xda, 0x00, 0xe5, 0x1f, 0xe1, 0x67, 0xe0, 0x00, 0xdd, 0x7f, 0x05, 0x00, 0xff, 0x00, 0xe0, 0x04, 0xc0, 0xc8, 0xc1, 0x96, 0x86, 0x3d, 0x50, 0x92, 0x51, 0x90, 0x52, 0x2c, 0x53, 0x00, 0x54, 0x00, 0x55, 0x88, 0x57, 0x00, 0x5a, 0x50, 0x5b, 0x3c, 0x5c, 0x00, 0xd3, 0x04, 0xe0, 0x00, 0xFF, 0x00, 0x05, 0x00, 0xDA, 0x08, 0xda, 0x09, 0x98, 0x00, 0x99, 0x00, 0x00, 0x00, }; const unsigned char OV2640_JPEG_INIT[][2] = { 0xff, 0x00, 0x2c, 0xff, 0x2e, 0xdf, 0xff, 0x01, 0x3c, 0x32, //0x11, 0x3f, // 最慢速采集 //0x11, 0x30, // 慢速采集 0x11, 0x18, // 不能使用下面两种速率, 因为DMA反应不过来, 会出现丢字节现象 //0x11, 0x00, // 快速采集 //0x11, 0x80, // 最快速采集 0x09, 0x02, 0x04, 0x28, 0x13, 0xe5, 0x14, 0x48, 0x2c, 0x0c, 0x33, 0x78, 0x3a, 0x33, 0x3b, 0xfB, 0x3e, 0x00, 0x43, 0x11, 0x16, 0x10, 0x39, 0x92, 0x35, 0xda, 0x22, 0x1a, 0x37, 0xc3, 0x23, 0x00, 0x34, 0xc0, 0x36, 0x1a, 0x06, 0x88, 0x07, 0xc0, 0x0d, 0x87, 0x0e, 0x41, 0x4c, 0x00, 0x48, 0x00, 0x5B, 0x00, 0x42, 0x03, 0x4a, 0x81, 0x21, 0x99, 0x24, 0x40, 0x25, 0x38, 0x26, 0x82, 0x5c, 0x00, 0x63, 0x00, 0x61, 0x70, 0x62, 0x80, 0x7c, 0x05, 0x20, 0x80, 0x28, 0x30, 0x6c, 0x00, 0x6d, 0x80, 0x6e, 0x00, 0x70, 0x02, 0x71, 0x94, 0x73, 0xc1, 0x12, 0x40, 0x17, 0x11, 0x18, 0x43, 0x19, 0x00, 0x1a, 0x4b, 0x32, 0x09, 0x37, 0xc0, 0x4f, 0x60, 0x50, 0xa8, 0x6d, 0x00, 0x3d, 0x38, 0x46, 0x3f, 0x4f, 0x60, 0x0c, 0x3c, 0xff, 0x00, 0xe5, 0x7f, 0xf9, 0xc0, 0x41, 0x24, 0xe0, 0x14, 0x76, 0xff, 0x33, 0xa0, 0x42, 0x20, 0x43, 0x18, 0x4c, 0x00, 0x87, 0xd5, 0x88, 0x3f, 0xd7, 0x03, 0xd9, 0x10, 0xd3, 0x82, 0xc8, 0x08, 0xc9, 0x80, 0x7c, 0x00, 0x7d, 0x00, 0x7c, 0x03, 0x7d, 0x48, 0x7d, 0x48, 0x7c, 0x08, 0x7d, 0x20, 0x7d, 0x10, 0x7d, 0x0e, 0x90, 0x00, 0x91, 0x0e, 0x91, 0x1a, 0x91, 0x31, 0x91, 0x5a, 0x91, 0x69, 0x91, 0x75, 0x91, 0x7e, 0x91, 0x88, 0x91, 0x8f, 0x91, 0x96, 0x91, 0xa3, 0x91, 0xaf, 0x91, 0xc4, 0x91, 0xd7, 0x91, 0xe8, 0x91, 0x20, 0x92, 0x00, 0x93, 0x06, 0x93, 0xe3, 0x93, 0x05, 0x93, 0x05, 0x93, 0x00, 0x93, 0x04, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x08, 0x97, 0x19, 0x97, 0x02, 0x97, 0x0c, 0x97, 0x24, 0x97, 0x30, 0x97, 0x28, 0x97, 0x26, 0x97, 0x02, 0x97, 0x98, 0x97, 0x80, 0x97, 0x00, 0x97, 0x00, 0xc3, 0xed, 0xa4, 0x00, 0xa8, 0x00, 0xc5, 0x11, 0xc6, 0x51, 0xbf, 0x80, 0xc7, 0x10, 0xb6, 0x66, 0xb8, 0xA5, 0xb7, 0x64, 0xb9, 0x7C, 0xb3, 0xaf, 0xb4, 0x97, 0xb5, 0xFF, 0xb0, 0xC5, 0xb1, 0x94, 0xb2, 0x0f, 0xc4, 0x5c, 0xc0, 0x64, 0xc1, 0x4B, 0x8c, 0x00, 0x86, 0x3D, 0x50, 0x00, 0x51, 0xC8, 0x52, 0x96, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x5a, 0xC8, 0x5b, 0x96, 0x5c, 0x00, 0xd3, 0x7f, 0xc3, 0xed, 0x7f, 0x00, 0xda, 0x00, 0xe5, 0x1f, 0xe1, 0x67, 0xe0, 0x00, 0xdd, 0x7f, 0x05, 0x00, 0x12, 0x40, 0xd3, 0x7f, 0xc0, 0x16, 0xC1, 0x12, 0x8c, 0x00, 0x86, 0x3d, 0x50, 0x00, 0x51, 0x2C, 0x52, 0x24, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x5A, 0x2c, 0x5b, 0x24, 0x5c, 0x00, }; const unsigned char OV2640_YUV422[][2] = { 0xFF, 0x00, 0x05, 0x00, 0xDA, 0x10, 0xD7, 0x03, 0xDF, 0x00, 0x33, 0x80, 0x3C, 0x40, 0xe1, 0x77, 0x00, 0x00, }; const unsigned char OV2640_JPEG[][2] = { 0xe0, 0x14, 0xe1, 0x77, 0xe5, 0x1f, 0xd7, 0x03, 0xda, 0x10, 0xe0, 0x00, 0xFF, 0x01, 0x04, 0x08, }; /* JPG 160x120 */ const unsigned char OV2640_160x120_JPEG[][2] = { 0xff, 0x01, 0x12, 0x40, 0x17, 0x11, 0x18, 0x43, 0x19, 0x00, 0x1a, 0x4b, 0x32, 0x09, 0x4f, 0xca, 0x50, 0xa8, 0x5a, 0x23, 0x6d, 0x00, 0x39, 0x12, 0x35, 0xda, 0x22, 0x1a, 0x37, 0xc3, 0x23, 0x00, 0x34, 0xc0, 0x36, 0x1a, 0x06, 0x88, 0x07, 0xc0, 0x0d, 0x87, 0x0e, 0x41, 0x4c, 0x00, 0xff, 0x00, 0xe0, 0x04, 0xc0, 0x64, 0xc1, 0x4b, 0x86, 0x35, 0x50, 0x92, 0x51, 0xc8, 0x52, 0x96, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x57, 0x00, 0x5a, 0x28, 0x5b, 0x1e, 0x5c, 0x00, 0xe0, 0x00, }; /* JPG, 176x144 */ const unsigned char OV2640_176x144_JPEG[][2] = { 0xff, 0x01, 0x12, 0x40, 0x17, 0x11, 0x18, 0x43, 0x19, 0x00, 0x1a, 0x4b, 0x32, 0x09, 0x4f, 0xca, 0x50, 0xa8, 0x5a, 0x23, 0x6d, 0x00, 0x39, 0x12, 0x35, 0xda, 0x22, 0x1a, 0x37, 0xc3, 0x23, 0x00, 0x34, 0xc0, 0x36, 0x1a, 0x06, 0x88, 0x07, 0xc0, 0x0d, 0x87, 0x0e, 0x41, 0x4c, 0x00, 0xff, 0x00, 0xe0, 0x04, 0xc0, 0x64, 0xc1, 0x4b, 0x86, 0x35, 0x50, 0x92, 0x51, 0xc8, 0x52, 0x96, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x57, 0x00, 0x5a, 0x2c, 0x5b, 0x24, 0x5c, 0x00, 0xe0, 0x00, }; /* JPG 320x240 */ const unsigned char OV2640_320x240_JPEG[][2] = { 0xff, 0x01, 0x12, 0x40, 0x17, 0x11, 0x18, 0x43, 0x19, 0x00, 0x1a, 0x4b, 0x32, 0x09, 0x4f, 0xca, 0x50, 0xa8, 0x5a, 0x23, 0x6d, 0x00, 0x39, 0x12, 0x35, 0xda, 0x22, 0x1a, 0x37, 0xc3, 0x23, 0x00, 0x34, 0xc0, 0x36, 0x1a, 0x06, 0x88, 0x07, 0xc0, 0x0d, 0x87, 0x0e, 0x41, 0x4c, 0x00, 0xff, 0x00, 0xe0, 0x04, 0xc0, 0x64, 0xc1, 0x4b, 0x86, 0x35, 0x50, 0x89, 0x51, 0xc8, 0x52, 0x96, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x57, 0x00, 0x5a, 0x50, 0x5b, 0x3c, 0x5c, 0x00, 0xe0, 0x00, }; /* JPG 352x288 */ const unsigned char OV2640_352x288_JPEG[][2] = { 0xff, 0x01, 0x12, 0x40, 0x17, 0x11, 0x18, 0x43, 0x19, 0x00, 0x1a, 0x4b, 0x32, 0x09, 0x4f, 0xca, 0x50, 0xa8, 0x5a, 0x23, 0x6d, 0x00, 0x39, 0x12, 0x35, 0xda, 0x22, 0x1a, 0x37, 0xc3, 0x23, 0x00, 0x34, 0xc0, 0x36, 0x1a, 0x06, 0x88, 0x07, 0xc0, 0x0d, 0x87, 0x0e, 0x41, 0x4c, 0x00, 0xff, 0x00, 0xe0, 0x04, 0xc0, 0x64, 0xc1, 0x4b, 0x86, 0x35, 0x50, 0x89, 0x51, 0xc8, 0x52, 0x96, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x57, 0x00, 0x5a, 0x58, 0x5b, 0x48, 0x5c, 0x00, 0xe0, 0x00, }; /* JPG 800x600 */ const unsigned char OV2640_800x600_JPEG[][2] = { 0xff, 0x01, 0x12, 0x00, 0x17, 0x11, 0x18, 0x75, 0x32, 0x36, 0x19, 0x01, 0x1a, 0x97, 0x03, 0x0f, 0x37, 0x40, 0x4f, 0xbb, 0x50, 0x9c, 0x5a, 0x57, 0x6d, 0x80, 0x3d, 0x34, 0x39, 0x02, 0x35, 0x88, 0x22, 0x0a, 0x37, 0x40, 0x34, 0xa0, 0x06, 0x02, 0x0d, 0xb7, 0x0e, 0x01, 0xff, 0x00, 0xe0, 0x04, 0xc0, 0xc8, 0xc1, 0x96, 0x86, 0x35, 0x50, 0x89, 0x51, 0x90, 0x52, 0x2c, 0x53, 0x00, 0x54, 0x00, 0x55, 0x88, 0x57, 0x00, 0x5a, 0xc8, 0x5b, 0x96, 0x5c, 0x00, 0xd3, 0x02, 0xe0, 0x00, }; /* JPG 1600x1200 */ // 输出的图像大约为60KB, 而STM32F103RE的SRAM只有64KB const unsigned char OV2640_1600x1200_JPEG[][2]= { 0xff, 0x01, 0x12, 0x00, 0x17, 0x11, 0x18, 0x75, 0x32, 0x36, 0x19, 0x01, 0x1a, 0x97, 0x03, 0x0f, 0x37, 0x40, 0x4f, 0xbb, 0x50, 0x9c, 0x5a, 0x57, 0x6d, 0x80, 0x3d, 0x34, 0x39, 0x02, 0x35, 0x88, 0x22, 0x0a, 0x37, 0x40, 0x34, 0xa0, 0x06, 0x02, 0x0d, 0xb7, 0x0e, 0x01, 0xff, 0x00, 0xe0, 0x04, 0xc0, 0xc8, 0xc1, 0x96, 0x86, 0x3d, 0x50, 0x00, 0x51, 0x90, 0x52, 0x2c, 0x53, 0x00, 0x54, 0x00, 0x55, 0x88, 0x57, 0x00, 0x5a, 0x90, 0x5b, 0x2c, 0x5c, 0x05, 0xd3, 0x02, 0xe0, 0x00 }; /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ /** * @brief Resets the OV2640 camera. * @param None * @retval None */ void OV2640_Reset(void) { OV2640_WriteReg(OV2640_DSP_RA_DLMT, 0x01); OV2640_WriteReg(OV2640_SENSOR_COM7, 0x80); } /** * @brief Reads the OV2640 Manufacturer identifier. * @param OV2640ID: Pointer to the OV2640 Manufacturer identifier * @retval None */ void OV2640_ReadID(OV2640_IDTypeDef *OV2640ID) { OV2640_WriteReg(OV2640_DSP_RA_DLMT, 0x01); OV2640ID->Manufacturer_ID1 = OV2640_ReadReg(OV2640_SENSOR_MIDH); OV2640ID->Manufacturer_ID2 = OV2640_ReadReg(OV2640_SENSOR_MIDL); OV2640ID->PIDH = OV2640_ReadReg(OV2640_SENSOR_PIDH); OV2640ID->PIDL = OV2640_ReadReg(OV2640_SENSOR_PIDL); } /** * @brief Configures DCMI/DMA to capture image from the OV2640 camera. * @param ImageFormat: Image format BMP or JPEG * @param BMPImageSize: BMP Image size * @retval None */ void OV2640_Init(ImageFormat_TypeDef ImageFormat) { OV2640_IDTypeDef OV2640ID; OV2640_ReadID(&OV2640ID); printf("Manufacturer ID: 0x%04x, ", (OV2640ID.Manufacturer_ID1 << 8) | OV2640ID.Manufacturer_ID2); printf("Product ID: 0x%04x\n", (OV2640ID.PIDH << 8) | OV2640ID.PIDL); OV2640_JPEGConfig(ImageFormat); //OV2640_BrightnessConfig(0x20); } /** * @brief Configures the OV2640 camera in QQVGA mode. * @param None * @retval None */ void OV2640_QQVGAConfig(void) { uint32_t i; OV2640_Reset(); delay(200); /* Initialize OV2640 */ for(i=0; i<(sizeof(OV2640_QQVGA)/2); i++) { OV2640_WriteReg(OV2640_QQVGA[i][0], OV2640_QQVGA[i][1]); delay(2); } } /** * @brief Configures the OV2640 camera in QVGA mode. * @param None * @retval None */ void OV2640_QVGAConfig(void) { uint32_t i; OV2640_Reset(); delay(200); /* Initialize OV2640 */ for(i=0; i<(sizeof(OV2640_QVGA)/2); i++) { OV2640_WriteReg(OV2640_QVGA[i][0], OV2640_QVGA[i][1]); delay(2); } } /** * @brief Configures the OV2640 camera in JPEG mode. * @param JPEGImageSize: JPEG image size * @retval None */ void OV2640_JPEGConfig(ImageFormat_TypeDef ImageFormat) { uint32_t i; OV2640_Reset(); delay(200); /* Initialize OV2640 */ for(i=0; i<(sizeof(OV2640_JPEG_INIT)/2); i++) { OV2640_WriteReg(OV2640_JPEG_INIT[i][0], OV2640_JPEG_INIT[i][1]); } /* Set to output YUV422 */ for(i=0; i<(sizeof(OV2640_YUV422)/2); i++) { OV2640_WriteReg(OV2640_YUV422[i][0], OV2640_YUV422[i][1]); } OV2640_WriteReg(0xff, 0x01); OV2640_WriteReg(0x15, 0x00); /* Set to output JPEG */ for(i=0; i<(sizeof(OV2640_JPEG)/2); i++) { OV2640_WriteReg(OV2640_JPEG[i][0], OV2640_JPEG[i][1]); } delay(100); switch(ImageFormat) { case JPEG_176x144: { for(i=0; i<(sizeof(OV2640_176x144_JPEG)/2); i++) { OV2640_WriteReg(OV2640_176x144_JPEG[i][0], OV2640_176x144_JPEG[i][1]); } break; } case JPEG_320x240: { for(i=0; i<(sizeof(OV2640_320x240_JPEG)/2); i++) { OV2640_WriteReg(OV2640_320x240_JPEG[i][0], OV2640_320x240_JPEG[i][1]); } break; } case JPEG_352x288: { for(i=0; i<(sizeof(OV2640_352x288_JPEG)/2); i++) { OV2640_WriteReg(OV2640_352x288_JPEG[i][0], OV2640_352x288_JPEG[i][1]); } break; } case JPEG_800x600: { for(i=0; i<(sizeof(OV2640_800x600_JPEG)/2); i++) { OV2640_WriteReg(OV2640_800x600_JPEG[i][0], OV2640_800x600_JPEG[i][1]); } break; } case JPEG_1600x1200: { for(i=0; i<(sizeof(OV2640_1600x1200_JPEG)/2); i++) { OV2640_WriteReg(OV2640_1600x1200_JPEG[i][0], OV2640_1600x1200_JPEG[i][1]); } break; } default: { for(i=0; i<(sizeof(OV2640_160x120_JPEG)/2); i++) { OV2640_WriteReg(OV2640_160x120_JPEG[i][0], OV2640_160x120_JPEG[i][1]); } } } } /** * @brief Configures the OV2640 camera brightness. * @param Brightness: Brightness value, where Brightness can be: * 0x40 for Brightness +2, * 0x30 for Brightness +1, * 0x20 for Brightness 0, * 0x10 for Brightness -1, * 0x00 for Brightness -2, * @retval None */ void OV2640_BrightnessConfig(uint8_t Brightness) { OV2640_WriteReg(0xff, 0x00); OV2640_WriteReg(0x7c, 0x00); OV2640_WriteReg(0x7d, 0x04); OV2640_WriteReg(0x7c, 0x09); OV2640_WriteReg(0x7d, Brightness); OV2640_WriteReg(0x7d, 0x00); } /** * @brief Configures the OV2640 camera Black and white mode. * @param BlackWhite: BlackWhite value, where BlackWhite can be: * 0x18 for B&W, * 0x40 for Negative, * 0x58 for B&W negative, * 0x00 for Normal, * @retval None */ void OV2640_BandWConfig(uint8_t BlackWhite) { OV2640_WriteReg(0xff, 0x00); OV2640_WriteReg(0x7c, 0x00); OV2640_WriteReg(0x7d, BlackWhite); OV2640_WriteReg(0x7c, 0x05); OV2640_WriteReg(0x7d, 0x80); OV2640_WriteReg(0x7d, 0x80); } /** * @brief Configures the OV2640 camera color effects. * @param value1: Color effects value1 * @param value2: Color effects value2 * where value1 and value2 can be: * value1 = 0x40, value2 = 0xa6 for Antique, * value1 = 0xa0, value2 = 0x40 for Bluish, * value1 = 0x40, value2 = 0x40 for Greenish, * value1 = 0x40, value2 = 0xc0 for Reddish, * @retval None */ void OV2640_ColorEffectsConfig(uint8_t value1, uint8_t value2) { OV2640_WriteReg(0xff, 0x00); OV2640_WriteReg(0x7c, 0x00); OV2640_WriteReg(0x7d, 0x18); OV2640_WriteReg(0x7c, 0x05); OV2640_WriteReg(0x7d, value1); OV2640_WriteReg(0x7d, value2); } /** * @brief Configures the OV2640 camera contrast. * @param value1: Contrast value1 * @param value2: Contrast value2 * where value1 and value2 can be: * value1 = 0x28, value2 = 0x0c for Contrast +2, * value1 = 0x24, value2 = 0x16 for Contrast +1, * value1 = 0x20, value2 = 0x20 for Contrast 0, * value1 = 0x1c, value2 = 0x2a for Contrast -1, * value1 = 0x18, value2 = 0x34 for Contrast -2, * @retval None */ void OV2640_ContrastConfig(uint8_t value1, uint8_t value2) { OV2640_WriteReg(0xff, 0x00); OV2640_WriteReg(0x7c, 0x00); OV2640_WriteReg(0x7d, 0x04); OV2640_WriteReg(0x7c, 0x07); OV2640_WriteReg(0x7d, 0x20); OV2640_WriteReg(0x7d, value1); OV2640_WriteReg(0x7d, value2); OV2640_WriteReg(0x7d, 0x06); } void OV2640_WriteReg(uint8_t addr, uint8_t data) { I2C1->CR1 |= I2C_CR1_START; while ((I2C1->SR1 & I2C_SR1_SB) == 0); I2C1->DR = OV2640_DEVICE_WRITE_ADDRESS; while ((I2C1->SR1 & (I2C_SR1_ADDR | I2C_SR1_AF)) == 0); if (I2C1->SR1 & I2C_SR1_AF) { printf("I2C Acknowledge failure! addr=0x%02x, data=0x%02x\n", addr, data); while (1); } if ((I2C1->SR2 & I2C_SR2_TRA) == 0) // 读SR2清除ADDR return; I2C1->DR = addr; // 向DR送入第一个数据后, I2C_SR1_TXE不会清零, 所以可以不用等待, 直接送入第二个数据 I2C1->DR = data; while ((I2C1->SR1 & I2C_SR1_BTF) == 0); I2C1->CR1 |= I2C_CR1_STOP; while (I2C1->CR1 & I2C_CR1_STOP); } uint8_t OV2640_ReadReg(uint8_t addr) { uint8_t data; I2C1->CR1 |= I2C_CR1_START; while ((I2C1->SR1 & I2C_SR1_SB) == 0); I2C1->DR = OV2640_DEVICE_WRITE_ADDRESS; while ((I2C1->SR1 & (I2C_SR1_ADDR | I2C_SR1_AF)) == 0); // 等待ADDR或AF置位 if (I2C1->SR1 & I2C_SR1_AF) { printf("I2C Acknowledge failure! addr=0x%02x\n", addr); while (1); } data = I2C1->SR2; I2C1->DR = addr; while ((I2C1->SR1 & I2C_SR1_BTF) == 0); I2C1->CR1 |= I2C_CR1_START; while ((I2C1->SR1 & I2C_SR1_SB) == 0); I2C1->DR = OV2640_DEVICE_READ_ADDRESS; while ((I2C1->SR1 & I2C_SR1_ADDR) == 0); data = I2C1->SR2; I2C1->CR1 |= I2C_CR1_STOP; // 必须在接收最后一字节数据之前请求STOP while ((I2C1->SR1 & I2C_SR1_RXNE) == 0); data = I2C1->DR; while (I2C1->CR1 & I2C_CR1_STOP); return data; } /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
-
VSwin32命令控制台与单片机串口数据传输免费版
2018-06-01 13:27:13例程1:摄像头识别小圆,然后通过串口输出小圆的xy坐标。单片机可以直接接受,具体串口配置自己配置。 例程2:VSwin32命令控制台程序 调用串口,可以根据自己需要配置串口,完成windows与单片机的数据传输。可作为... -
con排插与单片机相连_教你如何使用Labview和单片机通信(串口).pdf
2020-12-19 03:58:18第13 章 LabVIEW 串口通信程序设计第13 章 LabVIEW 串口通信程序设计以PC 作为上位机,以调制解调器(Modem )、串行打印机、各种监控模块、PLC 、摄像头云台、数控机床、单片机及智能设备等作为下位机广泛应用于测控... -
STM32单片机RT Thread + Micropython + OpenMV + USB摄像头移植整合过程
2020-11-05 17:47:09目标是基于RT Thread实时操作系统,将Micropython、OpenMV、USB摄像头+模拟摄像头+STM32本身自带的DVP摄像头,在OpenMV框架下,全部引入进来。这样的话,该软件平台同时具备了RTOS、Python脚本、USB OpenMV串口驱动... -
VS win32命令控制台程序与单片机串口数据传输
2017-08-11 08:40:46大致是需要用摄像头检测圆,然后把圆的xy坐标发送给单片机。 但是网上大部分都是基于MFC串口控件的例程。大海捞针找到了个win32命令控制台的串口例程 ,自己改了一下贡献出来。 直接调用API实现串口通信 ... -
飞思卡尔智能车摄像头上位机…
2014-11-13 23:08:23原文地址:飞思卡尔智能车摄像头上位机采集程序作者:玲声依旧美 ... S0为单片机RXD,接到串口模块的TXD中,S1为单片机TXD,接到单片机RXD中 波特率默认为9600,用户可自行修改波特率,图像大小为64*50,帧头帧 -
VB串口通信源码210个
2013-10-15 11:32:27065、VB开发的RS232串口图像处理器驱动(摄像头驱动) 066、VB开发的串口通信源码 067、VB开发的串口与三菱FX PLC通讯源码 068、VB控制串口232通讯,对飞利浦M1卡内数据进行处理,支持密码修改等 069、VB利用Mscomm控件... -
串口编程云台
2016-11-30 14:50:14云台设备,说白了就是一个单片机驱动电机或者继电器从而实现摄像头在垂直方向的运动,水平方向的摆动,以及电子镜头的聚焦光圈变化和变倍。 上位机通过串口连到单片机。真正的控制功能是通过上位机向串口发送... -
基于STM32的OV7725摄像头拍照实验
2018-04-15 13:44:55平台:STM32ZET6(核心板)+ST-LINK/V2+SD卡+USB串口线+鹰眼OV7725摄像头(注意,为了减少摄像头连线的麻烦,建议初学者选取单片机时选用带有摄像头接口的板子)工程介绍:需要移植FatFs文件系统,同时需要了解BMP... -
基于GPRS和单片机的彩信报警系统设计方案
2021-01-19 21:55:58用单片机根据sensor 控制串口摄像头图像采集和压缩处理,采集图像通过彩信的格式发送到用户手机,同时可以通过短信命令随时查看系统状态,或者摄像头采集图像,监控现场情况。 国内传统的电子防盗报警系统方案... -
能检测单片机奇偶校验的串口助手_拿了一台iPhoneXS Max翻新机,爱思助手能检测出多少问题?...
2020-12-02 12:19:36这款iPhone的屏幕换过、没有面容识别、后置摄像头、电池换过。爱思助手到底能检测出几项问题呢?这台iPhoneXS Max显示屏看着和原装屏幕的区别还是非常大的。可以看到屏幕很浑浊,不清晰。原装显示屏更加清晰透彻。... -
pc串口通信
2016-07-27 01:14:50如调制解调器,穿行打印机,各种监控模块,plc,摄像头云台,数控机床,单片机及相关智能设备,甚至路由器也不一般。 计算机测控系统主控机一般采用pc或plc ,通过串口与测控模块相连,测控模块在连接相应的传感器... -
通信与网络中的基于GPRS和单片机的彩信报警系统设计方案
2020-10-21 10:36:19用单片机根据sensor 控制串口摄像头图像采集和压缩处理,采集图像通过彩信的格式发送到用户手机,同时可以通过短信命令随时查看系统状态,或者摄像头采集图像,监控现场情况。 国内传统的电子防盗报警系统方案... -
opencv摄像头特定颜色轮廓重心提取 python2.7 (滚球系统)
2019-06-19 15:03:55采用opencv usb摄像头 提取小球位置 并串口输出给单片机 借鉴了很多网上的资源 实在没法一一列举,引用 了 对开源精神表示感谢 室友的美背出镜。。 # -*- coding:utf-8 -*- import serial import numpy as np ... -
STM32F103C8T6驱动ov2640拍照串口传输到上位机
2019-01-04 23:13:09最近想玩玩摄像头,于是在网上找找性价比比较高的摄像头(笔者喜欢用最廉价的东西做最牛逼的事情,给我一根足够长的杠杆,我就能撬动整个宇宙,哈哈哈~~~),之前用过OV7670这款摄像头,不过这款摄像头对单片机要求较... -
串口通信深度探究
2014-05-25 14:39:44所要求的软/硬件开发环境都很低,广泛应用于计算机及相关领域,如调制解调器(Modem)、串行打印机、各种监控模块、PLC、摄像头云台、数控机床、单片机及相关智能设备,甚至路由器也不例外(通过串口设置参数)。... -
如何利用WiFi进行单片机与电脑的实时图传
2019-04-08 23:07:14将摄像头与单片机的串口相连,连接好WiFi模块,将各个模块初始化完成。 连接电脑与WiFi模块,最后使用UDP协议,因为TCP协议有调错功能,会影响数据的传送,而UDP则没有,可以实现实时数据传输,就算有错误也会跳过... -
51单片机驱动ov2640做JPEG图片采集程序实例
2013-04-01 14:53:1551单片机驱动ov2640做JPEG图片采集程序实例,51单片机选用的是新华龙的C8051F380,摄像头为200W像素的OV2640,通过串口传送数据给上位机,图片格式为JPEG -
Visual C++串口通信技术详解.(机械工业.李景峰.杨丽娜.潘恒)
2016-06-06 02:44:26主要涵盖串口通信的理论基础、Visual c++集成开发环境简介、MSComm控件串口编程、Windows API串口编程、TAPI通信编程、串口实现双机互连、串口调试精灵、串口控制Modem设备、串口控制单片机、串口控制PLC、串口控制... -
2、51单片机视频教程 HJ-C52 功能模块讲解.mp4
2020-04-27 10:48:26星慈光零基础51单片机视频教程60讲,配套HJ-C52开发板,采用STC89C52RC,AT89S52单片机演示,从最基础的IO口操作,用简单C语言控制电平 0 1 有小学文化的同学都能看得明白,学习内部资源,中断,定时器、串口通信,... -
1、51单片机视频教程 HJ-C52 新手入门指导.mp4
2020-04-27 10:47:18星慈光零基础51单片机视频教程60讲,配套HJ-C52开发板,采用STC89C52RC,AT89S52单片机演示,从最基础的IO口操作,用简单C语言控制电平 0 1 有小学文化的同学都能看得明白,学习内部资源,中断,定时器、串口通信,... -
5、51单片机视频教程 HJ-C52 STC程序烧写方法.mp4
2020-04-27 10:51:22星慈光零基础51单片机视频教程60讲,配套HJ-C52开发板,采用STC89C52RC,AT89S52单片机演示,从最基础的IO口操作,用简单C语言控制电平 0 1 有小学文化的同学都能看得明白,学习内部资源,中断,定时器、串口通信,... -
4、51单片机视频教程 HJ-C52 STC烧写软件安装.mp4
2020-04-27 10:50:20星慈光零基础51单片机视频教程60讲,配套HJ-C52开发板,采用STC89C52RC,AT89S52单片机演示,从最基础的IO口操作,用简单C语言控制电平 0 1 有小学文化的同学都能看得明白,学习内部资源,中断,定时器、串口通信,...
-
Python3 列表list合并的4种方法
-
贴吧微信群采集软件免费
-
canvas实战之酷炫背景动画(二)
-
[JavaSE学习之旅]线程状态
-
xxljob源码分析
-
CEIWEI ParallelMonitor并口监控 v3.0 并口打印机监控, 并口打开印机, 并行端口过滤, 并行端口监控, 并口过滤, 并口监控
-
基于Hadoop 的离线视频处理技术研究与实现
-
SuperIO_Demo.rar
-
EEWLISTONDB2WSOCK-源码
-
基本的MySQL语句
-
sprincloud-config-源码
-
Vue.js devtools_3.1.2_0.zip
-
红外线自动寻的消防水炮生产厂家品牌讲解安装及数据说明
-
S3cmd使用手册
-
IIS7、IIS7.5中应用程序池最优配置方案
-
《文本处理 awk sed grep ”三剑客”》
-
投标方法论
-
Java2021年1月
-
SEC_KMQX10013M-B419_Datas.pdf
-
业余无线电短波小环天线计算器及匹配.rar