基于STM32的驿站取货小车系统设计

目 录

摘 要 I
Abstract II
引 言 3
1 控制系统设计 6
1.1系统方案 6
1.2 系统工作原理 6
1.2.1 系统的工作原理 6
1.2.2 系统的结构 7
2 硬件电路设计 9
2.1主控模块的选择 9
2.1.1 单片机及其选型介绍 8
2.1.2 复位电路的介绍 9
2.2 电机驱动模块 10
2.3 ov7670模块电路 10
2.4 电源模块电路 11
2.5 其他电路介绍 12
2.5.1 显示电路介绍 12
2.5.2 按键电路介绍 12
3 软件设计 13
3.1系统主程序设计 13
3.2 数字识别子程序设计 14
3.2.1 灰度处理 14
3.2.2 二值化 14
3.2.3 图像分割 15
3.2.4 识别 15
3.3 按键模块子程序设计 15
3.4 电机驱动子程序设计 16
3.5 LCD1602显示子程序设计 17
4仿真与调试 18
4.1 实物展示 18
4.2 实验效果 19
4.2.1 循迹过程 19
4.2.2 显示模块 19
结 论 20
附录1 硬件仿真图 21
附录2 源程序清单 22
参考文献 37
致 谢 39

摘 要

为了解决当今快递行业在快递过程中出现的快递错分,误分及丢件等问题,本着提高快递分拣正确率、取货效率,改善快递行业的形式的要求,本项目设计了一款将视觉识别技术与取货系统相结合的基于STM32的驿站取货小车。
本设计采用的是STM32F103C8T6单片机作为主控模块,视觉识别系统采用带FIFO的OV7670作为信号输入,实现数字识别的功能。显示系统部分采用的是ILI9341显示屏,具有显示及触摸功能,提高取货准确率。循迹部分采用的是黑色胶带对光的反射作用会对光敏电阻的阻值产生影响,继而实现本设计的循迹功能,确保小车不会脱轨,电机驱动部分采用强磁直流减速电机,为本设计提供驱动力。另外,本设计通过控制电机正反转实现设计的自由变换方向和启动停止。通过视觉识别功能,可以达到准确识别取货码,确定位置,实现取货的要求。
经过试验,本系统设计满足在功能上的要求,最终检验了各项设计应用的可能。通过完成本设计系统的功能设计、硬件电路设计、软件程序编写、系统实验以及参数对比的工作,实现了准确循迹及视觉识别的功能,使本设计可以按照目标要求到达货件放置位置,进行准确的取货。最终实验结果表明,基于STM32的驿站取货小车系统设计取货准确率更高,速度更快。

关键词:视觉识别; AD采样; STM32; 驿站取货

Abstract

In order to solve the problems of division, division and missing parts in the express delivery process of today’s express delivery industry, in order to improve the accuracy of express sorting, picking efficiency, and improve the form of express delivery industry The STM32-based station pick-up trolley that combines visual recognition technology with the pick-up system.
This design uses the STM32F103C8T6 single-chip microcomputer as the main control module, and the visual recognition system uses OV7670 with FIFO as the signal input to realize the function of digital recognition. The display system part uses the ILI9341 display screen, which has display and touch functions to improve the accuracy of pickup. The tracking part uses the black tape to reflect the light, which will affect the resistance of the photo-resistor, and then realize the tracking function of this design to ensure that the car will not derail. Design provides the driving force. In addition, this design realizes the free change of direction and the start and stop of the design by controlling the forward and reverse rotation of the motor. Through the visual recognition function, you can accurately identify the pickup code, determine the location, and fulfill the requirements for pickup.
After testing, the system design meets the functional requirements, and finally the possibility of various design applications was tested. Through the completion of the functional design, hardware circuit design, software program writing, system experiment and parameter comparison of the design system, the functions of accurate tracking and visual recognition are realized, so that the design can reach the place where the goods are placed according to the target requirements. Accurate pickup. The final experimental results show that the STM32-based station pick-up trolley system design has a higher pick-up accuracy and faster speed.

Keywords: Visual Identity; AD sampling; STM32; Pickup at the post

引 言

