当前位置: 首页 > news >正文

OV7670连接STM32F407VET

目录

常见问题

delay.c

delay.h

sys.c

sys.h

usart.c

usart.h

ov7670.c

ov7670.h

main.c

本地接收脚本


Github源码仓:ceilf6/SmartFruits · GitHub

我们老师让我们别用 HAL 库写,于是我们用的是官方库

常见问题

无法进行烧录:

        1.串口被占用:关闭其他占用串口的软件,然后拔掉串口重新插入

        2.烧录时波特率不对,一般都是115200

        3.先拔掉接到单片机上的外设,因为外设的接收输出串口会对烧录代码有影响

delay.c

#include "delay.h"static u8  fac_us=0;//us��ʱ������
static u16 fac_ms=0;//ms��ʱ������
//��ʼ���ӳٺ���
//SYSTICK��ʱ�ӹ̶�ΪHCLKʱ�ӵ�1/8
//SYSCLK:ϵͳʱ��
void delay_init(u8 SYSCLK)
{SysTick->CTRL&=0xfffffffb;//bit2���,ѡ���ⲿʱ��  HCLK/8fac_us=SYSCLK/8;		    fac_ms=(u16)fac_us*1000;
}								    
//��ʱnms
//ע��nms�ķ�Χ
//SysTick->LOADΪ24λ�Ĵ���,����,�����ʱΪ:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK��λΪHz,nms��λΪms
//��72M������,nms<=1864 
void delay_ms(u16 nms)
{	 		  	  u32 temp;		   SysTick->LOAD=(u32)nms*fac_ms;//ʱ�����(SysTick->LOADΪ24bit)SysTick->VAL =0x00;           //��ռ�����SysTick->CTRL=0x01 ;          //��ʼ����  do{temp=SysTick->CTRL;}while(temp&0x01&&!(temp&(1<<16)));//�ȴ�ʱ�䵽��   SysTick->CTRL=0x00;       //�رռ�����SysTick->VAL =0X00;       //��ռ�����	  	    
}   
//��ʱnus
//nusΪҪ��ʱ��us��.		    								   
void delay_us(u32 nus)
{		u32 temp;	    	 SysTick->LOAD=nus*fac_us; //ʱ�����	  		 SysTick->VAL=0x00;        //��ռ�����SysTick->CTRL=0x01 ;      //��ʼ���� 	 do{temp=SysTick->CTRL;}while(temp&0x01&&!(temp&(1<<16)));//�ȴ�ʱ�䵽��   SysTick->CTRL=0x00;       //�رռ�����SysTick->VAL =0X00;       //��ռ�����	 
}

delay.h

#ifndef __DELAY_H
#define __DELAY_H 			   
#include <sys.h>	  void delay_init(u8 SYSCLK);
void delay_ms(u16 nms);
void delay_us(u32 nus);#endif

sys.c

#include "sys.h"  //THUMBָ�֧�ֻ������
//�������·���ʵ��ִ�л��ָ��WFI  
//__asm void WFI_SET(void)
//{
//	WFI;		  
//}
�ر������ж�(���Dz�����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
//}
void NVIC_Configuration()
{NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_InitStructure);
}

sys.h

#ifndef __SYS_H
#define __SYS_H	 
#include "stm32f4xx.h" 
#include "delay.h"
#include "usart.h"	//λ������,ʵ��51���Ƶ�GPIO���ƹ���#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);	//���ö�ջ��ַ void NVIC_Configuration(void);
#endif

usart.c

