该代码实现了基于STM32F4的OV5640摄像头模块驱动,支持RGB565和JPEG两种图像输出模式。主要功能包括:1) 通过DCMI接口和DMA传输采集图像数据;2) 提供对比度调节、自动对焦、图像特效(7种)和分辨率切换(12种尺寸)功能;3) RGB565模式可直接在LCD显示,JPEG模式可通过串口发送图像数据;4) 包含帧缓冲管理机制,使用双缓冲技术实现连续采集。系统通过按键控制模式切换和参数调整,初始化时自动检测摄像头状态,具有完整的错误处理机制。

#include "sys.h"
#include "delay.h"  
#include "usart.h"   
#include "led.h"
#include "lcd.h"
#include "key.h"  
#include "usmart.h"  
#include "usart2.h"  
#include "timer.h" 
#include "ov5640.h" 
#include "dcmi.h" 

 
u8 ovx_mode=0;                            //bit0:0,RGB565模式;1,JPEG模式 

#define jpeg_buf_size   31*1024        //定义JPEG数据缓存jpeg_buf的大小(*4字节)
__align(4) u32 jpeg_buf[jpeg_buf_size];    //JPEG数据缓存buf
volatile u32 jpeg_data_len=0;             //buf中的JPEG有效数据长度 
volatile u8 jpeg_data_ok=0;                //JPEG数据采集完成标志 
                                        //0,数据没有采集完;
                                        //1,数据采集完了,但是还没处理;
                                        //2,数据已经处理完成了,可以开始下一帧接收
         
//JPEG尺寸支持列表
const u16 jpeg_img_size_tbl[][2]=
{
    160,120,    //QQVGA 
    320,240,    //QVGA  
    640,480,    //VGA
    800,600,    //SVGA
    1024,768,    //XGA
    1280,800,    //WXGA 
    1440,900,    //WXGA+
    1280,1024,    //SXGA
    1600,1200,    //UXGA    
    1920,1080,    //1080P
    2048,1536,    //QXGA
    2592,1944,    //500W 
};

const u8*EFFECTS_TBL[7]={"Normal","Cool","Warm","B&W","Yellowish ","Inverse","Greenish"};    //7种特效 
const u8*JPEG_SIZE_TBL[12]={"QQVGA","QVGA","VGA","SVGA","XGA","WXGA","WXGA+","SXGA","UXGA","1080P","QXGA","500W"};//JPEG图片 12种尺寸 