当今社会网络购物成为主流购物方式,物流水平的高低直接影响物流公司的发展。随着互联网技术的发展,网购大规模增加,快递的数量也随之增加,物流配送的时效性和准确性主要取决于物流货运中的分拣搬运环节。
分拣搬运是物流货运中劳动力最密集的部分,占用了大量的人力成本和大部分工作时间[18]。人工取货越来越不能满足效率需求,智能取货也成为主流。可以解决时间过长,错误率高,成本高等一系列问题。我国物流行业仍存在可完善的部分。在目前的发展大环境下,以人工为主题的快递分拣系统再也没办法提供高效的分拣,为大幅提升快递系统整体的效率和效益,应重点考虑快递分拣环节效率,对怎样提升快递分拣系统的效率进行研究,以此减少快递公司成本,提升快递公司的最大接单量,使快递公司实现新阶段的飞跃。
驿站取货小车设计作为社区物流业的出发口,在社会中一旦形成了这种闭环的生态物流圈,并将各种增值服务连接到生态圈,便会提高快递服务的效率,也会增强用户的粘性,在这种情况下,后来的产业链将很难打破这种闭合生态圈而切入进去。所以本设计将与实际情况相结合,现实意义很强。
随着电子商务的迅速发展,我们的物流服务强度也在发展。因此,时间和产品配置的优化往往反映了许多因素。多年来,我国发展了电子商务企业,其数量不断增加。因此高效率,高准确率的取货方式已成为大众需求的重点。对于国外,美国的物流行业占据世界领先地位,就国际后勤系统的组成部分而言,美国是世界上第一个后勤和服务分配中心。后勤分配中心是最好的私营公司,经验丰富,政府对后勤进行分块管理。
而对于相关信息准确、迅速的提取是高效的快递自动分拣系统的基本要求,以达到用信息取代快递。而在快递行业的过程分拣环节中,条形码的识别技术已经得到了一定的应用,但是因为条形码能够存储的信息十分有限,通过识别之后得到的数字序列仍需要和特定数据库进行比对才可以解码。此外,如果条形码被污损,扫描结果将会错误混乱并影响到识别的结果乃至分拣的准确性。二维码不仅可以存储大量的产品内容信息,而且占用空间小,也不需要与特定的数据库进行比对即可实现解码,而且,二维码本身的码制具有自纠错的能力,一些轻微的污损并不会影响最后的识别结果。同时,对二维码信息的提取方法也将直接影响快递分拣效率。传统模式是基于光电扫描技术,然而,以这种方式读取二维码并不能达到较理想的效果。随着对图像处理研究的更加深入,用于图像识别的传感设备的性能持续提高,使用图像处理技术进行条码识别的方式日益流行。
本设计的设计过程主要分为硬件模块设计和软件模块设计,硬件设计是以STM32为主控制芯片,并加入电机驱动模块、数字识别模块等。一个完整的数字识别过程包括图像获取;预处理;特征提取;识别分类;后处理;识别结果。软件设计主要基于Keil开发环境及Proteus仿真进行设计。
本设计重点解决以下三个问题:
⑴ 如何在视觉识别过程中准确获取图像
解决方式:分辨率作为摄像机的主要参数,包括空间和灰度分辨率两种。第一组以显示空间分辨率为主要目的,第二组显示在灰度空间的像素的明暗程度,之后会进行预处理,整个系统的运作将受到预处理的直接影响[11]。而对于预处理也有其目的,即提供有效的图像过滤器,用以消除噪音和恢复退化数据。
⑵ 获取图像之后,特征处理如何提取
解决方式:选择稳定的特点和代表性往往是该系统成功的关键。必须满足三个条件:一是在被提取出来的特征矢量之间必须互不干扰,也就是必须具有一定的独立性;二是特征矢量的提取之间的类内距离要尽可能的缩小,而类间距离则需要尽可能的增加;三是特征矢量具有较小的维度。满足此三方面要求后可提取图像特征[15]。
⑶ 如何用代码进行数字识别
解决方式:利用程序代码将原始的图像进行上下、左右的切割,使其具有与模板的数字图像同样的大小,之后将切割后的图片的对应坐标像素点与其余的模板的像素点相减(像素点一般挑选十个),求出差的绝对值之和。最后绝对值之和最小的,则确定这两个数字最匹配,即可得到该数字值。
本文的主要工作:
第一章介绍自动取货小车控制系统的设计,由要解决的问题入手引出系统将要实现的功能,进而对系统的工作原理与结构进行说明并设计,
第二章对自动取货小车的硬件进行设计,由单片机的选型与其外围电路入手,设计相应的OV7670数字识别电路、AD转换电路、主回路及其保护电路以及系统要求的其他电路。
第三章对自动取货小车的软件进行设计,通过绘制软件流程图,明确软件设计的结构与流程,明晰数据的存储结构,并且通过相应的软件进行程序的编写。
第四章介绍了系统仿真实验的过程与结果,确定系统的设计是否可行性,验证编写的程序是否正确。

1 控制系统设计

1.1系统方案
本设计对于实现自动取货的目的提出如下两套设计方案。
方案一:采用FPGA为主要芯片,加入图像采集单元,由驱动板连接主控芯片实现驱动,通过灰度处理提高对比度,准确识别。以磁条引导方式为驱动方式,为小车铺设路线。其中传感器用到了摄像头模块,超声波传感器,磁力传感器。此方案的缺点是FPGA芯片的编写可能会存在大量漏洞,需要通过多次查找漏洞,达到实现个别功能的目的。
方案二:采用STM32F103C8T6作为主控芯片控制,以OV7670作为信号输入摄像头,其驱动方式为PWM驱动技术。取货小车要求在短时间内准确快速的找到目标货物。加入按键,输入取货码,利用光的反射造成AD采样值不同驱动电机正反转。取货过程中运用视觉识别技术在一定数字范围内识别目标数字,通过灰度处理提高对比度,准确识别。本设计结合了实际分析,通过参考各种相关文献进而确立设计结构方案,使快件进入配送站后,该取货小车通过数字识别系统识别快件的电子标签,完成取件。
经过对比,基于对器件的成本与实物的难度的考虑,方案一编程复杂,耗时长。而方案二成本低,难度适中,因此选择方案二。
1.2 系统工作原理
1.2.1 系统的工作原理
⑴ 循迹原理:该原理利用了光的反射,相同光照强度的光照射在颜色不同的物体上,其反射之后的光亮是不同的,对于光敏电阻阻值的影响也是不同的,而且反射值可以通过AD采样值进行检测。光线反射到光敏电阻上,可以通过检测光敏电阻的阻值来判断小车是否在黑色区域内。离黑色区域越近,光吸收的越多,反射的越少,光敏电阻阻值越大,分压也就越大,反之,离黑色区域越远,分压越小,电压大小控制电机,进而控制小车方向。
⑵ 数字识别原理:
① 图片预处理。此步骤分为识别图像,灰度化以及二值化。
② 图像分割。首先对原始图像的字符进行上下切割个左右切割。基本原理是,从图像第一列开始,从左往右扫描,当遇到像素值为0时,记录该列号s Col,继续扫描遇到整列像素值为255时,记录列号e col,s col与e Col之间为字符所在区间。复制二值图该区域,这样完成了左右分割,之后再依照这种方式进行上下分割。
③ 识别。利用代码将原始图像进行上下左右切割,使其具有与模板的数字图像同样的大小,之后将切割后的图片的对应坐标像素点与其余的模板的像素点相减(像素点一般挑选十个),求出所有像素点之差的绝对值之和。
④ 最后切割后的图片与哪个模板之差的绝对值最小,则可以确定这两个数字最为匹配,即可得到该数字值。
1.2.2 系统的结构
系统结构框图如图1.1所示:
在这里插入图片描述

