使用STM32F407ZGT6控制ESP8266和OV2640进行百度智能图片识别

前言:STM32F407ZGT6控制OV2640下采集到JPG图片格式的二进制数据,然后对二进制数据进行BASE64编码,接着通过串口将数据传输给ESP8266并上传至训练好的EASYDL的AI算法识别平台进行识别并返回垃圾种类与边缘信息。

  1. STM32与ov2640

  1. ov2640简绍

  1. stm32f407zgt6之dcmi

  1. stm32f407zgt6代码

  1. main.c

  1. main.h

  1. led.c

  1. led.h

  1. key.c

  1. key.h

  1. systic.c

  1. systic.h

  1. uart.c

  1. uart.h

  1. dcmi.c

  1. dcmi.h

  1. ov2640.c

  1. ov2640.h

  1. sccb.c

  1. sccb.h

  1. time.c

  1. time.h

  1. sys.c

  1. sys.h

  1. ov2640cfg.c

  1. ov2640cfg.h

  1. base64.c

  1. base64.h

  1. uart_2.c

  1. uart_2.h

  1. STM32与ESP8266

  1. arduino中代码

  1. ESP8266与EasyDL

一、STM32与OV2640(库函数版本)

1、OV2640简绍

OV2640是ALIENTEK 推出的一款 200W 像素高清摄像头模块。该模块采用 OmniVision 公司生产的一颗 1/4 寸的 CMOS UXGA(1632*1232)图像传感器:OV2640。ATK-OV2640 模块采用该 OV2640 感器 作为核心部件,集成有源晶振和 LDO,接口简单,使用非常方便。 ATK-OV2640 模块的特点如下: 1.高灵敏度、低电压适合嵌入式应用 2.标准的 SCCB 接口,兼容 IIC 接口 3.支持 RawRGB、RGB(RGB565/RGB555)、GRB422、YUV(422/420)和 YCbCr(422) 输出格式 4.支持 UXGA、SXGA、SVGA 以及按比例缩小到从 SXGA 到 40*30 的任何尺寸 5.支持自动曝光控制、自动增益控制、自动白平衡、自动消除灯光条纹、自动黑电平 校准等自动控制功能。同时支持色饱和度、色相、伽马、锐度等设置。 6.支持图像缩放、平移和窗口设置 7.支持图像压缩,即可输出 JPEG 图像数据 8.自带嵌入式微处理器 9.集成有源晶振,无需外部提供时钟 10.集成 LDO,仅需提供 3.3V 电源即可正常工作

(一)OV2640原理图

OV2640模块自带了 1.3V 和 2.8V 的稳压芯片,给 OV2640 供电,因此外 部仅需提供 3.3V 电压 即可;同时自带了一个 12M 的有源晶振,所以模块不需要外部提供时 钟。

2、STM32F407ZGT6之DCMI

STM32F407ZGT6 自带了一个数字摄像头(DCMI)接口,该接口是一个同步并行接口,能够 接收外部 8 位、10 位、12 位或 14 位 CMOS 摄像头模块发出的高速数据流。可支持不同 的数据格式.

DCMI 接口是一个同步并行接口,可接收高速(可达 54 MB/s)数据流。该接口包含多达 14 条数据线和一条像素时钟线(PIXCLK)。像素时钟的极性可以编程,因此可以在像素时钟的上升沿或下降沿捕获数据。DCMI 接收到的摄像头数据被放到一个 32 位数据寄存器(DCMI_DR)中,然后通过通用DMA 进行传输。图像缓冲区由 DMA 管理,而不是由摄像头接口管理。

3、STM32F407ZGT6代码

main.c文件

#include "main.h"


/*********************************************
*函数功能:处理JPEG数据
*函数形参:None
*函数返回值:None
*备注:当采集完一帧JPEG数据后,调用此函数,切换JPEG BUF.开始下一帧采集.
*********************************************/
void jpeg_data_process(void)
{
    
    //jpeg数据还未采集完?
    if(jpeg_data_ok==0)    
    {    
        //停止当前传输
        DMA_Cmd(DMA2_Stream1, DISABLE); 
        //等待DMA2_Stream1可配置
        while (DMA_GetCmdStatus(DMA2_Stream1) != DISABLE)
        {
            ;
        }  
        //得到此次数据传输的长度
        jpeg_data_len=jpeg_buf_size-DMA_GetCurrDataCounter(DMA2_Stream1);
        //标记JPEG数据采集完按成,等待其他函数处理    
        jpeg_data_ok=1;                 
    }
    //上一次的jpeg数据已经被处理了
    if(jpeg_data_ok==2)    
    {
        DMA2_Stream1->NDTR=jpeg_buf_size;
        //传输长度为jpeg_buf_size*4字节
        DMA_SetCurrDataCounter(DMA2_Stream1,jpeg_buf_size);
        //重新传输
        DMA_Cmd(DMA2_Stream1, ENABLE);    
        //标记数据未采集
        jpeg_data_ok=0;                        
    }
    
} 

/*********************************************
*函数功能:JPEG测试
*函数形参:None
*函数返回值:None
*备注:JPEG数据,通过串口1发送给电脑.base64编码后串口2发给esp8266
*********************************************/
void jpeg_test(void)
{
    //u32 i; 
    u8 *p;    
    u32 a=0;
    //base64表
    char *base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    //用于存放图片数据
    unsigned char counts[4*4690];
    //用于分割数据
    unsigned char counts_1[4690];
    u16 count;
    //默认是QVGA 320*240尺寸 修改此值可以改变图片分辨率大小
    u8 size=3;
    //消息缓存区
    u8 msgbuf[15];
    //串口打印当前JPEG分辨率
    sprintf((char*)msgbuf,"JPEG Size:%s",JPEG_SIZE_TBL[size]);
     //JPEG模式
     OV2640_JPEG_Mode();
    //DCMI初始化
    My_DCMI_Init();    
    //DCMI DMA初始化
    DCMI_DMA_Init((u32)&jpeg_buf,jpeg_buf_size,DMA_MemoryDataSize_Word,DMA_MemoryInc_Enable); 
    //设置输出尺寸
    OV2640_OutSize_Set(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;
            //取出第一个字符的前6位并找出对应的结果字符
            counts[count]=base64_table[p[a]>>2]; 
            //将第一个字符的后位与第二个字符的前4位进行组合并找到对应的结果字符
            counts[1+count]=base64_table[(p[a]&0x3)<<4 | (p[a+1]>>4)];   
            //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符  
            counts[2+count]=base64_table[(p[a+1]&0xf)<<2 | (p[a+2]>>6)]; 
            //取出第三个字符的后6位并找出结果字符 
            counts[3+count]=base64_table[p[a+2]&0x3f]; 
            //3*8=4*6
            count=count+4;
            a=a+3;
            p[3]=0xe0;//强行赋值
            while(1){ //死循环进行base64编码
            //取出第一个字符的前6位并找出对应的结果字符
            counts[count]=base64_table[p[a]>>2]; 
            //将第一个字符的后位与第二个字符的前4位进行组合并找到对应的结果字符  
            counts[1+count]=base64_table[(p[a]&0x3)<<4 | (p[a+1]>>4)]; 
            //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符  
            counts[2+count]=base64_table[(p[a+1]&0xf)<<2 | (p[a+2]>>6)]; 
            //取出第三个字符的后6位并找出结果字符
            counts[3+count]=base64_table[p[a+2]&0x3f]; 
            a=a+3;
            count=count+4;
                //若图片编码结束,跳出循环
                if(p[a]==0&&p[a+1]==0&&p[a+2]==0&&p[a+3]==0&&p[a+4]==0&&p[a+5]==0&&p[a+6]==0&&p[a+7]==0&&p[a+8]==0)break;
            }
            //等待ESP8266
            Delay_s(5);
            Uart2_Send_String("o");
            Delay_s(2);
            //分第一段
            for(u32 i=0;i<(count/4);i++){ 
              counts_1[i]=counts[i];
            }
//            printf("%s\r\n",counts_1);
            Uart2_Send_String(counts_1);
            Delay_s(2);
//            分第二段
            for(u32 i=(count/4);i<((count/4)*2);i++){ 
              counts_1[i-(count/4)]=counts[i];
            }
            //printf("%s\r\n",counts_1);
            Uart2_Send_String(counts_1);
            Delay_s(2);
//            分第三段
            for(u32 i=((count/4)*2);i<((count/4)*3);i++){ 
              counts_1[i-((count/4)*2)]=counts[i];
            }
            //printf("%s\r\n",counts_1);
            Uart2_Send_String(counts_1);
            Delay_s(2);
//            分第四段
            for(u32 i=((count/4)*3);i<count+1;i++){ 
              counts_1[i-((count/4)*3)]=counts[i];
            }
            //printf("%s\r\n",counts_1);
            Uart2_Send_String(counts_1);
            //printf("%s",counts);
            //dma传输1次等于4字节,所以乘以4.
            //printf("%s",rev_buf_2);
            //标记jpeg数据处理完了,可以让DMA去采集下一帧了.
            jpeg_data_ok=2;                   
        }
    }
}
/*********************************************
*函数功能:主函数
*函数形参:None
*函数返回值:None
*备注:None
*********************************************/

int main(void)
{    
//    u8 t;
    //设置系统中断优先级分组2
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    //初始化串口波特率为115200
    Uart1_Init(115200);
    //初始化串口2波特率为115200
    Uart2_Init(115200);
    //初始化LED
    Led_Init();
    //按键初始化 
     Key_Init();    
    //10Khz计数,1秒钟中断一次
    TIM3_Int_Init(10000-1,8400-1);
    //初始化USMART
     //usmart_dev.init(84);        
    //初始化OV2640
    while(OV2640_Init())
    {
        printf("OV2640 ERR");
        Delay_ms(200);
    }
//    printf("OV2640 OK");
        while(1){ 
      if(rev_ok_2 == 1){ //串口二接受到数据        
        rev_ok_2 = 0;
        if(!strcmp((char *)rev_buf, "picture")){ //判断接受到的数据是否为“picture”
                    jpeg_test();
                    //printf("%s",rev_buf_2);
        }
      }
    }

}





main.h文件

#ifndef __MAIN_H_
#define __MAIN_H_


/********************头文件************************/
#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "systick.h"
#include "uart.h"
#include "sys.h" 
#include "uart_2.h"  
#include "time.h" 
#include "ov2640.h"
#include "dcmi.h" 
#include "base64.h"
/********************宏定义************************/
extern uint8_t rev_buf_2[REV_BUF_LEN];
extern uint8_t rev_ok_2;
#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,数据已经处理完成了,可以开始下一帧接收

/*****************声明外部变量*********************/
const  u8*EFFECTS_TBL[7]={"Normal","Negative","B&W","Redish","Greenish","Bluish","Antique"};    //7种特效 
const u8*JPEG_SIZE_TBL[9]={"QCIF","QQVGA","CIF","QVGA","VGA","SVGA","XGA","SXGA","UXGA"};    //JPEG图片 9种尺寸

//JPEG尺寸支持列表
const u16 jpeg_img_size_tbl[][2]=
{
    176,144,    //QCIF
    160,120,    //QQVGA
    352,288,    //CIF
    320,240,    //QVGA
    640,480,    //VGA
    800,600,    //SVGA
    1024,768,    //XGA
    1280,1024,    //SXGA
    1600,1200,    //UXGA
}; 


/*******************函数声明***********************/
void jpeg_test(void);
void jpeg_data_process(void);
void u32tostr(unsigned long dat,char *str);
#endif




led.c文件

#include "led.h"

/*********************************************
*函数功能:LED初始化
*函数形参:None
*函数返回值:None
*备注:    PF9  -- LED0
        PF10 -- LED1 低电平灯亮
*********************************************/
void Led_Init(void)
{    
    //开启GPIOF时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
    
    //配置GPIO PF9和PF10推挽输出
    GPIO_InitTypeDef  GPIO_InitStruct;
    //输出模式
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    //输出类型:推挽
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    //引脚号
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
    //上下拉 上拉
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    //输出速度
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
    
    GPIO_Init(GPIOF, &GPIO_InitStruct);
}





