基于STM32F407的摄像头(不带FIFO的OV7670)图像采集及LCD显示实验-笔记整理
硬件说明
STM32F4开发板
stm32f4系列的芯片处理的能力可以说非常强大了的,而且内部还自带有数字摄像头接口(DCMI),可以说stm32f407的核心板和不带FIFO的摄像头模块OV7670简直就是绝配!
我手上的这块张这个样子 (图片来源:某宝):
F4系列的DCMI接口内部结构框图如下图3所示,具体的配置使用方式可以参考以下这篇博文:《stm32f4的数字摄像头接口(DCMI)使用》
这位博主大大已经很详细地介绍了DCMI接口的具体使用方法和原理,更重要的是里面还有接口的配置函数,虽然不完全一样,但是非常具有参考意义!
TFT-LCD屏幕
LCD屏幕用的是原子哥的TFT-LCD 屏幕,去年学STM32F103的时候随便买的一块液晶屏幕,分辨率就是320*240,驱动IC是ILI9341(ID9341)。
长这个样子(图片来源:原子哥):
对应资料链接:https://leoeinstein.lanzous.com/iApMql9yzkj
资料有点大哈,因为这个资料有可能是最全的LCD驱动IC资料包了。(这句话很小米)
摄像头OV7670
OV7670摄像头模块的体积小、工作电压低,提供单片VGA摄像头和影像处理器的所有功能,因为我这个不带FIFO芯片,所有还特便宜,但是像素不算太高。(这个价钱也还是可以了)
通过SCCB总线控制,可以输出整帧、子采样、取窗口等方式的各种分辨率8位影响数据。该产品VGA图像最高达到30帧/秒。用户可以完全控制图像质量、数据格式和传输方式。
摄像头模块长这个样子(图片来源:某宝):
OV7670中文资料手册:
https://wenku.baidu.com/view/e60f19ea81c758f5f61f67df.html
硬件连接说明
开发板上有一个TFT-LCD的接口,你如果手上有这样的屏幕就可以直接插上去使用了,如果用的的原子哥的屏幕的话,就需要稍微外接一些线了。
我直接用杜邦线连的,有“亿点点”乱哈。
LCD与STM32
LCD | MCU | LCD | MCU |
---|---|---|---|
CS | PG12 | RS | PF12 |
WR/CLK | PD5 | RD | PD4 |
RST | RST | D0 | D0 |
D1 | D1 | D2 | D3 |
D3 | D3 | D4 | D4 |
D5 | D5 | D6 | D6 |
D7 | D7 | D8 | D8 |
D9 | D9 | D10 | D10 |
D11 | D11 | D12 | D12 |
D13 | D13 | D14 | D14 |
D15 | D15 | GND | GND |
BL | PB15 | VCC3.3 | 3.3V |
VCC3.3 | 3.3V | GND | GND |
GND | GND | BL_VDD | 5V |
MISO | MI | MOSI | MO |
T_PEN | PB1 | MO | ------- |
T_CS | PC13 | CLK | PB0 |
OV7670与STM32
可以参考这篇博文:https://blog.csdn.net/LiangWF22/article/details/112676289
编程实现
编程要点、思路
一、摄像头配置
无FIFO的摄像头需要注意 时钟配置和窗口配置,否则不能出图像;
二、DCMI配置
DCMI需要配置成 DMA传输模式和使用行场中断进行图像数据采集,同时需要注意DCMI硬件同步的行场信号以及像素信号的上升沿和有效电平。
可以参考上面那篇《stm32f4的数字摄像头接口(DCMI)使用》博文。
具体代码
dcmi.c
#include "sys.h"
#include "dcmi.h" u8 ov_frame=0; //帧率
u32 datanum=0;
u32 HSYNC=0;
u32 VSYNC=0;
DCMI_InitTypeDef DCMI_InitStructure;//DCMI 初始化
void DCMI_DMA_Init(void)
{ DMA_InitTypeDef DMA_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能 DMA_DeInit(DMA2_Stream1);while (DMA_GetCmdStatus(DMA2_Stream1) != DISABLE){}//等待DMA2_Stream1可配置 DMA_InitStructure.DMA_Channel = DMA_Channel_1; //通道1 DCMI通道 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&DCMI->DR;//外设地址为:DCMI->DR 摄像头DMA_InitStructure.DMA_Memory0BaseAddr = (u32)&LCD->LCD_RAM;//DMA 存储器0地址 lcdDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//外设到存储器模式 搬运数据:摄像头->lcdDMA_InitStructure.DMA_BufferSize = 10;//数据传输量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;//存储器增量模式 关闭DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//外设数据长度:32位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord ;//存储器数据长度 16bit DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// 使用循环模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High;//高优先级DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; //FIFO模式 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;//使用全FIFO DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//外设突发单次传输DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//存储器突发单次传输DMA_Init(DMA2_Stream1, &DMA_InitStructure);//初始化DMA StreamDMA_ITConfig(DMA2_Stream1,DMA_IT_TC,ENABLE);NVIC_InitStructure.NVIC_IRQChannel= DMA2_Stream1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、} void DMA2_Stream1_IRQHandler(void)
{ if(DMA_GetFlagStatus(DMA2_Stream1,DMA_FLAG_TCIF1)==SET)//DMA2_Steam1,传输完成标志{ DMA_ClearFlag(DMA2_Stream1,DMA_FLAG_TCIF1);//清除传输完成中断datanum++;}
}
//DCMI初始化
void DCMI_Initxx(void)
{GPIO_InitTypeDef GPIO_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOE, ENABLE);//使能GPIOA B C E 时钟RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI,ENABLE);//使能DCMI时钟//PA4/6初始化设置GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_6;//PA4/6 复用功能输出GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能输出GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHzGPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_6;// PB6/7 复用功能输出GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;//PC6/7/8/9 复用功能输出GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;//PE 4/5/6 复用功能输出 GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化 GPIO_PinAFConfig(GPIOA,GPIO_PinSource4,GPIO_AF_DCMI); //PA4,AF13 DCMI_HSYNCGPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_DCMI); //PA6,AF13 DCMI_PCLK GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_DCMI); //PB7,AF13 DCMI_VSYNC GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_DCMI); //PC6,AF13 DCMI_D0 GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_DCMI); //PC7,AF13 DCMI_D1 GPIO_PinAFConfig(GPIOC,GPIO_PinSource8,GPIO_AF_DCMI); //PC8,AF13 DCMI_D2GPIO_PinAFConfig(GPIOC,GPIO_PinSource9,GPIO_AF_DCMI); //PC9,AF13 DCMI_D3GPIO_PinAFConfig(GPIOE,GPIO_PinSource4,GPIO_AF_DCMI);//PE4,AF13 DCMI_D4 GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_DCMI); //PB6,AF13 DCMI_D5 GPIO_PinAFConfig(GPIOE,GPIO_PinSource5,GPIO_AF_DCMI); //PE5,AF13 DCMI_D6GPIO_PinAFConfig(GPIOE,GPIO_PinSource6,GPIO_AF_DCMI); //PE6,AF13 DCMI_D7DCMI_DeInit();//清除原来的设置 DCMI_InitStructure.DCMI_CaptureMode=DCMI_CaptureMode_Continuous;//连续模式DCMI_InitStructure.DCMI_CaptureRate=DCMI_CaptureRate_All_Frame;//全帧捕获DCMI_InitStructure.DCMI_ExtendedDataMode= DCMI_ExtendedDataMode_8b;//8位数据格式 DCMI_InitStructure.DCMI_HSPolarity = DCMI_HSPolarity_Low;//HSYNC 低电平有效DCMI_InitStructure.DCMI_PCKPolarity= DCMI_PCKPolarity_Falling;//PCLK 上升沿有效DCMI_InitStructure.DCMI_SynchroMode= DCMI_SynchroMode_Hardware;//硬件同步HSYNC,VSYNCDCMI_InitStructure.DCMI_VSPolarity=DCMI_VSPolarity_High;//VSYNC 低电平有效DCMI_Init(&DCMI_InitStructure);DCMI_ITConfig(DCMI_IT_FRAME,ENABLE);//开启帧中断 DCMI_ITConfig(DCMI_IT_LINE,ENABLE); //开启行中断DCMI_ITConfig(DCMI_IT_VSYNC,ENABLE); //开启场中断 DCMI_Cmd(ENABLE); //DCMI使能NVIC_InitStructure.NVIC_IRQChannel = DCMI_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级1NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
}
//DCMI,启动传输
void DCMI_Start(void)
{ LCD_Scan_Dir(U2D_L2R); //U2D_L2R //扫描方式从上到下,从左到右,一般模式 LCD_Set_Window(0,0,320,240); //LCD设置显示窗口,如果改变了分辨率,这里需要更改LCD_SetCursor(0,0); //设置光标 LCD_WriteRAM_Prepare(); //开始写入GRAMDMA_Cmd(DMA2_Stream1, ENABLE);//开启DMA2,Stream1 DCMI_CaptureCmd(ENABLE);//DCMI捕获使能
}
//DCMI,关闭传输
void DCMI_Stop(void)
{ DCMI_CaptureCmd(DISABLE);//DCMI捕获使关闭 while(DCMI->CR&0X01); //等待传输结束 DMA_Cmd(DMA2_Stream1,DISABLE);//关闭DMA2,Stream1
}
//DCMI中断服务函数
void DCMI_IRQHandler(void)
{if(DCMI_GetITStatus(DCMI_IT_LINE)==SET)//捕获到行{DCMI_ClearITPendingBit(DCMI_IT_LINE);//清除中断 ov_frame++;}}
//以下两个函数,供usmart调用,用于调试代码//DCMI设置显示窗口
//sx,sy;LCD的起始坐标
//width,height:LCD显示范围.
void DCMI_Set_Window(u16 sx,u16 sy,u16 width,u16 height)
{DCMI_Stop(); LCD_Clear(WHITE);LCD_Set_Window(sx,sy,width,height);// OV7670_OutSize_Set(width,height);LCD_SetCursor(0,0); LCD_WriteRAM_Prepare(); //开始写入GRAMDMA_Cmd(DMA2_Stream1,ENABLE); //开启DMA2,Stream1 DCMI_CaptureCmd(ENABLE);//DCMI捕获使能 }
摄像头初始化函数如下:
u8 OV7670_Init(void)
{u16 i=0;//设置IO GPIO_InitTypeDef GPIO_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//GPIOG9,15初始化设置pow和resetGPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_8;//PG9,8推挽输出GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //推挽输出GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100MHzGPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化OV7670_PWDN=0; //POWER ONdelay_ms(100);OV7670_RST=0; //复位OV7670delay_ms(100);OV7670_RST=1; //结束复位 SCCB_Init(); //初始化SCCB 的IO口SCCB_WR_Reg(0X12, 0x80); //软复位OV7670delay_ms(50); //初始化 OV7670,采用QVGA分辨率(320*240) for(i=0;i<sizeof(ov7670_init_reg_tbl)/sizeof(ov7670_init_reg_tbl[0]);i++){SCCB_WR_Reg(ov7670_init_reg_tbl[i][0],ov7670_init_reg_tbl[i][1]);} //OV7670_Window_Set(PIC_START_X,PIC_START_Y,PIC_WIDTH,PIC_HEIGHT);OV7670_Light_Mode(0);OV7670_Color_Saturation(2);OV7670_Brightness(1);OV7670_Contrast(2);//My_DCMI_Init();//DCMI_DMA_Init((uint32_t)&camera_buffer+54,(sizeof(camera_buffer)-54)/4,DMA_MemoryDataSize_HalfWord,DMA_MemoryInc_Enable);//DCMI DMA return 0x00; //ok
}
实现效果
这仅仅是显示RGB数据,如果要上云的话,需要将RGB数据转化为BMP数据,然后再上传到物联网平台上,在后面的博文里将会介绍到。
工程链接
链接1:https://download.csdn.net/download/LiangWF22/15020550
链接2:https://leoeinstein.lanzoum.com/icY0x0b627tg
2021年2月3日 星期三
基于STM32F407的摄像头(不带FIFO的OV7670)图像采集及LCD显示实验-笔记整理相关推荐
- 用20块的摄像头(不带fifo的OV7670)做WiFi实时传图小车
博客地址 用20块的摄像头(不带fifo的OV7670)做WiFi实时传图小车 – Infinite's Blog 零.导读 在这篇文章中,你将看到如下内容: OV7670 QVGA配置的注意事项: ...
- 【正点原子FPGA连载】 第三十章双目OV5640摄像头LCD显示实验 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南
1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670 3)全套实验源码+手册+视频下载地址: h ...
- 基于51单片机的双机串口通信排队叫号系统(LCD显示)设计
基于51单片机的双机串口通信排队叫号系统(LCD显示)设计 1 开发环境 视频讲解 2 功能说明介绍 3 仿真图 4 程序 5 原理图 6 视频讲解 7 设计报告 7.1 设计目的 7.2 设计要求及 ...
- 基于战舰V3的LCD显示实验详解和剖析
基于STM32的4.3寸TFTLCD的使用 在这里,我们只剖析NT35510部分的代码. LCD显示方向设置函数 代码示例 //设置LCD显示方向 //dir:0,竖屏:1,横屏 void LCD_D ...
- STM32F103C8T6+带FIFO的OV7670的输出测试图像实例代码
一.工程文件链接及说明 Keil5工程文件: 链接:https://pan.baidu.com/s/13wCMPQU0DgbJ57sSiR16NQ?pwd=7670 提取码:7670 工程文件中,主要 ...
- OV7670带FIFO入坑指南
本文针对带FIFO的OV7670摄像头模块进行说明. 对于新手入坑OV7670摄像头的小白来说,入坑之路漫漫,最坑爹的是不知道入口在哪里~~下面就来简单的说一下我这几天的实验心得. 什么是带FIFO的 ...
- 【正点原子FPGA连载】第四十一章OV5640摄像头RGB-LCD显示实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1
1)实验平台:正点原子新起点V2开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113 2)全套实验源码+手册+视频下载地址:ht ...
- 【正点原子FPGA连载】 第三十四章双目OV5640摄像头RGB-LCD显示实验 摘自【正点原子】DFZU2EG/4EV MPSoC 之FPGA开发指南V1.0
1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670 3)全套实验源码+手册+视频下载地址: h ...
- 【正点原子FPGA连载】第四十四章MT9V034摄像头HDMI显示实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1
1)实验平台:正点原子新起点V2开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113 2)全套实验源码+手册+视频下载地址:ht ...
最新文章
- linux下mysql的root密码忘记解决方法
- ♥看二本学渣如何进腾讯 分享面试经验、职场感悟、硬核知识、大厂内推♥
- JIPB:白洋组综述根系微生物组群落构建及其对植物适应性的贡献
- 非系统表空间损坏,rman备份恢复
- LiveVideoStackCon深圳 - 洞察多媒体技术生态趋势与机会
- ecm工作原理 usb_“好玩具”来了!往你的USB端口里藏入一个小开发板...
- 内核移植出现:Kernel panic - not syncing: No init found.
- 【Siddhi 5】Siddhi 自定义函数@Extension使用
- 查询所有_学会DSUM函数,轻松搞定所有的数据查询与数据求和
- Opera的一个神奇功能
- Python深度学习基于PyTorch (附完整PPT下载)
- C语言笔记 清屏(循环时不一闪一闪的) 光标移动到任意位置 带注释(详细)
- [论文笔记]JED:Towards Real-Time Multi-Object Tracking
- sin2x麦克劳林公式_sinx泰勒公式展开
- Navicat导入Excel提示无法打开Excel文件
- 最全的IMSI获取手机号段、归属地java代码
- SWING实现类似微信的泡泡聊天界面
- matlab增强图像饱和度,matlab增强图像饱和度
- GS1011无线模块的使用简介。
- 伟大的牛逼之前都是傻逼式的坚持
热门文章
- libreoffice安装教程_win10怎么安装libreoffice6.4_win10系统libreoffice6.4安装教程
- 关于EFI系统分区(ESP)你应该知道的3件事
- MAL-Gold Nanoparticle/Au nanoparticles纳米金颗粒/金纳米粒子|50nm浓度:0.5mg/ml
- 基于虚拟相机的人脸识别 (视频) - Face recognition based on virtual camera
- seo关键词排名点击优化软件
- AK F.*ing leetcode 流浪计划之线段树
- 简单抽样技术——简单随机样本方差是总体方差的无偏估计
- html下拉自动加载更多,H5页面下拉加载更多(实用版)
- 计算机硬件维护的注意事项有哪些,计算机的硬件维护注意事项
- 关于EDP触摸屏使用笔记