鹰眼摄像头的移植(LPLD V3)

关键词:

  • 鹰眼摄像头
  • LPLD V3库
  • OV7725

鹰眼摄像头的优点

1.硬件二值化,二值化效果理想(个人看法不一样)
2.一次传输8个像素,速度可达150帧每秒
3.成像质量、低照度好的OV7725
由于某宙捕食者摄像头停产,不得不换用市面上认为用于智能车比赛较好的摄像头——鹰眼(我也是偷懒的人,能用别人的坚决不自己写)。

鹰眼的驱动步骤

1.了解鹰眼的工作方式(可以参考《OV7725数字摄像头编程基本知识笔记》)

我在驱动鹰眼的时候和山外哥一样,并未使用行中断,而是采用场中断+DMA的方式,可能与大家习惯使用行场中断+DMA采集图像的方式存在差异,不过原理并没有太多区别。
鹰眼摄像头的移植(LPLD V3)_第1张图片
注意:①在K60与PCLK、VSYNC连接的IO处加下拉150Ω的电阻进行阻抗匹配,可以有效减少干扰。不过我在测试的时候并没有加,图像也很稳定,并没有异常。
②鹰眼使用3.3V供电,存在因电池电量不够出现图像上下错位的情况。

鹰眼摄像头的移植(LPLD V3)_第2张图片

2.搞清楚时序图

鹰眼摄像头的移植(LPLD V3)_第3张图片
(忽略图片中的行中断内容)采用场信号上升沿触发中断,开启DMA,根据PCLK的下降沿触发,传输图像。

3.采集图像的思路

使用场中断,DMA传输

①需要采集图像时,开场中断
②判断场中断来了,初始化DMA传输,并启动DMA传输
③每个PCLK下降沿来了都触发DMA传输,把摄像头的输出的值读取到内存数组里。
④DMA停止传输时触发中断,中断里面设置图像采集结束标志,图像采集完毕。

4.使用SCCB

OV7725摄像头的寄存器是EEPRON,有一定单片机基础的同学都知道,其不稳定,数据易丢失,因此程序每次初始化时我们都需要重新写入寄存器设置。下面定义摄像头的各寄存器地址:

#ifndef _OV7725_REG_H_
#define _OV7725_REG_H_

#define OV7725_ID           0x21


