今天通过自己的学习,我做了一个智能停车场,首先先来介绍一下他的功能,通过识别车辆的车牌号并在OLED屏幕上显示车牌号,然后升降杆升起,并通过语音播报提示车辆所去的车位,同时会有绿色指示灯提示该车位位置,当此车位停放车辆后,红色指示灯亮起提示该车位已经有车。下面是演示视频。效果还看的过去。
智能车库
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/40bde90c49ff42e1b798dcd8863806f6.png)
前言
相信各位看了这个视频也很想做出一个类似的智能停车场,其实很简单,就是基本的32单片机的知识,和K210的目标检测,接下来我们进入正文。
一、前期准备
1.硬件准备
STM32F103ZET6最小系统板X1
K210开发板X1
SYN6288语音播报X1
0.96寸四角OLED显示屏X1
MG945舵机X1
碳素管X2
木板X1
二极管、杜邦线若干
2.软件准备
Keil5
Maixpy
Mx-yolov3
如果以上的模块和软件,你还没有学习过或者不能熟练使用,可以先去了解各个模块。
二、具体步骤
1.K210篇
首先K210端要做的是识别车牌号并将数据通过串口传送到STM32单片机端,怎么训练模型,怎么实现目标检测,怎么进行串口通信,这些在我之前的博客已经写的很详细了,如果你还不会的话,可以去看我之前的博客。这里附上K210端的源码。
import sensor,image,lcd,time
import KPU as kpu
from machine import UART
from fpioa_manager import fm
lcd.init(freq=15000000)
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_hmirror(0)
sensor.run(1)
task = kpu.load("/sd/chepai.kmodel")
f=open("anchors.txt","r")
anchor_txt=f.read()
L=[]
for i in anchor_txt.split(","):
L.append(float(i))
anchor=tuple(L)
f.close()
f=open("lable.txt","r")
lable_txt=f.read()
lable = lable_txt.split(",")
f.close()
fm.register(10, fm.fpioa.UART1_TX, force=True)
fm.register(11, fm.fpioa.UART1_RX, force=True)
uart_A = UART(UART.UART1, 115200, 8, 1, 0, timeout=1000, read_buf_len=4096)
anchor = (0.1746, 0.1022, 0.2411, 0.3491, 0.2240, 0.5854, 1.0228, 0.9837, 2.128, 1.6843)
sensor.set_windowing((224, 224))
a = kpu.init_yolo2(task, 0.5, 0.3, 5, anchor)
classes=["京N·2B945","苏E·42J68","苏E·82L84" ]
while(True):
img = sensor.snapshot()
code = kpu.run_yolo2(task, img)
if code:
for i in code:
a=img.draw_rectangle(i.rect())
a = lcd.display(img)
list1=list(i.rect())
b=(list1[0]+list1[2])/2
c=(list1[1]+list1[3])/2
uart_A.write(classes[i.classid()]+'\r\n')
else:
a = lcd.display(img)
uart_A.deinit()
del uart_A
a = kpu.deinit(task)
以上便是K210的源码,仅供大家参考。
2.STM32篇
1.接收数据
K210识别到车牌号后需要经32单片机接收数据然后处理数据才可以使用,之前的博客并没有教大家32单片机端如何接收,只是顺带提了一下。这里附上32单片机串口的代码。
uart.c
#include "sys.h"
#include "usart.h"
#if SYSTEM_SUPPORT_OS
#include "includes.h"
#endif
#if 1
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
};
FILE __stdout;
_sys_exit(int x)
{
x = x;
}
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);
USART1->DR = (u8) ch;
return ch;
}
#endif
#if EN_USART1_RX
u8 USART_RX_BUF[USART_REC_LEN];
u16 USART_RX_STA=0;
void USART3_SendData(u8 data)
{
while((USART3->SR & 0X40) == 0);
USART3->DR = data;
}
void USART3_SendString(u8 *DAT, u8 len)
{
u8 i;
for(i = 0; i < len; i++)
{
USART3_SendData(*DAT++);
}
}
void uart_init(u32 bound){
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART1_RX GPIOA.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//Usart1 NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_InitStructure.USART_BaudRate = bound;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);
}
void USART1_IRQHandler(void)
{
u8 Res;
#if SYSTEM_SUPPORT_OS
OSIntEnter();
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART1);
if((USART_RX_STA&0x8000)==0)
{
if(USART_RX_STA&0x4000)
{
if(Res!=0x0a)USART_RX_STA=0;
else USART_RX_STA|=0x8000;
}
else
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;´íÎó,ÖØпªÊ¼½ÓÊÕ
}
}
}
}
#if SYSTEM_SUPPORT_OS
OSIntExit();
#endif
}
#endif
#if EN_USART3_RX
u8 USART3_RX_BUF[];
u16 USART3_RX_STA=0;
void USART3_Init(u32 bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
//USART3_TX GPIOC.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//USART3_RX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//USART3 NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_InitStructure.USART_BaudRate = bound;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART3, &USART_InitStructure);
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
USART_Cmd(USART3, ENABLE);
USART3_RX_STA = 0;
TIM_Cmd(TIM3, DISABLE);
}
void USART3_IRQHandler(void)
{
u8 Res;
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
Res = USART_ReceiveData(USART3);
if((USART3_RX_STA & 0x8000) == 0)
{
if(USART3_RX_STA < USART3_REC_LEN)
{
TIM_SetCounter(TIM3, 0);
if(USART3_RX_STA == 0)
{
TIM_Cmd(TIM3, ENABLE);
}
USART3_RX_BUF[USART3_RX_STA++] = Res;
}
else
{
USART3_RX_STA |= 1 << 15;
}
}
}
}
#endif
uart.h
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "sys.h"
#define USART_REC_LEN 200
#define EN_USART1_RX 1
#define USART3_REC_LEN 200
#define EN_USART3_RX 1
extern u8 USART3_RX_BUF[USART3_REC_LEN];
extern u16 USART3_RX_STA;
void USART3_SendString(u8 *DAT,u8 len);
void USART3_SendData(u8 data);
void USART3_Init(u32 bound);
extern u8 USART_RX_BUF[USART_REC_LEN];
extern u16 USART_RX_STA;
void uart_init(u32 bound);
#endif
2.SYN6288语音播报
语音播报模块用来提示车辆应该停的车位
SYN6288.c
#include "syn6288.h"
#include "usart.h"
#include "string.h"
#include "delay.h"
void SYN_FrameInfo(u8 Music, u8 *HZdata)
{
unsigned char Frame_Info[50];
unsigned char HZ_Length;
unsigned char ecc = 0;
unsigned int i = 0;
HZ_Length = strlen((char*)HZdata);
Frame_Info[0] = 0xFD ;
Frame_Info[1] = 0x00 ;
Frame_Info[2] = HZ_Length + 3;
Frame_Info[3] = 0x01 ;
Frame_Info[4] = 0x01 | Music << 4 ;
for(i = 0; i < 5; i++)
{
ecc = ecc ^ (Frame_Info[i]);
}
for(i = 0; i < HZ_Length; i++)
{
ecc = ecc ^ (HZdata[i]);
}
memcpy(&Frame_Info[5], HZdata, HZ_Length);
Frame_Info[5 + HZ_Length] = ecc;
USART3_SendString(Frame_Info, 5 + HZ_Length + 1);
}
void YS_SYN_Set(u8 *Info_data)
{
u8 Com_Len;
Com_Len = strlen((char*)Info_data);
USART3_SendString(Info_data, Com_Len);
}
uart.h
#ifndef __SYN6288_H
#define __SYN6288_H
#include "sys.h"
void SYN_FrameInfo(u8 Music, u8 *HZdata);
void YS_SYN_Set(u8 *Info_data);
#endif
3.OLED
OELD用来显示识别到的车牌号
oled代码太多了,包括汉字库,字符库。如果有需要可以去我主页下载。
4.舵机和二极管
通过舵机控制升降杆升降,二极管的作用的提示,引导与警示。
完整的工程代码我放到主页里了,有需要可以去下载。
到这里,这篇博客就结束了,感谢大家能够看到最后一行。
总结
大概用了不到一天的时间将这个项目做了出来,车牌识别准确率还是很稳定的,最后的效果也还可以,写这篇博客也记录自己大学做过的项目。同样还是送给大家一句话。
星路撒下的光芒,是承载过努力的力量。你的汗水与努力,最终会化作一切的美好,回报给你!加油,未来可期。