图1.1 系统框图
⑴ 主机控制模块
主控芯片采用STM32f103c8t6,通过软件程序控制显示模块、电机驱动模块及视觉识别模块。
⑵ 电机驱动模块
包括2个电机,一个万向轮。通过两个电机的正反转开控制小车的方向及行驶,达到符合程序所要求的目的。
⑶ 视觉识别模块
起到信号传递及识别的作用。通过ov7670完成图像的获取,再通过程序及stm32实现数字识别,最终根据已识别的数字准确找到目标快件。
数字识别过程框图如图1.2所示:
在这里插入图片描述

图1.2 数字识别过程框图

2 硬件电路设计

2.1主控模块的选择
2.1.1 单片机及其选型介绍
单片机选型应尽可能要符合成本、性能、控制精度、工作电压、功耗等要求,在此基础上确定系统所需要的功能,如计时器/定时器、串行数据接口、PWM调制、AD转换等,然后可以根据芯片厂商列出的芯片清单进行单片机选型,个别的功能可以通过单片机扩展芯片来实现。此外,应核算系统所使用的I/O口数量,程序存储空间、内存大小以确定合适的芯片,选择满足要求的芯片并尽量减少外部扩展的数据或程序存储芯片,并且留有部分余量。
考虑到上诉因素,选择了STM32系列芯片。STM32f103的芯片内核为ARM32位Cortex-M3 CPU,最高工作频率为72MHz,1.25DMIPS/MHz。芯片上集成32-512KB的Flash存储器和6-64KB的SRAM存储器。3种低功耗模式为休眠,停止,待机模式以及为RTC和备份寄存器供电的VBAT[2]。STM32F103xx微控制器带有一个嵌入式的ARM核,所以可以兼容所有的ARM工具和软件。除了模拟输入,所有的I/O口都可以接受5V以内的输入。
芯片引脚图如图2.1所示:
在这里插入图片描述

图2.1 STM32F103C8T6单片机引脚图

2.1.2 复位电路的介绍
STM32的复位电路支持三种复位形式,分别为系统复位、上电复位和备份区域复位。当系统上电、掉电,以及系统从待机模式返回时,发生电源复位。电源复位一种是在软件复位的时候设定备份区域控制寄存器中的对应位产生的;另一种是当电源和电池都掉电又重新上电时产生的。当系统上电瞬间,电容充电导致NRST在上电瞬间被拉为低电平信号,这个信号持续1100us的时间。(时间计算公式:t = 1.1RC = 1.110000Ω0.0000001F = 0.0011s = 1100us) 而这个时间对于STM32的NRST所需要的低电平信号时长已经足够[7]。综上所述,复位电路设计满足单片机复位要求。复位电路原理图如图2.2所示。
在这里插入图片描述

图2.2 复位电路原理图
2.2 电机驱动模块
电机驱动模块的作用是在小车行驶过程中,通过控制电机的正反转,完成小车在方向上的变化。对于电机,要求电机转速上限高。与STM32的P1.0、P1.1接口相连。
本设计采用的是强磁直流减速电机,直流减速电机即齿轮减速电机,是在普通直流电机的基础上,加上配套齿轮减速箱。齿轮减速箱是为了提供较低的转速,较大的力矩。齿轮箱不同的减速比可以提供不同的转速和力矩[8]。此款电机工作电压为3~6V,符合小车所带电池盒可提供的最高电压,采用双轴驱动,减速比为1:48。3V空载下,转速为125转/分钟,66毫米轮的速度为26米/分钟。5V空载下,转速为208转/分钟,66毫米轮的速度为44米/分钟,由此可见此款电机的驱动速度非常快,符合本设计对电机转速性能的需求。
2.3 ov7670模块电路
本设计将实现数字识别这一功能。采用摄像头ov7670摄像头对数字进行扫描并输入。OV7670带 FIFO模块增加了一个FIFO(先进先出)存储芯片,同样包含30w像素的CMOS图像感光芯片,FIFO的采用便捷了数据的采集,这样可减小甚至不用关心CMOS的控制以及时序关系,就能够实现图像的采集。
控制传感器所需的管脚定义如图2.3所示:
在这里插入图片描述

图2.3 FIFO 摄像头接口定义
2.4 电源模块电路
电机驱动模块工作电压为3~6V,因此本设计采用4节5号普通干电池串联供电,共为6V。使用电压调节器LM1117-33来达成稳压的目的。LM1117是一个低压差电压调节器系列。其压差在1.2V输出,负载电流为800mA时为1.2V。LM1117-33有可调电压的版本,另外还有5个固定电压输出(1.8V、2.5V、2.85V、3.3V和5V)的型号。输入电压为7V,输出电压为5V,输入与输出电压相差2V,达到稳压。电源模块电路图如图2.4所示。
在这里插入图片描述

图2.4 电源模块电路
2.5 其他电路介绍
2.5.1 显示电路介绍
显示电路采用LCD1602显示屏,LCD1602是一种工业字符型液晶,能够同时显示16x02即32个字符。LCD1602液晶显示的原理是利用液晶的物理特性,通过电压对其显示区域进行控制,即可以显示出图形。电路原理图如图2.5所示。
在这里插入图片描述

图2.5 LCD1602电路原理图
2.5.2 按键电路介绍
本电路要求通过按键准确输入取货码,考虑到键盘的功能有以下功能:参数显示选择、校正、排障确认。本着节约I/O口的原则,选择1×4矩阵键盘。四个I/O分别进行加一、减一、确认、启动。与单片机的P1.2到P1.5相连。按键原理图如图2.6所示。
在这里插入图片描述

图2.6 按键原理图

3 软件设计

