本系统有STM32F103RCT6单片机核心板、2.8寸TFT液晶屏显示、摄像头图像采集OV7670、蜂鸣器、LED电路组成。
1、stm32单片机通过摄像头采集图像,并实时驱动TFT液晶屏显示相应图像。
2、stm32单片机通过模式识别、匹配货的车牌的识别结果,并在屏幕上进行显示。
3、识别主要过程包括图像采集、二值化分析、识别车牌区域、字符分割、字符匹配五个过程。
4、车牌锁定后会有蜂鸣器提醒,在分析获取到车牌后对车停留时间进行计时,并进行计费。
5、在图像采集界面,通过按键可以进入后台计费界面。在车牌识别后进入计费界面,可以通过按键退出计费界面,回到图像采集界面。
注意:单片机处理能力及速率有限,目前识别汉字:渝、辽、沪、浙、苏、粤,车牌图片一定要清晰,无反光,容易识别。
车牌识别操作技巧与按键功能说明:
1、重要一点,通过摄像头前面螺钮可以调焦,拧到直到液晶显示图像最清晰(一般我们调试好的)。
2、尽量让车牌号处于液晶中央位置,让车牌号内容处于两蓝线之间,且两蓝线处于红线上方。
3、位置合适后,进入倒计时,到时蜂鸣器会“嘀”的一声响,表示开始分析识别。识别需要一定时间。
3.在没有识别出车牌前,按下K1可查看已经识别出的车牌信息,并可看到计费信息(模拟停车场),识别出车牌后,显示车牌信息后, 需要按下按键K2,方可返回主界面。
完整版 电路图和程序代码 下载地址
https://pan.baidu.com/s/1DN7P8MI8L9D5lYj-Qi6fTA?pwd=3456
部分代码展示
#include "stm32f10x.h"
#include "stm32f10x_it.h"
#include "led.h"
#include "key.h"
#include "usart.h"
#include "delay.h"
#include "lcd.h"
#include "ov7670.h"
#include "string.h"
#include "bsp_esp8266.h"
//#define WIFI
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
vu8 cur_status=0;
vu8 LED_flag=0;
//vu32 a=0;
//vu32 b=0;
vu16 AA=0,BB=0;
vu16 color=0;
vu16 color_save=0;//保存一个像素的值
vu8 R=0,G=0,B=0;//颜色分量
vu8 TableChangePoint_240[240];//跳变点240个
vu8 Max_ChangePoint_240=0,Min_ChangePoint_240=0,Max_bChangePoint=0,Min_bChangePoint=0;//跳变点纵轴始、末坐标,跳变点横轴始、末坐标
vu8 a_Continue=0,b_Continue=0;//记录纵、横轴突变点的连续性
vu8 flag_aMax=0;//末值更新标志
vu8 Max_aChangePoint_reset=0,Min_aChangePoint_reset=0;//修正后的上下限
vu16 Length_card=0,Width_card=0;//车牌的长和宽
vu8 Max_aChangePoint_reset_1=0,Min_aChangePoint_reset_1=0;//保存上次的数据
vu8 flag_MaxMinCompare=0;//Max_aChangePoint_reset_1和Max_aChangePoint_reset的标志
vu8 TableChangePoint_320[320];//纵向跳变点320个
float V=0.00,S=0.00,H=0.00;//定义HSV值
vu16 Min_blue=0;
vu16 Max_blue=0;//定义车牌蓝色区域的横向最大值和最小值
vu16 k1=0,kk1=0,k2=0,kk2=0,k3=0,kk3=0,k4=0,kk4=0,k5=0,kk5=0,k6=0,kk6=0,k7=0,kk7=0,k8=0,kk8=0;//八个字符边界
extern vu8 Table[6300];//所有字符集 (10+26)*150 = 5400 字节
extern vu8 talble_0[150];//字符3,测试用
extern vu8 table_yu[32];//渝字
extern vu8 table_min[32];//闽字
extern vu8 table_lu[32];//鲁字
extern vu8 table_zhe[32];//浙字
extern vu8 table_shan[32];//陕字
extern vu8 table_cuan[32];//川字
vu8 R_a=0,G_a=0,B_a=0;//阈值
vu8 table_picture[150];//定义保存图片的数组
vu8 table_char[36]={0,1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',};
vu8 table_char_char[36]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',};
vu8 table_card[5][8]={ //保存5个车牌的二维数组
{0,0,0,0,0,0,0,0}, //最后一位保存时间
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
};
vu8 tim3_num=0;//TIM3分钟计时
vu8 table_cardMeasure[7];//测量的车牌结果
void Show_Card(vu8 i);//显示第几组车牌
void Show_Title();//显示标题
void MYRCC_DeInit(void)//复位并配置向量表
{
NVIC_InitTypeDef NVIC_InitStructure;
RCC->APB1RSTR = 0x00000000;//复位结束
RCC->APB2RSTR = 0x00000000;
RCC->AHBENR = 0x00000014; //睡眠模式闪存和SRAM时钟使能.其他关闭.
RCC->APB2ENR = 0x00000000; //外设时钟关闭.
RCC->APB1ENR = 0x00000000;
RCC->CR |= 0x00000001; //使能内部高速时钟HSION
RCC->CFGR &= 0xF8FF0000; //复位SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0]
RCC->CR &= 0xFEF6FFFF; //复位HSEON,CSSON,PLLON
RCC->CR &= 0xFFFBFFFF; //复位HSEBYP
RCC->CFGR &= 0xFF80FFFF; //复位PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE
RCC->CIR = 0x00000000; //关闭所有中断
/* Enable the TIM3 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
void Stm32_Clock_Init(vu8 PLL)//系统时钟初始化函数 pll:选择的倍频数,从2开始,最大值为16
{
unsigned char temp=0;
MYRCC_DeInit(); //复位并配置向量表
RCC->CR|=0x00010000; //外部高速时钟使能HSEON
while(!(RCC->CR>>17));//等待外部时钟就绪
RCC->CFGR=0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1;
PLL-=2;//抵消2个单位
RCC->CFGR|=PLL<<18; //设置PLL值 2~16
RCC->CFGR|=1<<16; //PLLSRC ON
FLASH->ACR|=0x32; //FLASH 2个延时周期
RCC->CR|=0x01000000; //PLLON
while(!(RCC->CR>>25));//等待PLL锁定
RCC->CFGR|=0x00000002;//PLL作为系统时钟
while(temp!=0x02) //等待PLL作为系统时钟设置成功
{
temp=RCC->CFGR>>2;
temp&=0x03;
}
}
void LED()//LED指示灯-提示
{
GPIO_WriteBit(LED1_GPIO_PORT, LED1_GPIO_PIN,LED_flag>>7);
LED_flag=~LED_flag;
}
void Data_LCD_Display()//常规显示
{
vu16 a=0,b=0;
LCD_SetWindows(0,0,320,240);//设置显示窗口
GPIO_WriteBit(LCD_RS_PORT, LCD_RS_PIN,1);//标志:数据写入
while(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_0)==1);
GPIO_WriteBit(FIFO_WRST_PORT, FIFO_WRST_PIN, 0);
GPIO_WriteBit(FIFO_WRST_PORT, FIFO_WRST_PIN, 1);
GPIO_WriteBit(FIFO_WR_PORT, FIFO_WR_PIN, 1);
while(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_0)==0);
while(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_0)==1);
GPIO_WriteBit(FIFO_WR_PORT, FIFO_WR_PIN, 0);
FIFO_Reset_Read_Addr();
for (a=0;a<240;a++)
{
for(b=0;b<320;b++)
{
GPIOC->BRR =1<<4;
AA=GPIOA->IDR;
GPIOC->BSRR =1<<4;
GPIOC->BRR =1<<4;
BB=GPIOA->IDR&0x00ff;
GPIOC->BSRR =1<<4;
color=(AA<<8)|BB;
LCD_DATA_PORT->ODR = color;
GPIOC->BRR =1<<11;
GPIOC->BSRR =1<<11;
}
}
}
void RGB_HSV(vu16 num)//RGB565转HSV
{
float max=0.00,min=0.00;
vu8 r=0,g=0,b=0;
r=(num>>11)*255/31;g=((num>>5)&0x3f)*255/63;b=(num&0x1f)*255/31;
max=r;min=r;
if(g>=max)max=g;
if(b>=max)max=b;
if(g<=min)min=g;
if(b<=min)min=b;
V=100*max/255;//转换为百分比
S=100*(max-min)/max;//扩大100倍显示
if(max==r) H=(g-b)/(max-min)*60;
if(max==g) H=120+(b-r)/(max-min)*60;
if(max==b) H=240+(r-g)/(max-min)*60;
if(H<0) H=H+360;
}