问题

stm32驱动ov7670摄像头,但是没有屏幕,怎么查看照片呢?

思路

能否通过串口通信,把照片传输到电脑上呢?

通过百度搜索,发现了一款调试助手,这个调试助手支持摄像头调试,或许我先可以试试用一下这个调试助手,然后用python把实现它的摄像头调试功能。

山外多功能调试助手

这个软件的特点如下:

  • 支持彩色摄像头、灰度摄像头、二值化摄像头。
  • 分辨率可调
  • 彩色摄像头格式有:RGB565 小端和 RGB565 大端

通信协议如下:

根据它的通信协议,stm32串口传输代码可以这样写:

extern u8 ov_sta;   //在ov7670.c里面定义,当ov7670拍摄了完整的一张照片时,ov_sta=1void send_pic_using_USART() // 使用串口发送数据
{u8 pixel1, pixel2;u32 j=0;GPIO_WriteOutBits(OV7670_RRST_GPIO, OV7670_RRST_PIN, RESET); // RRST=0 复位读指针开始OV7670_RCK_L;OV7670_RCK_H;OV7670_RCK_L;GPIO_WriteOutBits(OV7670_RRST_GPIO, OV7670_RRST_PIN, SET);   // RRST=1 复位读指针结束 OV7670_RCK_H;// 发送帧头Usart_Sendbyte(COM_PORT, 0x01);Usart_Sendbyte(COM_PORT, 0xfe);for(j=0;j<76800;j++)   // 240*320=76800{OV7670_RCK_L;pixel1 = OV7670_DATA;  // 读1个数据,得到高字节OV7670_RCK_H;OV7670_RCK_L;pixel2 = OV7670_DATA;  // 读数据,得到低字节OV7670_RCK_H;// 发送数据,上位机要选择大端。Usart_Sendbyte(COM_PORT, pixel1); // 发送高字节 R5 G3Usart_Sendbyte(COM_PORT, pixel2); // 发送低字节 G3 B5}// 发送帧尾Usart_Sendbyte(COM_PORT, 0xfe);Usart_Sendbyte(COM_PORT, 0x01);ov_sta=0;  // 把ov_sta设成0后,ov7670会把新的照片数据写入到FIFO芯片中
}

调试经验:

多次调试发现,上位机设成小端时,传输的照片发蓝发绿,没法看。
上面的串口传输代码,是最终的代码,是可以看到照片的,把上位机设成这样就可以看到照片了。

相应的ov7670寄存器配置如下:

