pycharm控制STM32F103ZET6拍照并上位机接收显示(OV7670、照相机、STM32、TFTLCD)

基于STM32的照相机

  • 准备工作
  • 最终效果
  • 一、下位机
    • 1、主函数
    • 2、OV7670初始化
  • 二、上位机
    • 1、控制拍照
    • 2、接收图片数据
  • 三、资源获取

准备工作

一、硬件及片上资源:
1,串口1(波特率:921600,PA9/PA10通过usb转ttl连接电脑,或者其他方法)上传图片数据至上位机
2,串口2(波特率:115200,PA2/PA3通过usb转ttl连接电脑,或者其他方法)控制拍照
3,2.8寸TFTLCD模块
4,按键KEY1(PE3)
5,SD卡
6,外部中断8(PA8,用于检测OV7670的帧信号)
7,定时器6(用于打印摄像头帧率)
8,带FIFO的OV7670摄像头模块
9、STM32F103ET6
10、USB转TTL模块两个
11、STLINK(其他下载器也可以:DSP、JTAG…)
二、软件:
1、pycharm
2、keil5-MDK
3、串口调试助手(XCOM)
三、连线:
在代码中都有。

最终效果

开机的时候先检测字库,然后检测SD卡根目录是否存在PHOTO文件夹,如果不存在则创建,如果创建失败,则报错(提示拍照功能不可用)。在找到SD卡的PHOTO文件夹后,开始初始化OV7670,在初始化成功之后,就一直在TFTLCD上显示OV7670拍到的内容。当上位机按下拍照时,进行拍照,此时DS1亮,照片通过串口发送至上位机,当DS1灭之后,拍照成功。(也可以自己改一改用板子的按键控制拍照)
1、实物图:
在这里插入图片描述
2、上位机效果:
在这里插入图片描述

一、下位机

代码过多过长这里只展示重要的:

1、主函数

 int main(void){	 u8 res;	u8 *pname;				//带路径的文件名		   u16 i;	delay_init();	    	 //延时函数初始化	  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级uart_init1(921600);	 	//串口初始化为115200uart_init2(115200);	usmart_dev.init(72);		//初始化USMART		LED_Init();		  			//初始化与LED连接的硬件接口KEY_Init();					//初始化按键LCD_Init();			   		//初始化LCD    BEEP_Init();        		//蜂鸣器初始化	 W25QXX_Init();				//初始化W25Q128my_mem_init(SRAMIN);		//初始化内部内存池exfuns_init();				//为fatfs相关变量申请内存  f_mount(fs[0],"0:",1); 		//挂载SD卡 f_mount(fs[1],"1:",1); 		//挂载FLASH. EXTI8_Init();				//使能定时器捕获EXTIX_Init();POINT_COLOR=RED;      USART_SendData(USART2,0x31);while(USART_GetFlagStatus(USART2,USART_FLAG_TC)!=SET);//等待发送结束								   						    pname=mymalloc(SRAMIN,30);	//为带路径的文件名分配30个字节的内存		    while(pname==NULL)			//内存分配出错{	    Show_Str(30,190,240,16,"内存分配失败!",16,0);delay_ms(200);				  LCD_Fill(30,190,240,146,WHITE);//清除显示	     delay_ms(200);				  }   											  while(OV7670_Init())//初始化OV7670{Show_Str(30,190,240,16,"OV7670 错误!",16,0);delay_ms(2000);LCD_Fill(30,190,239,206,WHITE);delay_ms(2000);}delay_ms(10000);Show_Str(30,190,200,16,"OV7670 normal",16,0);delay_ms(14444);	delay_ms(14444);										  OV7670_Light_Mode(0);//0OV7670_Color_Saturation(0);OV7670_Brightness(2);//0OV7670_Contrast(2);//0OV7670_Special_Effects(0);OV7670_Window_Set(12,176,240,320);	//设置窗口	  OV7670_CS=0;				    		    LCD_Clear(BLACK);while(1){	if(Res_com2 == 0x31){delay_ms(1800);Res_com2 = 0;//Res_com = 0;LED1=0;	//点亮DS1,提示正在拍照res=bmp_encode(pname,(lcddev.width-240)/2,(lcddev.height-320)/2,240,320,0);Show_Str(40,130,240,12,"picture_capture_finish!",12,0);	LED1=1;//关闭DS1delay_ms(1800);//等待1.8秒钟LCD_Clear(BLACK);//jjj = 0;}else delay_ms(5);camera_refresh();//更新显示i++;if(i==10000)//DS0闪烁.{i=0;LED0=!LED0;}}	   										    
}

2、OV7670初始化

u8 OV7670_Init(void)
{u8 temp;u16 i=0;	  //设置IOGPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOG|RCC_APB2Periph_AFIO, ENABLE);	 //使能相关端口时钟GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_8; 	//PA8 输入 上拉GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA,GPIO_Pin_8);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4;				 // 端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4);	GPIO_InitStructure.GPIO_Pin  = 0xff; //PC0~7 输入 上拉GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_6;  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOD, &GPIO_InitStructure);GPIO_SetBits(GPIOD,GPIO_Pin_6);GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_14|GPIO_Pin_15;  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOG, &GPIO_InitStructure);GPIO_SetBits(GPIOG,GPIO_Pin_14|GPIO_Pin_15);GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);	//SWDSCCB_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
} 