led.h文件

#ifndef __LED_H_
#define __LED_H_


/********************头文件************************/
#include "stm32f4xx.h"

/********************宏定义************************/
#define LED0_ON        GPIO_ResetBits(GPIOF, GPIO_Pin_9)
#define LED0_OFF       GPIO_SetBits(GPIOF, GPIO_Pin_9) 
#define LED1_ON        GPIO_ResetBits(GPIOF, GPIO_Pin_10)
#define LED1_OFF       GPIO_SetBits(GPIOF, GPIO_Pin_10) 

/*****************声明外部变量*********************/

/*******************函数声明***********************/
void Led_Init(void);

#endif

key.c文件

#include "key.h"

/*********************************************
*函数功能:KEY初始化
*函数形参:None
*函数返回值:None
*备注:    KEY0 -- PE4
        KEY1 -- PA0
        高电平按键按下
*********************************************/
void Key_Init(void)
{    
    //开启GPIOA,GPIOE时钟
    RCC->AHB1ENR |= (0x1 << 4);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    
    
    //配置GPIO PA0和PE4浮空输入
    GPIO_InitTypeDef  GPIO_InitStruct;
    //PA0
    //输入模式
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
    //引脚号
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
    //无上下拉
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    //PE4
    //输入模式
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
    //引脚号
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
    //无上下拉
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOE, &GPIO_InitStruct);
}

/*********************************************
*函数功能:检测按键是否按下
*函数形参:None
*函数返回值:按下的按键值
*备注:KEY0按下返回1
      KEY1按下返回2
      无按键按下返回0
*********************************************/
uint8_t Key_Scan(void)
{
    if(KEY0 == 1){
        //粗略延时10ms
        Delay_Key(10);
        if(KEY0 == 1){
            return 1;
        }
    }
    if(KEY1 == 1){
        //粗略延时10ms
        Delay_Key(10);
        if(KEY1 == 1){
            return 2;
        }
    }
    
    return 0;
}

/*********************************************
*函数功能:粗略延时函数
*函数形参:延时ms值
*函数返回值:None
*备注:168MHz 168 000 000
*********************************************/
static void Delay_Key(uint16_t ms)
{
    uint16_t i = 0;
    uint16_t j = 0;
    
    for(i = 0; i < ms; ++i)
    {
        for(j = 0; j < 1000; ++j)
        {
            uint8_t temp = 168;
            while(temp--);
        }
    }
}








key.h

#ifndef __KEY_H_
#define __KEY_H_


/********************头文件************************/
#include "stm32f4xx.h"

/********************宏定义************************/
#define KEY0    GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4)
#define KEY1    GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)

/*****************声明外部变量*********************/

/*******************函数声明***********************/
void Key_Init(void);
uint8_t Key_Scan(void);
static void Delay_Key(uint16_t ms);

#endif

systick.c

#include "systick.h"

/*********************************************
*函数功能:Systick 1s定时
*函数形参:None
*函数返回值:None
*备注:21MHz时钟源
*********************************************/
void Delay_1S(void)
{
    Delay_ms(500);
    Delay_ms(500);
}

/*********************************************
*函数功能:Systick s级定时
*函数形参:uint8_t s
*函数返回值:None
*备注:21MHz时钟源
*********************************************/
void Delay_s(uint16_t s)
{
    uint8_t i = 0;
    
    for(i = 0; i < s; ++i){
        Delay_1S();
    }
    
}

/*********************************************
*函数功能:Systick ms级定时
*函数形参:uint16_t ms
*函数返回值:None
*备注:21MHz时钟源 定时范围0~1000
*********************************************/
void Delay_ms(uint16_t ms)
{
    //控制定时范围
    if(ms > 1000){
        ms = 1000;
    }
    if(ms > 500)
    {
        Delay_ms(ms - 500);
        ms = 500;
    }
    //选择Systick时钟
    SysTick->CTRL &= ~(0x1 << 2);
    //设置重载值
    SysTick->LOAD = 21000*ms;//24位递减计数器 最大值16777216
    //载入重载值
    SysTick->VAL = 0;
    //使能计数器
    SysTick->CTRL |= (0x1 << 0);
    //等待定时时间到
    while(!(SysTick->CTRL & (0x1 << 16)));
    //关闭定时器使能
    SysTick->CTRL &= ~(0x1 << 0);
}

/*********************************************
*函数功能:Systick us级定时
*函数形参:uint16_t us
*函数返回值:None
*备注:21MHz时钟源 
*********************************************/
void Delay_us(uint16_t us)
{
    //控制定时范围
    if(us > 1000){
        us = 1000;
    }
    //选择Systick时钟
    SysTick->CTRL &= ~(0x1 << 2);
    //设置重载值
    SysTick->LOAD = 21*us;//24位递减计数器 最大值16777216
    //载入重载值
    SysTick->VAL = 0;
    //使能计数器
    SysTick->CTRL |= (0x1 << 0);
    //等待定时时间到
    while(!(SysTick->CTRL & (0x1 << 16)));
    //关闭定时器使能
    SysTick->CTRL &= ~(0x1 << 0);
}

/*********************************************
*函数功能:Systick 延时函数
*函数形参:uint16_t ys
*函数返回值:None
*备注:9MHz时钟源 以毫秒为单位
*********************************************/
void Delay_Systick(uint16_t ys)
{
    uint16_t s = 0;
    uint16_t ms = 0;
    
    s = ys/1000;
    ms = ys%1000;
    
    if(s){
        Delay_s(s);
    }
    if(ms){
        Delay_ms(ms);
    }
}




systick.h文件

#ifndef __SYSTICK_H_
#define __SYSTICK_H_


/********************头文件************************/
#include "stm32f4xx.h"

/********************宏定义************************/

/*****************声明外部变量*********************/

/*******************函数声明***********************/
void Delay_1S(void);
void Delay_s(uint16_t s);
void Delay_ms(uint16_t ms);
void Delay_us(uint16_t us);
void Delay_Systick(uint16_t ys);

#endif


uart.c文件

#include "uart.h"

/*********************************************
*函数功能:UART1初始化
*函数形参:uint32_t band 波特率
*函数返回值:None
*备注:PA9     --   TX
      PA10  --   RX
*********************************************/
void Uart1_Init(uint32_t band)
{
    //开启GPIOA时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    //开启UART1时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    
    //配置GPIO
    //PA9和PA10为复用模式
    GPIO_InitTypeDef  GPIO_InitStruct;
    //输出模式
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    //引脚号
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); 
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    //配置UART1
    USART_InitTypeDef USART_InitStruct;
    //波特率
    USART_InitStruct.USART_BaudRate = band;
    //禁止硬件流控
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    //使能发送和接收
    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    //关闭奇偶校验
    USART_InitStruct.USART_Parity = USART_Parity_No;
    //1位停止位
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    //8位数据位
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_Init(USART1, &USART_InitStruct);
    
    //使能接收中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
    //设置中断优先级    串口优先级设置为最高,以防接收中被打断
    NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(7-2, 0, 1));
    //使能NVIC响应
    NVIC_EnableIRQ(USART1_IRQn);
    
    //使能UART1
    USART_Cmd(USART1, ENABLE);
}

uint8_t rev_buf[REV_BUF_LEN];
uint8_t rev_ok;

//编写中断服务函数
void USART1_IRQHandler(void)
{
    static uint8_t i = 0;
    
    //读数据寄存器非空
    if(USART1->SR & (0x1 << 5)){
        rev_buf[i++] = USART1->DR;//读取数据寄存器信息,清空标志位
        while(USART1->SR & (0x1 << 5));//等待标志位清零
    }else if(USART1->SR & (0x1 << 4)){//检测到总线空闲
        //清标志位
        if(USART1->SR) 
            ;
        if(USART1->DR)
            ;
        while(USART1->SR & (0x1 << 4));//等待标志位清零
        rev_buf[i] = '\0';//字符串结尾
        i = 0;
        rev_ok = 1;//接收完成
    }
}

/*********************************************
*函数功能:UART1发送字符串函数
*函数形参:uint8_t *str 要发送的字符串
*函数返回值:None
*备注:None
*********************************************/
void Uart1_Send_String(uint8_t *str)
{
    while(*str){
        //等待发送数据寄存器为空
        while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
        USART_SendData(USART1, *str); 
        str++;
    }
}


#pragma import(__use_no_semihosting_swi) //取消半主机状态

struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;

int fputc(int ch, FILE *f) {
    while((USART1->SR &(0X01<<7))==0);//等待发送缓冲区为空
    USART1->DR=ch;
  return (ch);
}
int ferror(FILE *f) {
  /* Your implementation of ferror */
  return EOF;
}


void _ttywrch(int ch) {
  while((USART1->SR &(0X01<<7))==0);
        USART1->DR=ch;
}


void _sys_exit(int return_code) {
label:  goto label;  /* endless loop */
}








uart.h文件

#ifndef __UART_H_
#define __UART_H_


/********************头文件************************/
#include "stm32f4xx.h"
#include "stdio.h"

/********************宏定义************************/
#define REV_BUF_LEN        (256)

/*****************声明外部变量*********************/
extern uint8_t rev_buf[REV_BUF_LEN];
extern uint8_t rev_ok;

/*******************函数声明***********************/
void Uart1_Init(uint32_t band);
void Uart1_Send_String(uint8_t *str);


#endif





dcmi.c文件

#include "dcmi.h"
u8 ov_frame=0;                          //帧率
/*********************************************
*函数功能:DCMI中断服务函数
*函数形参:None
*函数返回值:None
*备注:    None
*********************************************/
void DCMI_IRQHandler(void)
{    
    //捕获到一帧图像
    if(DCMI_GetITStatus(DCMI_IT_FRAME)==SET)
    {
        //jpeg数据处理
        jpeg_data_process();     
        //清除帧中断
        DCMI_ClearITPendingBit(DCMI_IT_FRAME);
        LED1_ON;
        ov_frame++;  
    }
}


//DCMI DMA配置
//DMA_Memory0BaseAddr:存储器地址    将要存储摄像头数据的内存地址(也可以是外设地址)
//DMA_BufferSize:存储器长度    0~65535
//DMA_MemoryDataSize:存储器位宽  
//DMA_MemoryDataSize:存储器位宽    @defgroup DMA_memory_data_size :DMA_MemoryDataSize_Byte/DMA_MemoryDataSize_HalfWord/DMA_MemoryDataSize_Word
//DMA_MemoryInc:存储器增长方式  @defgroup DMA_memory_incremented_mode  /** @defgroup DMA_memory_incremented_mode : DMA_MemoryInc_Enable/DMA_MemoryInc_Disable
void DCMI_DMA_Init(u32 DMA_Memory0BaseAddr,u16 DMA_BufferSize,u32 DMA_MemoryDataSize,u32 DMA_MemoryInc)
{ 
    DMA_InitTypeDef  DMA_InitStructure;
    //DMA2时钟使能
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE); 
    DMA_DeInit(DMA2_Stream1);
    //等待DMA2_Stream1可配置
    while (DMA_GetCmdStatus(DMA2_Stream1) != DISABLE)
    {
        ;
    } 
    
                            /* 配置 DMA Stream */
    //通道1 DCMI通道
    DMA_InitStructure.DMA_Channel = DMA_Channel_1; 
    //外设地址为:DCMI->DR
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&DCMI->DR;
    //DMA 存储器0地址
    DMA_InitStructure.DMA_Memory0BaseAddr = DMA_Memory0BaseAddr;
    //外设到存储器模式
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    //数据传输量
    DMA_InitStructure.DMA_BufferSize = DMA_BufferSize; 
    //外设非增量模式
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    //存储器增量模式
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc;
    //外设数据长度:32位
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
    //存储器数据长度 
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize;
    // 使用循环模式 
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    //高优先级
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    //FIFO模式
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;    
    //使用全FIFO
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; 
    //外设突发单次传输
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    //存储器突发单次传输
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    //初始化DMA Stream
    DMA_Init(DMA2_Stream1, &DMA_InitStructure);
} 

