STM32F407ZGT6控制ESP8266与OV2640下的百度智能图片识别

2023-05-16

前言: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是对自己的不负责任。关于其他方面的功能欢迎大家开发,开发好以后放在评论区,大家共同进步。既然你点进这篇文章,我希望它对你有帮助。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32F407ZGT6控制ESP8266与OV2640下的百度智能图片识别 的相关文章

  • 【STM32+ESP-12S连接腾讯云物联网开发平台 1】云平台的创建和AT固件烧录

    腾讯云物联网开发平台创建和ESP 12S的固件烧录 前言 一 腾讯云物联网开发平台的创建 1 创建产品 2 配置产品和创建设备 3 设备三元组说明 二 ESP 12S固件烧录 1 固件获取 2 固件烧录 三 连接测试 1 连接WiFi 2
  • ESP8266 使用TCP通信协议

    TCP服务器示例 include
  • 借助EspExceptionDecoder工具分析定位esp8266或esp32异常问题

    借助EspExceptionDecoder工具分析定位esp8266或esp32异常问题 文章目录 借助EspExceptionDecoder工具分析定位esp8266或esp32异常问题 问题出现Exception stack EspEx
  • 一、利用AT指令配置esp8266——esp8266WIFI模块初探&STM32串口通信再探

    文章目录 一 esp8266初探 1 esp8266简介 2 esp8266使用方式 什么是AT指令 通过何种方式发送AT指令 二 STM32串口通信再探 1 printf 函数与串口中断函数 2 例子 小试牛刀 3 例子 再进一步 三 局
  • ESP8266与网络服务器实时通讯

    目前 所有已呈现的通信都是基于请求响应方法的 其中一个实体正在发送请求 另一实体正在发送回响应 但是在某些情况下 您需要ESP8266模块与服务器之间的实时通信 而不仅仅是事务 实时通讯协议 ESP8266流数据 要从ESP8266流传输数
  • 【esp8266】史上最详细的Arduino uno R3接入机智云教程

    原文地址 http club gizwits com thread 6728 1 1 html 本文使用arduino UNO板卡和esp8266无线WIFI模块实现了通过手机APP远程监测单片机系统采集的数据和控制一个LED的亮灭 读者将
  • 【转载】ESP8266 基ESP8266_RTOS_SDK (ESP-IDF )中嵌入网页文件

    场景 在写ESP8266 web服务的时候 免不了要将自己设计的网页html和css等文件放入到固件中 在arduino中有fs可以进行上传文件 然后通过文件系统读出 那在ESP IDF中该怎么办呢 有几个思路 通过flash downlo
  • esp8266-01s介绍与使用

    esp826601s 是个比较常用的wifi模块 体积小 功能强大 说是可以用于工业 下面介绍esp826601s 可用引脚 以及可用功能 esp 01 ESP 01S 在ESP 01的基础上 优化了PCB天线 进行了一小步的升级 带来了一
  • ESP8266EX使用SDK开发串口调试乱码

    目录 问题如图所示 问题分析 问题解决 问题如图所示 问题分析 有输出信号 说明有数据产生 可能原因 波特率不匹配 时钟频率不对 问题解决 不断调整串口调试助手的波特率9600 115200 不管用 把ESP8266的默认波特率改为9600
  • 构建配置ESP8266 MQTT服务器

    我们将了解ESP8266模块如何通过消息队列遥测传输 MQTT 相互通信 MQTT术语 已经使用了诸如中央代理 主题 发布 订阅之类的术语 因此现在该用类似于邮局的方式来解释它们了 消息是报纸或杂志 代理 这是一个接收客户端消息的软件应用程
  • ESP8266 hspi的调试

    这一两个礼拜基本上都在爬这个坑 功夫不负有心人 终于搞定了 其实非常简单 以为这个东西有多么的复杂 其实不是这样的 被一些网上博主给误导了 8266端我用的是 ESP8266 NONOS SDK 3 0 examples periphera
  • esp8266学习笔记(5)——连接wifi、AP、UDP通信

    终于开始接触网络了 基础不行 这个摸索了有点久 还好网上资料多 有些细节还是没有怎么吃透 哈哈 开始联网了 ESP8266有三种模式 station模式 0x01 soft AP模式 0x02 soft AP station模式 0x03
  • ESP8266恒温控制器

    本文 我们将使用ESP8266构建家用恒温器 温控器将具有以下功能 它将从DHT22温度传感器读取温度 它将温度与所需温度进行比较 如果高于它 它将触发继电器关闭 如果低于它 它将触发继电器打开 在此之前 首先了解下ESP8266如何保持温
  • ESP8266基础开发(一)---读DHT11温湿度传感器

    注 对于ESP8266开源技术感兴趣的可以加群 我们一起探索交流学习 群号 579932824 群名 ESP8266开源技术交流群 这篇文章的目的是展示如何将DHT11传感器连接到ESP8266并编写一个简单的程序来测量温度和湿度 我们假设
  • 玩转ESP8266-01——AT指令集

    该指令集是接上一个 链接 初识AT指令 全部是根据本人在使用esp8266过程中用过的指令 可能有不全 有错误 还请理解指正 一起学习 AT指令集 一 基础指令 1 测试指令 2 复位指令 重启 二 设置指令 1 设置波特率 2 设置工作模
  • 基于ESP8266的CMSIS-DAP调试器

    前言 前段时间用8266制作了一个STM32的下载器 可以进行远程下载固件 不过我们用STM32的时候 经常需要进行各种调试 这时候一个调试器就很重要了 于是我想到也许可以做一个无线调试器 本来我打算自己写一个的 不过在github发现居然
  • 制作OLED图标

    制作OLED图标 陈拓 2021 06 24 2021 06 26 1 概述 制作用于OLED显示的图标 获取C语言图像点阵数据 2 图标库 先准备图标图像 可以从图标库中找需要的图案 下面两个是我常用的图标网站 2 1 Font Awes
  • 如何使用新的 SDK (NodeMCU) 发送多个数据 (conn:send())

    我一直在阅读 NodeMCU 文档和几个有关 SDK 更改的已解决问题 这些 SDK 以前允许发送多个数据流 就像排队的 net socket send 一样 这里似乎引发了一场巨大的争论 730 和那里 993 或者甚至在这里 999 然
  • ESP8266 烧录 (关于BearPi扩展Wifi模块的烧录方式)

    简介 ESP 12F 模块是BearPI IOT购买的一个套餐所带的扩展模块 用来接通网络 但是默认电路不支持重新烧录 下面就是可支持重新烧录的方式 ESP 12F 电路原理图 如上图 GPIO15 gt GND gt 高电平 GPIO2
  • ESP8266 烧录 (关于BearPi扩展Wifi模块的烧录方式)

    简介 ESP 12F 模块是BearPI IOT购买的一个套餐所带的扩展模块 用来接通网络 但是默认电路不支持重新烧录 下面就是可支持重新烧录的方式 ESP 12F 电路原理图 如上图 GPIO15 gt GND gt 高电平 GPIO2