系统的软件设计通过keiluVision5软件实现,在使用该软件的过程中,可以使用C语言或者汇编语言进行编程,编译后生成以.hex为后缀名的程序文件。在程序编写完成并检查完语法错误之后,可以生成编译调试器以方便观看程序运行过程中对单片机内部各个存储器的改变,更好的理解程序的运行与发现错误。
3.1系统主程序设计
主程序循环模块中的程序执行优先级应是最低的。主程序的设计首先应包含单片机初始化,以及开机过程中所必要的实施模块,这些模块大部分只在单片机开机复位结束之后执行一次。其次,单片机应该具有循环执行的模块,这些模块即是在单片机运行过程中保持单片机一直运行的模块。在程序设计中,最重要的操作是确定程序流程框图。
如图3.1主程序流程框图所示,主程序部分包括系统的初始化、等待取货码、循迹、识别、完成取货、最后返回。如图可知,这个循环处理模块分别包含等待取货码、循迹、识别、完成取货四个部分。
在这里插入图片描述
在这里插入图片描述

图3.1 主程序流程图 图3.2 数字识别子程序设计
3.2 数字识别子程序设计
数字识别实现的基本过程是:灰度处理、二值化、图像分割、识别。
子程序设计图如图3.2所示。
3.2.1 灰度处理
灰度处理的目的是将彩色图像转化成为灰度图像。彩色图像中的每个像素的颜色由R、G、B三个分量决定,而每个分量有255中值可取,这样一个像素点可以有1600多万(255255255)的颜色的变化范围,而灰度图像是R、G、B三个分量相同的一种特殊的彩色图像,其一个像素点的变化范围为255种,所以在数字图像处理种一般先将各种格式的图像转变成灰度图像以使后续的图像的计算量变得少一些[12]。灰度图像的描述与彩色图像一样仍然反映了整幅图像的整体和局部的色度和亮度等级的分布和特征[13]。
3.2.2 二值化
设阈值是二值化的主要理论基础,大于阈值时,为0即黑色或 255即白色,使图像称为黑白图。阈值可固定,也可以自适应阈值。自适应阈值一般为一点像素与这点为中序的区域像素平均值或者高斯分布加权和的比较,其中可以设置一个差值也可以不设置。
3.2.3 图像分割
图像分割,即通过图像不同的灰度,结构,颜色及纹理等,设计出多个阈值,之后 从而将这些像素点以此与阈值进行比较。并将其分为若干不同的领域。
在实际阈值分割过程中,往往需要能够自动获取阈值,下面的算法可以自动获得全局阈值:
⑴选取一个的初始估计值T;
⑵用T分割图像。这样便会生成两组像素集合: G1由所有灰度值大于T的像素组成,而G2由所有灰度值小于或等于T的像素组成;
⑶对G1和G2中所有像素计算平均灰度值ul和u2;
⑷计算新的阈值: T=1/2(u1 + u2)[13]。
3.2.4 识别
利用代码将原始图像进行上下左右的切割,使其具有与模板的数字图像同样的大小,之后将切割后的图片的对应坐标像素点与其余的模板的像素点相减(像素点一般挑选十个),求出所有差的绝对值之和。最后切割图像与哪个模板匹配时绝对值之和最小,则可以确定这两个数字最为匹配,即可得到该数字值。
3.3 按键模块子程序设计
按键所要实现的功能有:计数、确认、清除、启动。首先进行I/O口初始化,依次在按键上按下取货码,每按下一位,若输入正确,便储存,若错误,则可以重新输入。每按一轮取货码便进行复位,已达到清零的目的。按键输入流程图如图3.3所示。
在这里插入图片描述

图3.3 按键输入流程图
3.4 电机驱动子程序设计
自动取货小车的启动以及方向改变均由电机正反转控制,上电时电机启动,电机均正转时小车匀速前进,电机分别正反转时,小车改变方向,向左右转弯,电机均反转时,小车倒退。采用if循环,调整电机正反转。在岔路口转弯处和取货处,利用AD采样值不同,设计两种不同时间的停留,并在每次返回到出发点时,所有变量均初始化,每过一个岔路口变量加一,当变量与取货码第一位相同时就会转弯。电机驱动流程图如图3.4所示。
在这里插入图片描述

图3.4 电机驱动流程图
3.5 LCD1602显示子程序设计
LCD16021602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,字符型LCD1602通常有14条引脚线或16条引脚线的LCD,多出来的2条线是背光电源线VCC(15脚)和地线GND(16脚)。

4仿真与调试

4.1 实物展示
系统主要有六个部分组成:电源模块、ov7670模块、电机驱动模块、显示模块、按键模块以及主控模块这六个模块组成,在系统的搭建上,采用模块分别进行的方式在万用板上搭建电路。分模块进行的好处就是系统走线比较清晰,适合在万用板上进行电路的搭建。四节干电池放在电池盒内,与此同时引出两根导线,与电路板相接,为整个系统提供电流,系统控制主要模块展示如图4.1所示:
在这里插入图片描述

图4.1 系统设计实物展示
循迹模块展示图如图4.2所示:
在这里插入图片描述

图4.2 循迹模块展示图
4.2 实验效果
4.2.1 循迹过程
用黑胶带模拟取货路径,依次为1-1-1、1-1-2、1-1-3、1-2-1、1-2-2、1-2-3、2-1-1、2-1-2、2-1-3、2-2-1、2-2-2、2-2-3,在岔路口由于黑胶带反射光亮不同,AD采样值发生变化,当采样值大时,说明小车位于黑胶带之上,当采样值小时,说明小车位于岔口空白处,会有大约50ms短暂的停顿,之后按照按键输入的取货码,由单片机控制,在指定取货位停留5秒。之后单片机控制,电机反转原路返回。循迹路线模拟图如图4.2所示:
在这里插入图片描述

图4.3 循迹路线图
4.2.2 显示模块
在按键输入取货码后,LCD1602显示出相应的数字,用以查证输入是否正确,提高正确率,并且在取货数字识别的过程中ov7670模块识别数字之后也会显示相应数字。显示成果图如图4.4所示。
在这里插入图片描述

图4.4 显示成果图

结 论