/*********************************************
*函数功能:DCMI初始化
*函数形参:None
*函数返回值:None
*备注:    None
*********************************************/
void My_DCMI_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    DCMI_InitTypeDef DCMI_InitStructure;
    //使能GPIOA B C E 时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOE, ENABLE);
    //使能DCMI时钟
    RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI,ENABLE);
    //PA4、PA6初始化设置
    //PA4、PA6   复用功能输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_6;
    //复用功能输出
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; 
    //推挽输出
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    //100MHz
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    //上拉
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    //初始化
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    // PB6、PB7   复用功能输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_6;
    //初始化
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    //PC6/7/8/9/11 复用功能输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_11;
    //初始化
    GPIO_Init(GPIOC, &GPIO_InitStructure);    
    //PE5/6  复用功能输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6; 
    //初始化
    GPIO_Init(GPIOE, &GPIO_InitStructure);    

    GPIO_PinAFConfig(GPIOA,GPIO_PinSource4,GPIO_AF_DCMI); //PA4,AF13  DCMI_HSYNC
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_DCMI); //PA6,AF13  DCMI_PCLK  
     GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_DCMI); //PB7,AF13  DCMI_VSYNC 
     GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_DCMI); //PC6,AF13  DCMI_D0  
     GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_DCMI); //PC7,AF13  DCMI_D1 
    GPIO_PinAFConfig(GPIOC,GPIO_PinSource8,GPIO_AF_DCMI); //PC8,AF13  DCMI_D2
    GPIO_PinAFConfig(GPIOC,GPIO_PinSource9,GPIO_AF_DCMI); //PC9,AF13  DCMI_D3
    GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_DCMI);//PC11,AF13 DCMI_D4 
    GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_DCMI); //PB6,AF13  DCMI_D5 
    GPIO_PinAFConfig(GPIOE,GPIO_PinSource5,GPIO_AF_DCMI); //PE5,AF13  DCMI_D6
    GPIO_PinAFConfig(GPIOE,GPIO_PinSource6,GPIO_AF_DCMI); //PE6,AF13  DCMI_D7

    //清除原来的设置 
    DCMI_DeInit();
 
    //连续模式
    DCMI_InitStructure.DCMI_CaptureMode=DCMI_CaptureMode_Continuous;
    //全帧捕获
    DCMI_InitStructure.DCMI_CaptureRate=DCMI_CaptureRate_All_Frame;
    //8位数据格式
    DCMI_InitStructure.DCMI_ExtendedDataMode= DCMI_ExtendedDataMode_8b;
    //HSYNC 低电平有效
    DCMI_InitStructure.DCMI_HSPolarity= DCMI_HSPolarity_Low;
    //PCLK 上升沿有效
    DCMI_InitStructure.DCMI_PCKPolarity= DCMI_PCKPolarity_Rising;
    //硬件同步HSYNC,VSYNC
    DCMI_InitStructure.DCMI_SynchroMode= DCMI_SynchroMode_Hardware;
    //VSYNC 低电平有效
    DCMI_InitStructure.DCMI_VSPolarity=DCMI_VSPolarity_Low;
    DCMI_Init(&DCMI_InitStructure);
    //开启帧中断
    DCMI_ITConfig(DCMI_IT_FRAME,ENABLE); 
    //DCMI使能
    DCMI_Cmd(ENABLE);    

    NVIC_InitStructure.NVIC_IRQChannel = DCMI_IRQn;
    //抢占优先级1
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
    //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;    
    //IRQ通道使能
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    
    //根据指定的参数初始化VIC寄存器、
    NVIC_Init(&NVIC_InitStructure);    
 
}

/*********************************************
*函数功能:DCMI,启动传输
*函数形参:None
*函数返回值:None
*备注:    None
*********************************************/
void DCMI_Start(void)
{  
    //开启DMA2,Stream1
    DMA_Cmd(DMA2_Stream1, ENABLE);
    //DCMI捕获使能
    DCMI_CaptureCmd(ENABLE);  
}
/*********************************************
*函数功能:DCMI,关闭传输
*函数形参:None
*函数返回值:None
*备注:    None
*********************************************/
void DCMI_Stop(void)
{ 
    //DCMI捕获使关闭
    DCMI_CaptureCmd(DISABLE);    
    //等待传输结束
    while(DCMI->CR&0X01);         
    //关闭DMA2,Stream1
    DMA_Cmd(DMA2_Stream1,DISABLE);
} 










dcmi.h文件

#ifndef __DCMI_H_
#define __DCMI_H_


/********************头文件************************/
#include "dcmi.h" 
#include "led.h" 
#include "ov2640.h" 

/********************宏定义************************/
//u8 ov_frame=0;                          //帧率


/*****************声明外部变量*********************/

/*******************函数声明***********************/
extern void jpeg_data_process(void);    //JPEG数据处理函数 
void My_DCMI_Init(void);
void DCMI_DMA_Init(u32 DMA_Memory0BaseAddr,u16 DMA_BufferSize,u32 DMA_MemoryDataSize,u32 DMA_MemoryInc);
void DCMI_Start(void);
void DCMI_Stop(void);
#endif

ov2640.c文件

#include "ov2640.h"

/*********************************************
*函数功能:初始化OV2640
*函数形参:None
*函数返回值:返回值:0,成功 其他,错误代码
*备注:    配置完以后,输出默认尺寸的图片!
*********************************************/
u8 OV2640_Init(void)
{ 
    u16 i=0;
    u16 reg;
    //配置IO            
    GPIO_InitTypeDef  GPIO_InitStructure;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
    //GPIOG9,15初始化设置
    //PG9,15推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_15;
    //推挽输出
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 
    //推挽输出
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    //50MHz
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    //上拉
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    //初始化
    GPIO_Init(GPIOG, &GPIO_InitStructure);
    //POWER ON
     OV2640_PWDN=0;    
    Delay_ms(10);
    //复位OV2640
    OV2640_RST=0;    
    Delay_ms(10);
    //结束复位
    OV2640_RST=1;     
    //初始化SCCB 的IO口
    SCCB_Init();  
    //操作sensor寄存器
    SCCB_WR_Reg(OV2640_DSP_RA_DLMT, 0x01);
    //软复位OV2640
     SCCB_WR_Reg(OV2640_SENSOR_COM7, 0x80);    
    Delay_ms(50); 
    //读取厂家ID 高八位
    reg=SCCB_RD_Reg(OV2640_SENSOR_MIDH);    
    reg<<=8;
    //读取厂家ID 低八位
    reg|=SCCB_RD_Reg(OV2640_SENSOR_MIDL);    
    if(reg!=OV2640_MID)
    {
        printf("MID:%d\r\n",reg);
        return 1;
    }
    //读取厂家ID 高八位
    reg=SCCB_RD_Reg(OV2640_SENSOR_PIDH);    
    reg<<=8;
    //读取厂家ID 低八位
    reg|=SCCB_RD_Reg(OV2640_SENSOR_PIDL);    
    if(reg!=OV2640_PID)
    {
        printf("HID:%d\r\n",reg);
        return 2;
    }   
     //初始化 OV2640,采用SXGA分辨率(1600*1200)  
    for(i=0;i<sizeof(ov2640_sxga_init_reg_tbl)/2;i++)
    {
           SCCB_WR_Reg(ov2640_sxga_init_reg_tbl[i][0],ov2640_sxga_init_reg_tbl[i][1]);
     } 
      return 0x00;     //ok
}

/*********************************************
*函数功能:OV2640切换为JPEG模式
*函数形参:None
*函数返回值:None
*备注:None
*********************************************/
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]);  
    }  
}

/*********************************************
*函数功能:OV2640自动曝光等级设置
*函数形参:None
*函数返回值:None
*备注:level:0~4
*********************************************/
void OV2640_Auto_Exposure(u8 level)
{  
    u8 i;
    u8 *p=(u8*)OV2640_AUTOEXPOSURE_LEVEL[level];
    for(i=0;i<4;i++)
    { 
        SCCB_WR_Reg(p[i*2],p[i*2+1]); 
    } 
}

/*********************************************
*函数功能:白平衡设置
*函数形参:None
*函数返回值:None
*备注://0:自动
      //1:太阳sunny
      //2,阴天cloudy
      //3,办公室office
      //4,家里home
*********************************************/
void OV2640_Light_Mode(u8 mode)
{
    u8 regccval=0X5E;//Sunny 
    u8 regcdval=0X41;
    u8 regceval=0X54;
    switch(mode)
    { 
        case 0://auto 
            SCCB_WR_Reg(0XFF,0X00);     
            SCCB_WR_Reg(0XC7,0X10);//AWB ON 
            return;      
        case 2://cloudy
            regccval=0X65;
            regcdval=0X41;
            regceval=0X4F;
            break;    
        case 3://office
            regccval=0X52;
            regcdval=0X41;
            regceval=0X66;
            break;    
        case 4://home
            regccval=0X42;
            regcdval=0X3F;
            regceval=0X71;
            break;    
    }
    SCCB_WR_Reg(0XFF,0X00);     
    SCCB_WR_Reg(0XC7,0X40);    //AWB OFF 
    SCCB_WR_Reg(0XCC,regccval); 
    SCCB_WR_Reg(0XCD,regcdval); 
    SCCB_WR_Reg(0XCE,regceval);  
}

/*********************************************
*函数功能:色度设置
*函数形参:None
*函数返回值:None
*备注://0:-2
      //1:-1
      //2,0
      //3,+1
      //4,+2
*********************************************/
void OV2640_Color_Saturation(u8 sat)
{ 
    u8 reg7dval=((sat+2)<<4)|0X08;
    SCCB_WR_Reg(0XFF,0X00);        
    SCCB_WR_Reg(0X7C,0X00);        
    SCCB_WR_Reg(0X7D,0X02);                
    SCCB_WR_Reg(0X7C,0X03);            
    SCCB_WR_Reg(0X7D,reg7dval);            
    SCCB_WR_Reg(0X7D,reg7dval);         
}

/*********************************************
*函数功能:亮度设置
*函数形参:None
*函数返回值:None
*备注:  //0:(0X00)-2
        //1:(0X10)-1
        //2,(0X20) 0
        //3,(0X30)+1
        //4,(0X40)+2
*********************************************/
void OV2640_Brightness(u8 bright)
{
  SCCB_WR_Reg(0xff, 0x00);
  SCCB_WR_Reg(0x7c, 0x00);
  SCCB_WR_Reg(0x7d, 0x04);
  SCCB_WR_Reg(0x7c, 0x09);
  SCCB_WR_Reg(0x7d, bright<<4); 
  SCCB_WR_Reg(0x7d, 0x00); 
}

/*********************************************
*函数功能:对比度设置
*函数形参:None
*函数返回值:None
*备注:  //0:-2
        //1:-1
        //2,0
        //3,+1
        //4,+2
*********************************************/
void OV2640_Contrast(u8 contrast)
{
    u8 reg7d0val=0X20;//默认为普通模式
    u8 reg7d1val=0X20;
      switch(contrast)
    {
        case 0://-2
            reg7d0val=0X18;          
            reg7d1val=0X34;          
            break;    
        case 1://-1
            reg7d0val=0X1C;          
            reg7d1val=0X2A;          
            break;    
        case 3://1
            reg7d0val=0X24;          
            reg7d1val=0X16;          
            break;    
        case 4://2
            reg7d0val=0X28;          
            reg7d1val=0X0C;          
            break;    
    }
    SCCB_WR_Reg(0xff,0x00);
    SCCB_WR_Reg(0x7c,0x00);
    SCCB_WR_Reg(0x7d,0x04);
    SCCB_WR_Reg(0x7c,0x07);
    SCCB_WR_Reg(0x7d,0x20);
    SCCB_WR_Reg(0x7d,reg7d0val);
    SCCB_WR_Reg(0x7d,reg7d1val);
    SCCB_WR_Reg(0x7d,0x06);
}