//初始化寄存器序列及其对应的值:{寄存器, 值}
const u8 ov7670_init_reg_tbl[][2]=
{   /*以下为OV7670 QVGA RGB565参数  */{0x3a, 0x04},//当分辨率改变时,传感器不会自动设置窗口,后端处理器能立即调整窗口{0x40, 0xd0},//输出范围:[00]到[FF],RGB565,在RGB444[1]为低时有效   {0x12, 0x14},//SCCB Register Reset: 0(Not),输出格式:QVGA,RGB/*输出窗口设置*///Horizontal Frame {0x32, 0x80},//HREF control,bit[2:0]:HREF start 3 LSB,bit[5:3]:HREF end 3 LSB,bit[7:6]:HREF edge offset to data output{0x17, 0x16},//HSTART start high 8-bit MSB       {0x18, 0x04},//HSTOP end high 8-bit MSB//Vertical Frame{0x19, 0x02},//VSTRT start high 8-bit MSB{0x1a, 0x7b},//VSTOP end high 8-bit MSB{0x03, 0x06},//VREF control, bit[1:0]: VREF start 2 LSB,bit[3:2] VREF end 2 LSB,bit[7:6]:AGC[9:8]{0x0c, 0x00},//省电模式期间输出时钟三态和数据三态,禁止缩放,禁止DCW使能{0x15, 0x00},//PCLK连续输出,在PCLK的下降沿VSYNC改变{0x3e, 0x00},//正常的PCLK,禁止缩放参数手动调节,PCLK分频(PCLK divider)为1(不分频){0x70, 0x3a},//无测试图案输出,垂直缩放系数为0x3a{0x71, 0x35},//水平缩放系数为0x35{0x72, 0x11},//竖直平均计算、水平平均计算、竖直亚抽样、水平亚抽样{0x73, 0x00},//DSP缩放时钟分频{0xa2, 0x02},//15{0x11, 0x81},//时钟分频设置,0,不分频.{0x7a, 0x20},{0x7b, 0x1c},{0x7c, 0x28},{0x7d, 0x3c},//20{0x7e, 0x55},{0x7f, 0x68},{0x80, 0x76},{0x81, 0x80},{0x82, 0x88},{0x83, 0x8f},{0x84, 0x96},{0x85, 0xa3},{0x86, 0xaf},{0x87, 0xc4},//30{0x88, 0xd7},{0x89, 0xe8},{0x13, 0xe0},{0x00, 0x00},//AGC{0x10, 0x00},{0x0d, 0x00},//全窗口, 位[5:4]: 01 半窗口,10 1/4窗口,11 1/4窗口 {0x14, 0x28},//0x38, limit the max gain{0xa5, 0x05},{0xab, 0x07},{0x24, 0x75},//40{0x25, 0x63},{0x26, 0xA5},{0x9f, 0x78},{0xa0, 0x68},{0xa1, 0x03},//0x0b,{0xa6, 0xdf},//0xd8,{0xa7, 0xdf},//0xd8,{0xa8, 0xf0},{0xa9, 0x90},{0xaa, 0x94},//50{0x13, 0xe5},{0x0e, 0x61},{0x0f, 0x4b},{0x16, 0x02},{0x1e, 0x07},//图像输出镜像控制//修改配置值将产生图像显示上下或左右颠倒{0x21, 0x02},{0x22, 0x91},{0x29, 0x07},{0x33, 0x0b},{0x35, 0x0b},//60{0x37, 0x1d},{0x38, 0x71},{0x39, 0x2a},{0x3c, 0x78},{0x4d, 0x40},{0x4e, 0x20},{0x69, 0x00},{0x6b, 0x40},//PLL*4=48Mhz{0x74, 0x19},{0x8d, 0x4f},{0x8e, 0x00},//70{0x8f, 0x00},{0x90, 0x00},{0x91, 0x00},{0x92, 0x00},//0x19,//0x66{0x96, 0x00},{0x9a, 0x80},{0xb0, 0x84},{0xb1, 0x0c},{0xb2, 0x0e},{0xb3, 0x82},//80{0xb8, 0x0a},{0x43, 0x14},{0x44, 0xf0},{0x45, 0x34},{0x46, 0x58},{0x47, 0x28},{0x48, 0x3a},{0x59, 0x88},{0x5a, 0x88},{0x5b, 0x44},//90{0x5c, 0x67},{0x5d, 0x49},{0x5e, 0x0e},{0x64, 0x04},{0x65, 0x20},{0x66, 0x05},{0x94, 0x04},{0x95, 0x08},{0x6c, 0x0a},{0x6d, 0x55},{0x4f, 0x80},{0x50, 0x80},{0x51, 0x00},{0x52, 0x22},{0x53, 0x5e},{0x54, 0x80},//{0x54, 0x40},//110{0x09, 0x03},//驱动能力最大{0x6e, 0x11},//100{0x6f, 0x9f},//0x9e for advance AWB{0x55, 0x00},//亮度{0x56, 0x40},//对比度 0x40{0x57, 0x40},//0x40,  change according to Jim's request///
//以下部分代码由开源电子网网友:duanzhang512 提出
//添加此部分代码将可以获得更好的成像效果,但是最下面一行会有蓝色的抖动.
//如不想要,可以屏蔽此部分代码.然后将:OV7670_Window_Set(12,176,240,320);
//改为:OV7670_Window_Set(12,174,240,320);,即可去掉最下一行的蓝色抖动{0x6a, 0x40},{0x01, 0x40},{0x02, 0x40},{0x13, 0xe7},{0x15, 0x00},  {0x58, 0x9e},{0x41, 0x08},{0x3f, 0x00},{0x75, 0x05},{0x76, 0xe1},{0x4c, 0x00},{0x77, 0x01},{0x3d, 0xc2},    {0x4b, 0x09},{0xc9, 0x60},{0x41, 0x38},{0x34, 0x11},{0x3b, 0x02}, {0xa4, 0x89},{0x96, 0x00},{0x97, 0x30},{0x98, 0x20},{0x99, 0x30},{0x9a, 0x84},{0x9b, 0x29},{0x9c, 0x03},{0x9d, 0x4c},{0x9e, 0x3f},{0x78, 0x04},{0x79, 0x01},{0xc8, 0xf0},{0x79, 0x0f},{0xc8, 0x00},{0x79, 0x10},{0xc8, 0x7e},{0x79, 0x0a},{0xc8, 0x80},{0x79, 0x0b},{0xc8, 0x01},{0x79, 0x0c},{0xc8, 0x0f},{0x79, 0x0d},{0xc8, 0x20},{0x79, 0x09},{0xc8, 0x80},{0x79, 0x02},{0xc8, 0xc0},{0x79, 0x03},{0xc8, 0x40},{0x79, 0x05},{0xc8, 0x30},{0x79, 0x26}, {0x09, 0x00},
///
};

用python实现这个通信协议,作一个上位机软件

需要的库:serial、PIL、numpy