本设计采用STM32作为主控芯片,利用ov7670进行数字识别、将LCD1602作为显示屏,通过光的反射影响AD采样值不同这一原理完成循迹。在按键输入取货码后,识别数字,按照程序设定,小车到达指定取货位置,停留5秒进行取件并由ov7670摄像头进行扫描确认快递无误后,再同样的循迹原理按照原路返回。
本设计主要实现的功能有:
⑴ 通过ov7670完成图像的获取;
⑵ 通过程序及stm32实现数字识别;
⑶ 根据已识别的数字准确找到目标快件。
本设计通过分析快递运输中丢件、错分的现象,提出使用自动取货的方案,完成了准确取件、快速取件的工作,进行了具体的方案设计,并且进行了实际验证。通过完成系统功能设计、硬件电路设计、软件编写、检验系统运行的工作,得出了系统设计符合锂电池管理系统的要求以及验证了各项设计符合工程应用的结论。
不过,设计仍有些许不足还有待提高,比如如何在保证准确率的情况下提升速度,如何识别手写数字以扩大业务范围,如何进行一次性取多件快递以及将机械臂液压杆加入设计,快递行业是我国新型发展行业,智能工程专业也是重点发展对象,将智能技术与快递行业相融合,也是未来发展趋势之一,本设计还有待进一步的时间。

附录1 硬件原理图

在这里插入图片描述

硬件原理图

附录2 源程序清单

#include “delay.h”
#include “sys.h”
#include “lcd.h”
#include “ov7670.h”
#include “exti.h”
#include “key.h”
#include “sram.h”
#include “math.h”
#include “usart.h”
#include “malloc.h”
#include “w25qxx.h”

void Prewitt(void);
void horizontal(void);
void small2big(u8 YL,u8 YH,u16 XL,u16 XH);
void big2small(u8 x1,u16 y1);
u8 charcter_zoen();

extern u8 ov_sta;
u16 picture[320][240] attribute((at(0X68000000)));
u8 dis_gray[320][240] attribute((at(0X68025804)));
u8 dis_sobel1[320][240] attribute((at(0X68038408)));
u8 dis_sobel2[320][240] attribute((at(0X6804b00c)));

u16 astart,aend;
u8 bstart,bend;

u8 mheight,mwidth;

#define RGB565_RED 0xf800
#define RGB565_GREEN 0x7e0
#define RGB565_BLUE 0x1f

void camera_refresh(void)
{
u32 j;
u16 color;
u8 r,g,b;
if(ov_sta)
{

	LCD_WriteRAM_Prepare(); 	
	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=GPIOC->IDR&0XFF;	
		OV7670_RCK_H; 
		color<<=8;  
		OV7670_RCK_L;
		color|=GPIOC->IDR&0XFF;	
		OV7670_RCK_H; 
		picture[j%320][j/320] = color;
		r=(color&RGB565_RED)>>11;
		g=(color&RGB565_GREEN)>>6;
		b=(color&RGB565_BLUE);
		color=(r*19595+g*38469+b*7472+32768)>>16;			
		dis_gray[j%320][j/320] = color;
	   
	}   							  
	ov_sta=0;					

} 

}

void datashow(u8 mode)
{
u32 j;
for(j=0;j<76800;j++){
if(1mode)
LCD->LCD_RAM=picture[j%320][j/320];
else if(2
mode)
LCD->LCD_RAM=(u16)((dis_gray[j%320][j/320]<<11)|(dis_gray[j%320][j/320]<<6)|dis_gray[j%320][j/320]);
else if(4mode)
LCD->LCD_RAM=(u16)((dis_sobel1[j%320][j/320]<<11)|(dis_sobel1[j%320][j/320]<<6)|dis_sobel1[j%320][j/320]);
else if(6
mode)
LCD->LCD_RAM=(u16)((dis_sobel2[j%320][j/320]<<11)|(dis_sobel2[j%320][j/320]<<6)|dis_sobel2[j%320][j/320]);
}
}

u8 key=0;