/*********************************************
*函数功能:特效设置
*函数形参:None
*函数返回值:None
*备注:  //0:普通模式    
        //1,负片
        //2,黑白   
        //3,偏红色
        //4,偏绿色
        //5,偏蓝色
        //6,复古
*********************************************/        
void OV2640_Special_Effects(u8 eft)
{
    u8 reg7d0val=0X00;//默认为普通模式
    u8 reg7d1val=0X80;
    u8 reg7d2val=0X80; 
    switch(eft)
    {
        case 1://负片
            reg7d0val=0X40; 
            break;    
        case 2://黑白
            reg7d0val=0X18; 
            break;     
        case 3://偏红色
            reg7d0val=0X18; 
            reg7d1val=0X40;
            reg7d2val=0XC0; 
            break;    
        case 4://偏绿色
            reg7d0val=0X18; 
            reg7d1val=0X40;
            reg7d2val=0X40; 
            break;    
        case 5://偏蓝色
            reg7d0val=0X18; 
            reg7d1val=0XA0;
            reg7d2val=0X40; 
            break;    
        case 6://复古
            reg7d0val=0X18; 
            reg7d1val=0X40;
            reg7d2val=0XA6; 
            break;     
    }
    SCCB_WR_Reg(0xff,0x00);
    SCCB_WR_Reg(0x7c,0x00);
    SCCB_WR_Reg(0x7d,reg7d0val);
    SCCB_WR_Reg(0x7c,0x05);
    SCCB_WR_Reg(0x7d,reg7d1val);
    SCCB_WR_Reg(0x7d,reg7d2val); 
}

/*********************************************
*函数功能:彩条测试
*函数形参:None
*函数返回值:None
*备注:  //sw:0,关闭彩条
        //   1,开启彩条(注意OV2640的彩条是叠加在图像上面的)
*********************************************/     
void OV2640_Color_Bar(u8 sw)
{
    u8 reg;
    SCCB_WR_Reg(0XFF,0X01);
    reg=SCCB_RD_Reg(0X12);
    reg&=~(1<<1);
    if(sw)reg|=1<<1; 
    SCCB_WR_Reg(0X12,reg);
}

/*********************************************
*函数功能:设置图像输出窗口
*函数形参:u16 sx,u16 sy,u16 width,u16 height
*函数返回值:None
*备注:  //sx,sy,起始地址
        //width,height:宽度(对应:horizontal)和高度(对应:vertical)
*********************************************/      
void OV2640_Window_Set(u16 sx,u16 sy,u16 width,u16 height)
{
    u16 endx;
    u16 endy;
    u8 temp; 
    endx=sx+width/2;    //V*2
     endy=sy+height/2;
    
    SCCB_WR_Reg(0XFF,0X01);            
    temp=SCCB_RD_Reg(0X03);                //读取Vref之前的值
    temp&=0XF0;
    temp|=((endy&0X03)<<2)|(sy&0X03);
    SCCB_WR_Reg(0X03,temp);                //设置Vref的start和end的最低2位
    SCCB_WR_Reg(0X19,sy>>2);            //设置Vref的start高8位
    SCCB_WR_Reg(0X1A,endy>>2);            //设置Vref的end的高8位
    
    temp=SCCB_RD_Reg(0X32);                //读取Href之前的值
    temp&=0XC0;
    temp|=((endx&0X07)<<3)|(sx&0X07);
    SCCB_WR_Reg(0X32,temp);                //设置Href的start和end的最低3位
    SCCB_WR_Reg(0X17,sx>>3);            //设置Href的start高8位
    SCCB_WR_Reg(0X18,endx>>3);            //设置Href的end的高8位
}

/*********************************************
*函数功能:设置图像输出大小
*函数形参:u16 width,u16 height
*函数返回值:None
*备注:  /OV2640输出图像的大小(分辨率),完全由改函数确定
        //width,height:宽度(对应:horizontal)和高度(对应:vertical),width和height必须是4的倍数
        //返回值:0,设置成功
        //    其他,设置失败
*********************************************/
u8 OV2640_OutSize_Set(u16 width,u16 height)
{
    u16 outh;
    u16 outw;
    u8 temp; 
    if(width%4)return 1;
    if(height%4)return 2;
    outw=width/4;
    outh=height/4; 
    SCCB_WR_Reg(0XFF,0X00);    
    SCCB_WR_Reg(0XE0,0X04);            
    SCCB_WR_Reg(0X5A,outw&0XFF);        //设置OUTW的低八位
    SCCB_WR_Reg(0X5B,outh&0XFF);        //设置OUTH的低八位
    temp=(outw>>8)&0X03;
    temp|=(outh>>6)&0X04;
    SCCB_WR_Reg(0X5C,temp);                //设置OUTH/OUTW的高位 
    SCCB_WR_Reg(0XE0,0X00);    
    return 0;
}

/*********************************************
*函数功能:设置图像开窗大小
*函数形参:uu16 offx,u16 offy,u16 width,u16 height
*函数返回值:None
*备注:  //由:OV2640_ImageSize_Set确定传感器输出分辨率从大小.
        //该函数则在这个范围上面进行开窗,用于OV2640_OutSize_Set的输出
        //注意:本函数的宽度和高度,必须大于等于OV2640_OutSize_Set函数的宽度和高度
        //     OV2640_OutSize_Set设置的宽度和高度,根据本函数设置的宽度和高度,由DSP
        //     自动计算缩放比例,输出给外部设备.
        //width,height:宽度(对应:horizontal)和高度(对应:vertical),width和height必须是4的倍数
        //返回值:0,设置成功
        //    其他,设置失败
*********************************************/
u8 OV2640_ImageWin_Set(u16 offx,u16 offy,u16 width,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/OFFX,OFFY的高位
    SCCB_WR_Reg(0X57,(hsize>>2)&0X80);    //设置H_SIZE/V_SIZE/OFFX,OFFY的高位
    SCCB_WR_Reg(0XE0,0X00);    
    return 0;
} 

/*********************************************
*函数功能:该函数设置图像尺寸大小,也就是所选格式的输出分辨率
*函数形参:u16 width,u16 height
*函数返回值:None
*备注:  //该函数设置图像尺寸大小,也就是所选格式的输出分辨率
        //UXGA:1600*1200,SVGA:800*600,CIF:352*288
        //width,height:图像宽度和图像高度
        //返回值:0,设置成功
        //    其他,设置失败
*********************************************/
u8 OV2640_ImageSize_Set(u16 width,u16 height)
{ 
    u8 temp; 
    SCCB_WR_Reg(0XFF,0X00);            
    SCCB_WR_Reg(0XE0,0X04);            
    SCCB_WR_Reg(0XC0,(width)>>3&0XFF);        //设置HSIZE的10:3位
    SCCB_WR_Reg(0XC1,(height)>>3&0XFF);        //设置VSIZE的10:3位
    temp=(width&0X07)<<3;
    temp|=height&0X07;
    temp|=(width>>4)&0X80; 
    SCCB_WR_Reg(0X8C,temp);    
    SCCB_WR_Reg(0XE0,0X00);                 
    return 0;
}








ov2640.h文件

#ifndef __OV2640_H_
#define __OV2640_H_


/********************头文件************************/
#include "ov2640.h"
#include "sys.h"
#include "time.h"      
#include "systick.h"
#include "uart.h"             
#include "sccb.h"
#include "ov2640cfg.h"
/********************宏定义************************/
#define OV2640_PWDN      PGout(9)            //POWER DOWN控制信号 
#define OV2640_RST      PGout(15)            //复位控制信号 
// 
#define OV2640_MID                0X7FA2
#define OV2640_PID                0X2642
 
//当选择DSP地址(0XFF=0X00)时,OV2640的DSP寄存器地址映射表
#define OV2640_DSP_R_BYPASS     0x05
#define OV2640_DSP_Qs           0x44
#define OV2640_DSP_CTRL         0x50
#define OV2640_DSP_HSIZE1       0x51
#define OV2640_DSP_VSIZE1       0x52
#define OV2640_DSP_XOFFL        0x53
#define OV2640_DSP_YOFFL        0x54
#define OV2640_DSP_VHYX         0x55
#define OV2640_DSP_DPRP         0x56
#define OV2640_DSP_TEST         0x57
#define OV2640_DSP_ZMOW         0x5A
#define OV2640_DSP_ZMOH         0x5B
#define OV2640_DSP_ZMHH         0x5C
#define OV2640_DSP_BPADDR       0x7C
#define OV2640_DSP_BPDATA       0x7D
#define OV2640_DSP_CTRL2        0x86
#define OV2640_DSP_CTRL3        0x87
#define OV2640_DSP_SIZEL        0x8C
#define OV2640_DSP_HSIZE2       0xC0
#define OV2640_DSP_VSIZE2       0xC1
#define OV2640_DSP_CTRL0        0xC2
#define OV2640_DSP_CTRL1        0xC3
#define OV2640_DSP_R_DVP_SP     0xD3
#define OV2640_DSP_IMAGE_MODE   0xDA
#define OV2640_DSP_RESET        0xE0
#define OV2640_DSP_MS_SP        0xF0
#define OV2640_DSP_SS_ID        0x7F
#define OV2640_DSP_SS_CTRL      0xF8
#define OV2640_DSP_MC_BIST      0xF9
#define OV2640_DSP_MC_AL        0xFA
#define OV2640_DSP_MC_AH        0xFB
#define OV2640_DSP_MC_D         0xFC
#define OV2640_DSP_P_STATUS     0xFE
#define OV2640_DSP_RA_DLMT      0xFF 

//当选择传感器地址(0XFF=0X01)时,OV2640的DSP寄存器地址映射表
#define OV2640_SENSOR_GAIN       0x00
#define OV2640_SENSOR_COM1       0x03
#define OV2640_SENSOR_REG04      0x04
#define OV2640_SENSOR_REG08      0x08
#define OV2640_SENSOR_COM2       0x09
#define OV2640_SENSOR_PIDH       0x0A
#define OV2640_SENSOR_PIDL       0x0B
#define OV2640_SENSOR_COM3       0x0C
#define OV2640_SENSOR_COM4       0x0D
#define OV2640_SENSOR_AEC        0x10
#define OV2640_SENSOR_CLKRC      0x11
#define OV2640_SENSOR_COM7       0x12
#define OV2640_SENSOR_COM8       0x13
#define OV2640_SENSOR_COM9       0x14
#define OV2640_SENSOR_COM10      0x15
#define OV2640_SENSOR_HREFST     0x17
#define OV2640_SENSOR_HREFEND    0x18
#define OV2640_SENSOR_VSTART     0x19
#define OV2640_SENSOR_VEND       0x1A
#define OV2640_SENSOR_MIDH       0x1C
#define OV2640_SENSOR_MIDL       0x1D
#define OV2640_SENSOR_AEW        0x24
#define OV2640_SENSOR_AEB        0x25
#define OV2640_SENSOR_W          0x26
#define OV2640_SENSOR_REG2A      0x2A
#define OV2640_SENSOR_FRARL      0x2B
#define OV2640_SENSOR_ADDVSL     0x2D
#define OV2640_SENSOR_ADDVHS     0x2E
#define OV2640_SENSOR_YAVG       0x2F
#define OV2640_SENSOR_REG32      0x32
#define OV2640_SENSOR_ARCOM2     0x34
#define OV2640_SENSOR_REG45      0x45
#define OV2640_SENSOR_FLL        0x46
#define OV2640_SENSOR_FLH        0x47
#define OV2640_SENSOR_COM19      0x48
#define OV2640_SENSOR_ZOOMS      0x49
#define OV2640_SENSOR_COM22      0x4B
#define OV2640_SENSOR_COM25      0x4E
#define OV2640_SENSOR_BD50       0x4F
#define OV2640_SENSOR_BD60       0x50
#define OV2640_SENSOR_REG5D      0x5D
#define OV2640_SENSOR_REG5E      0x5E
#define OV2640_SENSOR_REG5F      0x5F
#define OV2640_SENSOR_REG60      0x60
#define OV2640_SENSOR_HISTO_LOW  0x61
#define OV2640_SENSOR_HISTO_HIGH 0x62