#include "sys.h"
#include "usart.h"	
#include "stm32f4xx.h"//
// 支持printf函数重定向
#if 1
#pragma import(__use_no_semihosting)             
// 标准库需要支持的函数                 
struct __FILE 
{ int handle; 
}; FILE __stdout;       
// 定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ x = x; 
} 
// 重定义fputc函数 
int fputc(int ch, FILE *f)
{ 	while((USART1->SR&0X40)==0); // 循环发送,直到发送完成   USART1->DR = (u8) ch;      return ch;
}
#endifu8 USART_RX_BUF[USART_REC_LEN];     // 接收缓冲,最大USART_REC_LEN个字节.// 初始化IO 串口1 
// bound: 波特率
void uart_init(u32 bound){// GPIO端口设置GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); // 使能GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); // 使能USART1时钟// 串口1对应引脚复用映射GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); // GPIOA9复用为USART1GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); // GPIOA10复用为USART1// USART1端口配置GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; // GPIOA9与GPIOA10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // 复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; // 速度提高到100MHzGPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 推挽复用输出GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 上拉GPIO_Init(GPIOA,&GPIO_InitStructure); // 初始化PA9,PA10// USART1 初始化设置USART_InitStructure.USART_BaudRate = bound; // 波特率设置USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1; // 一个停止位USART_InitStructure.USART_Parity = USART_Parity_No; // 无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 收发模式USART_Init(USART1, &USART_InitStructure); // 初始化串口1// 配置USART1 DMA发送和接收// 启用DMA时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);// 配置DMA用于USART传输(可选,如果您想进一步提高传输效率)// 此处省略DMA配置,如需使用请添加相应代码NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置系统中断优先级分组2// Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // 串口1中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级提高到1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 子优先级0NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能NVIC_Init(&NVIC_InitStructure); // 根据指定的参数初始化VIC寄存器USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 开启相关中断USART_Cmd(USART1, ENABLE);  // 使能串口1// 使能发送和接收USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);USART_ITConfig(USART1, USART_IT_TXE, DISABLE); // 发送中断先禁用,需要时再开启
}void USART1_IRQHandler(void)                	// 串口1中断服务程序
{if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){// 接收中断处理uint8_t data = USART_ReceiveData(USART1);// 清除中断标志USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}

usart.h

#ifndef __USART_H
#define __USART_H
#include "stdio.h"	
#include "stm32f4xx_conf.h"
#include "sys.h" //USART_REC_LEN,���ڶ��崮������������յ��ֽ���(������2��14�η�)
//EN_USART1_RX��ʹ�ܷ�ʽ
// 	
#define USART_REC_LEN  			200  	//�����������ֽ��� 200extern u8  USART_RX_BUF[USART_REC_LEN]; //���ջ���,���USART_REC_LEN���ֽ�.ĩ�ֽ�Ϊ���з� void uart_init(u32 bound);
#endif

ov7670.c

#include "sys.h"
#include "ov7670.h"
#include "ov7670cfg.h"
#include "timer.h"	  
#include "delay.h"
#include "usart.h"			 
#include "sccb.h"	
#include "exti.h"
#include "stm32f4xx.h"
u8 OV7670_Init(void)
{u8 temp;u16 i=0;      //??IOGPIO_InitTypeDef  GPIO_InitStructure;// ??GPIO??RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB, ENABLE);// PC9-HREF???(????)GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;       // ??PA8GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;    // ????GPIO_Init(GPIOC, &GPIO_InitStructure);// PA9 - VSY ?? ??GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);// PB12 - WR ????GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_12);// PA10 - RCK ????GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA,GPIO_Pin_11);    // PA0~7 ?? ??GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;GPIO_Init(GPIOA, &GPIO_InitStructure);// PA14 - OE ????GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_14;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA,GPIO_Pin_15);// PB0 - RRST, PB1 - WRST ????GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0|GPIO_Pin_1;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_1);// ?F4???,SWD??????,???????SCCB_Init();                //???SCCB?IO?          if(SCCB_WR_Reg(0x12,0x80))return 1;    //??SCCB      delay_ms(50);  //??????temp=SCCB_RD_Reg(0x0b);  if(temp!=0x73)return 2;  temp=SCCB_RD_Reg(0x0a);  if(temp!=0x76)return 2;//?????      for(i=0;i<sizeof(ov7670_init_reg_tbl)/sizeof(ov7670_init_reg_tbl[0]);i++){SCCB_WR_Reg(ov7670_init_reg_tbl[i][0],ov7670_init_reg_tbl[i][1]);}return 0x00;     //ok
}void OV7670_Light_Mode(u8 mode)
{u8 reg13val=0xE7;  //????????????u8 reg01val=0;u8 reg02val=0;switch(mode){case 1:  //sunnyreg13val=0xE5;reg01val=0x5A;reg02val=0x5C;break;    case 2:  //cloudyreg13val=0xE5;reg01val=0x58;reg02val=0x60;break;    case 3:  //officereg13val=0xE5;reg01val=0x84;reg02val=0x4C;break;    case 4:  //homereg13val=0xE5;reg01val=0x96;reg02val=0x40;break;    }SCCB_WR_Reg(0x13, reg13val);  //COM8?? SCCB_WR_Reg(0x01, reg01val);  //AWB?????? SCCB_WR_Reg(0x02, reg02val);  //AWB?????? 
}//????
//0:-2
//1:-1
//2,0
//3,1
//4,2void OV7670_Color_Saturation(u8 sat)
{u8 reg4f5054val = 0x80;  //????sat=2,?????????u8 reg52val = 0x22;u8 reg53val = 0x5E;switch(sat){case 0:  //-2reg4f5054val = 0x40;     reg52val = 0x11;reg53val = 0x2F;     break;case 1:  //-1reg4f5054val = 0x66;    reg52val = 0x1B;reg53val = 0x4B;  break;case 3:  //1reg4f5054val = 0x99;   reg52val = 0x28;reg53val = 0x71;   break;case 4:  //2reg4f5054val = 0xC0;   reg52val = 0x33;reg53val = 0x8D;   break;}// ??OV7670?????SCCB_WR_Reg(0x4F, reg4f5054val);  //??????1SCCB_WR_Reg(0x50, reg4f5054val);  //??????2SCCB_WR_Reg(0x51, 0x00);          //??????3SCCB_WR_Reg(0x52, reg52val);      //??????4SCCB_WR_Reg(0x53, reg53val);      //??????5SCCB_WR_Reg(0x54, reg4f5054val);  //??????6SCCB_WR_Reg(0x58, 0x9E);          //MTXS
}// ????
// 0:-2
// 1:-1
// 2,0
// 3,1
// 4,2
void OV7670_Brightness(u8 bright)
{u8 reg55val = 0x00;  // ??bright=2switch(bright){case 0:  // -2reg55val = 0xB0;break;case 1:  // -1reg55val = 0x98;break;case 3:  // 1reg55val = 0x18;break;case 4:  // 2reg55val = 0x30;break;}SCCB_WR_Reg(0x55, reg55val);  // ????
}// ?????
// 0:-2
// 1:-1
// 2,0
// 3,1
// 4,2
void OV7670_Contrast(u8 contrast)
{u8 reg56val = 0x40;  // ??contrast=2switch(contrast){case 0:  // -2reg56val = 0x30;break;case 1:  // -1reg56val = 0x38;break;case 3:  // 1reg56val = 0x50;break;case 4:  // 2reg56val = 0x60;break;}SCCB_WR_Reg(0x56, reg56val);  // ?????
}// ????
// 0:????
// 1:??
// 2:??
// 3:???
// 4:???
// 5:???
// 6:??
void OV7670_Special_Effects(u8 eft)
{u8 reg3aval = 0x04;  // ???????u8 reg67val = 0xC0;u8 reg68val = 0x80;switch(eft){case 1:  // ??reg3aval = 0x24;reg67val = 0x80;reg68val = 0x80;break;case 2:  // ??reg3aval = 0x14;reg67val = 0x80;reg68val = 0x80;break;case 3:  // ???reg3aval = 0x14;reg67val = 0xC0;reg68val = 0x80;break;case 4:  // ???reg3aval = 0x14;reg67val = 0x40;reg68val = 0x40;break;case 5:  // ???reg3aval = 0x14;reg67val = 0x80;reg68val = 0xC0;break;case 6:  // ??reg3aval = 0x14;reg67val = 0xA0;reg68val = 0x40;break;}SCCB_WR_Reg(0x3A, reg3aval);  // TSLB??SCCB_WR_Reg(0x68, reg67val);  // MANU,??U?SCCB_WR_Reg(0x67, reg68val);  // MANV,??V?
}// ????????
// ?QVGA??
void OV7670_Window_Set(u16 sx, u16 sy, u16 width, u16 height)
{u16 endx;u16 endy;u8 temp;endx = sx + width * 2;  // V*2endy = sy + height * 2;if(endy > 784) endy -= 784;temp = SCCB_RD_Reg(0x03);  // ??Vref????temp &= 0xF0;temp |= ((endx & 0x03) << 2) | (sx & 0x03);SCCB_WR_Reg(0x03, temp);   // ??Vref?start?end???2?SCCB_WR_Reg(0x19, sx >> 2);  // ??Vref?start?8?SCCB_WR_Reg(0x1A, endx >> 2); // ??Vref?end??8?temp = SCCB_RD_Reg(0x32);  // ??Href????temp &= 0xC0;temp |= ((endy & 0x07) << 3) | (sy & 0x07);SCCB_WR_Reg(0x17, sy >> 3);  // ??Href?start?8?SCCB_WR_Reg(0x18, endy >> 3); // ??Href?end??8?
}// ??????
void OV7670_Effects_Set(void)
{u8 lightmode = 0, effect = 0;s8 saturation = 4, brightness = 0, contrast = 0;OV7670_Light_Mode(lightmode);OV7670_Color_Saturation(saturation);OV7670_Brightness(brightness);OV7670_Contrast(contrast);OV7670_Special_Effects(effect);// OV7670_Window_Set(184,10,320,240); // ???? 320*240 ?x?OV7670_Window_Set(12, 176, 240, 320); // ????
}

ov7670.h

#ifndef _OV7670_H
#define _OV7670_H
#include "stm32f4xx.h"
#include "sys.h"
#include "sccb.h"#include <stdint.h>  // ???????????typedef uint8_t  u8;   // ???8???
typedef uint16_t u16;  // ???16???
typedef uint32_t u32;  // ???32???
//     
//????????guanfu_wang??
//ALIENTEK??STM32???V3
//OV7670 ????       
//????@ALIENTEK
//????:www.openedv.com
//????:2015/1/18
//??:V1.0                                          
//// ???????F407?????
#define OV7670_VSYNC    PAin(8)         //??????IO
#define OV7670_WRST     PBout(0)        //????? 
#define OV7670_WREN     PBout(12)       //??FIFO??// F4????BSRR?BRR??????F1??
#define OV7670_RCK_H    GPIOA->BSRRH=1<<11 //??????????
#define OV7670_RCK_L    GPIOA->BSRRL=1<<11  //??????????#define OV7670_RRST     PBout(1)        //?????
#define OV7670_CS       PAout(15)       //????(OE)// ??????????????
#define OV7670_DATA     (GPIOA->IDR & 0x00FF)  //??????// ????                                 
u8   OV7670_Init(void);                  
void OV7670_Light_Mode(u8 mode);
void OV7670_Color_Saturation(u8 sat);
void OV7670_Brightness(u8 bright);
void OV7670_Contrast(u8 contrast);
void OV7670_Special_Effects(u8 eft);
void OV7670_Window_Set(u16 sx, u16 sy, u16 width, u16 height);
void OV7670_Effects_Set(void);#endif

main.c

#include "stm32f4xx.h"
#include "delay.h"
#include "lcd.h"
#include "spi.h"
#include "test.h"
#include "GUI.h"
#include "ov7670.h"
#include "sccb.h"
#include "usart.h"
#include "timer.h"
#include "exti.h"
#include "stm32f4xx_gpio.h"extern u8 ov_sta;  // 在 exit.c 中定义
extern u8 ov_frame;  // 在 time.c 中定义// 更新LCD显示
void camera_refresh(void) {u32 j;u16 color;if (ov_sta) {  // 有新的一帧图像捕获成功LCD_direction(1);LCD_SetWindows(0, 0, 319, 239);OV7670_RRST = 0;  // 开始复位读指针OV7670_RCK_L;OV7670_RCK_H;OV7670_RCK_L;OV7670_RRST = 1;  // 复位读指针结束OV7670_RCK_H;for (j = 0; j < 76800; j++) {  // 读取数据OV7670_RCK_L;color = GPIOA->IDR & 0xFF;  // 读数据OV7670_RCK_H;color <<= 8;OV7670_RCK_L;color |= GPIOA->IDR & 0xFF;  // 读数据OV7670_RCK_H;Lcd_WriteData_16Bit(color);}EXTI_ClearITPendingBit(EXTI_Line8);  // 清除中断标志位ov_sta = 0;  // 开始下一次采集ov_frame++;}
}// 通过串口发送图像
void camera_refresh_1(void) {u32 j;u8 data1, data2;if (ov_sta) {  // 有新的一帧图像捕获成功OV7670_RRST = 0;  // 开始复位读指针OV7670_RCK_L;OV7670_RCK_H;OV7670_RCK_L;OV7670_RRST = 1;  // 复位读指针结束OV7670_RCK_H;printf("%c", 0x01);  // 帧起始标记printf("%c", 0xFE);for (j = 0; j < 76800; j++) {  // 读取数据OV7670_RCK_L;data1 = GPIOA->IDR & 0xFF;  // 读数据OV7670_RCK_H;OV7670_RCK_L;data2 = GPIOA->IDR & 0xFF;  // 读数据OV7670_RCK_H;// 使用printf可能会导致数据发送速度较慢,这里改用直接发送while(!(USART1->SR & USART_SR_TXE));USART1->DR = data1;while(!(USART1->SR & USART_SR_TXE));USART1->DR = data2;}printf("%c", 0xFE);  // 帧结束标记printf("%c", 0x01);EXTI_ClearITPendingBit(EXTI_Line8);  // 清除中断标志位ov_sta = 0;  // 开始下一次采集ov_frame++;}
}int main(void) {// 系统初始化SystemInit();  // 配置RCC,配置系统时钟为72MHzdelay_init(72);  // 延时初始化SPI2_Init();  // 配置SPI2接口类型LCD_Init();  // 初始化液晶屏// 配置串口,使用适中波特率以提高稳定性uart_init(460800);  // 使用460800波特率初始化串口// 初始化OV7670while (OV7670_Init()) {LCD_ShowString(100, 20, 16, "ERROR", 1);delay_ms(200);delay_ms(200);}LCD_ShowString(200, 200, 16, "ok", 1);delay_ms(1500);LCD_Clear(BLACK);EXTI8_Init();  // 使能帧中断OV7670_Effects_Set();  // 设置OV7670效果OV7670_CS = 0;  // 使能摄像头LCD_Clear(BLACK);// 主循环while (1) {// 通过串口传输图像数据到电脑端camera_refresh_1();  // 也可以在LCD上显示图像(可选)// camera_refresh();}
}

本地接收脚本

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
OV7670摄像头图像接收显示脚本
用于接收STM32通过串口发送的OV7670摄像头图像数据并显示
"""import serial
import numpy as np
import cv2
import time
import argparse
from threading import Thread# 图像参数 - OV7670默认为RGB565格式
IMG_WIDTH = 320
IMG_HEIGHT = 240class OV7670Viewer:def __init__(self, port, baudrate=921600):"""初始化OV7670图像查看器参数:port: 串口端口名baudrate: 波特率,默认为921600 (可根据实际STM32设置调整)"""self.port = portself.baudrate = baudrateself.ser = Noneself.running = Falseself.frame = np.zeros((IMG_HEIGHT, IMG_WIDTH, 3), dtype=np.uint8)self.new_frame = Falsedef connect(self):"""连接到串口设备"""try:self.ser = serial.Serial(port=self.port,baudrate=self.baudrate,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,timeout=1)print(f"已连接到 {self.port} (波特率: {self.baudrate})")return Trueexcept serial.SerialException as e:print(f"无法连接串口: {e}")return Falsedef close(self):"""关闭串口连接"""if self.ser and self.ser.is_open:self.ser.close()print("串口连接已关闭")def start_capture(self):"""开始捕获图像"""self.running = Trueself.capture_thread = Thread(target=self._capture_loop)self.capture_thread.daemon = Trueself.capture_thread.start()def stop_capture(self):"""停止捕获图像"""self.running = Falseif hasattr(self, 'capture_thread'):self.capture_thread.join(timeout=1.0)def _rgb565_to_rgb888(self, byte1, byte2):"""将RGB565格式转换为RGB888参数:byte1, byte2: RGB565的两个字节返回:(r, g, b): RGB888元组"""rgb = (byte1 << 8) | byte2r = (rgb & 0xF800) >> 8  # 取高5位作为红色g = (rgb & 0x07E0) >> 3  # 取中间6位作为绿色b = (rgb & 0x001F) << 3  # 取低5位作为蓝色return (r, g, b)def _capture_loop(self):"""捕获图像循环"""buffer = bytearray()frame_start_detected = Falseframe_end_detected = Falseframe_data = bytearray()while self.running:try:if self.ser.in_waiting:# 读取可用数据data = self.ser.read(self.ser.in_waiting)buffer.extend(data)# 查找帧开始标记 (0x01 0xFE)if not frame_start_detected:start_index = buffer.find(b'\x01\xFE')if start_index >= 0:buffer = buffer[start_index + 2:]  # 跳过开始标记frame_start_detected = Trueframe_data = bytearray()# 如果已经找到帧开始,查找帧结束标记 (0xFE 0x01)if frame_start_detected:end_index = buffer.find(b'\xFE\x01')if end_index >= 0:# 添加结束标记前的所有数据frame_data.extend(buffer[:end_index])# 处理完整帧self._process_frame(frame_data)# 重置为下一帧做准备buffer = buffer[end_index + 2:]  # 跳过结束标记frame_start_detected = Falseelse:# 还没找到帧结束标记,但已经有足够多的数据,可能是因为缓冲区中有部分帧if len(buffer) > IMG_WIDTH * IMG_HEIGHT * 2 + 100:  # 预留空间用于查找结束标记# 丢弃过多的数据,避免缓冲区过大buffer = buffer[-100:]frame_start_detected = Falseelif frame_start_detected:# 继续收集此帧的数据frame_data.extend(buffer)buffer = bytearray()time.sleep(0.001)  # 短暂休眠,避免CPU占用过高except Exception as e:print(f"捕获过程出错: {e}")time.sleep(0.5)  # 出错后暂停一下,避免连续报错def _process_frame(self, data):"""处理完整帧的数据参数:data: 图像数据字节数组"""try:# 检查数据是否足够if len(data) < IMG_WIDTH * IMG_HEIGHT * 2:print(f"帧数据不完整: {len(data)}/{IMG_WIDTH * IMG_HEIGHT * 2}")return# 创建新的图像帧new_frame = np.zeros((IMG_HEIGHT, IMG_WIDTH, 3), dtype=np.uint8)# 逐像素填充图像for y in range(IMG_HEIGHT):for x in range(IMG_WIDTH):idx = (y * IMG_WIDTH + x) * 2if idx + 1 < len(data):# 从RGB565格式转换为RGB888r, g, b = self._rgb565_to_rgb888(data[idx], data[idx+1])new_frame[y, x] = [b, g, r]  # OpenCV使用BGR顺序# 更新图像self.frame = new_frameself.new_frame = Trueexcept Exception as e:print(f"处理帧出错: {e}")def display(self):"""显示摄像头图像"""cv2.namedWindow("OV7670 Camera", cv2.WINDOW_NORMAL)try:last_time = time.time()frame_count = 0while True:if self.new_frame:cv2.imshow("OV7670 Camera", self.frame)self.new_frame = False# 计算帧率frame_count += 1current_time = time.time()if current_time - last_time >= 1.0:fps = frame_count / (current_time - last_time)print(f"FPS: {fps:.2f}")frame_count = 0last_time = current_timekey = cv2.waitKey(1) & 0xFFif key == ord('q') or key == 27:  # 'q' 或 ESC 键退出breakelif key == ord('s'):  # 's' 键保存图像timestamp = time.strftime("%Y%m%d_%H%M%S")filename = f"ov7670_image_{timestamp}.png"cv2.imwrite(filename, self.frame)print(f"图像保存为 {filename}")except KeyboardInterrupt:passfinally:cv2.destroyAllWindows()def main():parser = argparse.ArgumentParser(description='OV7670摄像头图像显示程序')parser.add_argument('-p', '--port', required=True, help='串口端口名')parser.add_argument('-b', '--baudrate', type=int, default=921600, help='波特率 (默认: 921600)')args = parser.parse_args()viewer = OV7670Viewer(port=args.port, baudrate=args.baudrate)if viewer.connect():viewer.start_capture()try:viewer.display()finally:viewer.stop_capture()viewer.close()if __name__ == "__main__":main()

相关文章:

  • Java迭代器知识点详解
  • 从编程助手到AI工程师:Trae插件Builder模式实战Excel合并工具开发
  • 在CentOS系统上部署GitLabRunner并配置CICD自动项目集成!
  • 《算法导论(第4版)》阅读笔记:p86-p90
  • Windows逆向工程提升之二进制分析工具:HEX查看与对比技术
  • 自制操作系统day4(c指针)(指针和数组)(CLI和STI)(EFLAGS)
  • 力扣刷题Day 50:接雨水(42)
  • 你的it管理员已经限制对此应用一些区域的访问
  • MySQL进阶篇-InnoDB引擎(超细)
  • MySQL死锁:面试通关“三部曲”心法
  • Linux的权限问题
  • 【SPIN】PROMELA语言编程入门同步机制(SPIN学习系列--4)
  • std::ranges::iota
  • R²AIN SUITE 亮相第九届智能工厂高峰论坛
  • [CSS3]属性增强2
  • 卷积神经网络中的局部卷积:原理、对比与应用解析
  • PHP 实现连续子数组的最大和、整数中1出现的次数
  • [ 计算机网络 ] | 宏观谈谈计算机网络
  • Ultralytics YOLO11模型预测初体验(+实例+亲测)
  • OSD原理以及模块的讲解
  • 多家国有大行存款利率即将迎来新一轮下调
  • 中国戏剧梅花奖终评结果公示,蓝天和朱洁静等15名演员入选
  • 戛纳参赛片《爱丁顿》评论两极,导演:在这个世道不奇怪
  • 澎湃思想周报|《混沌少年时》与青少年社媒禁令;自雇陷阱
  • AI快速迭代带来知识焦虑,褚君浩院士提出“四维能力模型”
  • 七猫征文大赛颁出112万奖金,非遗题材作品斩获金奖