STM32F407-摄像头拍照网络通信实验

应单片机课设要求,做了一个摄像头拍照网络通信C/S实时LCD显示。该工程基于原子STM32F4的摄像头与网络通信实验,在此基础上,将其整合。

1.预期功能:

  • 摄像头拍取的内容实时传输至LCD进行显示

  • 通过网络通信C/S方式将STM32摄像头拍取的照片传输到电脑端

  • 在PC端开发可视化界面接受摄像头数据并更新显示

2.实施步骤:

  • 1.参考STM32原子摄像头实验与网络通信实验例程,主要需要了解以下知识。

    • 1.1摄像头的数据如何传输至STM32中?

    • 1.2摄像头照片的传输数据格式是如何组成的?

    • 1.3LCD如何显示图片?

    • 1.4如何通过STM32与外界建立CS服务关系?

    • 1.5STM32如何通过网络向外界进行发送基本的数据?

  • 2.整合两个实验工程,实现照片实时显示至LCD上,并同时通过CS服务端发送摄像头获取的数据。

  • 3.socket编程实现数据包的接收与重组,在了解数据格式的基础上编写照片解码程序,编写PC端可视化界面。

3.设计思路:

以下为实施步骤中对应的设计思路与问题解答:

  • 1.1 STM32F4自带有一个一个数字摄像头( DCMI)接口,该接口是通过与摄像头的帧同步、行同步进行传输数据,并将接收到的数据放到一个32位的数据寄存器(DCMI_DR)中,然后通过DMA进行数据传输。

  • 1.2 摄像头OV2640可以支持两种照片数据格式输出:RGB565或JPEG格式。设置分辨率后,假定为640*320,以RGB格式输出时,则传输时序会参考行同步信号、帧同步信号、像素时钟进行传输,一幅图片即为一帧,其中一帧由640行组成,一行有320个像素,每个像素由两个字节组成(RGB565 5+6+5=16 bit=2byte),一个PCLK时钟传输一个字节,这便为传输时序。当以JPEG格式传输时,摄像头内部会自动先对照片进行压缩,随后以同种方式进行传输数据,只是其中PCLK的数目大大减少,且不连续。输出的JPEG输出以0XFF、0XD8开头,以0XFF、0XD9结束。在0XFF,0XD8之前,或者 0XFF,0XD9 之后,会有不定数量的0存在,我们一般选择忽略即可。

  • 1.3 LCD在内存中构建了一个映射缓冲区,当往该缓冲区写数据时,硬件会自动将该数据解析后显示在LCD上。LCD与图片类似,都是以一个像素为单位进行显示,一般格式为RGB565进行显示,所以当DCMI接收到摄像头传输的数据后,通过DMA将数据直接写入LCD的缓冲区地址便可实现图片的显示。

  • 1.4 STM32通过LWIP小型的协议栈以TCP/IP协议的格式实现C/S端网络通信。程序每次初始化时,会通过DHCP获取IP地址,并且设定固定端口,当作为Client时,还需用户用按键指定Server端的IP与port,设定完毕后,开发板会不断的尝试向Server端发起连接。

  • 1.5当通信双方建立连接后,不断互相进行侦听,STM32采用回调函数的方式进行发送信息,设定一个u8类型的数据,将其各位作为标志位,当有数据需要发送时,置其最高位,采用定时器的方式不断对变量lwip_localtime增加,在main函数中进入while循环,采用轮询的方式,相当于一个软定时器,每xms秒调用一次相关的处理函数。

  • 2.1 摄像头实验与网络通信实验两个工程整合后,进行编译时提示RAM不足,困扰了许求,后来发现是因为摄像头实验中申请的照片缓冲区太大约有100K,而网络通信实验中的也申请了很大的发送缓冲区与接收缓冲区,将这两个变量改小后,程序编译通过。

  • 2.2网络通信C/S建立完成,开始尝试发送少量数据,发现PC端接收没问题。但当发送大量照片数据包时,发现其实际的总接收量每次总是1912byte,考虑是否发送数据量过大,发送端无法自己分片,只能发送MTU数量大小,因此在发送数据前增加了一个数据分片发送程序,随后数据量发送正常,一次发送后的总接收量可以大于1912byte,甚至可达20K。

  • 2.3数据发送量解决后,但接收的数据不正确,对数据仔细观察后,前几个数据包数据都正确,但后面的数据包就开始出现丢包重的现象,同时数据包到达的顺序也有些不对,写该文档时在想,是否我的数据发送缓冲区定义的稍小了,但我每次发送数据时有限量分片的,所以该问题暂时还无法解决,最后我们决定用串口进行代替网络通信发送数据。

  • 3.Sokert编程在接收端其实也是有些问题,当发送数据量过大时,PC端接收数据时一次也只能接收到部分数据,因此在接收端还需要编写数据包重组程序。
    最后我们计划使用串口来接收数据,我们采用python语言进行编写接收程序与图片解码程序。使用串口接收库读取接收到的数据,判断如果为JPEG格式图片的包头则创建文件,接收数据,以二进制的方式将数据写人文件,直到检测到结束标志,关闭储存文件。PC端的可视化软件采用MFC编程,使用定时器的事件,循环读取文件夹中的指定照片并显示,于是便实现类似与视频的效果。由于可视化界面与图片解码是两个进程,无法进行直接的数据共享,因此我们采用文件的方式进行数据传输,所以每次python脚本接收到照片后需要写入硬盘,随后MFC软件需要从硬盘中读取该照片,这期间设计到两次的硬盘的读写,所以效率较低,速度较慢,从而导致最后视频显示器的帧率较低。

