基于STM32与OV7670的简陋型光流模块

admin 2020-5-10 4901

首先上传电路和程序:
 电路.rar (992.51 KB, 下载次数: 1)
 程序.rar (767.78 KB, 下载次数: 0)
还有两个VB上位机用于调试:
 串口图片显示1.0.rar (6.68 MB, 下载次数: 0)
 多波形显示V2.0.rar (6.71 MB, 下载次数: 0)

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

简介:

此模块是利用STM32F103CBT6驱动OV7670摄像头模组,可作简单的图像处理,打算用于四轴飞行器的悬停。

实际应用中可能会不理想,假如环境太单调,那效果就不好。

听说PX4FLOW做得挺好,查了下好像挺贵。

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

OV7670驱动原理:

电源(DOVDD,AVDD)为2.5V左右(HT7333输出串1N4148降压,因为我没有HT7325),

DVDD采用OV7670内部的LDO(1.8V),外部只需接一只电容.

单片机为STM32F103CBT6,采用HSI时钟,PLL倍频到64MHz,可省去外部晶振.

由于只需要处理灰度图像,OV7670配置为YUV格式,Y在前,

TIM4_CH1的捕获分频设置为2分频,就可以只采集Y(亮度).

TIM3_CH3产生XCLK,(16MHz对应VSYNC约20HZ,实测最低约8MHZ)

TIM4_CH1检测PCLK(4MHz),下降沿捕获,滤波为1,二分频,触发DMA,采集PA0~PA7的数据至数组DMA_Buf.

TIM3_CH4检测VSYNC,下降沿捕获中断,控制DMA的关与开.

HREF忽略.

引脚连接:

PA12:                        LED

PA0~7:                        OV7670_D0~D7

PB0(TIM3_CH3):        OV7670_XCLK

PB1(TIM3_CH4):        OV7670_VSYNC

PB2:                        OV7670_RST

PB7(TIM4_CH2):        OV7670_HREF(可省略)

PB6(TIM4_CH1):        OV7670_PCLK

PB10:                        OV7670_SIO_C

PB11:                        OV7670_SIO_D

PB12:                        OV7670_PWDN

建议:

        为加快速度,SIO_C与SIO_D可加外部上拉电阻

注意:

        看了下SCCB时序,貌似与IIC略有区别,指定地址读数据时:

        OV7670:        ...IICWByte(add);IICACK(0);IICEnd();IICStart();...

        普通IIC:...IICWByte(add);IICACK(0);         IICStart();...

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

图像处理:

上次图像中部区域(按STEP间隔)存入数组MID_Buf,在当前采集的

图像中遍历,寻找差值最小的位置,从而得到座标增量。

程序中配置摄像头为YUV格式,窗口为160*80像素,得到80*80的Y(亮度)数据;

中心区为40*40像素,STEP设置为5,也就成了8*8的稀疏点阵,处理一幅图像大约耗时45ms.

(由于接收图像还需要时间,所以程序中约100ms处理一次)

程序经KEIL3编译后:Code=12054 RO-data=358 RW-data=48 ZI-data=8608;

可以看出代码量和内存消耗都不大。

图像处理核心算法:

(注意,由于二维数组访问速度较低,真实的代码略有优化,详见附件)