/*****************声明外部变量*********************/
//自动曝光设置参数表,支持5个等级
const static u8 OV2640_AUTOEXPOSURE_LEVEL[5][8]=
{
    {
        0xFF,0x01,
        0x24,0x20,
        0x25,0x18,
        0x26,0x60,
    },
    {
        0xFF,0x01,
        0x24,0x34,
        0x25,0x1c,
        0x26,0x00,
    },
    {
        0xFF,0x01,    
        0x24,0x3e,    
        0x25,0x38,
        0x26,0x81,
    },
    {
        0xFF,0x01,
        0x24,0x48,
        0x25,0x40,
        0x26,0x81,
    },
    {
        0xFF,0x01,    
        0x24,0x58,    
        0x25,0x50,    
        0x26,0x92,    
    },
};


/*******************函数声明***********************/
u8 OV2640_Init(void);  
void OV2640_JPEG_Mode(void);
void OV2640_RGB565_Mode(void);
void OV2640_Auto_Exposure(u8 level);
void OV2640_Light_Mode(u8 mode);
void OV2640_Color_Saturation(u8 sat);
void OV2640_Brightness(u8 bright);
void OV2640_Contrast(u8 contrast);
void OV2640_Special_Effects(u8 eft);
void OV2640_Color_Bar(u8 sw);
void OV2640_Window_Set(u16 sx,u16 sy,u16 width,u16 height);
u8 OV2640_OutSize_Set(u16 width,u16 height);
u8 OV2640_ImageWin_Set(u16 offx,u16 offy,u16 width,u16 height);
u8 OV2640_ImageSize_Set(u16 width,u16 height);
/



#endif











sccb.c文件

#include "sccb.h"

/*********************************************
*函数功能:初始化SCCB接口
*函数形参:None
*函数返回值:None
*备注:    None
*********************************************/ 
void SCCB_Init(void)
{                
    GPIO_InitTypeDef  GPIO_InitStructure;
    //使能GPIOD时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
    //GPIOF9,F10初始化设置
    //PD6,7 推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
    //PD6,7 推挽输出
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;  
    //推挽输出
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    //100MHz
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    //上拉
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    //初始化
    GPIO_Init(GPIOD, &GPIO_InitStructure);
 
    GPIO_SetBits(GPIOD,GPIO_Pin_6|GPIO_Pin_7);
    SCCB_SDA_OUT();       
}    

/*********************************************
*函数功能:SCCB起始信号
*函数形参:None
*函数返回值:None
*备注:    //当时钟为高的时候,数据线的高到低,为SCCB起始信号
        //在激活状态下,SDA和SCL均为低电平
*********************************************/ 
void SCCB_Start(void)
{
    SCCB_SDA=1;     //数据线高电平       
    SCCB_SCL=1;        //在时钟线高的时候数据线由高至低
    Delay_us(50);  
    SCCB_SDA=0;
    Delay_us(50);     
    SCCB_SCL=0;        //数据线恢复低电平,单操作函数必要      
}

/*********************************************
*函数功能:SCCB停止信号
*函数形参:None
*函数返回值:None
*备注:    //当时钟为高的时候,数据线的低到高,为SCCB停止信号
        //空闲状况下,SDA,SCL均为高电平
*********************************************/ 
void SCCB_Stop(void)
{
    SCCB_SDA=0;
    Delay_us(50);     
    SCCB_SCL=1;    
    Delay_us(50); 
    SCCB_SDA=1;    
    Delay_us(50);
}  

/*********************************************
*函数功能:产生NA信号
*函数形参:None
*函数返回值:None
*备注:    //当时钟为高的时候,数据线的低到高,为SCCB停止信号
        //空闲状况下,SDA,SCL均为高电平
*********************************************/ 
void SCCB_No_Ack(void)
{
    Delay_us(50);
    SCCB_SDA=1;    
    SCCB_SCL=1;    
    Delay_us(50);
    SCCB_SCL=0;    
    Delay_us(50);
    SCCB_SDA=0;    
    Delay_us(50);
}

/*********************************************
*函数功能:SCCB,写入一个字节
*函数形参:u8 dat
*函数返回值:返回值:0,成功;1,失败
*备注:    None
*********************************************/  
u8 SCCB_WR_Byte(u8 dat)
{
    u8 j,res;     
    for(j=0;j<8;j++) //循环8次发送数据
    {
        if(dat&0x80)SCCB_SDA=1;    
        else SCCB_SDA=0;
        dat<<=1;
        Delay_us(50);
        SCCB_SCL=1;    
        Delay_us(50);
        SCCB_SCL=0;           
    }             
    SCCB_SDA_IN();        //设置SDA为输入 
    Delay_us(50);
    SCCB_SCL=1;            //接收第九位,以判断是否发送成功
    Delay_us(50);
    if(SCCB_READ_SDA)res=1;  //SDA=1发送失败,返回1
    else res=0;         //SDA=0发送成功,返回0
    SCCB_SCL=0;         
    SCCB_SDA_OUT();        //设置SDA为输出    
    return res;  
}

/*********************************************
*函数功能:SCCB 读取一个字节
*函数形参:NONE
*函数返回值://返回值:读到的数据
*备注:    //在SCL的上升沿,数据锁存

*********************************************/ 
u8 SCCB_RD_Byte(void)
{
    u8 temp=0,j;    
    //设置SDA为输入
    SCCB_SDA_IN();         
    //循环8次接收数据
    for(j=8;j>0;j--)     
    {                   
        Delay_us(50);
        SCCB_SCL=1;
        temp=temp<<1;
        if(SCCB_READ_SDA)temp++;   
        Delay_us(50);
        SCCB_SCL=0;
    }    
    //设置SDA为输出
    SCCB_SDA_OUT();            
    return temp;
}     

/*********************************************
*函数功能:写寄存器
*函数形参:u8 reg,u8 data
*函数返回值:
*备注:    //返回值:0,成功;1,失败.
*********************************************/
u8 SCCB_WR_Reg(u8 reg,u8 data)
{
    u8 res=0;
    SCCB_Start();                     //启动SCCB传输
    if(SCCB_WR_Byte(SCCB_ID))res=1;    //写器件ID      
    Delay_us(100);
      if(SCCB_WR_Byte(reg))res=1;        //写寄存器地址      
    Delay_us(100);
      if(SCCB_WR_Byte(data))res=1;     //写数据     
      SCCB_Stop();      
      return    res;
}

/*********************************************
*函数功能:读寄存器
*函数形参:u8 reg
*函数返回值:
*备注:    返回值:读到的寄存器值
*********************************************/
u8 SCCB_RD_Reg(u8 reg)
{
    u8 val=0;
    SCCB_Start();                 //启动SCCB传输
    SCCB_WR_Byte(SCCB_ID);        //写器件ID      
    Delay_us(100);     
      SCCB_WR_Byte(reg);            //写寄存器地址      
    Delay_us(100);      
    SCCB_Stop();   
    Delay_us(100);       
    //设置寄存器地址后,才是读
    SCCB_Start();
    SCCB_WR_Byte(SCCB_ID|0X01);    //发送读命令      
    Delay_us(100);
      val=SCCB_RD_Byte();             //读取数据
      SCCB_No_Ack();
      SCCB_Stop();
      return val;
}






sccb.h文件

#ifndef __SCCB_H_
#define __SCCB_H_


/********************头文件************************/
#include "sccb.h"
#include "sys.h"
#include "systick.h"
/********************宏定义************************/
//IO方向设置
#define SCCB_SDA_IN()  {GPIOD->MODER&=~(3<<(7*2));GPIOD->MODER|=0<<7*2;}    //PD7 输入
#define SCCB_SDA_OUT() {GPIOD->MODER&=~(3<<(7*2));GPIOD->MODER|=1<<7*2;}     //PD7 输出


//IO操作函数     
#define SCCB_SCL            PDout(6)         //SCL
#define SCCB_SDA            PDout(7)         //SDA     

#define SCCB_READ_SDA        PDin(7)          //输入SDA    
#define SCCB_ID               0X60              //OV2640的ID

/*****************声明外部变量*********************/

/*******************函数声明***********************/
void SCCB_Init(void);
void SCCB_Start(void);
void SCCB_Stop(void);
void SCCB_No_Ack(void);
u8 SCCB_WR_Byte(u8 dat);
u8 SCCB_RD_Byte(void);
u8 SCCB_WR_Reg(u8 reg,u8 data);
u8 SCCB_RD_Reg(u8 reg);

#endif

time.c文件

#include "time.h"

/*********************************************
*函数功能:通用定时器3中断初始化
*函数形参:None
*函数返回值:None
*备注:    //arr:自动重装值。
//psc:时钟预分频数
//定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz
//这里使用的是定时器3!
*********************************************/
void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);  ///使能TIM3时钟
    
    TIM_TimeBaseInitStructure.TIM_Prescaler=psc;  //定时器分频
    TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
    TIM_TimeBaseInitStructure.TIM_Period=arr;   //自动重装载值
    TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
    
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
    
    TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许定时器3更新中断
    TIM_Cmd(TIM3,ENABLE); //使能定时器3
    
    NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定时器3中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //抢占优先级1
    NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
}

//定时器3中断服务函数
void TIM3_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
    {
//        printf("frame:%d\r\n",ov_frame);//打印帧率
//        printf("jpeg_data_len:%d\r\n",jpeg_data_len);//打印帧率
        ov_frame=0;
    }
    TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  //清除中断标志位
}






time.h文件

#ifndef __TIME_H_
#define __TIME_H_


/********************头文件************************/
#include "stm32f4xx.h"
#include "led.h"
#include "uart.h"
/********************宏定义************************/

/*****************声明外部变量*********************/
extern u8 ov_frame;
extern volatile u32 jpeg_data_len;
/*******************函数声明***********************/
void TIM3_Int_Init(u16 arr,u16 psc);

#endif

sys.c文件

#include "sys.h"  
//     
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F407开发板
//系统时钟初始化    
//包括时钟设置/中断管理/GPIO设置等
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2014/5/2
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved
//********************************************************************************
//修改说明
//无
//  


//THUMB指令不支持汇编内联
//采用如下方法实现执行汇编指令WFI  
__asm void WFI_SET(void)
{
    WFI;          
}
//关闭所有中断(但是不包括fault和NMI中断)
__asm void INTX_DISABLE(void)
{
    CPSID   I
    BX      LR      
}
//开启所有中断
__asm void INTX_ENABLE(void)
{
    CPSIE   I
    BX      LR  
}
//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(u32 addr) 
{
    MSR MSP, r0             //set Main Stack value
    BX r14
}










sys.h文件

#ifndef __SYS_H
#define __SYS_H     
#include "stm32f4xx.h" 
//     
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F407开发板
//系统时钟初始化    
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2014/5/2
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved
//********************************************************************************
//修改说明
//无
// 


//0,不支持ucos
//1,支持ucos
#define SYSTEM_SUPPORT_OS        0        //定义系统文件夹是否支持UCOS
                                                                        
     
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).M4同M3类似,只是寄存器地址变了.
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014     

#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 
#define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入

#define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //输出 
#define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //输入

//以下为汇编函数
void WFI_SET(void);        //执行WFI指令
void INTX_DISABLE(void);//关闭所有中断
void INTX_ENABLE(void);    //开启所有中断
void MSR_MSP(u32 addr);    //设置堆栈地址 
#endif











ov2640cfg.c文件

#include "ov2640cfg.h" 

//                  
 

