博主主页:单片机辅导设计
博主简介:专注单片机技术领域和毕业设计项目。
主要内容:毕业设计、简历模板、学习资料、技术咨询。
文章目录
主要介绍
本设计采用的是STM32F103C8T6单片机作为主控模块,视觉识别系统采用带FIFO的OV7670作为信号输入,实现数字识别的功能。显示系统部分采用的是ILI9341显示屏,具有显示及触摸功能,提高取货准确率。循迹部分采用的是黑色胶带对光的反射作用会对光敏电阻的阻值产生影响,继而实现本设计的循迹功能,确保小车不会脱轨,电机驱动部分采用强磁直流减速电机,为本设计提供驱动力。另外,本设计通过控制电机正反转实现设计的自由变换方向和启动停止。通过视觉识别功能,可以达到准确识别取货码,确定位置,实现取货的要求。
一、系统主要功能
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 数字识别过程框图
二、 软件设计
3.1系统主程序设计
主程序循环模块中的程序执行优先级应是最低的。主程序的设计首先应包含单片机初始化,以及开机过程中所必要的实施模块,这些模块大部分只在单片机开机复位结束之后执行一次。其次,单片机应该具有循环执行的模块,这些模块即是在单片机运行过程中保持单片机一直运行的模块。在程序设计中,最重要的操作是确定程序流程框图。
如图3.1主程序流程框图所示,主程序部分包括系统的初始化、等待取货码、循迹、识别、完成取货、最后返回。如图可知,这个循环处理模块分别包含等待取货码、循迹、识别、完成取货四个部分。
3.2 数字识别子程序设计
数字识别实现的基本过程是:灰度处理、二值化、图像分割、识别。
子程序设计图如图3.2所示。
三、实物展示
系统主要有六个部分组成:电源模块、ov7670模块、电机驱动模块、显示模块、按键模块以及主控模块这六个模块组成,在系统的搭建上,采用模块分别进行的方式在万用板上搭建电路。分模块进行的好处就是系统走线比较清晰,适合在万用板上进行电路的搭建。四节干电池放在电池盒内,与此同时引出两根导线,与电路板相接,为整个系统提供电流,系统控制主要模块展示如图4.1所示:
循迹模块展示图如图4.2所示:
图4.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(1==mode)
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(4==mode)
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