int main(void)
{

u8 s,data;
u8* demo;
int i,j,kk;
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
KEY_Init();
EXTIX_Init();
W25QXX_Init();
uart_init(115200);
FSMC_SRAM_Init();
LCD_Init();
LCD_Scan_Dir(U2D_L2R);

demo=mymalloc(0,180*90);
memset(demo,0,90*180); 
while(OV7670_Init())//初始化OV7670
{

  LCD_Fill(30,230,239,246,WHITE);
	delay_ms(200);
}

OV7670_Mode_Init();
EXTI8_Init();
OV7670_Window_Set(12,176,240,320);
OV7670_CS=0;
LCD_Clear(BLACK);

while(1)
{	
	camera_refresh();
	datashow(1);
	
	 if(key!=0)
	 {
		switch(key)
		{				 
			case  2:	
			{		
				for(s=1;s<11;s++)
				{
				 W25QXX_Read((u8*)demo,s*16200,16200);
				
				for(i=0;i<180;i++)
        {
	        for(j=0;j<90;j++)
					{
						kk=i*90+j;
						dis_sobel2[i][j]=demo[kk];
					}
				}
				 LCD_Clear(WHITE);	 
	     datashow(6);
				delay_ms(1000);
		
			}
		}
				break;
			
			case 4:	
			{
				datashow(2);
				Prewitt();
      datashow(4);
				horizontal();
				small2big(bstart,bend,astart,aend);
		    big2small(0,0);
		   data=charcter_zoen();
       LCD_Scan_Dir(DFT_SCAN_DIR);					
				POINT_COLOR=BLACK;
      LCD_ShowString(15,250,200,24,24,"The number is:  ");	
      POINT_COLOR=RED;					
			  LCD_ShowNum(190,250,data,1,24); 
				delay_ms(5000);
				LCD_Scan_Dir(U2D_L2R);		
			}
				break;
			
		}

  	key=0;
}	

}
}
void Templat(u8 dis_sobel[320][240],u8 wide,u16 height,u8 tempH,u8 tempW,u8 tempMX,u8 tempMY,float fparray[],float fCoef)
{
u16 lie,hang,k,l;
float fResult;
for(hang=tempMY;hang<height-tempH+tempMY+1;hang++)
for(lie=tempMX;lie<wide-tempW+tempMX+1;lie++)
{
fResult=0;
for(k=0;k<tempH;k++)
for(l=0;l<tempW;l++)
{
fResult+=dis_gray[(hang-tempMY+k)][(lie-tempMX+l)]fparray[ktempW+l];
}
fResult*=fCoef;
fResult=(float)fabs(fResult);
if(fResult>31) dis_sobel[hang][lie]=31;
else dis_sobel[hang][lie]=(u8)(fResult+0.5);
}
}
void Prewitt(void)
{
u16 i,j;
float tempC,Template[9];
u8 tempH,tempW,tempMX,tempMY;
tempW=3;
tempH=3;
tempC=1;
tempMX=1;
tempMY=1;
Template[0]=-1;
Template[1]=-1;
Template[2]=-1;
Template[3]=0;
Template[4]=0;
Template[5]=0;
Template[6]=1;
Template[7]=1;
Template[8]=1;
Templat(dis_sobel1,240,320,tempH,tempW,tempMX,tempMY,Template,tempC);
Template[0]=1;
Template[1]=0;
Template[2]=-1;
Template[3]=1;
Template[4]=0;
Template[5]=-1;
Template[6]=1;
Template[7]=0;
Template[8]=-1;
Templat(dis_sobel2,240,320,tempH,tempW,tempMX,tempMY,Template,tempC);
for(i=0+1;i<240-1;i++)
for(j=0+1;j<320-1;j++)
{
if(dis_sobel2[j][i]>dis_sobel1[j][i])
dis_sobel1[j][i]=dis_sobel2[j][i];
}

}
void aver_t(u8 temp[320][240],u16 h,u16 w,u16 begin_x,u16 begin_y)
{
u8 T1=0;
u32 i,j,t=0;

for(j=begin_y;j<h+begin_y;j++)
	for(i=begin_x;i<w+begin_x;i++)
		t+=dis_gray[j][i];
T1=t/((h)*(w))-12;

for(i=begin_x;i<w+begin_x;i++)
{
	for(j=begin_y;j<h+begin_y;j++)
	{
		if(temp[j][i]<T1) temp[j][i]=0;
		else temp[j][i]=31;
	
	}
}

}