OV2640 SXGA初始化寄存器序列表
此模式下帧率为15帧
SXGA(1600*1200) 
// const u8 ov2640_sxga_init_reg_tbl[][2]= 
//{   
//    0xff, 0x00,
//    0x2c, 0xff,
//    0x2e, 0xdf,
//    0xff, 0x01,
//    0x3c, 0x32,
//    //
//    0x11, 0x00,
//    0x09, 0x02,
//    0x04, 0xD8,//水平镜像,垂直翻转
//    0x13, 0xe5,
//    0x14, 0x48,
//    0x2c, 0x0c,
//    0x33, 0x78,
//    0x3a, 0x33,
//    0x3b, 0xfB,
//    //
//    0x3e, 0x00,
//    0x43, 0x11,
//    0x16, 0x10,
//    //
//    0x39, 0x92,
//    //
//    0x35, 0xda,
//    0x22, 0x1a,
//    0x37, 0xc3,
//    0x23, 0x00,
//    0x34, 0xc0,
//    0x36, 0x1a,
//    0x06, 0x88,
//    0x07, 0xc0,
//    0x0d, 0x87,
//    0x0e, 0x41,
//    0x4c, 0x00,
//    
//    0x48, 0x00,
//    0x5B, 0x00,
//    0x42, 0x03,
//    //
//    0x4a, 0x81,
//    0x21, 0x99,
//    //
//    0x24, 0x40,
//    0x25, 0x38,
//    0x26, 0x82,
//    0x5c, 0x00,
//    0x63, 0x00,
//    0x46, 0x00,
//    0x0c, 0x3c,
//    //
//    0x61, 0x70,
//    0x62, 0x80,
//    0x7c, 0x05,
//    //
//    0x20, 0x80,
//    0x28, 0x30,
//    0x6c, 0x00,
//    0x6d, 0x80,
//    0x6e, 0x00,
//    0x70, 0x02,
//    0x71, 0x94,
//    0x73, 0xc1, 
//    0x3d, 0x34, 
//    0x5a, 0x57,
//    //
//    0x12, 0x00,//UXGA 1600*1200
//    
//    0x17, 0x11,
//    0x18, 0x75,
//    0x19, 0x01,
//    0x1a, 0x97,
//    0x32, 0x36,
//    0x03, 0x0f, 
//    0x37, 0x40,
//    // 
//    0x4f, 0xca,
//    0x50, 0xa8,
//    0x5a, 0x23,
//    0x6d, 0x00,
//    0x6d, 0x38,
//    //
//    0xff, 0x00,
//    0xe5, 0x7f,
//    0xf9, 0xc0,
//    0x41, 0x24,
//    0xe0, 0x14,
//    0x76, 0xff,
//    0x33, 0xa0,
//    0x42, 0x20,
//    0x43, 0x18,
//    0x4c, 0x00,
//    0x87, 0xd5,
//    0x88, 0x3f,
//    0xd7, 0x03,
//    0xd9, 0x10,
//    0xd3, 0x82,
//    //
//    0xc8, 0x08,
//    0xc9, 0x80,
//    //
//    0x7c, 0x00,
//    0x7d, 0x00,
//    0x7c, 0x03,
//    0x7d, 0x48,
//    0x7d, 0x48,
//    0x7c, 0x08,
//    0x7d, 0x20,
//    0x7d, 0x10,
//    0x7d, 0x0e,
//    //
//    0x90, 0x00,
//    0x91, 0x0e,
//    0x91, 0x1a,
//    0x91, 0x31,
//    0x91, 0x5a,
//    0x91, 0x69,
//    0x91, 0x75,
//    0x91, 0x7e,
//    0x91, 0x88,
//    0x91, 0x8f,
//    0x91, 0x96,
//    0x91, 0xa3,
//    0x91, 0xaf,
//    0x91, 0xc4,
//    0x91, 0xd7,
//    0x91, 0xe8,
//    0x91, 0x20,
//    //
//    0x92, 0x00,
//    0x93, 0x06,
//    0x93, 0xe3,
//    0x93, 0x05,
//    0x93, 0x05,
//    0x93, 0x00,
//    0x93, 0x04,
//    0x93, 0x00,
//    0x93, 0x00,
//    0x93, 0x00,
//    0x93, 0x00,
//    0x93, 0x00,
//    0x93, 0x00,
//    0x93, 0x00,
//    //
//    0x96, 0x00,
//    0x97, 0x08,
//    0x97, 0x19,
//    0x97, 0x02,
//    0x97, 0x0c,
//    0x97, 0x24,
//    0x97, 0x30,
//    0x97, 0x28,
//    0x97, 0x26,
//    0x97, 0x02,
//    0x97, 0x98,
//    0x97, 0x80,
//    0x97, 0x00,
//    0x97, 0x00,
//    //
//    0xc3, 0xef,
//    
//    0xa4, 0x00,
//    0xa8, 0x00,
//    0xc5, 0x11,
//    0xc6, 0x51,
//    0xbf, 0x80,
//    0xc7, 0x10,
//    0xb6, 0x66,
//    0xb8, 0xA5,
//    0xb7, 0x64,
//    0xb9, 0x7C,
//    0xb3, 0xaf,
//    0xb4, 0x97,
//    0xb5, 0xFF,
//    0xb0, 0xC5,
//    0xb1, 0x94,
//    0xb2, 0x0f,
//    0xc4, 0x5c,
//    //
//    0xc0, 0xc8,
//    0xc1, 0x96,
//    0x8c, 0x00,
//    0x86, 0x3d,
//    0x50, 0x00,
//    0x51, 0x90,
//    0x52, 0x2c,
//    0x53, 0x00,
//    0x54, 0x00,
//    0x55, 0x88,
//    
//    0x5a, 0x90,
//    0x5b, 0x2C,
//    0x5c, 0x05,
//    
//    0xd3, 0x05,//auto设置要小心
//    //
//    0xc3, 0xed,
//    0x7f, 0x00,
//    
//    0xda, 0x09,
//    
//    0xe5, 0x1f,
//    0xe1, 0x67,
//    0xe0, 0x00,
//    0xdd, 0x7f,
//    0x05, 0x00,
//};  
OV2640 SVGA初始化寄存器序列表
此模式下,帧率可以达到30帧
SVGA 800*600
//const u8 ov2640_svga_init_reg_tbl[][2]= 
//{    
//    0xff, 0x00,
//    0x2c, 0xff,
//    0x2e, 0xdf,
//    0xff, 0x01,
//    0x3c, 0x32,
//    //
//    0x11, 0x00,
//    0x09, 0x02,
//    0x04, 0xD8,//水平镜像,垂直翻转
//    0x13, 0xe5,
//    0x14, 0x48,
//    0x2c, 0x0c,
//    0x33, 0x78,
//    0x3a, 0x33,
//    0x3b, 0xfB,
//    //
//    0x3e, 0x00,
//    0x43, 0x11,
//    0x16, 0x10,
//    //
//    0x39, 0x92,
//    //
//    0x35, 0xda,
//    0x22, 0x1a,
//    0x37, 0xc3,
//    0x23, 0x00,
//    0x34, 0xc0,
//    0x36, 0x1a,
//    0x06, 0x88,
//    0x07, 0xc0,
//    0x0d, 0x87,
//    0x0e, 0x41,
//    0x4c, 0x00,
//    0x48, 0x00,
//    0x5B, 0x00,
//    0x42, 0x03,
//    //
//    0x4a, 0x81,
//    0x21, 0x99,
//    //
//    0x24, 0x40,
//    0x25, 0x38,
//    0x26, 0x82,
//    0x5c, 0x00,
//    0x63, 0x00,
//    0x46, 0x22,
//    0x0c, 0x3c,
//    //
//    0x61, 0x70,
//    0x62, 0x80,
//    0x7c, 0x05,
//    //
//    0x20, 0x80,
//    0x28, 0x30,
//    0x6c, 0x00,
//    0x6d, 0x80,
//    0x6e, 0x00,
//    0x70, 0x02,
//    0x71, 0x94,
//    0x73, 0xc1,
//    
//    0x3d, 0x34, 
//    0x5a, 0x57,
//    //根据分辨率不同而设置
//    0x12, 0x40,//SVGA 800*600
//    0x17, 0x11,
//    0x18, 0x43,
//    0x19, 0x00,
//    0x1a, 0x4b,
//    0x32, 0x09,
//    0x37, 0xc0,
//    //
//    0x4f, 0xca,
//    0x50, 0xa8,
//    0x5a, 0x23,
//    0x6d, 0x00,
//    0x3d, 0x38,
//    //
//    0xff, 0x00,
//    0xe5, 0x7f,
//    0xf9, 0xc0,
//    0x41, 0x24,
//    0xe0, 0x14,
//    0x76, 0xff,
//    0x33, 0xa0,
//    0x42, 0x20,
//    0x43, 0x18,
//    0x4c, 0x00,
//    0x87, 0xd5,
//    0x88, 0x3f,
//    0xd7, 0x03,
//    0xd9, 0x10,
//    0xd3, 0x82,
//    //
//    0xc8, 0x08,
//    0xc9, 0x80,
//    //
//    0x7c, 0x00,
//    0x7d, 0x00,
//    0x7c, 0x03,
//    0x7d, 0x48,
//    0x7d, 0x48,
//    0x7c, 0x08,
//    0x7d, 0x20,
//    0x7d, 0x10,
//    0x7d, 0x0e,
//    //
//    0x90, 0x00,
//    0x91, 0x0e,
//    0x91, 0x1a,
//    0x91, 0x31,
//    0x91, 0x5a,
//    0x91, 0x69,
//    0x91, 0x75,
//    0x91, 0x7e,
//    0x91, 0x88,
//    0x91, 0x8f,
//    0x91, 0x96,
//    0x91, 0xa3,
//    0x91, 0xaf,
//    0x91, 0xc4,
//    0x91, 0xd7,
//    0x91, 0xe8,
//    0x91, 0x20,
//    //
//    0x92, 0x00,
//    0x93, 0x06,
//    0x93, 0xe3,
//    0x93, 0x05,
//    0x93, 0x05,
//    0x93, 0x00,
//    0x93, 0x04,
//    0x93, 0x00,
//    0x93, 0x00,
//    0x93, 0x00,
//    0x93, 0x00,
//    0x93, 0x00,
//    0x93, 0x00,
//    0x93, 0x00,
//    //
//    0x96, 0x00,
//    0x97, 0x08,
//    0x97, 0x19,
//    0x97, 0x02,
//    0x97, 0x0c,
//    0x97, 0x24,
//    0x97, 0x30,
//    0x97, 0x28,
//    0x97, 0x26,
//    0x97, 0x02,
//    0x97, 0x98,
//    0x97, 0x80,
//    0x97, 0x00,
//    0x97, 0x00,
//    //
//    0xc3, 0xed,
//    0xa4, 0x00,
//    0xa8, 0x00,
//    0xc5, 0x11,
//    0xc6, 0x51,
//    0xbf, 0x80,
//    0xc7, 0x10,
//    0xb6, 0x66,
//    0xb8, 0xA5,
//    0xb7, 0x64,
//    0xb9, 0x7C,
//    0xb3, 0xaf,
//    0xb4, 0x97,
//    0xb5, 0xFF,
//    0xb0, 0xC5,
//    0xb1, 0x94,
//    0xb2, 0x0f,
//    0xc4, 0x5c,
//    //根据分辨率不同而设置
//    0xc0, 0x64,
//    0xc1, 0x4B,
//    0x8c, 0x00,
//    0x86, 0x3D,
//    0x50, 0x00,
//    0x51, 0xC8,
//    0x52, 0x96,
//    0x53, 0x00,
//    0x54, 0x00,
//    0x55, 0x00,
//    0x5a, 0xC8,
//    0x5b, 0x96,
//    0x5c, 0x00,
//    
//    0xd3, 0x02,//auto设置要小心
//    //
//    0xc3, 0xed,
//    0x7f, 0x00,
//    
//    0xda, 0x09,
//    
//    0xe5, 0x1f,
//    0xe1, 0x67,
//    0xe0, 0x00,
//    0xdd, 0x7f,
//    0x05, 0x00,
//};   
//const u8 ov2640_jpeg_reg_tbl[][2]=
//{
//    0xff, 0x01, 
//    0xe0, 0x14,
//    0xe1, 0x77,
//    0xe5, 0x1f,
//    0xd7, 0x03,
//    0xda, 0x10,
//    0xe0, 0x00, 
//};

