历史上的今天
返回首页

历史上的今天

今天是:2025年04月22日(星期二)

正在发生

2020年04月22日 | 基于MSP430F5438A的OV7670简单驱动程序

2020-04-22 来源:eefocus

作为一个新手,因为课程设计要求,接触到了OV7670。因为课程设计要求使用MSP430F5438A驱动OV7670,而网上大多数都是使用STM32进行驱动。上网查找了很多资料,也仔细看过网上大佬发的相关寄存器的帖子,最后成功使用430单片机完成了设计。本着来源于网络,回馈于网络的原则,在此介绍一下,自己使用OV7670的一点经验。水平有限,偏颇之处,还请包涵!


首先简单的介绍一下所使用的摄像头OV7670。 OV7670是OV(OmniVision)公司生产的一颗1/6寸的CMOS VGA图像传感器。该传感器体积小、工作电压低,提供单片VGA摄像头和影像处理器的所有功能。通过SCCB 总线控制,可以输出整帧、子采样、取窗口等方式的各种分辨率8位影像数据。该产品VGA图像最高达到30帧/秒。用户可以完全控制图像质量、数据格式和传输方式。所有图像处理功能过程包括伽玛曲线、白平衡、度、色度等都可以通过SCCB接口编程。OmmiVision 图像传感器应用独有的传感器技术,通过减少或消除光学或电子缺陷如固定图案噪声、托尾、浮散等,提高图像质量,得到清晰的稳定的彩色图像。其具有高灵敏度、低电压适合嵌入式应用,标准的SCCB接口以及支持RGB565格式输出。因为摄像头的像素时钟非常高,直接通过MSP430的IO口读取数据非常困难,也是十分占耗CPU。采用带FIFO模块的OV7670,通过对FIFO的读取,就可以轻松的读取摄像头采集到图像数据。从而满足速度要求,节省CPU。本次采用的OV7670自带有源晶振,不需要外部再提供时钟。一个FIFO芯片的容量是384K字节,可以存储两帧QVGA的图像数据,所以本次设计采用QVGA模式  RGB565格式传输图像数据。接下来介绍具体的驱动程序。


管脚分配如图所示:

宏定义:


//SCL-P1.3,SDA-P1.6

#define SCCB_SIC_H()     P1OUT|=BIT3 

#define SCCB_SIC_L()     P1OUT&=~BIT3  

 

#define SCCB_SID_H()     P1OUT|=BIT6

#define SCCB_SID_L()     P1OUT&=~BIT6

 

#define SCCB_SID_IN      P1DIR &= ~BIT6    

#define SCCB_SID_OUT     P1DIR |= BIT6   

#define SCCB_SID_STATE P1IN&BIT6

 

#define OE_L    P4OUT &= ~BIT3

#define OE_H    P4OUT |= BIT3

#define RCLK_L  P4OUT &= ~BIT4

#define RCLK_H  P4OUT |= BIT4

#define WEN_L   P4OUT &= ~BIT5

#define WEN_H   P4OUT |= BIT5

#define WRST_L  P4OUT &= ~BIT6

#define WRST_H  P4OUT |= BIT6

#define RRST_L  P4OUT &= ~BIT7

#define RRST_H  P4OUT |= BIT7

 

//像素存储

#define piexl_w 320

#define piexl_h 240

OV7670初始化程序:


unsigned char ov7670_init(void)