随机推荐

  • 全景图拼接

    目录 一 图像拼接基本流程 二 RANSAC 随机一致性采样 2 1 RANSAC基本思想 xff1a 数据中包含正确的点和噪声点 xff0c 合理的模型应该能够在描述正确数据点的同时摒弃噪声点 2 2 RANSAC基本流程 xff1a 2
  • 11. JS操作节点续(2) + DOM 重点核心

    关于dom操作 xff0c 我们主要针对于元素的操作 主要有创建 增 删 改 查 属性操作 事件操作 DOM xff1a 我们获取过来的DOM元素是一个对象 xff08 object xff09 xff0c 所以称为 文档对象模型 创建 d
  • Docker-使用篇

    文章目录 一 Docker镜像和容器 镜像命令镜像下载 xff08 pull xff09 查看镜像 xff08 images xff09 镜像搜索 xff08 search xff09 删除镜像 xff08 rmi xff09 容器命令新建
  • Rviz上发布的点位信息机器人不执行(网络配置原因)已解决

    在调试机器人时发现Rviz上发布的点位信息机器人没有执行 xff0c 经检查是由于网络配置原因 xff0c 本文记录解决方法 使用ssh将笔记本与实物机器人连接 xff0c 机器人中控使用的工控机 xff0c 机器人作为显示器和键盘输入 p
  • gazebo小车自主路径规划导航仿真

    gazebo小车自主路径规划仿真 在之前的文章中完成了对地图的构建 xff0c 接下来使用 Ros navgition完成机器人自主导航 首先是Ros navigation的下载安装 ros功能包 xff1a Navigation ros
  • 关于结构体对齐

    首先我们先了解一下各数据类型所占的字节数 x64系统 xff08 64位 xff09 x86系统 xff08 32位 xff09 在这里有一个很有意思的点 xff0c 我使用VS在x86与x64系统下运行出来的long类型所占据的空间都是4
  • 安装docker报出的错误及解决方案

    1 错误一 xff1a 解决方案 xff1a yum erase podman buildan yum install y docker ce allowerasing 重启服务 systemtl restart docker yum源的安
  • make、makefile的使用解释(Linux项目自动化构建工具)

    本文所使用系统为Linux centos 7 makefile是一个文件 里面包含了 xff1a 1 文件与文件的依赖关系 2 文件与文件的依赖方法 为什么需要包含文件与文件的依赖方法和依赖方法呢 xff1f 一个工程中的源文件不计数 xf
  • elementUI中neditor第一次加载无法正常赋值的解决方法

    1 lt neditor v if 61 34 neditorLoad 34 v model 61 34 formFields content 34 class 61 34 wd editor 34 gt 加上v if 61 34 nedi
  • Gazebo仿真中光源的设置

    目录 写在前面官方文档链接point类型directional类型spot类型 写在前面 最近研究在Gazebo中仿真px4 xff0c 使用Apriltag ros包对Apriltag二维码检测的时候发现光源对检测影响非常大 xff0c
  • 使用Java操作Hbase

    目录 修改hosts文件 导入jar包 配置hbase信息 xff0c 连接hbase数据库 创建表 删除表 获取namespace 获取tables 添加数据 查询表中的数据 查询表中所有数据 关闭流 修改hosts文件 位置 xff1a
  • CAN协议国际标准化协议部分总结(一)

    前言 xff1a 本文主要是对CAN协议中ISO11898做一个简短的总结 ISO11898 ISO11519 ISO15765 CAN协议在OSI模型中包含三层 xff0c 物理层 数据链路层和传输层 各层中CAN定义内容可参考下图 其协
  • STM32 串口 DMA 数据读取(详细代码)

    最近重新开始学32 xff0c 搞到串口 DMA 的时候 xff0c 数据读取卡了很长一段时间 xff0c 最终 xff0c 功夫不负有心人终于搞出来了 在此以记录一下 xff0c 方便以后查询使用 在调试的过程中也遇到了很多bug xff
  • 在阿里云购买Linux服务器,配置宝塔环境,全图文,最最详细图解,保姆级教学

    在阿里云购买Linux服务器 xff08 CentOs 7 xff09 xff0c 配置宝塔环境 一 在阿里云购买CentOs服务器 Linux系统 CentOS是免费的 开源的 可以重新分发的开源操作系统 xff0c CentOS xff
  • (Linux)FreeRTOS(任务)

    任务调度器 调度器就是使用相关的调度算法来决定当前需要执行的任务 xff0c 调度器总是在所有处于就绪列表的任务中 xff0c 选择具有最高优先级的任务来执行 抢占式调度 xff1a 主要是针对优先级不同的任务 xff0c 每个任务都有一个
  • 制作一个串口助手 | python + pyqt5

    目录 一 背景 1 1 开发流程图 二 前提 2 1 关于环境 2 2 关于源码 三 步骤 3 1 使用pyqt创建一个 ui界面并生成 py文件 3 2 创建两个 py文件 xff0c 一个用来继承ui界面生成的 py类 xff0c 一个
  • FreeRTOS任务调度与任务切换 | FreeRTOS八

    目录 说明 xff1a 一 任务调度器 1 1 开启任务调度器函数 1 2 任务调度器实现步骤 1 3 xPortStartScheduler 函数 二 启动一个任务 2 1 prvStartFirstTask 函数 2 2 vPortSV
  • 单片机原理简介

    提出问题 xff1a 什么是单片机 xff1f 类似于一台性能相对较弱的微型电脑 xff0c 具有完整的计算机结构和片内外设 xff08 例如串口 xff0c I2C xff0c ADC等硬件 xff09 xff0c 将他们集成封装在一颗芯
  • composer安装第三方库

    用法 xff1a 在thinkphp根目录下执行 composer require wechatpay wechatpay 1 4
  • STM32F407ZGT6控制ESP8266与OV2640下的百度智能图片识别

    前言 xff1a STM32F407ZGT6控制OV2640下采集到JPG图片格式的二进制数据 xff0c 然后对二进制数据进行BASE64编码 xff0c 接着通过串口将数据传输给ESP8266并上传至训练好的EASYDL的AI算法识别平