二、上位机

1、控制拍照

# 和另一个.py文件一起运行,点击可视化界面的拍照即可拍照
import serial
import time
import tkinter as tkdef send_command():command_to_send = b'\x31\r\n'ser.write(command_to_send)# You can add any additional actions or updates here# Create the serial connection
ser = serial.Serial('COM13', 115200)
time.sleep(2)# Create the Tkinter window
window = tk.Tk()
window.title("Serial control take photos")# Create a button to send the command
send_button = tk.Button(window, text="拍照", command=send_command)
send_button.pack(pady=20)# Run the Tkinter main loop
window.mainloop()# Close the serial connection when the window is closed
ser.close()

2、接收图片数据

# 用波特率为921600的串口接收下位机上传的图片数据,接受的图片会有一点色彩问题,怀疑是传输出现的问题,用高斯滤波就可以基本滤除。
# 注意要连接好串口,板子上好电,这个代码才能运行不然报错找不到串口
import serial
import struct
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
import cv2
import osser = serial.Serial('COM5', 921600)# 初始化一个空的二维数组,用于存储接收到的数据
received_data = np.zeros((320, 240), dtype=np.uint16)# 初始化图像计数器
image_counter = 1
# 全局变量,保存当前索引
image_index = 0
# 设置图像保存目录
save_dir = "pic_receive"# 如果目录不存在,则创建目录
if not os.path.exists(save_dir):os.makedirs(save_dir)while True:# 初始化索引和计数器received_index = 0row = 0col = 0# 接收数据直到收到足够的数据print("可以发送数据")while received_index < 240 * 320:# 读取两个字节的数据data = ser.read(2)# 解析uint16数据color_value = struct.unpack('>H', data)[0]  # '>H'表示大端字节序的uint16# 将数据存入二维数组received_data[row, col] = color_valuecol += 1received_index += 1# 判断是否接收完一行数据if col >= 240:col = 0row += 1# 如果接收完一帧数据,进行解析和显示if row >= 320:# 解析RGB565格式的数据为RGB888格式# 不知道什么原因发上来列发生错误,进行重组selected_columns1 = received_data[:, 0:47]selected_columns2 = received_data[:, 47:240]merged_array = np.concatenate((selected_columns2, selected_columns1), axis=1)rgb888_data = []for i in range(320):for j in range(240):color_value = merged_array[i, j]r = (color_value & 0xF800) >> 8g = (color_value & 0x07E0) >> 3b = (color_value & 0x001F) << 3rgb888_data.append((r, g, b))# 创建RGB888格式的图像对象image = Image.new('RGB', (240, 320))# 将RGB888格式的数据填充到图像对象中image.putdata(rgb888_data)# 保存图像到文件夹image_filename = os.path.join(save_dir, f"{image_counter:010d}.png")image.save(image_filename)# 增加图像计数器image_counter += 1# 显示图像#plt.imshow(image)#plt.show()# 重置二维数组,准备接收下一帧数据received_data = np.zeros((320, 240), dtype=np.uint16)row = 0col = 0# 清空串口接收缓冲区ser.flushInput()

三、资源获取

我用夸克网盘分享了「照相机+双串口+上位机接收并显示.rar」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。
链接:https://pan.quark.cn/s/125911f5def1
提取码:Za2E

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/680060.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java语法学习反射

Java语法学习反射 大纲 基本介绍class的介绍 具体案例 1. 基本介绍 流程图&#xff08;程序在计算机的阶段&#xff09; 反射的主要的类 这个提高效率不大 2. class的介绍 对于第三点&#xff1a;首先类只会加载一次&#xff0c;得到的class的对象&#xff0c;也只有一…

Linux第52步_移植ST公司的linux内核第4步_关闭内核模块验证和log信息时间戳_编译_并通过tftp下载测试

1、采用程序配置关闭“内核模块验证” 默认配置文件“stm32mp1_atk_defconfig”路径为“arch/arm/configs”; 使用VSCode打开默认配置文件“stm32mp1_atk_defconfg”&#xff0c;然后将下面的4条语句屏蔽掉&#xff0c;如下&#xff1a; CONFIG_MODULE_SIGy CONFIG_MODULE_…

【C语言】实现双向链表

目录 &#xff08;一&#xff09;头文件 &#xff08;二&#xff09; 功能实现 &#xff08;1&#xff09;初始化 &#xff08;2&#xff09;打印链表 &#xff08;3&#xff09; 头插与头删 &#xff08;4&#xff09;尾插与尾删 &#xff08;5&#xff09;指定位置之后…

STM32 + ESP8266,连接阿里云 上报/订阅数据

&#xff08;文章正在编辑中&#xff0c;一点点地截图操作过程&#xff0c;估计要拖拉两三天&#xff09; 一、烧录MQTT固件 ESP8266出厂时&#xff0c;默认是AT固件。连接阿里云&#xff0c;需要使用MQTT固件。 1、独立EPS8266模块的烧录方法 2、魔女开发板&#xff0c;板载…