import serial
import serial.tools.list_ports
import numpy as np
from PIL import Image
import time
import osdef rgb5652array(rgb565, normal_type=False):img_list = []for i in range(0, len(rgb565), 2):pixel = (rgb565[i] << 8) | rgb565[i+1]r = pixel >> 11g = (pixel >> 5) & 0x3fb = pixel & 0x1fif normal_type is True:  # 回到正常范围r = r * 255.0 / 31.0g = g * 255.0 / 63.0b = b * 255.0 / 31.0img_list.append([r, g, b])img_list = np.array(img_list).reshape((240, 320, 3))return img_list# %%
# 获取串口列表
ports_list = list(serial.tools.list_ports.comports())
if len(ports_list) <= 0:print("无串口设备。")
else:print("可用的串口设备如下:")for comport in ports_list:print(list(comport)[0], list(comport)[1])# %%
ser = serial.Serial()
ser.port = ports_list[0][0]
ser.baudrate = 115200
ser.bytesize = 8
ser.stopbits = 1
ser.parity = 'N'
print("串口详情参数: ", ser)try:ser.open()  # 打开串口
except Exception as e:print(e)# %%
running_time = time.time()
threshold = 120
pic_count = 0  # 统计从下位机收到的照片数
while ser.isOpen():try:size = ser.inWaiting()if time.time() - running_time > threshold:  # threshold秒后没接到信息就退出breakif size >= 24:running_time = time.time()cmd = ser.read(24).decode('utf-8', 'replace')start_idx = cmd.find('car')  # 找到指令头car的起始位置if start_idx != -1:print("接收到指令:", cmd)# 形如 car0000001 17 00000000endpark_id = int(cmd[start_idx+3:start_idx+3+8])opcode = int(cmd[start_idx+11:start_idx+11+2])data = cmd[start_idx+13:start_idx+13+8]if opcode == 17:  # 上传照片print('正在上传照片')flag_start = time.time()flag_end = flag_startdata = []count = 0number = 1  # 获取1张照片while ser.isOpen():if count >= number:breaktry:size = ser.inWaiting()if size >= 2:two_byte = ser.read(2)if two_byte[0] == 1 and two_byte[1] == 254:flag_start = time.time()print('检测到帧头')elif two_byte[0] == 254 and two_byte[1] == 1:flag_end = time.time()print('检测到帧尾')if flag_start > flag_end:data.append(two_byte[0])data.append(two_byte[1])elif flag_start < flag_end or len(data) >= 200000:flag_start = time.time()flag_end = flag_startcount = count + 1pic_count = pic_count + 1length = len(data) - 2print('照片数据长度:{}'.format(length))if length == 153600:  # 240×320=76800的图片数据data = data[0+2:]elif length > 153600:data = data[0+2:153600+2]else:data.extend(list([0 for i in range(153600 - (length))]))data = data[0+2:]print('处理后长度:{}'.format(len(data)))pic = rgb5652array(data, True)print('RGB565解码完成')pic = pic.astype('uint8')img = Image.fromarray(pic).convert('RGB')img_path = './inference/images/pic_{}.png'.format(pic_count)print('保存照片到: %s\n' % img_path)img.save(img_path)data = []except Exception as e:print(e)elif opcode == 18:  # 识别车牌passelif opcode == 15:  # 计费passelse:passexcept Exception as e:print(e)ser.close()

简单的介绍一下吧,这是我做为车牌识别这个项目而写的上位机软件。
单片机先发送24位的指令,如果这个指令的操作码是17,即这个指令为car0000001 17 00000000end,上位机进入接收照片模式,等待下位机发送1张照片数据,下位机发送照片的协议就是山外调试助手的照片通信协议,上位机软件(python程序)使用按照这个通信协议来解析照片。
至于那个24位的指令,则是为了实现上位机多功能而设计的,你可以根据自己的需求来修改。

指令头 车位号 操作码 数据段 指令尾
car 七位 两位 八位 end
car 0000001 17 00000000 end

这个指令是一个字符串,单片机通过串口发送字符串给上位机(python程序)。