//处理JPEG数据
//当采集完一帧JPEG数据后,调用此函数,切换JPEG BUF.开始下一帧采集.
void jpeg_data_process(void)
{
    if(ovx_mode&0X01)    //只有在JPEG格式下,才需要做处理.
    {
        if(jpeg_data_ok==0)    //jpeg数据还未采集完?
        {
            DMA2_Stream1->CR&=~(1<<0);        //停止当前传输
            while(DMA2_Stream1->CR&0X01);    //等待DMA2_Stream1可配置   
            jpeg_data_len=jpeg_buf_size-DMA2_Stream1->NDTR;//得到此次数据传输的长度
            jpeg_data_ok=1;                 //标记JPEG数据采集完按成,等待其他函数处理
        }
        if(jpeg_data_ok==2)    //上一次的jpeg数据已经被处理了
        {
            DMA2_Stream1->NDTR=jpeg_buf_size;    //传输长度为jpeg_buf_size*4字节
            DMA2_Stream1->CR|=1<<0;                //重新传输
            jpeg_data_ok=0;                        //标记数据未采集
        }
    }else
    {
        LCD_SetCursor(0,0);  
        LCD_WriteRAM_Prepare();        //开始写入GRAM
    }    

//JPEG测试
//JPEG数据,通过串口2发送给电脑.
void jpeg_test(void)
{
    u32 i,jpgstart,jpglen; 
    u8 *p;
    u8 key,headok=0;
    u8 effect=0,contrast=2;
    u8 size=2;            //默认是QVGA 640*480尺寸
    u8 msgbuf[15];        //消息缓存区 
    LCD_Clear(WHITE);
  POINT_COLOR=RED; 
    LCD_ShowString(30,50,200,16,16,"ALIENTEK STM32F4");
    LCD_ShowString(30,70,200,16,16,"OV5640 JPEG Mode");
    LCD_ShowString(30,100,200,16,16,"KEY0:Contrast");            //对比度
    LCD_ShowString(30,120,200,16,16,"KEY1:Auto Focus");         //执行自动对焦
    LCD_ShowString(30,140,200,16,16,"KEY2:Effects");             //特效 
    LCD_ShowString(30,160,200,16,16,"KEY_UP:Size");                //分辨率设置 
    sprintf((char*)msgbuf,"JPEG Size:%s",JPEG_SIZE_TBL[size]);
    LCD_ShowString(30,180,200,16,16,msgbuf);                    //显示当前JPEG分辨率
    //自动对焦初始化
    OV5640_RGB565_Mode();    //RGB565模式 
    OV5640_Focus_Init(); 
    
     OV5640_JPEG_Mode();        //JPEG模式
    
    OV5640_Light_Mode(0);    //自动模式
    OV5640_Color_Saturation(3);//色彩饱和度0
    OV5640_Brightness(4);    //亮度0
    OV5640_Contrast(3);        //对比度0
    OV5640_Sharpness(33);    //自动锐度
    OV5640_Focus_Constant();//启动持续对焦
    
    DCMI_Init();            //DCMI配置
    DCMI_DMA_Init((u32)&jpeg_buf,jpeg_buf_size,2,1);//DCMI DMA配置 
     OV5640_OutSize_Set(4,0,jpeg_img_size_tbl[size][0],jpeg_img_size_tbl[size][1]);//设置输出尺寸 
    DCMI_Start();         //启动传输
    while(1)
    {
        if(jpeg_data_ok==1)    //已经采集完一帧图像了
        {  
            p=(u8*)jpeg_buf;
            printf("jpeg_data_len:%d\r\n",jpeg_data_len*4);//打印帧率
            LCD_ShowString(30,210,210,16,16,"Sending JPEG data..."); //提示正在传输数据 
            jpglen=0;    //设置jpg文件大小为0
            headok=0;    //清除jpg头标记
            for(i=0;i<jpeg_data_len*4;i++)//查找0XFF,0XD8和0XFF,0XD9,获取jpg文件大小
            {
                if((p[i]==0XFF)&&(p[i+1]==0XD8))//找到FF D8
                {
                    jpgstart=i;
                    headok=1;    //标记找到jpg头(FF D8)
                }
                if((p[i]==0XFF)&&(p[i+1]==0XD9)&&headok)//找到头以后,再找FF D9
                {
                    jpglen=i-jpgstart+2;
                    break;
                }
            }
            if(jpglen)    //正常的jpeg数据 
            {
                p+=jpgstart;            //偏移到0XFF,0XD8处 
                for(i=0;i<jpglen;i++)    //发送整个jpg文件
                {
                    while((USART2->SR&0X40)==0);    //循环发送,直到发送完毕   
                    USART2->DR=p[i];  
                    key=KEY_Scan(0); 
                    if(key)break;
                }  
            }
            if(key)    //有按键按下,需要处理
            {  
                LCD_ShowString(30,210,210,16,16,"Quit Sending data   ");//提示退出数据传输
                switch(key)
                {                    
                    case KEY0_PRES:    //对比度设置
                        contrast++;
                        if(contrast>6)contrast=0;
                        OV5640_Contrast(contrast);
                        sprintf((char*)msgbuf,"Contrast:%d",(signed char)contrast-3);
                        break; 
                    case KEY1_PRES:    //执行一次自动对焦
                        OV5640_Focus_Single();
                        break;
                    case KEY2_PRES:    //特效设置                 
                        effect++;
                        if(effect>6)effect=0;
                        OV5640_Special_Effects(effect);//设置特效
                        sprintf((char*)msgbuf,"%s",EFFECTS_TBL[effect]);
                        break;
                    case WKUP_PRES:    //JPEG输出尺寸设置   
                        size++;  
                        if(size>2)size=0;     //QQVGA~VGA
                        OV5640_OutSize_Set(16,4,jpeg_img_size_tbl[size][0],jpeg_img_size_tbl[size][1]);//设置输出尺寸  
                        sprintf((char*)msgbuf,"JPEG Size:%s",JPEG_SIZE_TBL[size]);
                        break;
                }
                LCD_Fill(30,180,239,190+16,WHITE);
                LCD_ShowString(30,180,210,16,16,msgbuf);//显示提示内容
                delay_ms(800);                   
            }else LCD_ShowString(30,210,210,16,16,"Send data complete!!");//提示传输结束设置 
            jpeg_data_ok=2;    //标记jpeg数据处理完了,可以让DMA去采集下一帧了.
        }        
    }    
}
//RGB565测试
//RGB数据直接显示在LCD上面
void rgb565_test(void)

    u8 key;
    u8 effect=0,contrast=2,fac;
    u8 scale=1;        //默认是全尺寸缩放
    u8 msgbuf[15];    //消息缓存区 
    LCD_Clear(WHITE);
  POINT_COLOR=RED; 
    LCD_ShowString(30,50,200,16,16,"ALIENTEK STM32F4");
    LCD_ShowString(30,70,200,16,16,"OV5640 RGB565 Mode");
    
    LCD_ShowString(30,100,200,16,16,"KEY0:Contrast");            //对比度
    LCD_ShowString(30,130,200,16,16,"KEY1:Saturation");     //色彩饱和度
    LCD_ShowString(30,150,200,16,16,"KEY2:Effects");             //特效 
    LCD_ShowString(30,170,200,16,16,"KEY_UP:FullSize/Scale");    //1:1尺寸(显示真实尺寸)/全尺寸缩放
    
    //自动对焦初始化
    OV5640_RGB565_Mode();    //RGB565模式 
    OV5640_Focus_Init();
    
    OV5640_Light_Mode(0);    //自动模式
    OV5640_Color_Saturation(3);//色彩饱和度0
    OV5640_Brightness(4);    //亮度0
    OV5640_Contrast(3);        //对比度0
    OV5640_Sharpness(33);    //自动锐度
    OV5640_Focus_Constant();//启动持续对焦
    DCMI_Init();            //DCMI配置
    /////////////////////////////////////////////////////////////////////
    DCMI_DMA_Init((u32)&LCD->LCD_RAM,1,1,0);//DCMI DMA配置  
     OV5640_OutSize_Set(4,0,lcddev.width,lcddev.height); 
    DCMI_Start();         //启动传输
    while(1)
    { 
        key=KEY_Scan(0); 
        if(key)
        { 
            if(key!=KEY1_PRES)DCMI_Stop(); //非KEY1按下,停止显示
            switch(key)
            {                    
                case KEY0_PRES:    //对比度设置
                    contrast++;
                    if(contrast>6)contrast=0;
                    OV5640_Contrast(contrast);
                    sprintf((char*)msgbuf,"Contrast:%d",(signed char)contrast-3);
                    break;
                case KEY1_PRES:    //执行一次自动对焦
                    OV5640_Focus_Single();
                    break;
                case KEY2_PRES:    //特效设置                 
                    effect++;
                    if(effect>6)effect=0;
                    OV5640_Special_Effects(effect);//设置特效
                    sprintf((char*)msgbuf,"%s",EFFECTS_TBL[effect]);
                    break;
                case WKUP_PRES:    //1:1尺寸(显示真实尺寸)/缩放        
                    scale=!scale;  
                    if(scale==0)
                    {
                        fac=800/lcddev.height;//得到比例因子
                         OV5640_OutSize_Set((1280-fac*lcddev.width)/2,(800-fac*lcddev.height)/2,lcddev.width,lcddev.height);      
                        sprintf((char*)msgbuf,"Full Size 1:1");
                    }else 
                    {
                        OV5640_OutSize_Set(4,0,lcddev.width,lcddev.height);
                         sprintf((char*)msgbuf,"Scale");
                    }
                    break;
            }
            if(key!=KEY1_PRES)    //非KEY1按下
            {
                LCD_ShowString(30,50,210,16,16,msgbuf);//显示提示内容
                delay_ms(800); 
                DCMI_Start();    //重新开始传输
            }
        } 
        delay_ms(10);        
    }    

int main(void)
{        
    u8 key;
    u8 t;
    Stm32_Clock_Init(336,8,2,7);//设置时钟,168Mhz 
    delay_init(168);            //延时初始化  
    uart_init(84,115200);        //初始化串口波特率为115200 
    usart2_init(42,921600);        //初始化串口2波特率为921600
    LED_Init();                    //初始化LED 
     LCD_Init();                    //LCD初始化  
     KEY_Init();                    //按键初始化 
    TIM3_Int_Init(10000-1,8400-1);//10Khz计数,1秒钟中断一次
    usmart_dev.init(84);        //初始化USMART
     POINT_COLOR=RED;//设置字体为红色 
    LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");    
    LCD_ShowString(30,70,200,16,16,"OV5640 TEST");    
    LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
    LCD_ShowString(30,110,200,16,16,"2016/4/30");       
    while(OV5640_Init())//初始化OV2640
    {
        LCD_ShowString(30,130,240,16,16,"OV5640 ERROR");
        delay_ms(200);
      LCD_Fill(30,130,239,170,WHITE);
        delay_ms(200);
        LED0=!LED0;
    } 
    LCD_ShowString(30,130,200,16,16,"OV5640 OK");        
     while(1)
    {    
        key=KEY_Scan(0);
        if(key==KEY0_PRES)            //RGB565模式
        {
            ovx_mode=0;   
            break;
        }else if(key==KEY1_PRES)    //JPEG模式
        {
            ovx_mode=1;
            break;
        }
        t++;                                       
        if(t==100)LCD_ShowString(30,150,230,16,16,"KEY0:RGB565  KEY1:JPEG"); //闪烁显示提示信息
         if(t==200)
        {    
            LCD_Fill(30,150,210,150+16,WHITE);
            t=0; 
            LED0=!LED0;
        }
        delay_ms(5);      
    }
    if(ovx_mode==1)jpeg_test();
    else rgb565_test(); 
}


 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