我是靠谱客的博主 虚拟日记本,最近开发中收集的这篇文章主要介绍STM32——OV2640摄像头实验,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、硬件连接原理图

实物图:

 

二、OV2640驱动代码

1、SCCB_Init函数

//初始化SCCB接口
void SCCB_Init(void)
{
  GPIO_InitTypeDef GPIO_InitABC;
 
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);//使能GPIO时钟
  
  GPIO_InitABC.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;//PD6,7
  GPIO_InitABC.GPIO_Mode=GPIO_Mode_OUT;//PD6,7推挽输出
  GPIO_InitABC.GPIO_OType=GPIO_OType_PP;//推挽输出
  GPIO_InitABC.GPIO_Speed=GPIO_Speed_50MHz;//50MHz
  GPIO_InitABC.GPIO_PuPd=GPIO_PuPd_UP;//上拉
  GPIO_Init(GPIOD,&GPIO_InitABC);//初始化

  GPIO_SetBits(GPIOD,GPIO_Pin_6|GPIO_Pin_7);
  SCCB_SDA_OUT();
}

2、OV2640_Init函数

u8 OV2640_Init(void)
{
  u16 i=0;
  u16 reg;
  GPIO_InitTypeDef GPIO_InitABC;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE);
  GPIO_InitABC.GPIO_Pinn=GPIO_Pin_9|GPIO_Pin_15;//PG9,15推挽输出
  GPIO_InitABC.GPIO_Mode=GPIO_Mode_OUT;//推挽输出
  GPIO_InitABC.GPIO_OType=GPIO_OType_PP;//推挽输出
  GPIo-InitABC.GPIO_Speed=GPIO_Speed_50MHz;//50MHz
  GPIO_InitABC.GPIO_PuPd=GPIO_PuPd_UP;//上拉
  GPIO_Init(GPIOG,&GPIO_InitABC);//初始化
  
  OV2640_PWDN=0;//POWER  ON
  delay_ms(10);
  OV2640_RST=0;//硬复位OV2640
  delay_ms(10);
  OV2640_RST=1;//结束复位
  SCCB_Init();//初始化SCCB的IO口
  SCCB_WR_Reg(OV2640_DSP_RA_DLMT,0x01);//操作sensor寄存器
  SCCB_WR_Reg(OV2640_SENSOR_COM7,0x80);//软复位OV2640
  delay_ms(50);
  reg=SCCB_RD_Reg(OV2640_SENSOR_MIDH);//读取厂家ID高八位
  reg<<=8;
  reg|=SCCB_RD_Reg(OV2640_SENSOR_MIDL);//读取厂家ID低八位
  if(reg!=OV2640_MID)
  {
    printf("MID:%drn",reg);
    return 1;
  }
  reg=SCCB_RD_Reg(OV2640_SENSOR_PIDH);//读取厂家ID高八位
  reg<<=8;
  reg|=SCCB_RD_Reg(OV2640_SENSOR_PIDL);//读取厂家ID低八位
  if(reg!=OV2640_PID) 
  {
    printf("HID:%drn",reg);
    return 2;
  }
  //
  for(i=0;i<sizeof(ov2640_uxga_init_reg_tbl)/2;i++)
  {
    SCCB_WR_Reg(ov2640_uxga_init_reg_tbl[i][0],ov2640_uxga_init_reg_tbl[i][1]);
  }
  return 0x00;//ok
}

3、OV2640_IPEG_Moed函数

//OV2640切换为JPEG模式
void OV2640_JPEG_Mode(void)
{
  u16 i=0;
  //设置:YUV422模式
  for(i=0;i<sizeof(ov2640_yuv422_reg_tbl)/2;i++)
  {
    SCCB_WR_Reg(ov2640_yuv422_reg_tbl[i][0],ov2640_yuv422_reg_tbl[i][1]);
  }
  //设置:输出JPEG数据
  for(i=0;i<(sizeof(ov2640_jpeg_reg_tbl)/2);i++)
  {
    SCCB_WR_Reg(ov2640_jpeg_reg_tbl[i][0],ov2640_jpeg_reg_tbl[i][1]);
  }
}

4、OV2640_RGB565_Mode函数

//OV2640切换为RGB565模式
void OV2640_RGB565_Mode(void)
{
  u16 i=0;
  //设置RGB565
  for(i=0;i<(sizeof(ov2640_rgb565_reg_tbl)/2);i++)
  {
    SCCB_WR_Reg(ov2640_rgb565_reg_tbl[i][0],ov2640_rgb565_reg_tbl[i][1]);
  }
}

5、OV2640_ImageWin_Set函数