//const u8 ov2640_yuv422_reg_tbl[][2]= 
//{
//    0xFF, 0x00, 
//    0xDA, 0x10,
//    0xD7, 0x03,
//    0xDF, 0x00,
//    0x33, 0x80,
//    0x3C, 0x40,
//    0xe1, 0x77,
//    0x00, 0x00,
//};









ov2640cfg.h文件

#ifndef _OV2640CFG_H
#define _OV2640CFG_H
#include "ov2640.h" 
#include "stm32f4xx.h"                  
// 

//OV2640 SXGA初始化寄存器序列表
//此模式下帧率为15帧
//SXGA(1600*1200) 
 static const u8 ov2640_sxga_init_reg_tbl[][2]= 
{   
    0xff, 0x00,
    0x2c, 0xff,
    0x2e, 0xdf,
    0xff, 0x01,
    0x3c, 0x32,
    //
    0x11, 0x00,
    0x09, 0x02,
    0x04, 0xD8,//水平镜像,垂直翻转
    0x13, 0xe5,
    0x14, 0x48,
    0x2c, 0x0c,
    0x33, 0x78,
    0x3a, 0x33,
    0x3b, 0xfB,
    //
    0x3e, 0x00,
    0x43, 0x11,
    0x16, 0x10,
    //
    0x39, 0x92,
    //
    0x35, 0xda,
    0x22, 0x1a,
    0x37, 0xc3,
    0x23, 0x00,
    0x34, 0xc0,
    0x36, 0x1a,
    0x06, 0x88,
    0x07, 0xc0,
    0x0d, 0x87,
    0x0e, 0x41,
    0x4c, 0x00,
    
    0x48, 0x00,
    0x5B, 0x00,
    0x42, 0x03,
    //
    0x4a, 0x81,
    0x21, 0x99,
    //
    0x24, 0x40,
    0x25, 0x38,
    0x26, 0x82,
    0x5c, 0x00,
    0x63, 0x00,
    0x46, 0x00,
    0x0c, 0x3c,
    //
    0x61, 0x70,
    0x62, 0x80,
    0x7c, 0x05,
    //
    0x20, 0x80,
    0x28, 0x30,
    0x6c, 0x00,
    0x6d, 0x80,
    0x6e, 0x00,
    0x70, 0x02,
    0x71, 0x94,
    0x73, 0xc1, 
    0x3d, 0x34, 
    0x5a, 0x57,
    //
    0x12, 0x00,//UXGA 1600*1200
    
    0x17, 0x11,
    0x18, 0x75,
    0x19, 0x01,
    0x1a, 0x97,
    0x32, 0x36,
    0x03, 0x0f, 
    0x37, 0x40,
    // 
    0x4f, 0xca,
    0x50, 0xa8,
    0x5a, 0x23,
    0x6d, 0x00,
    0x6d, 0x38,
    //
    0xff, 0x00,
    0xe5, 0x7f,
    0xf9, 0xc0,
    0x41, 0x24,
    0xe0, 0x14,
    0x76, 0xff,
    0x33, 0xa0,
    0x42, 0x20,
    0x43, 0x18,
    0x4c, 0x00,
    0x87, 0xd5,
    0x88, 0x3f,
    0xd7, 0x03,
    0xd9, 0x10,
    0xd3, 0x82,
    //
    0xc8, 0x08,
    0xc9, 0x80,
    //
    0x7c, 0x00,
    0x7d, 0x00,
    0x7c, 0x03,
    0x7d, 0x48,
    0x7d, 0x48,
    0x7c, 0x08,
    0x7d, 0x20,
    0x7d, 0x10,
    0x7d, 0x0e,
    //
    0x90, 0x00,
    0x91, 0x0e,
    0x91, 0x1a,
    0x91, 0x31,
    0x91, 0x5a,
    0x91, 0x69,
    0x91, 0x75,
    0x91, 0x7e,
    0x91, 0x88,
    0x91, 0x8f,
    0x91, 0x96,
    0x91, 0xa3,
    0x91, 0xaf,
    0x91, 0xc4,
    0x91, 0xd7,
    0x91, 0xe8,
    0x91, 0x20,
    //
    0x92, 0x00,
    0x93, 0x06,
    0x93, 0xe3,
    0x93, 0x05,
    0x93, 0x05,
    0x93, 0x00,
    0x93, 0x04,
    0x93, 0x00,
    0x93, 0x00,
    0x93, 0x00,
    0x93, 0x00,
    0x93, 0x00,
    0x93, 0x00,
    0x93, 0x00,
    //
    0x96, 0x00,
    0x97, 0x08,
    0x97, 0x19,
    0x97, 0x02,
    0x97, 0x0c,
    0x97, 0x24,
    0x97, 0x30,
    0x97, 0x28,
    0x97, 0x26,
    0x97, 0x02,
    0x97, 0x98,
    0x97, 0x80,
    0x97, 0x00,
    0x97, 0x00,
    //
    0xc3, 0xef,
    
    0xa4, 0x00,
    0xa8, 0x00,
    0xc5, 0x11,
    0xc6, 0x51,
    0xbf, 0x80,
    0xc7, 0x10,
    0xb6, 0x66,
    0xb8, 0xA5,
    0xb7, 0x64,
    0xb9, 0x7C,
    0xb3, 0xaf,
    0xb4, 0x97,
    0xb5, 0xFF,
    0xb0, 0xC5,
    0xb1, 0x94,
    0xb2, 0x0f,
    0xc4, 0x5c,
    //
    0xc0, 0xc8,
    0xc1, 0x96,
    0x8c, 0x00,
    0x86, 0x3d,
    0x50, 0x00,
    0x51, 0x90,
    0x52, 0x2c,
    0x53, 0x00,
    0x54, 0x00,
    0x55, 0x88,
    
    0x5a, 0x90,
    0x5b, 0x2C,
    0x5c, 0x05,
    
    0xd3, 0x05,//auto设置要小心
    //
    0xc3, 0xed,
    0x7f, 0x00,
    
    0xda, 0x09,
    
    0xe5, 0x1f,
    0xe1, 0x67,
    0xe0, 0x00,
    0xdd, 0x7f,
    0x05, 0x00,
};  
//OV2640 SVGA初始化寄存器序列表
//此模式下,帧率可以达到30帧
//SVGA 800*600
static const u8 ov2640_svga_init_reg_tbl[][2]= 
{    
    0xff, 0x00,
    0x2c, 0xff,
    0x2e, 0xdf,
    0xff, 0x01,
    0x3c, 0x32,
    //
    0x11, 0x00,
    0x09, 0x02,
    0x04, 0xD8,//水平镜像,垂直翻转
    0x13, 0xe5,
    0x14, 0x48,
    0x2c, 0x0c,
    0x33, 0x78,
    0x3a, 0x33,
    0x3b, 0xfB,
    //
    0x3e, 0x00,
    0x43, 0x11,
    0x16, 0x10,
    //
    0x39, 0x92,
    //
    0x35, 0xda,
    0x22, 0x1a,
    0x37, 0xc3,
    0x23, 0x00,
    0x34, 0xc0,
    0x36, 0x1a,
    0x06, 0x88,
    0x07, 0xc0,
    0x0d, 0x87,
    0x0e, 0x41,
    0x4c, 0x00,
    0x48, 0x00,
    0x5B, 0x00,
    0x42, 0x03,
    //
    0x4a, 0x81,
    0x21, 0x99,
    //
    0x24, 0x40,
    0x25, 0x38,
    0x26, 0x82,
    0x5c, 0x00,
    0x63, 0x00,
    0x46, 0x22,
    0x0c, 0x3c,
    //
    0x61, 0x70,
    0x62, 0x80,
    0x7c, 0x05,
    //
    0x20, 0x80,
    0x28, 0x30,
    0x6c, 0x00,
    0x6d, 0x80,
    0x6e, 0x00,
    0x70, 0x02,
    0x71, 0x94,
    0x73, 0xc1,
    
    0x3d, 0x34, 
    0x5a, 0x57,
    //根据分辨率不同而设置
    0x12, 0x40,//SVGA 800*600
    0x17, 0x11,
    0x18, 0x43,
    0x19, 0x00,
    0x1a, 0x4b,
    0x32, 0x09,
    0x37, 0xc0,
    //
    0x4f, 0xca,
    0x50, 0xa8,
    0x5a, 0x23,
    0x6d, 0x00,
    0x3d, 0x38,
    //
    0xff, 0x00,
    0xe5, 0x7f,
    0xf9, 0xc0,
    0x41, 0x24,
    0xe0, 0x14,
    0x76, 0xff,
    0x33, 0xa0,
    0x42, 0x20,
    0x43, 0x18,
    0x4c, 0x00,
    0x87, 0xd5,
    0x88, 0x3f,
    0xd7, 0x03,
    0xd9, 0x10,
    0xd3, 0x82,
    //
    0xc8, 0x08,
    0xc9, 0x80,
    //
    0x7c, 0x00,
    0x7d, 0x00,
    0x7c, 0x03,
    0x7d, 0x48,
    0x7d, 0x48,
    0x7c, 0x08,
    0x7d, 0x20,
    0x7d, 0x10,
    0x7d, 0x0e,
    //
    0x90, 0x00,
    0x91, 0x0e,
    0x91, 0x1a,
    0x91, 0x31,
    0x91, 0x5a,
    0x91, 0x69,
    0x91, 0x75,
    0x91, 0x7e,
    0x91, 0x88,
    0x91, 0x8f,
    0x91, 0x96,
    0x91, 0xa3,
    0x91, 0xaf,
    0x91, 0xc4,
    0x91, 0xd7,
    0x91, 0xe8,
    0x91, 0x20,
    //
    0x92, 0x00,
    0x93, 0x06,
    0x93, 0xe3,
    0x93, 0x05,
    0x93, 0x05,
    0x93, 0x00,
    0x93, 0x04,
    0x93, 0x00,
    0x93, 0x00,
    0x93, 0x00,
    0x93, 0x00,
    0x93, 0x00,
    0x93, 0x00,
    0x93, 0x00,
    //
    0x96, 0x00,
    0x97, 0x08,
    0x97, 0x19,
    0x97, 0x02,
    0x97, 0x0c,
    0x97, 0x24,
    0x97, 0x30,
    0x97, 0x28,
    0x97, 0x26,
    0x97, 0x02,
    0x97, 0x98,
    0x97, 0x80,
    0x97, 0x00,
    0x97, 0x00,
    //
    0xc3, 0xed,
    0xa4, 0x00,
    0xa8, 0x00,
    0xc5, 0x11,
    0xc6, 0x51,
    0xbf, 0x80,
    0xc7, 0x10,
    0xb6, 0x66,
    0xb8, 0xA5,
    0xb7, 0x64,
    0xb9, 0x7C,
    0xb3, 0xaf,
    0xb4, 0x97,
    0xb5, 0xFF,
    0xb0, 0xC5,
    0xb1, 0x94,
    0xb2, 0x0f,
    0xc4, 0x5c,
    //根据分辨率不同而设置
    0xc0, 0x64,
    0xc1, 0x4B,
    0x8c, 0x00,
    0x86, 0x3D,
    0x50, 0x00,
    0x51, 0xC8,
    0x52, 0x96,
    0x53, 0x00,
    0x54, 0x00,
    0x55, 0x00,
    0x5a, 0xC8,
    0x5b, 0x96,
    0x5c, 0x00,
    
    0xd3, 0x02,//auto设置要小心
    //
    0xc3, 0xed,
    0x7f, 0x00,
    
    0xda, 0x09,
    
    0xe5, 0x1f,
    0xe1, 0x67,
    0xe0, 0x00,
    0xdd, 0x7f,
    0x05, 0x00,
};   
static const u8 ov2640_jpeg_reg_tbl[][2]=
{
    0xff, 0x01, 
    0xe0, 0x14,
    0xe1, 0x77,
    0xe5, 0x1f,
    0xd7, 0x03,
    0xda, 0x10,
    0xe0, 0x00, 
};

static const u8 ov2640_yuv422_reg_tbl[][2]= 
{
    0xFF, 0x00, 
    0xDA, 0x10,
    0xD7, 0x03,
    0xDF, 0x00,
    0x33, 0x80,
    0x3C, 0x40,
    0xe1, 0x77,
    0x00, 0x00,
};

