主要介绍
本设计采用的是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=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[k*tempW+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)&&(1==white)) in=1;
if((1==in)&&(1==white)) num++;
if((1==in)&&(0==white)&&(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;
}
电路原理图:
)
四、结论
本设计采用STM32作为主控芯片,利用ov7670进行数字识别、将LCD1602作为显示屏,通过光的反射影响AD采样值不同这一原理完成循迹。在按键输入取货码后,识别数字,按照程序设定,小车到达指定取货位置,停留5秒进行取件并由ov7670摄像头进行扫描确认快递无误后,再同样的循迹原理按照原路返回。
本设计主要实现的功能有:
⑴ 通过ov7670完成图像的获取;
⑵ 通过程序及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