#define OV7725_GAIN      0x00
#define OV7725_BLUE      0x01
#define OV7725_RED       0x02
#define OV7725_GREEN     0x03
#define OV7725_BAVG      0x05
#define OV7725_GAVG      0x06
#define OV7725_RAVG      0x07
#define OV7725_AECH      0x08
#define OV7725_COM2      0x09
#define OV7725_PID       0x0A
#define OV7725_VER       0x0B
#define OV7725_COM3      0x0C
#define OV7725_COM4      0x0D
#define OV7725_COM5      0x0E
#define OV7725_COM6      0x0F
#define OV7725_AEC       0x10
#define OV7725_CLKRC     0x11
#define OV7725_COM7      0x12
#define OV7725_COM8      0x13
#define OV7725_COM9      0x14
#define OV7725_COM10     0x15
#define OV7725_REG16     0x16
#define OV7725_HSTART    0x17
#define OV7725_HSIZE     0x18
#define OV7725_VSTRT     0x19
#define OV7725_VSIZE     0x1A
#define OV7725_PSHFT     0x1B
#define OV7725_MIDH      0x1C
#define OV7725_MIDL      0x1D
#define OV7725_LAEC      0x1F
#define OV7725_COM11     0x20
#define OV7725_BDBase    0x22
#define OV7725_BDMStep   0x23
#define OV7725_AEW       0x24
#define OV7725_AEB       0x25
#define OV7725_VPT       0x26
#define OV7725_REG28     0x28
#define OV7725_HOutSize  0x29
#define OV7725_EXHCH     0x2A
#define OV7725_EXHCL     0x2B
#define OV7725_VOutSize  0x2C
#define OV7725_ADVFL     0x2D
#define OV7725_ADVFH     0x2E
#define OV7725_YAVE      0x2F
#define OV7725_LumHTh    0x30
#define OV7725_LumLTh    0x31
#define OV7725_HREF      0x32
#define OV7725_DM_LNL    0x33
#define OV7725_DM_LNH    0x34
#define OV7725_ADoff_B   0x35
#define OV7725_ADoff_R   0x36
#define OV7725_ADoff_Gb  0x37
#define OV7725_ADoff_Gr  0x38
#define OV7725_Off_B     0x39
#define OV7725_Off_R     0x3A
#define OV7725_Off_Gb    0x3B
#define OV7725_Off_Gr    0x3C
#define OV7725_COM12     0x3D
#define OV7725_COM13     0x3E
#define OV7725_COM14     0x3F
#define OV7725_COM16     0x41
#define OV7725_TGT_B     0x42
#define OV7725_TGT_R     0x43
#define OV7725_TGT_Gb    0x44
#define OV7725_TGT_Gr    0x45
#define OV7725_LC_CTR    0x46
#define OV7725_LC_XC     0x47
#define OV7725_LC_YC     0x48
#define OV7725_LC_COEF   0x49
#define OV7725_LC_RADI   0x4A
#define OV7725_LC_COEFB  0x4B
#define OV7725_LC_COEFR  0x4C
#define OV7725_FixGain   0x4D
#define OV7725_AREF1     0x4F
#define OV7725_AREF6     0x54
#define OV7725_UFix      0x60
#define OV7725_VFix      0x61
#define OV7725_AWBb_blk  0x62
#define OV7725_AWB_Ctrl0 0x63
#define OV7725_DSP_Ctrl1 0x64
#define OV7725_DSP_Ctrl2 0x65
#define OV7725_DSP_Ctrl3 0x66
#define OV7725_DSP_Ctrl4 0x67
#define OV7725_AWB_bias  0x68
#define OV7725_AWBCtrl1  0x69
#define OV7725_AWBCtrl2  0x6A
#define OV7725_AWBCtrl3  0x6B
#define OV7725_AWBCtrl4  0x6C
#define OV7725_AWBCtrl5  0x6D
#define OV7725_AWBCtrl6  0x6E
#define OV7725_AWBCtrl7  0x6F
#define OV7725_AWBCtrl8  0x70
#define OV7725_AWBCtrl9  0x71
#define OV7725_AWBCtrl10 0x72
#define OV7725_AWBCtrl11 0x73
#define OV7725_AWBCtrl12 0x74
#define OV7725_AWBCtrl13 0x75
#define OV7725_AWBCtrl14 0x76
#define OV7725_AWBCtrl15 0x77
#define OV7725_AWBCtrl16 0x78
#define OV7725_AWBCtrl17 0x79
#define OV7725_AWBCtrl18 0x7A
#define OV7725_AWBCtrl19 0x7B
#define OV7725_AWBCtrl20 0x7C
#define OV7725_AWBCtrl21 0x7D
#define OV7725_GAM1      0x7E
#define OV7725_GAM2      0x7F
#define OV7725_GAM3      0x80
#define OV7725_GAM4      0x81
#define OV7725_GAM5      0x82
#define OV7725_GAM6      0x83
#define OV7725_GAM7      0x84
#define OV7725_GAM8      0x85
#define OV7725_GAM9      0x86
#define OV7725_GAM10     0x87
#define OV7725_GAM11     0x88
#define OV7725_GAM12     0x89
#define OV7725_GAM13     0x8A
#define OV7725_GAM14     0x8B
#define OV7725_GAM15     0x8C
#define OV7725_SLOP      0x8D
#define OV7725_DNSTh     0x8E
#define OV7725_EDGE0     0x8F
#define OV7725_EDGE1     0x90
#define OV7725_DNSOff    0x91
#define OV7725_EDGE2     0x92
#define OV7725_EDGE3     0x93
#define OV7725_MTX1      0x94
#define OV7725_MTX2      0x95
#define OV7725_MTX3      0x96
#define OV7725_MTX4      0x97
#define OV7725_MTX5      0x98
#define OV7725_MTX6      0x99
#define OV7725_MTX_Ctrl  0x9A
#define OV7725_BRIGHT    0x9B
#define OV7725_CNST      0x9C
#define OV7725_UVADJ0    0x9E
#define OV7725_UVADJ1    0x9F
#define OV7725_SCAL0     0xA0
#define OV7725_SCAL1     0xA1
#define OV7725_SCAL2     0xA2
#define OV7725_SDE       0xA6
#define OV7725_USAT      0xA7
#define OV7725_VSAT      0xA8
#define OV7725_HUECOS    0xA9
#define OV7725_HUESIN    0xAA
#define OV7725_SIGN      0xAB
#define OV7725_DSPAuto   0xAC