4.具体实现

4.1 LCD显示

通过源代码分析以及上面的解答,该功能很容易实现,通过DMA直接传输摄像头的数据便可。

4.2 照片数据发送至电脑端

前面已经说过,实际上工程最后采用了串口进行数据发送,发送代码可参考原子本身的摄像头实验,分析后便可知串口发送数据如下:

for (i=0;i4;i++)
{
 while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET);
 USART_SendData(USART2,p[i]);
}

接收端我用python写了一个脚本进行数据的接收及照片的解码,运行后会将照片存在当前文件夹下:

#!/usr/bin/python2.7
#-*- encoding: UTF-8 -*-

import serial
import sys
import time
import os
def getFileName():
    global i
    i = i + 1 
    return "photo" + str(i) + ".jpeg"

def receiveData():
    ser = serial.Serial('COM5',115200)
    try:
        while (True):
            start_1st = ser.read()
            if ord(start_1st) == 0xFF:
                start_2st = ser.read()
                if ord(start_2st) == 0xD8:
                    fileName = getFileName()
                    print fileName
                    fjpg = open(fileName,"wb")
                    fjpg.write(start_1st)
                    fjpg.write(start_2st)
                    while (True):
                        data = ser.read()
                        fjpg.write(data)
                        if ord(data) == 0xFF:
                            end_1st = ser.read()
                            fjpg.write(end_1st)
                            if ord(end_1st) == 0xD9:
                                fjpg.close()
                                print("recieve data finish")
                                break
                else:
                    print("no 2st start code")
            else:
                print("no 1st start code")
    except KeyboardInterrupt:
        print "Interrupted by user, shutting down"
        sys.exit(0)

global i
i = 0
if __name__ == "__main__":
    receiveData()

3.PC端开发可视化界面显示照片并更新

1.PC端采用MFC进行编程,照片使用Picture Control控件显示。

2.当需要实时更新Picture Contro中的图片,想让它变成类似于一个视频帧时,可以设置MFC中的定时器事件,这个定时时间关系到帧率,每次读取固定文件夹目录下的照片并显示,同时使用python脚本更新图片,便可实现该功能。

你可能感兴趣的:(stm32,单片机,摄像头,网络,通信)