#endif












base64.c文件

#include "base64.h"

//unsigned char counts[4*4096];  
//u16 count=0;
unsigned char *base64_encode( const char  *str) // const char *str
{  
    long len;  
    long str_len;  
    unsigned char *res;  
    int i,j;  
//定义base64编码表  
     char *base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";  
  
//计算经过base64编码后的字符串长度  
    str_len=strlen(str);  
    if(str_len % 3 == 0)  
        len=str_len/3*4;  
    else  
        len=(str_len/3+1)*4;  
  
    res=malloc(sizeof(unsigned char)*len+1);  
    res[len]='\0';  
  
//以3个8位字符为一组进行编码  
    for(i=0,j=0;i<len-2;j+=3,i+=4)  
    {  
        res[i]=base64_table[str[j]>>2]; //取出第一个字符的前6位并找出对应的结果字符  
        res[i+1]=base64_table[(str[j]&0x3)<<4 | (str[j+1]>>4)]; //将第一个字符的后位与第二个字符的前4位进行组合并找到对应的结果字符  
        res[i+2]=base64_table[(str[j+1]&0xf)<<2 | (str[j+2]>>6)]; //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符  
        res[i+3]=base64_table[str[j+2]&0x3f]; //取出第三个字符的后6位并找出结果字符  
    }  
  
//    switch(str_len % 3)  
//    {  
//        case 1:  
//            res[i-2]='=';  
//            res[i-1]='=';  
//            break;  
//        case 2:  
//            res[i-1]='=';  
//            break;  
//    }  
  
    return res;  
}



int base64( u8 a,u8 b,u8 c)
{
    char *base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
      unsigned char *res;
//printf("\r\n%x",a);
//printf("%x",b);
//printf("%x     ",c);    
    res[0]=base64_table[a>>2]; //取出第一个字符的前6位并找出对应的结果字符  
    
        res[1]=base64_table[(a&0x3)<<4 | (b>>4)]; //将第一个字符的后位与第二个字符的前4位进行组合并找到对应的结果字符  
        res[2]=base64_table[(b&0xf)<<2 | (c>>6)]; //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符  
        res[3]=base64_table[c&0x3f]; //取出第三个字符的后6位并找出结果字符 
//        res[4]='\0';
    //strcat(counts,res);
        printf("%s",res);
    //count=count+4;
        return 1;
}

//void OutPut(void){ 
  printf("%s",counts);
    printf("\r\n%d",count);
//  count = 0;
//}








base64.h文件

#ifndef __BASE64_H_
#define __BASE64_H_


/********************头文件************************/
#include "stm32f4xx.h"
#include "stdio.h"
#include "string.h"
#include <stdlib.h>
/********************宏定义************************/

/*****************声明外部变量*********************/

/*******************函数声明***********************/
unsigned char *base64_encode( const char  *str);//const char
int base64( u8 a,u8 b,u8 c);
void OutPut(void);
#endif

uart_2.c文件

#include "uart_2.h"

/*********************************************
*函数功能:UART1初始化
*函数形参:uint32_t band 波特率
*函数返回值:None
*备注:PA2     --   RX
      PA3   --   TX
*********************************************/
void Uart2_Init(uint32_t band)
{
    //开启GPIOA时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    //开启UART1时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    
    //配置GPIO
    //PA2和PA3为复用模式
    GPIO_InitTypeDef  GPIO_InitStruct;
    //输出模式
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    //引脚号
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2); 
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    //配置UART1
    USART_InitTypeDef USART_InitStruct;
    //波特率
    USART_InitStruct.USART_BaudRate = band;
    //禁止硬件流控
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    //使能发送和接收
    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    //关闭奇偶校验
    USART_InitStruct.USART_Parity = USART_Parity_No;
    //1位停止位
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    //8位数据位
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_Init(USART2, &USART_InitStruct);
    
    //使能接收中断
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
    USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
    //设置中断优先级    串口优先级设置为最高,以防接收中被打断
    NVIC_SetPriority(USART2_IRQn, NVIC_EncodePriority(7-2, 0, 0));
    //使能NVIC响应
    NVIC_EnableIRQ(USART2_IRQn);
    
    //使能UART1
    USART_Cmd(USART2, ENABLE);
}

uint8_t rev_buf_2[REV_BUF_LEN];
uint8_t rev_ok_2;

//编写中断服务函数
void USART2_IRQHandler(void)
{
    static uint8_t i = 0;
    
    //读数据寄存器非空
    if(USART2->SR & (0x1 << 5)){
        rev_buf_2[i++] = USART2->DR;//读取数据寄存器信息,清空标志位
        while(USART2->SR & (0x1 << 5));//等待标志位清零
    }else if(USART2->SR & (0x1 << 4)){//检测到总线空闲
        //清标志位
        if(USART2->SR) 
            ;
        if(USART2->DR)
            ;
        while(USART2->SR & (0x1 << 4));//等待标志位清零
        rev_buf_2[i] = '\0';//字符串结尾
        i = 0;
        rev_ok_2 = 1;//接收完成
    }
}

/*********************************************
*函数功能:UART2发送字符串函数
*函数形参:uint8_t *str 要发送的字符串
*函数返回值:None
*备注:None
*********************************************/
void Uart2_Send_String(uint8_t *str)
{
    while(*str){
        //等待发送数据寄存器为空
        while(!USART_GetFlagStatus(USART2, USART_FLAG_TXE));
        USART_SendData(USART2, *str); 
        str++;
    }
}












uart_2.h文件

#ifndef __UART_2_H_
#define __UART_2_H_


/********************头文件************************/
#include "stm32f4xx.h"
#include "stdio.h"

/********************宏定义************************/
#define REV_BUF_LEN        (256)

/*****************声明外部变量*********************/
extern uint8_t rev_buf_2[REV_BUF_LEN];
extern uint8_t rev_ok_2;

/*******************函数声明***********************/
void Uart2_Init(uint32_t band);
void Uart2_Send_String(uint8_t *str);

#endif

二、STM32与ESP8266

当ESP8266向stm32发送数据“picture”并且stm32接收到时stm32会控制ov2640拍得jpeg格式的图片。当stm32取得二进制数据时会进行base64编码,当编码后会对数据进行分段(4段防止过长使得数据丢失)。此时esp8266会等待接收数据,一共会检测四次并接收四次。

arduino

#include <ESP8266WiFi.h>
String buffers;//用于存放接收到的数据
  int b=0;//串口接收
  int a=0;//用来判断物体的种类
  char* output;//用来存放服务器响应数据

  #define SSID              "12345678"//改为你自己的WiFi名称
  #define PASSWORD          "1qaz1qaz"//改为你自己的密码
  #define ACCESS_TOKEN      "24.70cf22c4e99c1228ff5d3cd1cca80766.2592000.1657886015."//改为你自己的access_token教程见下文
  #define Json_begin        "{\"image\": \""
  #define Json_end          "\",\"threshold\": 0.1}"//此处0.1为置信度可以改0~1之间

//串口接收函数
int uart(){ 
  while(Serial.available()>0){ 
    if(Serial.available()>0){buffers=Serial.readString();b++;}
  }
}
//采用https方法访问百度服务器
static void Baidu_AI(){ 
    //判断接收到信息的数据长度
    uint32_t len =  buffers.length();
    Serial.print(len);
    WiFiClientSecure client;
    client.setInsecure();
    delay(1000);
    if(client.connect("aip.baidubce.com",443)){
        Serial.println("Connection succeeded");
        //注意下面代码中的空格很重要  此处的***********************也要换为自己的详见下文
        client.println("POST ***********************?access_token=" + String(ACCESS_TOKEN)  + " HTTP/1.1");
        client.println(F("Host: aip.baidubce.com"));
        client.println("Content-Length: " + String(len + strlen(Json_begin Json_end)));
        client.println(F("Content-Type: application/json"));
        client.println();
        client.print(F(Json_begin));
        client.print(buffers);
        client.print(F(Json_end));
        //Serial.println("Waiting for response...");
        uint8_t i_i = 0;
        while (!client.available()){
            i_i += 1;
            delay(100);
            if(i_i > 200){ //超时
                Serial.println("No response...");
                break;
            }
        }
        String body;//响应体
        while (client.available()){ 
          body= client.readString();
          //Serial.print(body);
          output= const_cast<char*>(body.c_str());
          Serial.print(output);//串口输出服务器响应结果
            //Serial.print(char(client.read()));  
        }
        client.stop();
        //Serial.println();
        }else Serial.println("Connection failed");
}

void setup() { 
  //初始化串口
  Serial.begin(115200);
  //连接WIFI
  WiFi.begin(SSID,PASSWORD);
  while (WiFi.status() != WL_CONNECTED){ 
    //Serial.println("Waitting for wifi connection...");
    delay(500);
  }
  Serial.println("wifi已近连接");
}



void loop() {
  while(Serial.available()>0){ //是否串口有输入
    if((Serial.read()=='o')&&b==0){ 判断串口接收是否为"o"
      String buffers_s;//整合分段接收的数据
      while(1){ 
        uart();
      if(b==1){ 
        Serial.println(buffers);
         output=const_cast<char*>(buffers.c_str());
         if(output[1]=='9'&&output[2]=='j'){ //用于判断接收到的数据是否为"/9j"开头,用于精确定位开头
        buffers_s=buffers_s+buffers;
        b=2;}
        else {b=0;}
        //Serial.println(buffers);
       }
     else if(b==3){ 
       buffers_s=buffers_s+buffers;
       //delay(100);
       b=4;
       //Serial.println(buffers);
       }
       else if(b==5){ 
       buffers_s=buffers_s+buffers;
       //delay(100);
       b=6;
       //Serial.println(buffers);
       }
       else if(b==7){ 
       buffers_s=buffers_s+buffers;
       b=0;
       break;
       }
       //Serial.println(b);
    }
    buffers=buffers_s;
    Serial.println();
    Serial.println();
    Serial.println(buffers);
    Baidu_AI();
    }
}
}

上边的代码中最重要的就是需要更换一些信息。有WiFi名称,WiFi密码,你自己专属的access_token码,此码有效期为一个月,过时需要更换,还有就是需要更换访问链接就是代码中的*******************要被更换掉。

三、ESP8266与EasyDL

此时主要是需要在EASYDL平台部署模型,这里就不详细进行简绍了,可以直接找官方的教程有文档形式的有视频教学过程,这里写一下重要的过程。首先获取access_token的过程是

首先当你部署好模型并且发布以后找到在线服务点击控制台进去以后应是

点击公有云部署中的应用列表如下

此时可以找到API Key与Secret Key要注意的是复制Secret Key时要注意空格

将你上边的API Key与Secret Key替换下边的这个链接里的就行,然后将替换以后的链接在浏览器上打开就行,这时你可以找到access_token码注意是“”里边的

https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=API Key&client_secret=Secret Key

此时回到easydl平台的在线服务点击服务详情会看到接口地址https://aip.baidubce.com/rpc/2.0/ai_custom/v1/detection/xiadoz像这样一样,你们的和我的后半部分不太一样,这是因为模型的名字不一样。至此arduino中的代码只差访问链接也就是代码中的*******************需要被接口地址中的红色部分替换。

至此所有的操作就完成了,代码方面也就这些东西,对于easydl方面官方都有。对于接线方面有些记不清楚了。(其实也不多)对于摄像头有专门的排线,对于esp8266与stm32就只有串口通讯而已,如果没记错的话应该是串口二,代码中应该有注释。希望大家可以仔细看一遍,看一遍也是一种学习的过程,直接ctrl c ctrl v是对自己的不负责任。关于其他方面的功能欢迎大家开发,开发好以后放在评论区,大家共同进步。既然你点进这篇文章,我希望它对你有帮助。

感谢你的阅读,若有问题欢迎雅正。

物联沃分享整理
物联沃-IOTWORD物联网 » 使用STM32F407ZGT6控制ESP8266和OV2640进行百度智能图片识别

发表评论