#endif

摄像头初始化配置表单:

reg_s ov7725_eagle_reg[] =
{
    //寄存器,寄存器值次             50   75   112  150
    {OV7725_COM4         , 0xC1},//0xc1;0x41;0x81;0xc1
    {OV7725_CLKRC        , 0x00},//0x02;0x00;0x00;0x00
    {OV7725_COM2         , 0x03},
    {OV7725_COM3         , 0xD0},
    {OV7725_COM7         , 0x40},
    {OV7725_COM10        , 0x20},
    {OV7725_HSTART       , 0x3F},
    {OV7725_HSIZE        , 0x50},
    {OV7725_VSTRT        , 0x03},
    {OV7725_VSIZE        , 0x78},
    {OV7725_HREF         , 0x00},
    {OV7725_SCAL0        , 0x0A},
    {OV7725_AWB_Ctrl0    , 0xE0},
    {OV7725_DSPAuto      , 0xff},
    {OV7725_DSP_Ctrl2    , 0x0C},
    {OV7725_DSP_Ctrl3    , 0x00},
    {OV7725_DSP_Ctrl4    , 0x00},

#if (CAMERA_W == 80)
    {OV7725_HOutSize     , 0x14},
#elif (CAMERA_W == 160)
    {OV7725_HOutSize     , 0x28},
#elif (CAMERA_W == 240)
    {OV7725_HOutSize     , 0x3c},
#elif (CAMERA_W == 320)
    {OV7725_HOutSize     , 0x50},
#else

#endif

#if (CAMERA_H == 60 )
    {OV7725_VOutSize     , 0x1E},
#elif (CAMERA_H == 120 )
    {OV7725_VOutSize     , 0x3c},
#elif (CAMERA_H == 180 )
    {OV7725_VOutSize     , 0x5a},
#elif (CAMERA_H == 240 )
    {OV7725_VOutSize     , 0x78},
#else

#endif

    {OV7725_EXHCH        , 0x00},
    {OV7725_GAM1         , 0x0c},
    {OV7725_GAM2         , 0x16},
    {OV7725_GAM3         , 0x2a},
    {OV7725_GAM4         , 0x4e},
    {OV7725_GAM5         , 0x61},
    {OV7725_GAM6         , 0x6f},
    {OV7725_GAM7         , 0x7b},
    {OV7725_GAM8         , 0x86},
    {OV7725_GAM9         , 0x8e},
    {OV7725_GAM10        , 0x97},
    {OV7725_GAM11        , 0xa4},
    {OV7725_GAM12        , 0xaf},
    {OV7725_GAM13        , 0xc5},
    {OV7725_GAM14        , 0xd7},
    {OV7725_GAM15        , 0xe8},
    {OV7725_SLOP         , 0x20},
    {OV7725_LC_RADI      , 0x00},
    {OV7725_LC_COEF      , 0x13},
    {OV7725_LC_XC        , 0x08},
    {OV7725_LC_COEFB     , 0x14},
    {OV7725_LC_COEFR     , 0x17},
    {OV7725_LC_CTR       , 0x05},
    {OV7725_BDBase       , 0x99},
    {OV7725_BDMStep      , 0x03},
    {OV7725_SDE          , 0x04},
    {OV7725_BRIGHT       , 0x00},
    {OV7725_CNST         , 0x90},
    {OV7725_SIGN         , 0x06},
    {OV7725_UVADJ0       , 0x11},
    {OV7725_UVADJ1       , 0x02},

};

OV77寄存器初始化函数:

uint8 ov7725_eagle_reg_init(void)
{
    uint16 i = 0;
    uint8 Sensor_IDCode = 0;
    SCCB_GPIO_init();

    if( 0 == SCCB_WriteByte ( OV7725_COM7, 0x80 ) ) /*复位摄像头传感器*/
    {
        return 0 ;
    }

    LPLD_SYSTICK_DelayMs(50);

    if( 0 == SCCB_ReadByte( &Sensor_IDCode, 1, OV7725_VER ) )    /* 读取摄像头传感器 ID号*/
    {
        return 0;
    }
    if(Sensor_IDCode == OV7725_ID)
    {
        for( i = 0 ; i < ov7725_eagle_cfgnum ; i++ )
        {
            if( 0 == SCCB_WriteByte(ov7725_eagle_reg[i].addr, ov7725_eagle_reg[i].val) )
            {
                return 0;
            }
        }
    }
    else
    {
        return 0;
    }
    return 1;
}

SCCB配置:

#include "common.h"
#include "SCCB.h"

static void SCCB_delay(uint16 i);

/*!
 *  @brief      SCCB延迟函数
 */
static void SCCB_delay(volatile uint16 time)
{
    while(time)
    {
        time--;
    }
}

/*!
 *  @brief      SCCB管脚配置
 */
void SCCB_GPIO_init(void)
{
  GPIO_InitTypeDef ptb;
  /********用户可修改值 开始***********/
  ptb.GPIO_PTx = PTA;
  ptb.GPIO_Pins = GPIO_Pin25 | GPIO_Pin26;
  /********用户可修改值 结束***********/
  ptb.GPIO_Dir = DIR_OUTPUT;
  ptb.GPIO_Output = OUTPUT_H;
  ptb.GPIO_PinControl = NULL;
  LPLD_GPIO_Init(ptb);
}

/*!
 *  @brief      SCCB起始信号
 */
static uint8 SCCB_Start(void)
{
    SDA_H();
    SCL_H();
    SCCB_DELAY();

    SDA_DDR_IN();
    if(!SDA_IN())
    {
        SDA_DDR_OUT();
        return 0;   /* SDA线为低电平则总线忙,退出 */
    }
    SDA_DDR_OUT();
    SDA_L();

    SCCB_DELAY();
    SCL_L();

    if(SDA_IN())
    {
        SDA_DDR_OUT();
        return 0;   /* SDA线为高电平则总线出错,退出 */
    }
    //SDA_DDR_OUT();
    //SDA_L();
    //SCCB_delay();
    return 1;
}

/*!
 *  @brief      SCCB停止信号
 */
static void SCCB_Stop(void)
{
    SCL_L();
    //SCCB_DELAY();
    SDA_L();
    SCCB_DELAY();
    SCL_H();
    SCCB_DELAY();
    SDA_H();
    SCCB_DELAY();
}

/*!
 *  @brief      SCCB应答信号
 */
static void SCCB_Ack(void)
{
    SCL_L();
    SCCB_DELAY();
    SDA_L();
    SCCB_DELAY();
    SCL_H();
    SCCB_DELAY();
    SCL_L();
    SCCB_DELAY();
}

/*!
 *  @brief      SCCB无应答信号
 */
static void SCCB_NoAck(void)
{
    SCL_L();
    SCCB_DELAY();
    SDA_H();
    SCCB_DELAY();
    SCL_H();
    SCCB_DELAY();
    SCL_L();
    SCCB_DELAY();
}

/*!
 *  @brief      SCCB 等待应答
 *  @return     应答结果(0表示无应答,1表示有应答)
 */
static int SCCB_WaitAck(void)
{
    SCL_L();
    //SDA_H();
    SDA_DDR_IN();

    SCCB_DELAY();
    SCL_H();

    SCCB_DELAY();

    if(SDA_IN())           //应答为高电平,异常,通信失败
    {
        SDA_DDR_OUT();
        SCL_L();
        return 0;
    }
    SDA_DDR_OUT();
    SCL_L();
    return 1;
}

/*!
 *  @brief      SCCB 发送的数据
 *  @param      SendByte    需要发送的数据
 */
static void SCCB_SendByte(uint8 SendByte)
{
    uint8 i = 8;
    while(i--)
    {

        if(SendByte & 0x80)     //SDA 输出数据
        {
            SDA_H();
        }
        else
        {
            SDA_L();
        }
        SendByte <<= 1;
        SCCB_DELAY();
        SCL_H();                //SCL 拉高,采集信号
        SCCB_DELAY();
        SCL_L();                //SCL 时钟线拉低
        //SCCB_DELAY();
    }
    //SCL_L();
}