//--------------------------------------------------
//变量定义
//--------------------------------------------------
U8         DMA_Buf[CAMHEIGHT][CAMWIDTH];//本次采集的摄像头数据
U8         MID_Buf[MIDHEIGHT][MIDWIDTH];//上次中部区域的数据
//--------------------------------------------------
//计算差值的绝对值
//--------------------------------------------------
__INLINE U8  caldif(U8 v1,U8 v2)
{
        if(v1>v2)return v1-v2;
        return v2-v1;
}
//--------------------------------------------------
//图像处理:用上次图像中部区域去与当前采集图像(从x,y
//开始的区域)求差,寻找差值最小的位置,
//从而得到x增量(MovIncX)与y增量(MovIncY)
//--------------------------------------------------
void PicProcess(void)
{
        U16 i,j,x,y;
        U32 dif,min=0xffffffff;        //差值,最小值
        U16 minx,miny;                        //最小值处的左上角座标
        //--------遍历整个当前图像,查找与之前中部图像相差最小的位置        
        for(y=0;y<CAMHEIGHT-MIDHEIGHT;y++)//从上到下
        {
                for(x=0;x<CAMWIDTH-MIDWIDTH;x++)//从左到右
                {                
                        dif=0;//误差清0                        
                        for(i=0;i<MIDHEIGHT;i+=STEP)
                        {
                                for(j=0;j<MIDWIDTH;j+=STEP)
                                {//计算当前图像中的点与上次图像中部区域的点的差值
                                        dif+=caldif(DMA_Buf[y+i][x+j],MID_Buf[i][j]);//误差累加        
                                }
                        }
                        if(min>dif)//误差小于当前最小值,则记最小值为当前值,且记下座标
                        {
                                min=dif;
                                minx=x;
                                miny=y;
                        }
                }
        }
        //------------------------------计算座标增量
        if(min>30000)min=30000;//此句可省,是为了便于串口发送该值
        if(min<15*(MIDHEIGHT/STEP)*(MIDWIDTH/STEP))//允许平均每个点15的误差
        {
                MovIncX=minx-MIDX;//x增量
                MovIncY=miny-MIDY;//y增量
                MovX+=MovIncX;//模拟成鼠标的绝对座标,便于查看
                MovY+=MovIncY;        
                if(MovX<-1000)MovX=-1000;//限幅
                if(MovX>1000)MovX=1000;        
                if(MovY<-1000)MovY=-1000;
                if(MovY>1000)MovY=1000;
        }        
        //------------------------------复制当前中部区域
        for(i=0;i<MIDHEIGHT;i+=STEP)
        {
                //memcpy(MID_Buf[i],DMA_Buf[MIDY+i]+MIDX,MIDWIDTH);
                for(j=0;j<MIDWIDTH;j+=STEP)
                {
                        MID_Buf[i][j]=DMA_Buf[MIDY+i][MIDX+j];                        
                }
        }
        //------------------------------串口查看误差与座标
        UART1_SendByte(0xaa);
        UART1_SendByte(6);        
        UART1_SendByte(min>>8);
        UART1_SendByte(min);                        
        UART1_SendByte(MovX>>8);
        UART1_SendByte(MovX);        
        UART1_SendByte(MovY>>8);
        UART1_SendByte(MovY);
}

链接: https://pan.baidu.com/s/12j0wI2Dmpp7y1UgUrcE_-w 提取码: 隐藏内容,回复可看

最新回复 [7]
  • uylor 2020-5-17
    0 2
    thank!thank!thank!
  • luohua 2021-1-20
    0 3
    good
  • chase_liu 2021-5-18
    0 4
    感谢!
  • xiaoliang 2021-8-9
    0 5
    多多学习,加油
  • cyrs 2021-8-17
    0 6
    看看楼主的好东西
  • haokong 2022-1-28
    0 7
  • 安保66 2022-4-29
    0 8


    澳洲幸运5开奖直播 铁水罐运输方式该方式采用铁水罐作为铁水从高炉到炼钢的运输和储存容器,从高炉出铁场受铁开始至炼钢铁水兑入转炉终止,全过程采用一个铁水罐,减少了鱼雷罐运输流程中的铁水倒罐环节。铁元素也是构成人体的必不可少的元素之一。成人体内约有45克铁,其中72%以血红蛋白、3%以肌红蛋白、0.2以其它化合物形式存在

    福彩七乐彩预测投注 其余为储备铁。储备铁约占25%,主要以铁蛋白的形式储存在肝、脾和骨髓中。成人摄取量是1015mg。妊娠期妇女需要30mg1个月内,女性所流失的铁大约为男性的两倍,吸收铁时需要铜、钴、锰、维生素C。需要人群:妇女特别是孕妇需要补充铁质,但要注意妊娠期妇女服用过多铁剂会使胎儿发生铁中毒。假如您正在服用消炎药或每天必须服用阿司匹林的话

     极速飞艇开奖直播 那么您就需要补充铁。经常喝红茶或咖啡的人请注意,饮用大量的红茶和咖啡会阻碍铁的吸收。铁是人体含量的必需微量元素,人体内铁的总量约45克,是血红蛋白的重要部分,人全身都需要它,这种矿物质可以存在于向肌肉供给氧气的红细胞中,还是许多酶和免疫系统化合物的成分,人体从食物中摄取所需的大部分铁,并小心控制着铁含量。


返回