‘vue-cli-service‘ 不是内部或外部命令,也不是可运行的程序

遇到 vue-cli-service 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。 的错误时&#xff0c;通常意味着Vue CLI没有被正确安装或配置在项目中。这可能是因为node_modules目录缺失了必要的包&#xff0c;或者局部安装的Vue CLI没有被正确设置到系统的PATH环境…

洛谷: P1308 [NOIP2011 普及组] 统计单词数

前言: 这道题没理解清题目表达意思&#xff0c;我开始想的是用map来记录个数&#xff0c;然后一个变量记录一开始出现的单词位置&#xff0c;不挺简单的吗&#xff0c;然后....就AC了2个..从错误提示能看到个数没啥问题&#xff0c;但是第一个单词位置不对&#xff0c;看了新样…

【51单片机】AT24C02(江科大、爱上半导体)

一、AT24C02 1.AT24C02介绍 AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息 存储介质:E2PROM 通讯接口:12C总线 容量:256字节 2.引脚即应用电路 本开发板AT24C02原理图 12C地址全接地,即全为0 WE接地,没有写使能 SCL接P21 S…

Microsoft Excel 加载数据分析工具

Microsoft Excel 加载数据分析工具 1. 打开 Excel&#xff0c;文件 -> 选项2. 加载项 -> 转到…3. 分析工具库、分析工具库 - VBA4. 打开 Excel&#xff0c;数据 -> 数据分析References 1. 打开 Excel&#xff0c;文件 -> 选项 2. 加载项 -> 转到… ​​​ 3…

不安全的 HTTP请求 漏洞原理以及修复方法

漏洞名称&#xff1a;不安全的HTTP方法、危险的HTTP方法 漏洞描述&#xff1a;不安全的HTTP方法一般包括&#xff1a;TRACE、PUT、DELETE、COPY 等。其中最常见的为TRACE方法可以回显服务器收到的请求&#xff0c;主要用于测试或诊断&#xff0c;恶意攻击者可以利用该方法进行…

【Java程序设计】【C00270】基于Springboot的moba类游戏攻略分享平台(有论文)

基于Springboot的moba类游戏攻略分享平台&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的游戏攻略分享平台 本系统分为系统功能模块、管理员功能模块、以及用户后台功能模块。 系统功能模块&#xff1a;在平台首…

【开源】基于JAVA+Vue+SpringBoot的房屋出售出租系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 房屋销售模块2.2 房屋出租模块2.3 预定意向模块2.4 交易订单模块 三、系统展示四、核心代码4.1 查询房屋求租单4.2 查询卖家的房屋求购单4.3 出租意向预定4.4 出租单支付4.5 查询买家房屋销售交易单 五、免责说明 一、摘…

Ocr之TesseractOcr的安装及使用

目录 一、安装环境 二、安装内容 三、安装过程及识别测试 1. 安装过程 2. 程序编写 总结 1. 安装复杂度较低 2. 国外开源Ocr 3. 可设置识别参数 4. 工具类 一、 系统环境windows 10 linux环境也可安装, 可借鉴此篇文章>> | 二、安装内容 Tesseract exe 程序安…

python学习23

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

数模.matlab符号计算方程

一、符号函数 a&#xff1a;整理简化&#xff1a; b&#xff1a;因式分解&#xff1a; c&#xff1a;多项式展开 d&#xff1a;合并&#xff1a; e&#xff1a;计算分子分母&#xff1a; f&#xff1a;求导&#xff1a; f&#xff1a;差分&#xff1a; g&#xff1a;不定积分&a…

阿里云服务器“带宽计费模式”怎么选?有啥区别?

阿里云服务器带宽计费模式分为“按固定带宽”和“按使用流量”&#xff0c;有什么区别&#xff1f;按固定带宽是指直接购买多少M带宽&#xff0c;比如1M、5M、10M、100M等&#xff0c;阿里云直接分配用户所购买的带宽值&#xff0c;根据带宽大小先付费再使用&#xff1b;按使用…

BYTEVALUE 百为流控路由器远程命令执行漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

单片机接收PC发出的数据

#include<reg51.h> //包含单片机寄存器的头文件 /***************************************************** 函数功能&#xff1a;接收一个字节数据 ***************************************************/ unsigned char Receive(void) { unsigned char dat; …

网络编程项目:电子辞典

项目要求&#xff1a; 登录注册功能&#xff0c;不能重复登录&#xff0c;重复注册。用户信息也存储在数据库中。单词查询功能历史记录功能&#xff0c;存储单词&#xff0c;意思&#xff0c;以及查询时间&#xff0c;存储在数据库基于TCP&#xff0c;支持多客户端连接&#x…

C++引用(内含和指针的对比)

1.引用的概念 概念&#xff1a;引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它和它引用的变量共用一块内存空间。 类型& 引用变量名(对象名) 引用实体&#xff1b;&#xff08;&这个符…