void aver_t1(u8 temp[320][240],u16 h,u16 w,u16 begin_x,u16 begin_y)
{
u8 T1=0;
u32 i,j,t=0;

for(j=begin_y;j<h+begin_y;j++)
	for(i=begin_x;i<w+begin_x;i++)
		t+=dis_gray[j][i];
T1=t/((h)*(w))-5;

for(i=begin_x;i<w+begin_x;i++)
{
	for(j=begin_y;j<h+begin_y;j++)
	{
		if(temp[j][i]<T1) temp[j][i]=0;
		else temp[j][i]=31;
	
	}
}

}
void horizontal(void)
{
u16 i,j;
u16 start=0,end=0;
u8 in=0,white=0,num=0,uline=0,x=0;
aver_t(dis_sobel1,320,240,0,0);
datashow(4);
for(j=10;j<320;j++)
for(i=10;i<240;i++)
dis_sobel2[j][i]=0;
for(j=0;j<319;j++)
{
for(i=0;i<239;i++)
{
if(dis_sobel1[j][i]==31) white=1;

		if((0==in)&&(1==white))in=1;
		else if((1==in)&&(1==white))num++;
		else if((1==in)&&(0==white)&&(num>=1)) 
		{
			in=0;
			x++;
			num=0;
		}
		white=0;
	}
	if(x>=1)
	{
		if(0==uline)
			start=j;
		  uline++;
	}
	else
	{
		if(uline>=5)
		{
			//end=j;
			astart=start;
			aend=j;
			break;
		}
		start=0;
		uline=0;
	}
	x=0;
}	

	POINT_COLOR=BLUE;  	
LCD_DrawLine(astart,0,astart,319);

POINT_COLOR=GREEN;
LCD_DrawLine(aend,0,aend,319);
mheight=start-end+1+8;
white=0;
in=0;
num=0;
x=0;
uline=0;
for(i=0;i<239;i++)
{
for(j=astart-4;j<aend+4;j++)
{
if(dis_sobel1[j][i]31) white=1;
if((0
in)&&(1white)) in=1;
if((1
in)&&(1white)) num++;
if((1
in)&&(0white)&&(num>=1))
{
in=0;
x++;
num=0;
}
white=0;
}
if(x>=1)
{
if(0
uline)
start=i;
uline++;
}
else
{
if(uline>=5)
{
end=i;
bstart=start;
bend=end;
break;
}
start=0;
uline=0;
}
x=0;
}
POINT_COLOR=RED;
LCD_DrawLine(0,bstart,319,bstart);
POINT_COLOR=YELLOW;
LCD_DrawLine(0,bend,319,bend);
printf(“astart=%d,aend=%d,mheight=%d,bstart=%d,bend=%d,uline=%d\t\n”,astart,aend,mheight,bstart,bend,uline);
for(j=astart;j<aend;j++)
for(i=bstart;i<bend;i++)
{
dis_sobel2[j][i]=dis_gray[j][i];
}

  mwidth=bend-bstart+1;
	delay_ms(1000);
LCD_Clear(WHITE);	 
	datashow(6);
	
  aver_t1(dis_sobel2,320,240,0,0);
	delay_ms(1000);
LCD_Clear(WHITE);	 
	datashow(6);

}
void small2big(u8 YL,u8 YH,u16 XL,u16 XH)
{
u16 w1;
u16 h1;
u8 w0,h0,j;
u16 size0,size1,kk;
vu16 i;
float fw;
float fh;
int y1,y2,x1,x2,x0,y0;
float fx1,fx2, fy1,fy2;
float s1,s2,s3,s4;
int rd, ld, lu, ru;
int pix;

u8 *ipDIBBITS=0,*pTemp;

w0=YH-YL+1;	   
h0=(XH-XL)+1; 
w1=90;
h1=180;
mheight=h1;
mwidth=w1;
fw=(float)(w0-1)/(w1-1);
fh=(float)(h0-1)/(h1-1);
size0=(w0)*(h0);
size1=(w1)*(h1);
ipDIBBITS=mymalloc(0,size0);
pTemp=mymalloc(0,size1);

datashow(6);
for(i=XL;i<XH+1;i++)
{
	for(j=YL;j<YH+1;j++)
	{	
		kk=(i-XL)*(w0)+(j-YL);
		ipDIBBITS[kk]=dis_sobel2[i][j];
	}
}
    

for(i=0; i<h1;i++)
{
	y0 = i*fh;
	y1=(int)(y0);
	if(y1 == h0-1) y2 = y1;
	else y2 = y1 + 1;
	fy1 = y1-y0; 
	fy2 = 1.0f - fy1;
	for(j=0; j<w1;j++)
	{
		x0 = j*fw;
		x1 = (int)(x0);
		if(x1 == w0-1)    
			x2 = x1;
		else
			x2 = x1+1;
		fx1=y1-y0;
		fx2=1.0f-fx1;
		s1 = fx1*fy1;
		s2 = fx2*fy1;
		s3 = fx2*fy2;
		s4 = fx1*fy2;
		rd=y1*(w0)+x1;
		ld=y2*(w0)+x1;
		ru=y2*(w0)+x2;
		lu=y1*(w0)+x2;
		pix=i*(w1)+j;
		pTemp[pix]=ipDIBBITS[ru]*s1+ipDIBBITS[lu]*s2+ipDIBBITS[rd]*s3+ipDIBBITS[ld]*s4; 
	}
}


for(i=0;i<h1;i++)
{
	for(j=0;j<w1;j++)
	{	
		kk=(i)*(w1)+(j);
		dis_sobel2[i][j]=pTemp[kk];
	}
}  
myfree(0,ipDIBBITS);	
myfree(0,pTemp);
datashow(6);

}
void big2small(u8 x1,u16 y1)
{
u16 i,j;
u8 flag_1,flag_2,flag_3,flag_4,fp=1,count;
vu8 m,n;
u8 s[5][5];

while(fp)
{
	fp=0;	
	for(j=y1;j<mheight+y1;j++)
	{
		for(i=x1;i<mwidth+x1;i++)
		{
			dis_sobel1[j][i]=31;
		}
	}
	for(j=y1+2;j<mheight+y1-2;j++)
	{
		for(i=x1+2;i<mwidth+x1-2;i++)
		{
			flag_1=0;
			flag_2=0;
			flag_3=0;
			flag_4=0;
			if(31==dis_sobel2[j][i])
				continue;
			for(m=0;m<5;m++)
			{
				for(n=0;n<5;n++)
				{
					s[m][n]=(31-dis_sobel2[(j+m-2)][(i+n-2)])/31;//白色为0,黑色为1
				}
			}
			
			count=s[1][1]+s[1][2]+s[1][3]+s[2][1]+s[2][3]+s[3][1]+s[3][2]+s[3][3];
			if((count>=2)&&(count<=6))
				flag_1=1;
			count=0;
			if((0==s[1][2])&&(1==s[1][1]))
				count++;
			if((0==s[1][1])&&(1==s[2][1]))
				count++;
			if((0==s[2][1])&&(1==s[3][1]))
				count++;
			if((0==s[3][1])&&(1==s[3][2]))
				count++;
			if((0==s[3][2])&&(1==s[3][3]))
				count++;
			if((0==s[3][3])&&(1==s[2][3]))
				count++;
			if((0==s[2][3])&&(1==s[1][3]))
				count++;
			if((0==s[1][3])&&(1==s[1][2]))
				count++;
			if(1==count)
				flag_2=1;
			if(0==s[1][2]*s[2][1]*s[2][3])
				flag_3=1;
			else
			{
				count=0;
				if((0==s[0][2])&&(1==s[0][1]))
					count++;
				if((0==s[0][1])&&(1==s[1][1]))
					count++;
				if((0==s[1][1])&&(1==s[2][1]))
					count++;
				if((0==s[2][1])&&(1==s[2][2]))
					count++;
				if((0==s[2][2])&&(1==s[2][3]))
					count++;
				if((0==s[2][3])&&(1==s[1][3]))
					count++;
				if((0==s[1][3])&&(1==s[0][3]))
					count++;
				if((0==s[0][3])&&(1==s[0][2]))
					count++;
				if(1!=count)
					flag_3=1;					
			}
			
			if(0==s[1][2]*s[2][1]*s[3][2])
				flag_4=1;
			else
			{
				count=0;
				if((0==s[1][1])&&(1==s[1][0]))
					count++;
				if((0==s[1][0])&&(1==s[2][0]))
					count++;
				if((0==s[2][0])&&(1==s[3][0]))
					count++;
				if((0==s[3][0])&&(1==s[3][1]))
					count++;
				if((0==s[3][1])&&(1==s[3][2]))
					count++;
				if((0==s[3][2])&&(1==s[2][2]))
					count++;
				if((0==s[2][2])&&(1==s[1][2]))
					count++;
				if((0==s[1][2])&&(1==s[1][1]))
					count++;
				if(1!=count)
					flag_4=1;					
			}
			if(flag_1*flag_2*flag_3*flag_4)
			{
				dis_sobel1[j][i]=31;
				fp=1;
			}
			else
			{
				dis_sobel1[j][i]=0;
			}				
		}
	}
	for(j=y1;j<mheight+y1;j++)
	{
		for(i=x1;i<mwidth+x1;i++)
		{
			dis_sobel2[j][i]=dis_sobel1[j][i];
		}
	}
	/**********/
}
for(j=y1;j<mheight+y1;j++)
{
	for(i=x1;i<mwidth+x1;i++)
	{
		dis_sobel2[j][i]=dis_sobel1[j][i];					
	}
}
/***********/
datashow(6);

}
u8 charcter_zoen()
{
u8 j,x;
u16 i,kk,number,flag;
u8 *ipDIBBITS=0,*pTemp;
u8 error[10];
ipDIBBITS=mymalloc(1,16200);
pTemp=mymalloc(1,16200);

	for(i=0;i<180;i++)
{
	for(j=0;j<90;j++)
	{	
		 kk=(i)*90+(j);
		 ipDIBBITS[kk]=dis_sobel2[i][j];
	}
}

for(i=1;i<11;i++)
{
	W25QXX_Read(pTemp,0+16200*i,16200);	 //取数模班
	number=0;
	flag=0;
	for(kk=0;kk<16200;kk++)
	{
  if(ipDIBBITS[kk]==0)
		{
		   number++;
			if(pTemp[kk]==0)
			{
				flag++;
			}
		}
		error[i-1]=number-flag;
	}
}

for(i=0,number=0;i<10;i++)
{
  if(error[i]<error[number])
		number=i;
}
printf("%d\r\n",number);
myfree(0,ipDIBBITS);	
myfree(0,pTemp);
return number;

}