/*!
 *  @brief      接收SCCB总线的数据
 *  @return     接收到的数据
 */
static int SCCB_ReceiveByte(void)
{
    uint8 i = 8;
    uint8 ReceiveByte = 0;

    //SDA_H();
    //SCCB_DELAY();
    SDA_DDR_IN();

    while(i--)
    {
        ReceiveByte <<= 1;
        SCL_L();
        SCCB_DELAY();
        SCL_H();
        SCCB_DELAY();

        if(SDA_IN())
        {
            ReceiveByte |= 0x01;
        }


    }
    SDA_DDR_OUT();
    SCL_L();
    return ReceiveByte;
}

/******************************************************
* 函数名:SCCB_WriteByte
* 描述  :写一字节数据
* 输入  :- WriteAddress: 待写入地址    - SendByte: 待写入数据  - DeviceAddress: 器件类型
* 输出  :返回为:=1成功写入,=0失败
**********************************/
static int SCCB_WriteByte_one( uint16 WriteAddress , uint8 SendByte );


int SCCB_WriteByte( uint16 WriteAddress , uint8 SendByte )            //考虑到用sccb的管脚模拟,比较容易失败,因此多试几次
{
    uint8 i = 0;
    while( 0 == SCCB_WriteByte_one ( WriteAddress, SendByte ) )
    {
        i++;
        if(i == 20)
        {
            return 0 ;
        }
    }
    return 1;
}

int SCCB_WriteByte_one( uint16 WriteAddress , uint8 SendByte )
{
    if(!SCCB_Start())
    {
        return 0;
    }
    SCCB_SendByte( DEV_ADR );                    /* 器件地址 */
    if( !SCCB_WaitAck() )
    {
        SCCB_Stop();
        return 0;
    }
    SCCB_SendByte((uint8)(WriteAddress & 0x00FF));   /* 设置低起始地址 */
    SCCB_WaitAck();
    SCCB_SendByte(SendByte);
    SCCB_WaitAck();
    SCCB_Stop();
    return 1;
}




/******************************************************
 * 函数名:SCCB_ReadByte
 * 描述  :读取一串数据
 * 输入  :- pBuffer: 存放读出数据  - length: 待读出长度    - ReadAddress: 待读出地址        - DeviceAddress: 器件类型
 * 输出  :返回为:=1成功读入,=0失败
********/
static int SCCB_ReadByte_one(uint8 *pBuffer,   uint16 length,   uint8 ReadAddress);

int SCCB_ReadByte(uint8 *pBuffer,   uint16 length,   uint8 ReadAddress)
{
    uint8 i = 0;
    while( 0 == SCCB_ReadByte_one(pBuffer, length, ReadAddress) )
    {
        i++;
        if(i == 30)
        {
            return 0 ;
        }
    }
    return 1;
}

int SCCB_ReadByte_one(uint8 *pBuffer,   uint16 length,   uint8 ReadAddress)
{
    if(!SCCB_Start())
    {
        return 0;
    }
    SCCB_SendByte( DEV_ADR );         /* 器件地址 */
    if( !SCCB_WaitAck() )
    {
        SCCB_Stop();
        return 0;
    }
    SCCB_SendByte( ReadAddress );           /* 设置低起始地址 */
    SCCB_WaitAck();
    SCCB_Stop();

    if(!SCCB_Start())
    {
        return 0;
    }
    SCCB_SendByte( DEV_ADR + 1 );               /* 器件地址 */

    if(!SCCB_WaitAck())
    {
        SCCB_Stop();
        return 0;
    }
    while(length)
    {
        *pBuffer = SCCB_ReceiveByte();
        if(length == 1)
        {
            SCCB_NoAck();
        }
        else
        {
            SCCB_Ack();
        }
        pBuffer++;
        length--;
    }
    SCCB_Stop();
    return 1;
}

5.场中断、PCLK、数据端口配置