/*设置图像开窗大小
由:OV2640_ImageSize_Set确定传感器输出分辨率大小
该函数则在这个范围上面进行开窗,用于OV2640_OutSize_Set的输出
注意:本函数的宽度和高度必须大于等于OV2640_OutSize_Set1函数的宽度和高度
OV2640_OutSize_Set设置的宽度和高度,根据本函数设置的宽度和高度,由DSP自动计算缩放比例,输出给外部设备。
width,height:宽度(对应:horizontal)和高度(对应:vertical)width和height都必须是四的倍数
返回值:0 设置成功  其它设置失败*/
u8 OV2640_ImageWin_Set(u16 offx,u16 offy,u16width,u16 height)
{
  u16 hsize;
  u16 vsize;
  u8 temp;
  if(width%4) return 1;
  if(height%4) return 2;
  hsize=width/4;
  vsize=height/4;
  SCCB_WR_Reg(0XFF,0X00);
  SCCB_WR_Reg(0XE0,0X04);
  SCCB_WR_Reg(0X51,hsize&0XFF);//设置H_SIZE的低八位
  SCCB_WR_Reg(0X52,vsize&0XFF);//设置V_SIZE的低八位
  SCCB_WR_Reg(0X53,offx&0XFF);//设置offx的低八位
  SCCB_WR_Reg(0X54,offy&0XFF);//设置offy的低八位
  temp=(vsize>>1)&0X80;
  temp|=(offy>>4)&0X70;
  temp|=(hsize>>5)&0X08;
  temp|=(offx>>8)&0X07;
  SCCB_WR_Reg(0X55,temp);//设置H_SIZE/V_SIZE/0FFX,0FFY的高位
  SCCB_WR_Reg(0X57,(hsize>>2)&0X80);//设置H_SIZE/V_SIZE/0FFX,0FFY的高位
  SCCB_WR_Reg(0XE0,0X00);
  return 0;
}

三、DCMI驱动代码

1、My_DCMI_Init函数(完成DCMI的初始化、中断的配置、IO口的配置)

2、DCMI_DMA_Init函数

该函数用来配置DMA,包含四个参数: DMA_Memory0BaseAddr、DMA_BufferSize、DMA_MemoryDataSize、DMA_MemoryInc

DMA_Memory0BaseAddr:存储器地址,存储摄像头数据的内存地址(也可以是外设地址)

DMA_BufferSize:存储器长度

DMA_MemoryDataSize:存储器位宽

DMA_MemoryInc:存储器增长方式(用SRAM则地址自增,用LCD则不用增加)

3、单纯初始化函数是无法启用DCMI的,需要再加一个开始函数(DCMI_Start),有开启就会有关闭,后面呢还有一个关闭函数(DCMI_STOP)

//DCMI启动传输
void DCMI_Start(void)
{
  LCD_SetCursor(0,0);
  LCD_WriteRAM_Prepare();//开始写入GRAM
  DMA_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
}

4、DCMI中断服务函数

void DCMI_IRQHandler(void)
{
  if(DCMI_GetITStatus(DCMI_IT_FRAME)==SET)//捕获到一帧图像
  {
    jpeg_data_process;//JPEG数据处理
    DCMI_ClearITPendingBit(DCMI_IT_FRAME);//清除帧中断
    LED1=!LED1;//LED取反
    ov_frame++;
  }
}

5、jpeg_data_process函数

//处理JPEG数据
//当采集完一帧JPEG数据后,调用此函数,切换JPEG BUF,开始下一帧采集
void jpeg_data_process(void)
{
  if(ov2640_mode)//只有在JPEG格式下才需要处理
  {
    if(jpeg_data_ok==0)//JPEG数据还未采集完
    {
      DMA_Cmd(DMA2_Stream1,DISABLE);//停止当前传输
      while(DMA_GetCmdStatus(DMA2_Stream1)!=DISABLE){}//等待DMA2_Stream1可配置
      jpeg_data_len=jpeg_buf_size-DMA_GetCurrDataCounter(DMA2_Stream1);//得到此次数据传输的长度
      jpeg_data_ok=1;//标记JPEG数据采集完成,等待其他函数处理
    }
    if(jpeg_data_ok==2)//上一次的JPEG数据已经被处理
    {
      DMA2_Stream1->NDTR=jpeg_buf_size;
      DMA_SetCurrDataCounter(DMA2_Stream1,jpeg_buf_size);//传输长度为jpeg_buf_size*4字节
      DMA_Cmd(DMA2_Stream1,ENABLE);//重新传输
      jpeg_data_ok=0;//标记数据未采集
    }
  }
}

最后

以上就是虚拟日记本为你收集整理的STM32——OV2640摄像头实验的全部内容,希望文章能够帮你解决STM32——OV2640摄像头实验所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(37)

评论列表共有 0 条评论

立即
投稿
返回
顶部