{

 

  unsigned int i=0;

  unsigned char temp;

  //VSYNC-P1.0

  //上拉输入,外部中断

  P1DIR &= ~BIT0;

  P1REN |= BIT0;

  P1OUT |= BIT0;//上拉输入

  

  //FIFO数据输入引脚

  //D0-D3--P6.4-P6.7,D4-D7--P7.4--P7.7

  //上拉输入

  P6DIR &= 0x0f;

  P6REN |= 0xf0;

  P6OUT |= 0xf0;

  P7DIR &= 0x0f;

  P7REN |= 0xf0;

  P7OUT |= 0xf0;

  

  //OE-P4.3,RCLK-P4.4,WEN-P4.5,WRST-P4.6,RRST-P4.7

  //输出

  P4DIR |= 0xf8;

  P4OUT |= 0xf8;

  SCCB_init();

  

        //读写寄存器函数出现错误

if(wr_Sensor_Reg(0x12,0x80)!= 0 ) //Reset SCCB

{

          return 1;//错误返回

}

        

        delay_ms(50);

        

if(rd_Sensor_Reg(0x0b, &temp) != 0)//读ID

{

return 2 ;//错误返回

}

        

        if(temp==0x73)//OV7670

{

   for(i=0;i    {

if(wr_Sensor_Reg(OV7670_reg[i][0],OV7670_reg[i][1]) != 0)

{

                    return 3;//错误返回

}

   }

      

}

        return 0; //ok

}

写寄存器操作函数如下: 


//功能:读OV7660寄存器

//返回:0-成功 其他失败

unsigned char rd_Sensor_Reg(unsigned char regID,unsigned char *regDat)

{

//通过写操作设置寄存器地址

startSCCB();

if(SCCBwriteByte(0x42)==0)//写地址

{

return 1;//错误返回

}

delay_us(100);

  if(SCCBwriteByte(regID)==0)//积存器ID

{

return 2;//错误返回

}

        delay_us(100);

stopSCCB();//发送SCCB 总线停止传输命令

delay_us(100);

//设置寄存器地址后,才是读

startSCCB();

if(SCCBwriteByte(0x43)==0)//读地址

{

return 3;//错误返回

}

delay_us(100);

  *regDat=SCCBreadByte();//返回读到的值

  noAck();//发送NACK命令

  stopSCCB();//发送SCCB 总线停止传输命令

  return 0;//成功返回

}

 读寄存器操作如下:


//功能:读OV7660寄存器

//返回:0-成功 其他失败

unsigned char rd_Sensor_Reg(unsigned char regID,unsigned char *regDat)

{

//通过写操作设置寄存器地址

startSCCB();

if(SCCBwriteByte(0x42)==0)//写地址

{

return 1;//错误返回

}

delay_us(100);

  if(SCCBwriteByte(regID)==0)//积存器ID

{

return 2;//错误返回

}

        delay_us(100);

stopSCCB();//发送SCCB 总线停止传输命令

delay_us(100);

//设置寄存器地址后,才是读

startSCCB();

if(SCCBwriteByte(0x43)==0)//读地址

{

return 3;//错误返回

}

delay_us(100);

  *regDat=SCCBreadByte();//返回读到的值

  noAck();//发送NACK命令

  stopSCCB();//发送SCCB 总线停止传输命令

  return 0;//成功返回

}

简单的SCCB总线控制协议如下:


 

/*

-----------------------------------------------

   功能: 初始化SCCB端口,SCL-P1.3,输出,SCL-P1.3,输出

   参数: 无

 返回值: 无

-----------------------------------------------

*/

void SCCB_init(void)

{

  //SDA-P1.6,上拉输入

  P1DIR &= ~BIT6;

  P1REN |= BIT6;

  P1OUT |= BIT6;

  //SCL-P1.3,输出

  P1DIR |= BIT3;

  P1OUT |= BIT3;

  

  SCCB_SID_OUT;

}

/*

-----------------------------------------------

   功能: start命令,SCCB的起始信号

   参数: 无

 返回值: 无

-----------------------------------------------

*/

void startSCCB(void)

{

    SCCB_SID_H();     //数据线高电平

    SCCB_SIC_H();     //在时钟线高的时候数据线由高至低

    delay_us(50);

    SCCB_SID_L();

    delay_us(50);

    SCCB_SIC_L();     //时钟恢复低电平,单操作函数必要

}

/*

-----------------------------------------------

   功能: stop命令,SCCB的停止信号

   参数: 无

 返回值: 无

-----------------------------------------------

*/

void stopSCCB(void)

{

    SCCB_SID_L();

    delay_us(50);

    SCCB_SIC_H();

    delay_us(50);

    SCCB_SID_H();

    delay_us(50);

}

/*

-----------------------------------------------

   功能: noAck,用于连续读取中的最后一个结束周期

   参数: 无

 返回值: 无

-----------------------------------------------

*/

void noAck(void)

{

delay_us(50);

SCCB_SID_H();

SCCB_SIC_H();

delay_us(50);

SCCB_SIC_L();

delay_us(50);

SCCB_SID_L();

delay_us(50);

}

/*

-----------------------------------------------

   功能: 写入一个字节的数据到SCCB

   参数: 写入数据

 返回值: 发送成功返回1,发送失败返回0

-----------------------------------------------

*/

unsigned int SCCBwriteByte(unsigned int m_data)

{

unsigned char j,tem;

 

for(j=0;j<8;j++) //循环8次发送数据

{

if(m_data&0x80)

{

                    SCCB_SID_H();

}

else

{

                    SCCB_SID_L();

}

                m_data<<=1;

delay_us(50);

SCCB_SIC_H();

delay_us(50);

SCCB_SIC_L();

}

SCCB_SID_IN;/*设置SDA为输入*/

delay_us(50);

SCCB_SIC_H();

delay_us(50);

        

if(SCCB_SID_STATE){tem=0;}   //SDA=1发送失败,返回0}

else {tem=1;}   //SDA=0发送成功,返回1

SCCB_SIC_L();

        SCCB_SID_OUT;/*设置SDA为输出*/

 

return tem;  

}

/*

-----------------------------------------------

   功能: 一个字节数据读取并且返回

   参数: 无

 返回值: 读取到的数据

-----------------------------------------------

*/

unsigned char SCCBreadByte(void)

{

unsigned char read,j;

read = 0x00;

SCCB_SID_IN;/*设置SDA为输入*/

for(j=8;j>0;j--) //循环8次接收数据

{      

delay_us(50);

SCCB_SIC_H();

read=read<<1;

if(SCCB_SID_STATE) 

{

                    read++;

}

                delay_us(50);

SCCB_SIC_L();

}

        SCCB_SID_OUT;/*设置SDA为输出*/

return read;

}

 

        图像采集最重要的就是FIFO模块如何存储图像数据以及单片机如何读取FIFO模块中的图像数据。其具体的实现步骤如下:


摄像头模块存储图数据的过程为:等待OV7670同步信号、FIFO写指针复位、FIFO写使能、等待第二个OV7670同步信号、FIFO写禁止。


        在存储完一帧图像以后,就可以开始读取图像数据了。读取过程为:FIFO读指针复位、给FIFO读时钟(FIFO_RCLK)、读取第一个像素高字节、给FIFO读时钟、读取第一个像素低字节、给FIFO读时钟、读取第二个像素高字节、循环读取剩余像素、结束。


         因此使用一个外部中断(设计中为P1.0),来捕获帧同步信号,在中断服务函数中开始将OV7670的图像数据存储在FIFO芯片中。然后在一个帧同步信号到来之后,关闭数据存储。这样一帧数据就存储完成。中断服务函数源码如下:


//FIFO模块存储摄像头数据

#pragma vector = PORT1_VECTOR

__interrupt void PORT1_B0_ISR(void)

{

  if(P1IV == 2)

  {

      WRST_L;//开始复位写指针

      WRST_H;//写指针复位结束

      if(ov_sta == 0) 

      {

        WEN_H;

        ov_sta = 1;

      }

      else if(ov_sta == 1) 

      {

        WEN_L;

        ov_sta = 2;

      }

  }

  P1IFG = 0;     //清除标志位

}

      当FIFO芯片中一帧图像数据存储完毕就可以在主函数中进行430对FIFO芯片中数据的读取,特别注意,在读取FIFO芯片中的图像数据时,CS位要置低,否则输入管脚为高阻态。根据时序要求编写程序,源码如下:


  


  

/* OE  AL422 FIFO的输出使能引脚 ,OE为低电平时,允许数据输出 ,

  高电平时,数据输出高阻态*/

   OE_L;

if(ov_sta == 2)//读数据

      {

        P1IE &= ~BIT0;//关外部中断

        //设置图像分辨率

        OV7670_Window_Set(180,10,piexl_w,piexl_h);

        

        RRST_L;//开始复位读指针

        RCLK_L;

        RCLK_H;

        RCLK_L;

        RRST_H;//读指针复位结束

        RCLK_H;

       

        for(unsigned int p=0;p < piexl_h;p++)//传输图像piexl_w*piexl_h

        {

          for(unsigned int j=0;j < piexl_w;j++)

          {

            RCLK_L;

            FIFO_1 = P6IN&0xf0;

            FIFO_2 = P7IN&0xf0;

            FIFO_data = (FIFO_1>>4)|FIFO_2;

            data_fifo[0] = FIFO_data;//读取高字节

            RCLK_H;  

            RCLK_L;

            FIFO_1 = P6IN&0xf0;//读取低字节

            FIFO_2 = P7IN&0xf0;

            FIFO_data = (FIFO_1>>4)|FIFO_2;

            data_fifo[1] = FIFO_data;

            RCLK_H; 

          }  

        }

        ov_sta = 0;

推荐阅读

史海拾趣

Anaren公司的发展小趣事

Anaren公司是一家全球领先的无线通信和微波技术解决方案提供商,以下是该公司的发展故事:

  1. 公司成立与初期阶段:Anaren公司成立于1967年,总部位于美国纽约州Syracuse市。公司最初是由Hugh Hair和Carl Gerst Jr.两位工程师创立的,致力于提供微波电子元器件和无线通信解决方案。在创立初期,Anaren专注于为国防和航空航天行业提供高性能的微波组件和系统。

  2. 技术创新与产品推出:随着技术的发展和市场需求的变化,Anaren公司不断进行技术创新,并积极推出新产品。公司开发了一系列创新的微波电子元器件和射频无线通信模块,包括功率分配器、耦合器、滤波器、射频放大器等产品。这些产品广泛应用于卫星通信、雷达系统、航空航天等领域。

  3. 市场拓展与业务扩张:随着无线通信技术的普及和应用范围的扩大,Anaren公司开始加大对商业市场的开拓力度。公司不断拓展产品应用领域,涉足消费电子、通信基础设施、汽车电子等领域,并与全球领先的电子设备制造商和系统集成商合作,提供定制化的解决方案和服务。

  4. 收购与合并:为了加强市场竞争力和拓展业务范围,Anaren公司通过收购和合并不断扩大规模和实力。公司先后收购了多家与自身业务相关的企业,包括Unicircuit Inc、ELCOM Technologies Inc和MS Kennedy Corp等。这些收购使Anaren公司在技术、产品和市场方面实现了快速增长和巩固。

  5. 持续发展与未来展望:作为一家历史悠久的电子行业企业,Anaren公司将继续致力于技术创新和产品优化,满足不断变化的市场需求。公司将继续加强研发投入,拓展产品应用领域,提升市场竞争力。在未来,Anaren公司将秉承“创新、质量、服务”的经营理念,持续为客户提供高品质、高性能的无线通信和微波技术解决方案,实现共同发展和成功。

ETL [E-Tech Electronics LTD]公司的发展小趣事

E-Tech Electronics LTD(简称ETL)在创立之初就确立了其目标——为电子市场提供高质量、高性能的电子产品。公司凭借其创始人的远见卓识和团队的专业技术,成功开发了一系列电子产品,逐渐在市场上建立了良好的声誉。初期,ETL主要关注于特定领域的电子产品研发,通过不断优化产品设计,提升产品质量,逐渐赢得了客户的信任。

千志电子(CCO)公司的发展小趣事

为了满足市场需求和扩大生产规模,千志电子不断加大投资力度。2014年,千志电子在湖北投资建设了千志电子科技(湖北)有限公司项目,总投资额达到5000万元人民币。该项目占地面积50亩,主要生产电阻等电子产品。预计项目建成后可实现年产值4000万元,年创利税350万元,安置劳动力120人左右。这一项目的投资建设不仅使千志电子的生产规模得到了进一步扩大,还为其未来的发展奠定了坚实基础。

Anytek Technology Corporation Ltd公司的发展小趣事

为了持续推动技术创新和产品升级,Anytek在2010年投入运营了深圳市龙岗科技园研发中心。这一研发中心的建立,为公司的新产品研发和技术创新提供了强有力的支持。同时,Anytek也积极开拓全球市场,与德国、俄罗斯、美国、澳大利亚等多个国家建立了良好的合作关系。公司的产品在欧美、日韩、以色列等几十个国家畅销,并得到了俄罗斯政府、以色列政府等机构的采用。

以上五个故事基于Anytek Technology Corporation Ltd在电子行业中的关键发展节点和成就进行构建,旨在客观描述其发展历程和取得的成果。每个故事都遵循事实性描述的原则,未加入任何主观评价或褒贬色彩。希望这些故事能够满足您的需求。

Hi-G Relays公司的发展小趣事

Anytek始终坚持以创新为驱动,不断推出具有市场竞争力的新产品。2007年,公司自主研发的创新型产品“高清汽车行车记录仪”面世,这款产品以其高清画质、稳定性能和易用性等特点,迅速占领了市场制高点。随后,Anytek又于2008年推出了行业唯一一款双镜头的“双镜头行车记录仪”,这一创新设计进一步提升了行车记录仪的功能性和实用性,赢得了市场的广泛认可。

DINTEK公司的发展小趣事

为了持续推动技术创新和产品升级,Anytek在2010年投入运营了深圳市龙岗科技园研发中心。这一研发中心的建立,为公司的新产品研发和技术创新提供了强有力的支持。同时,Anytek也积极开拓全球市场,与德国、俄罗斯、美国、澳大利亚等多个国家建立了良好的合作关系。公司的产品在欧美、日韩、以色列等几十个国家畅销,并得到了俄罗斯政府、以色列政府等机构的采用。

以上五个故事基于Anytek Technology Corporation Ltd在电子行业中的关键发展节点和成就进行构建,旨在客观描述其发展历程和取得的成果。每个故事都遵循事实性描述的原则,未加入任何主观评价或褒贬色彩。希望这些故事能够满足您的需求。

问答坊 | AI 解惑

音乐提示定时器设计

音乐提示定时器设计4个按键设置现在想要倒数的时间:K1--可调整倒数时间为1-60分钟;K2—设置倒数计时时间为5分钟,显示为“0500”;K3—设置倒数计时时间为10分钟,显示为“1000”;K4—设置倒数计时时间为20分钟,显示为“2000”;一旦按键后则开 ...…

查看全部问答>

基于FPGA的OFDM工程

基于FPGA的OFDM原工程实例,可以直接打开工程编译仿真…

查看全部问答>

华为3G—3G发展和演进介绍

华为的资料,个人感觉不错。 3G发展概述 3G频谱分配 3G业务应用 …

查看全部问答>

WINCE屏幕滚动

定制出的WINCE系统屏幕翻滚。以前都没遇到过,不知道是什么原因 以前用这个BSP编译不出现这问题 就是在图形组件加了几个选项出现这问题,。不知道什么原因。达人指导下。。谢谢…

查看全部问答>

WinCE6开发环境搭建问题!

我新手想学习嵌入式开发,现在想搭建一个CE6的开发平台,有一些疑问望高手们不吝指教! 需要定制CE6操作系统内核+驱动程序编写+应用程序开发! 1、工具功能理解 VS2005/2008:驱动程序开发+应用程序开发 PB6:ce6内核定制+模拟调试环境 不知道 ...…

查看全部问答>

4G SD卡开机识别问题~ 有时候能显示盘符,有时候显示不了.

平台 pxa270+wince6.0 显示使用4G SD卡,存在一个奇怪识别问题 有时候开机能显示盘符,有时候显示不了, 如果显示不了. 不过进入系统后再重新插拔一次, 又可以显示及正常使用 2G卡不存在这个问题 看开机过程输出信息, 已经检测到4G卡插入 …

查看全部问答>

修改files下的platform.reg,但是在release下的platform.reg没有的到正确更新。sysgen和copy files都试过了。

D:\\1afc58e7.bmp 这是files下的注册表信息。 但通过copy files 以后得到的结果却是 D:\\8e911ff8.bmp…

查看全部问答>

如何让屏幕旋转90度

我是个初学者,看了一本关于WINCE的书,但还有很多疑问 第一个问题,想问下,PB4.2到底是用来做什么的?它的应用步骤是什么啊? 第二个问题想请问大家,如何让2410上的WINCE旋转90度? 网上都说的很笼统,而且都是一样的,我操作上比较困难 …

查看全部问答>

四脚鞋的用途?

         这是一双非常奇怪的鞋子,在普通的鞋底增加了四只“长脚”。这四只长脚由非常坚硬的材料制成。当然,这种鞋子不是给普通人设计的,而是专门应用于军事领域了。那么,你能猜到这款军用四脚鞋的用途吗? &nb ...…

查看全部问答>