void ov7725_eagle_port_init()//注意先初始化数据口在初始化DMA
{      

  //数据口初始化:PTB0~PTB7
    pte_init.GPIO_PTx = PTB;
    pte_init.GPIO_Dir = DIR_INPUT;
    pte_init.GPIO_Pins = GPIO_Pin0_7;
    pte_init.GPIO_PinControl = IRQC_DIS | INPUT_PULL_DIS;
    LPLD_GPIO_Init(pte_init);

    dma_init();

    LPLD_DMA_DisableReq(CAMERA_DMA_CH);
    disable_irq(PORTA_IRQn);                        //关闭PTA的中断
    DMA0->INT |= 0x1u<<0;                           //清除中断标志位
    LPLD_GPIO_ClearIntFlag(PORTA);
    LPLD_DMA_EnableIrq(dma_init_struct);

  //行信号接口初始化:PTA28-H;‘’并未使用行信号产生中断--hl‘’
    h_init.GPIO_PTx = PTA;
    h_init.GPIO_Dir = DIR_INPUT;
    h_init.GPIO_Pins = GPIO_Pin28;
    h_init.GPIO_PinControl = IRQC_DIS|INPUT_PULL_DOWN;
    //h_init.GPIO_Isr = coms_isr;
    LPLD_GPIO_Init(h_init); 

  //场信号接口初始化:PTA29-V
    v_init.GPIO_PTx = PTA;
    v_init.GPIO_Dir = DIR_INPUT;
    v_init.GPIO_Pins = GPIO_Pin29;
    v_init.GPIO_PinControl = IRQC_RI|INPUT_PULL_DOWN;
    v_init.GPIO_Isr = ov7725_eagle_vsync;
    LPLD_GPIO_Init(v_init); 

  // PCLK信号接口初始化:PTA27-PCLK
    p_init.GPIO_PTx = PTA;
    p_init.GPIO_Pins = GPIO_Pin27;
    p_init.GPIO_Dir = DIR_INPUT;
    p_init.GPIO_PinControl = IRQC_DMAFA | INPUT_PULL_DOWN|INPUTPF_EN;
    LPLD_GPIO_Init(p_init); 
}
void dma_init()
{
  //DMA参数配置
  dma_init_struct.DMA_CHx = CAMERA_DMA_CH;                     //CH0通道
  dma_init_struct.DMA_Req = PORTA_DMAREQ;                      //PORTA为请求源
  dma_init_struct.DMA_MajorLoopCnt = CAMERA_DMA_NUM;           //主循环计数值
  dma_init_struct.DMA_MinorByteCnt = 1;                        //次循环一次传输字节的个数
  dma_init_struct.DMA_SourceAddr = (uint32)&PTB->PDIR;         //源地址:PTB0~7
  dma_init_struct.DMA_DestAddr = (uint32)ov7725_eagle_img_buff;//目的地址:存放图像的数组
  dma_init_struct.DMA_DestAddrOffset = 1;                      //目的地址偏移:每次读入增加1
  dma_init_struct.DMA_AutoDisableReq = TRUE;                   //自动禁用请求
  dma_init_struct.DMA_MajorCompleteIntEnable=TRUE;             //使能DMA主循环完成中断
  (DMA0->TCD[CAMERA_DMA_CH].CSR =0|DMA_CSR_BWC(3));            //每读一次,eDMA暂停4个周期
  dma_init_struct.DMA_Isr=ov7725_eagle_dma;
  //初始化DMA
  LPLD_DMA_Init(dma_init_struct);

}

6.中断服务函数