参考文献

[1] 陈飞,顾启民,王伟. 基于Proteus和Keil的项目教学法在单片机教学中的应用[J]. 实验科学与技术,2013,11(05):48-52
[2] 高立新. 基于Proteus软件的单片机仿真实验[J]. 常州信息职业技术学院学报,2011,10(03):29-32
[3] 王梓桥,刘沛丰,郝峰,王铮,崔现伟. 基于深度学习的手写数字识别技术应用[J]. 数字技术与应用,2018,36(11):78-79
[4] 周国运. 单片机C语言教学探索[J]. 计算机教育,2009(22):63-65
[5] 陈军,包建华,齐美星. 《单片机原理及接口技术》课程改革探讨[J]. 科技咨询导报,2007(25):165-167
[6 张俊谟. 单片机的发展与应用[J]. 电子制作,2007(08):6-9+42
[7] 肖艳军,毛哲,温博,周围,孙凌宇,孟召宗,刘伟玲. 基于STM32的综合实验平台设计[J]. 实验技术与管理,2019,36(12):72-76
[8] 陈丹,叶飞跃,柳益君,赵小荣. 基于RFID的变电站便携式智能控制系统设计[J]. 实验室研究与探索,2018,37(06):63-67
[9] 杨卫波,阮秀凯,崔桂华. 基于STM32的嵌入式系统实验平台设计[J]. 中国教育技术装备,2017(20):32-34
[10] 廉佐政,王海珍. 基于STM32的PWM输出实验设计[J]. 实验技术与管理,2017,34(08):137-140
[11] 祝永志,张彩廷. 基于Tensor Flow深度学习的Mini-st手写数字识别技术[J]. 通信技术,2020,53(01):46-51
[12] 齐燕. 基于人工智能算法的图像识别与生成研究[J]. 电子元器件与信息技术,2019,3(11):45-47
[13] 蔡玉婷,王外忠,杜孟杰,杨鑫,周铁军. 数字字符识别技术及应用[J]. 电子技术与软件工程,2019(21):66-68
[14] 赛朋飞,李梁娟. 浅析智能交通中数字图像处理技术的运用[J]. 数字技术与应用,2019,37(10):81+83
[15] 吕雪,吴轩. 基于彩色图像分割的数字技术图像识别方案研究(英文)[J]. 机床与液压,2019,47(12):157-162
[16] 楼怡杭. 基于数字图像处理的车牌识别技术[J]. 电子制作,2019(Z1):72-75
[17] 王梓桥,刘沛丰,郝峰,王铮,崔现伟. 基于深度学习的手写数字识别技术应用[J]. 数字技术与应用,2018,36(11):78-79
[18] 马启周. 数字图像处理技术的发展现状及趋势[J]. 电脑迷,2018(11):183
[19] 李苏. 继电保护自动化技术在电力系统中的应用解析[J]. 科技与创新, 2018,(17) :3-4
[20] 张俊谟. 单片机中级教程原理与应用[M]. 北京: 航空航天大学出版社, 2002.4:30-46

致 谢

时光荏苒,岁月如梭,转眼间几个月的毕设时间已经不知不觉地过去了。通过完成此次毕业设计,我学到了很多,提升了自己的理论知识与动手操作能力也有很多的感悟。总而言之,概括为一句话——纸上得来终觉浅,深知此事需躬行。
作为一名工科学生,只学习书本上的知识是远远不够的,还需要很多时间的经验才能支持我们将所学知识转化为生产力。在今后的学习生活之中,要更加努力的学习与实践,不负韶华。须知,国之复兴尽在吾辈。通过完成毕业设计的这一段时间,有很多帮助我的人,需要一一致谢。首先要感谢我的指导老师胡海龙老师和于宏波老师,他们是两位位认真负责有耐心的好老师,在毕业设计之中给了我很多帮助,在论文的选题、资料收集、写作修改以及最终的定稿,老师都倾注了极大的关心和鼓励。在论文的写作过程中,每当我有所疑问,老师总会放下繁忙的工作,孜孜不倦地指点我,给予我答疑解惑,他们为了指导我的毕业论文,放弃了自己的休息时间,这种无私奉献的精神令人敬佩。可以看出他热爱自己的职业,喜欢自己的学生。
此外,感谢每一个帮助我解决问题的同学,在我的学习生涯中遇见他们是一件很幸福的事情。最后,感谢一下自己,从无到有,从不会到会,虽然失败过彷徨过,但仍没有放弃。接下来的日子还很长,吾辈责任亦重,必将再接再厉。

  • 19
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值