stm32摄像头调试 | 串口传输照片数据 | 用python来设计上位机通信软件相关推荐

  1. 用python做一个上位机串口通信_【教程】简易Python上位机之LED控制

    电子爱好者应该不会对"上位机"这个词感到陌生,毕竟或多或少有过接触.但若是说到上位机的开发的话,大家就不一定熟悉了.很多电子爱好者完全没有接触过上位机的开发工作,他们真的没有相应的 ...

  2. 基于STM32智能小车蓝牙遥控实验(有代码含上位机)

    小车设计 利用STM32作为智能小车的主控制器来驱动智能小车的直流电机工作,电机驱动芯片采用L298N微型集成电路电机驱动芯片,配合STM32核心板使用实现四个直流电机运行和pwm软件调速,通过改变直 ...

  3. 语音控制单片机(python做的上位机控制arduino)

    最近看了垃圾分类很多人做,身为学电子出身的我,也想试试.那首先怎么实现分类呢? 搞摄像头识别....感觉有点难度,还要算法,慢慢研究,然后灵机一动就想到语音控制,我的想法是我说这个垃圾的名称,然后下位 ...

  4. STM32 USB 开发(二)HID Slave 通信 --- 简单上位机开发

    文章目录 前言 一.准备数据 二.在VS中开发上位机 1.引入国外大神写的USB通讯库HidLibary 2.新建HID管理类 CustomHIDManager.cs 3.运行结果 总结 前言 在网上 ...

  5. 用python做一个上位机串口通信_PYTHON制作画加书法源程序

    from turtle import * from random import * from math import * def tree(n,l): pd()#下笔 #阴影效果 t = cos(ra ...

  6. python上位机界面设计_用Python写界面--上位机开发

    Python真的可以说是无所不能,上到人工智能.图像识别.下到控制电机.爬虫.数据处理,前不久发现Python还可以做界面,虽然比较丑,但是还是可以一试. Python内置图形界面库--Tkinter ...

  7. 用Python写界面--上位机开发

    Python真的可以说是无所不能,上到人工智能.图像识别.下到控制电机.爬虫.数据处理,前不久发现Python还可以做界面,虽然比较丑,但是还是可以一试. Python内置图形界面库--Tkinter ...

  8. Qt6串口多功能助手64位版本上位机源码

    开发平台:Qt 6.3 编译环境:MinGW 11.2.0  64bit 源码免费下载方式在文末!部分功能参照源码学习使用! 一.继承QSerialPort类创建子类Serial(serial.h) ...

  9. STM32与PC串口通信 实现步进电机转速可调 程序及调试过程分享

    在读书期间,需要用到步进电机.用STM32F103ZET6作为下位机,采用计时器产生PWM波,通过改变改变ARR的值,改变PWM波的频率,实现步进电机调速,LCD屏幕显示串口收到的数值. PC作为上位 ...

  10. stm32驱动 ov7670发送到串口上位机显示图像

    所需硬件: 1.stm32 103ZET6核心板,没有lcd(调试摄像头一定要买一个lcd,太方便了,都是泪): 2.OV7670带FIFO淘宝一搜一大把最常见的那种: 驱动代码:参考正点原子官方例程 ...

最新文章

  1. 在iis中让asp.net的错误显示在远程访问电脑中
  2. 智能判断图片中是否存在某物体_智能家居组件漫谈——人体传感器
  3. P1038 神经网络(拓扑排序)
  4. EDAS微服务应用同城容灾最佳实践
  5. CentOS自动打开网络连接
  6. Python学习入门基础教程(learning Python)--5 Python文件处理
  7. matlab中关闭mexfunction,mex文件的运行时Matlab自动关闭
  8. Eprime的txt数据转换为excel
  9. win7修复计算机消失,详细教您win7 aero效果消失了怎么恢复
  10. 计算机电脑故障,电脑常见故障解决方法
  11. 智源社区周刊:Gary Marcus谈大模型研究可借鉴的三个因素;OpenAI提出视频预训练模型VPT,可玩MC游戏...
  12. animejs走马灯_web前端攻城狮超爱的JS动画库插件—anime.js
  13. WINDOWS XP中使用DOS命令查看分区的格式
  14. Android9.0默认将开发者选项中的OEM锁开关打开
  15. 收藏了,挺有意思的生成太极图
  16. 无心剑中译纳瓦尔·拉维肯特《如何不靠运气致富》
  17. 凯勒姆机器人系统_苏州凯勒姆机器人系统工程有限公司
  18. axios发送异步请求文件,并下载文件到本地
  19. es获取最大时间的记录_荣耀手表ES值得买吗?长方形大屏设计,健康运动功能比较全面...
  20. WCF Data transfer buffered VS streamed

热门文章

  1. 僵尸网络研究报告(2016)
  2. xp计算机调亮度,老xp系统怎么调亮度台式电脑(教你XP系统如何调节亮度)
  3. 史上最全的疫情历史数据
  4. Java初学笔记30-【MiniQQ聊天部分代码】
  5. Kaggle案例泰坦尼克号问题
  6. c语言里strcpy作用是什么,c语言中的strcpy是什么意思?
  7. dist文件夹、src文件夹、dest文件夹是什么意思?
  8. Period、Duration计算时间间隔
  9. 苹果9L0-403测试对于被选入苹果认证支持专家(ACSP)10.6名称
  10. 树莓派—raspbian软件源