void ov7725_eagle_vsync(void)
{   
  if(LPLD_GPIO_IsPinxExt(PORTA, GPIO_Pin29))//很关键,必须判断是否为PTA29上的中断
  {
    //场中断需要判断是场结束还是场开始
    if(ov7725_eagle_img_flag==IMG_START)                   //需要开始采集图像
    {        
     ov7725_eagle_img_flag=IMG_GATHER;    //标记图像采集中
         disable_irq(PORTA_IRQn);
#if 1        
         PORTA->ISFR =1<<27;
     LPLD_DMA_EnableReq(CAMERA_DMA_CH);  //使能通道CHn 硬件请求
         PORTA->ISFR =1<<27;
         LPLD_DMA_LoadDstAddr(CAMERA_DMA_CH,(uint32)ov7725_eagle_img_buff);
         //LPLD_GPIO_Toggle_b(PTC,0);
#else
         PORTA->ISFR =1<<27;
         //dma_init();
         DMA0->INT |= 0x1u<<0;//清除中断标志位
         (DMA0->TCD[CAMERA_DMA_CH].CITER_ELINKNO=(((uint16_t)(((uint16_t)(CAMERA_DMA_NUM))<TCD[CAMERA_DMA_CH].BITER_ELINKNO=(((uint16_t)(((uint16_t)(CAMERA_DMA_NUM))<TCD[CAMERA_DMA_CH].SADDR=(uint32)&PTB->PDIR);
         (DMA0->TCD[CAMERA_DMA_CH].DADDR=(uint32)ov7725_eagle_img_buff);
         LPLD_DMA_EnableReq(CAMERA_DMA_CH);

#endif         
    }
    else                                    //图像采集错误
    {
        disable_irq(PORTA_IRQn);            //关闭PTA的中断
        ov7725_eagle_img_flag = IMG_FAIL;   //标记图像采集失败
    }
  }
}
void ov7725_eagle_dma()
{
    ov7725_eagle_img_flag = IMG_FINISH ;
}

7.解压图像

因为摄像头传输回来的数据是并不是一个像素一个字节,而是八个像素一个字节,所以无论是发送到上位机观察图像还是屏幕显示图像,都必须先解压图像。

void img_extract(void *dst, void *src, uint32_t srclen)
{
    uint8_t colour[2] = {255, 0}; //0 和 1 分别对应的颜色
    uint8_t * mdst = dst;
    uint8_t * msrc = src;
    //注:山外的摄像头 0 表示 白色,1表示 黑色
    uint8_t tmpsrc;
    while(srclen --)
    {
        tmpsrc = *msrc++;
        *mdst++ = colour[ (tmpsrc >> 7 ) & 0x01 ];
        *mdst++ = colour[ (tmpsrc >> 6 ) & 0x01 ];
        *mdst++ = colour[ (tmpsrc >> 5 ) & 0x01 ];
        *mdst++ = colour[ (tmpsrc >> 4 ) & 0x01 ];
        *mdst++ = colour[ (tmpsrc >> 3 ) & 0x01 ];
        *mdst++ = colour[ (tmpsrc >> 2 ) & 0x01 ];
        *mdst++ = colour[ (tmpsrc >> 1 ) & 0x01 ];
        *mdst++ = colour[ (tmpsrc >> 0 ) & 0x01 ];
    }
}

以上完成了基础的配置,调用下面两个初始化函数和采集图像函数,就可以正常使用这款摄像头。

uint8 ov7725_eagle_init(uint8 *imgaddr)
{
    ov7725_eagle_img_buff = imgaddr;
    while(ov7725_eagle_reg_init() == 0);
    ov7725_eagle_port_init();
    return 0;
}
void ov7725_eagle_get_img()
{
    ov7725_eagle_img_flag = IMG_START;                   //开始采集图像
    LPLD_GPIO_ClearIntFlag(PORTA);
    enable_irq(PORTA_IRQn);                         //允许PTA的中断
    while(ov7725_eagle_img_flag != IMG_FINISH)           //等待图像采集完毕
    {
        if(ov7725_eagle_img_flag == IMG_FAIL)            //假如图像采集错误,则重新开始采集
        {
            ov7725_eagle_img_flag = IMG_START;           //开始采集图像
            LPLD_GPIO_ClearIntFlag(PORTA);
            enable_irq(PORTA_IRQn);                 //允许PTA的中断
        }
    }
}

总结

对于摄像头的使用,一般来讲都是按照上续步骤,注意处理好各中断就好。根据上位机的不同,先发送不同的命令后传输数据。后续出稳定的图像后,可以更改OV7725初始化配置表单中的数值来调节帧率、像素等。
附上两张在屏幕上显示的照片。
鹰眼摄像头的移植(LPLD V3)_第4张图片
鹰眼摄像头的移植(LPLD V3)_第5张图片

你可能感兴趣的:(飞思卡尔)