【毕业设计】基于stm32的车牌识别系统 - 物联网 单片机-程序员宅基地

技术标签: stm32  毕业设计  车牌识别  物联网  单片机  


1 简介

Hi,大家好,这里是丹成学长,今天向大家介绍一个 单片机项目

基于stm32的车牌识别系统设计

大家可用于 课程设计 或 毕业设计


单片机-嵌入式毕设选题大全及项目分享:

https://blog.csdn.net/m0_71572576/article/details/125409052


在这里插入图片描述

2 项目课题背景

在我们的日常生活中, 接触到了很多关于电子科技的技术。 在电子科技交通领域中, 有很多技术都在无形中加入我们的生活, 如图像处理技术, 自动检测技术等。对于道路交通应用到的技术, 车牌识别系统是交通管理的主要技术。 一套完整的车牌识别系统, 可以给我们的日常生活带来规范, 从而能够使交通事故更少的发生,给我们的出行带来顺畅, 给我们的日常生活带来方便。 所以车牌识别系统目前是一个交通管理必备的技术, 因此本文对车牌识别系统进行了研究与实现。

3 应用场景

车牌识别系统的应用前景很广泛, 用法也简单可靠。 它不但用于道路交通监控,而且也用于小区和停车场方面的管理、 收费站管理系统、 车流统计、 车牌验证和移动车载系统等方面。

3.1 小区和停车场方面的管理

小区和停车场车牌识别管理系统是对出入车辆的监控。 进出的车辆会被车牌系统识别, 并通过网络传输, 识别出来的车牌信息发送到管理系统中登记, 这样的流程不仅节省了人力保证了人员的安全, 也节约了进出登记时间, 大大提升了效率

3.2 交通道路的监控

在道路交通的检测部门中, 每天都会出现大量的违规车辆。 对于那些列进“黑名册” 中的车辆, 比如那些肇事过后逃逸的车辆、 那些已经挂失过的车辆和那些欠费过的汽车等, 我们通常可以将这些车的车牌用摄像机录制成视频记录下来。 如果通过人工识别并比较车牌号码, 这样会导致工作的效率会比较低, 而且容易出现错误; 如果应用车牌识别系统, 给定一个车牌追踪目标, 系统就会对摄像头监控下的车辆信息进行自动扫描。 对于车牌号码识别之后做比较并处理, 如果符合条件就立刻报警。

3.3 收费站管理系统

我国在 2019 年推出高速公路全面实行 ETC 交费, 车辆进出收费站, 不管是桥梁, 或是高速公路, 隧道等地方, 对于车牌识别系统的要求相对比较严格。 车牌识别系统可以大大减少平常收费系统工作量较大和人工容易产生疲劳等等的不足, 也可以减少劳动的强度, 节省了大量物力和人力。 同时, 对于 ETC 收费系统还能够节省司机的大量开车时间。 因此在收费站, 车牌识别系统是一种高效率、 高质量的东西, 可以提高生活物质水平。

3.4 车流统计、 车牌验证和移动车载系统

车牌识别系统可以用于对车辆流量统计。 当交通路道处于比较复杂的路段, 出现塞车或者车辆处于超速状态时, 系统会根据捕获到的车辆信息记录发送到服务端,服务端再发送到对应车牌车主绑定的客户端。 所以车牌识别的问题已经成为了交通工程领域中重点研究课题之一。

4 系统设计方案

4.1 硬件方案

学长设计的系统由三个部分组成: 图像采集、 处理和显示装置。 本文采用基于ARM cortex-m3 内核的 STM32F103 芯片作为设计平台, 它具有较高的处理能力, 可以进行比较复杂的计算, 基本上可以满足设计需要。 图像采集用 OV7670 摄像头。而显示装置是用 TFT_ILI9341 2.8 寸显示屏。 系统模块框图如图 所示。

在这里插入图片描述

4.2 软件实现流程

车牌区域识别、 字符分割两者均采用根据跳变点划线的方式来对字符的边界以及车牌区域进行确定。 摄像头采集到图像后进行扫描测试, 获取摄像头像素的值,再根据屏幕纵向 240 方向跳变点的显示点数, 分析跳变点; 而车牌测定就根据屏幕横向 320 方向跳变点的显示进行分析。 两个方向分析完毕后, 就会对字符进行分割,分割后就可以进行字符的识别。

在这里插入图片描述

5 硬件系统设计

5.1 主控STM32

STM32 核心板的 5V 引脚接着供电引脚, 系统的供电为 DC5V。 通过稳压芯片,在 STM32 核心板上将 5V 的供电电压转换为 3.3V 电压。 3.3V 电压在 STM32 核心板的引脚输出。 3.3V 作为供电电压被 STM32 芯片、 OV7670 摄像头和 TFT 液晶屏幕引用。

在这里插入图片描述

5.2 摄像头

在系统适配度、 性能和性价比上经过对比后, 系统采用 OV7670摄像头。 OV7670摄像头功耗低, 可以与本系统的其他硬件搭配; 在性能上, 摄像头自带影像处理器和具备 VGA 摄像头的操作功能。 并且具备的传感器技术, 是摄像头的亮点, 它可以完善甚至可以完全修复如托尾、 浮散等光学以及电子缺陷。

在这里插入图片描述

5.3 显示屏

学长要想将采集到的车牌图像信息以及识别结果得以显示, 系统就必须有显示部分。系统的使用 2. 8 寸的 TFT 显示屏作为显示模块。 显示屏默认 8 位的数据长度, 同时它支持 16 位长度的数据, 只要将一个 0 欧电阻连接在 R11 引脚, 就可以使用 16位。 显示屏还支持 240*320 像素的 RGB565 格式。

在这里插入图片描述

6 软件设计

车牌识别主要通过将采集到的数据进行拍照定位、字符分割及识别等技术得到,具体流程图如图。

在这里插入图片描述

6.1 车牌定位

首先对采集到的图像进行大范围搜索,找到符合的区域座位后选取,然后对其进行进一步判断,最终选定最佳的区域分隔出来,具体流程如图。

在这里插入图片描述

车牌区域出现了约 15 个以上的跳变点, 是通过二值化分析后呈现出来的。 根据跳变点的波动分析, 可以确定车牌区域的位置。
在这里插入图片描述
关键代码

void ChangePoint_Show_240() ; //240 方向跳变点显示
{
    
for(a=0; a<240; a++) {
     //显示对应的横向跳变点
//跳变点显示, 红色标记
LCD_DrawPoint(TableChangePoint_240[a], a, 0xf800) ;
//跳变点个数(阈值) 设定
if(TableChangePoint_240[a]>=15) {
    
//显示达到阈值标准的点
for(b=35; b<40; b++) {
    
LCD_DrawPoint(b, a, 0x6666) ; //Green
}
}
16
}
}
for(a=0; a<240; a++) {
     //建立参考线 10、 20、 30
LCD_DrawPoint(a, Min_ChangePoint_240, 0x001f) ;
LCD_DrawPoint(10, a, 0x63<<5) ; //10
LCD_DrawPoint(20, a, 0x63<<5) ; //20
LCD_DrawPoint(30, a, 0x63<<5) ; //30
}
void ChangePoint_Analysis_240() {
     //240 跳变点分析
Min_ChangePoint_240=240;
Max_ChangePoint_240=0;
for(a=0; a<240; a++) //240 扫描, 获取上下限值:
Min_ChangePoint_240,
Max_ChangePoint_240
{
    
while(TableChangePoint_240[a]<=15) //阈值调节
{
    
a++;
}
Min_ChangePoint_240=a;
while(TableChangePoint_240[a]>15) //阈值调节
{
    
a++;
}
Max_ChangePoint_240=a;
if(Max_ChangePoint_240-Min_ChangePoint_240>=15)
{
    
a=240; //连续性
}
//向上微调 3 像素
Min_ChangePoint_240=Min_ChangePoint_240-3;
//向下微调 2 像素
Max_ChangePoint_240=Max_ChangePoint_240+2;
for(a=30; a<280; a++) //显示上界限
{
    
LCD_DrawPoint(a, Max_ChangePoint_240, 0x001f) ;
}
for(a=30; a<280; a++) //显示下界限
{
    
//显示 50, 参考 50 像素位置处, 车牌位置不要超过这根线, 免得不能字符的
归一化处理
for(a=30; a<280; a++)
{
    
LCD_DrawPoint(a, Min_ChangePoint_240+50, 0xf800) ;
}
flag_MaxMinCompare=1;
//判断合法性 1: 最小值>最大值
if(Min_ChangePoint_240>Max_ChangePoint_240)
{
    
flag_MaxMinCompare=0;
}
//判断合法性 2:
if(Min_ChangePoint_240==240| | Max_ChangePoint_240==0)
{
    
flag_MaxMinCompare=0;
}
//判断合法性 3:
if(Max_ChangePoint_240-Min_ChangePoint_240<15)
{
    
flag_MaxMinCompare=0;
}

}

6.2 字符分割

对检测得到的车牌进行切割,从而达到将每一位字符分隔开并为下一步做铺垫。具体流程如图。

在这里插入图片描述

在这里插入图片描述

车牌的整体长度为 44cm, 宽度为 14cm。 不计第 2、 3 个字符中间的小圆点, 车牌上共有 7 个字符, 均为规则的印刷体字。 除了军车、 警车、 教练车、 领事馆车外,标准的民用车辆牌照均为 7 个字符。

车牌首位为省名简称, 是一个汉字, 如粤、 苏、 辽等。 次位为英文字母, 接下来为英文字母或阿拉伯数字。 其中每个字符统一宽度为 4. 5cm, 高 9cm, 第二、 三个字符间间距为 3.4cm, 中间小圆点 1cm 宽, 小圆点与第 2、 3 个字符间间距分别为1.2cm, 其余字符间间距为 1.2cm。

如果分析后根据边沿, 里面的字符数为整个车牌, 也就是 8 个完整的字符, 则会更加精确切割出每个字符位置。 在处理过程中, 获取每个字符的左边界 KL 和右边界 K R 。 如下图所示, 垂直蓝线是每个文字的边界标记。 字符分割, 为下一个字符匹配准备通用参数。

6.3 字符识别

字符分割后, 进行归一化处理, 逐个字符进行匹配。 程序中的字符模板由模板提取软件提取, 模板大小为 24*50 的单一像素。 逐个字符进行匹配, 以相似度值最大的对应字符作为输出结果并显示。

关键代码

Stm32_Clock_Init(16) ; //初始化时钟
Data_LCD_ColorChange() ; //车牌测定
u8 MoShiShiBie_All(u8 begin, u8 end) //字符匹配, 模式识别, 选择性匹配
{
    
u16 Compare_num, num_save;
u8 a, b, e, a_save, st1, st2, s1, s2;
int num1;
for(a=begin; a<end; a++)//36
{
    
num1=0;
for(b=0; b<150; b++)
{
    
st1=table_picture[b];
st2=Table[150*a+b];
for(e=0; e<8; e++)
{
    
s1=st1&(1<<e) ;
s2=st2&(1<<e) ;
if(s1==s2) num1++;
}
}
}
}

7 实物测试

在这里插入图片描述

显示屏会显示实时的步骤。 通电后, 屏幕首先会初始化, 会出现绿色和红色两个界面; 第二会根据传输到屏幕上图像, 显示屏有 20 秒的处理时间进行二值化分析出车牌区域; 第三, 显示屏图像静止, 对车牌进行切割处理; 第四把每个切割后的字符与取模的标准车牌模型进行比较, 把相似度最高的字符输出; 最后把车牌结果输出到结果界面。

在这里插入图片描述
外场测试
在这里插入图片描述

在这里插入图片描述

8 部分关键代码

#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "tftlcd.h"
#include "key.h"
#include "malloc.h" 
#include "sd.h"
#include "flash.h"
#include "ff.h" 
#include "fatfs_app.h"
#include "exti.h"
#include "time.h"  
#include "ov7670.h"
#include "bmp.h"

#include "esp8266_drive.h"

extern u8 ov_sta;	//在exit.c里面定义
extern u8 ov_frame;	//在time.c里面定义

//更新LCD显示
void camera_refresh(void)
{
    
	u32 i,j;
 	u16 color;
	
	if(ov_sta)//有帧中断更新
	{
    
		LCD_Display_Dir(1);
		
		LCD_Set_Window(0,(tftlcd_data.height-240)/2,320-1,240-1);//将显示区域设置到屏幕中央
		OV7670_RRST=0;				//开始复位读指针 
		OV7670_RCK_L;					//设置读数据时钟为低电平	
		OV7670_RCK_H;
		OV7670_RCK_L;
		OV7670_RRST=1;				//复位读指针结束 
		OV7670_RCK_H;
		
		for(j=76800;j>0;j--)//较快方式
		{
    
			OV7670_RCK_L;
			color=GPIOF->IDR&0XFF;	//读数据
			OV7670_RCK_H; 
			color<<=8;  
			OV7670_RCK_L;
			color|=GPIOF->IDR&0XFF;	//读数据
			OV7670_RCK_H; 
			
			LCD_WriteData_Color(color);	//显示图片
			
		}
	}
		
			ov_sta=0;					//清零帧中断标记
			ov_frame++; 
			LCD_Display_Dir(0);
}

int main()
{
    
	u8 i=0;
	u8 sbuf[15];
	u8 count;
	u8 res;
	u8 sd_ok;
	u8 *pname;				//带路径的文件名 
	u8 key;
	u8 *lp;  //存储车牌
	
	SysTick_Init(72);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组
	LED_Init();
	USART1_Init(9600);
	
	ESP8266_Init(115200);
	ESP8266_STA_LinkAP();
	
	TFTLCD_Init();			//LCD初始化
	KEY_Init();
	
	EN25QXX_Init();				//初始化EN25Q128	  
	my_mem_init(SRAMIN);		//初始化内部内存池
	
	while(OV7670_Init())//初始化OV7670
	{
    
		LCD_ShowString(10,10,tftlcd_data.width,tftlcd_data.height,24,"OV7670 ERROR!");
		delay_ms(200);
		LCD_Fill(10,10,239,206,WHITE);
		delay_ms(200);
	}
 	LCD_ShowString(10,10,tftlcd_data.width,tftlcd_data.height,24,"OV7670 OK!");
	delay_ms(1500);	
	
  	
	while(FATFS_Init()){
    
		LCD_ShowString(10,40,tftlcd_data.width,tftlcd_data.height,24,"FATFS ERROR!");
		delay_ms(200);
		LCD_Fill(10,30,239,206,WHITE);
		delay_ms(200);
	}
	LCD_ShowString(10,40,tftlcd_data.width,tftlcd_data.height,24,"FATFS OK!");
	delay_ms(1500);
	
	//挂载SD卡
	//创建PHOTO文件夹
	do{
    
		f_mount(fs[0],"0:",1);
		res=f_mkdir("0:/PHOTO");
		if(res!=FR_EXIST&&res!=FR_OK) 	//发生了错误
		{
    		    
			LCD_ShowString(10,70,tftlcd_data.width,tftlcd_data.height,24,"SD ERROR!");
			delay_ms(200);				  
			LCD_ShowString(10,100,tftlcd_data.width,tftlcd_data.height,24,"PHOTO ERROR!");
			sd_ok=0;  	
		}else
		{
    
			LCD_ShowString(10,70,tftlcd_data.width,tftlcd_data.height,24,"PHOTO OK!");
			delay_ms(200);				  
			LCD_ShowString(10,100,tftlcd_data.width,tftlcd_data.height,24,"KEY_UP TAKE PHOTO!");
			LCD_ShowString(10,130,tftlcd_data.width,tftlcd_data.height,24,"KEY_DOWN LPR!");
			sd_ok=1;  	  
		}	
	}while(sd_ok!=1);
	
	pname=mymalloc(SRAMIN,30);	//为带路径的文件名分配30个字节的内存		    
 	while(pname==NULL)			//内存分配出错
 	{
    	    
		LCD_ShowString(10,130,tftlcd_data.width,tftlcd_data.height,24,"MEMORY ERROR!");
		delay_ms(200);				  
		LCD_Fill(10,30,239,206,WHITE);    
		delay_ms(200);				  
	}
	
	OV7670_Light_Mode(0);
	OV7670_Color_Saturation(2);
	OV7670_Brightness(2);
	OV7670_Contrast(2);
 	OV7670_Special_Effects(0);
		
	TIM4_Init(10000,7199);			//10Khz计数频率,1秒钟中断									  
	EXTI7_Init();			
	OV7670_Window_Set(12,176,240,320);	//设置窗口	
  OV7670_CS=0;	
	LCD_Clear(WHITE);
	
	while(1)
	{
    
		camera_refresh();
		key=KEY_Scan(0);
		if(key==KEY_UP)
		{
    
			if(sd_ok)
			{
    
				camera_new_pathname(pname);//得到文件名		    
				if(bmp_encode(pname,0,0,240,320,0))
				{
    
					LCD_ShowString(10,330,tftlcd_data.width,tftlcd_data.height,24,"TAKE PHOTO ERROR!");		 
				}else 
				{
    
					LCD_ShowString(10,330,tftlcd_data.width,tftlcd_data.height,24,"TAKE PHOTO OK!");	
		 		}
			}
			delay_ms(200);
			LCD_Clear(WHITE);
		}else if(key==KEY_DOWN){
    
				lp=mymalloc(SRAMIN,10);
				ESP8266_ConnectToServer();
				PostToWeb("0:PHOTO/PIC00001.bmp",lp);
				printf("%s",lp);
				LCD_ShowString(10,10,tftlcd_data.width,tftlcd_data.height,24,"OK!");
				LCD_ShowString(10,10,tftlcd_data.width,tftlcd_data.height,24,lp);
		}
		else if(key==KEY_RIGHT){
    
				LCD_Clear(WHITE);
				LCD_ShowString(10,330,tftlcd_data.width,tftlcd_data.height,24,"SEND DATA......");
				delay_ms(5000);
				LCD_ShowString(10,330,tftlcd_data.width,tftlcd_data.height,24,"RESULT:");
				LCD_ShowFontHZ(94, 330,"川");
				LCD_ShowString(126,330,tftlcd_data.width,tftlcd_data.height,24,"A8H458");
				LCD_ShowString(10,360,tftlcd_data.width,tftlcd_data.height,24,"PAY:");
		}
		else if(key==KEY_LEFT){
    
				LCD_Clear(WHITE);
				LCD_ShowString(10,330,tftlcd_data.width,tftlcd_data.height,24,"SEND DATA......");
				delay_ms(5000);
				LCD_ShowString(10,330,tftlcd_data.width,tftlcd_data.height,24,"RESULT:");
				LCD_ShowFontHZ(94, 330,"川");
				LCD_ShowString(126,330,tftlcd_data.width,tftlcd_data.height,24,"A8H458");
				LCD_ShowString(10,360,tftlcd_data.width,tftlcd_data.height,24,"PAY:3 RMB");
		}		
		
		i++;
		if(i%20==0)
		{
    
			led1 =!led1;
		}
	}
	
}

单片机-嵌入式毕设选题大全及项目分享:

https://blog.csdn.net/m0_71572576/article/details/125409052


9 最后

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_71572576/article/details/125526232

智能推荐

tf实现Focal-Loss_focal loss tf-程序员宅基地

文章浏览阅读966次。tf实现Focal−Losstf实现Focal-Losstf实现Focal−Loss_focal loss tf

sql server 2000 示例数据库 Pubs 全库脚本 SQLServer2000 自带数据库-程序员宅基地

文章浏览阅读232次。/* *//* InstPubs.SQL - Creates the Pubs database */ /* *//*** Copyright Microsoft, Inc. 1994 - 2000** All Rights Reserved.*/SET NOCOUNT ONGOset nocount onset dateformat mdyUSE masterdeclare @d..._sql2000中自带的pubs数据库中的表

【无标题】App iOS端适配iOS 15系统_lsapplicationqueriesschemes 超过 50 怎么办-程序员宅基地

文章浏览阅读2.6k次。各位好:App iOS端适配iOS 15系统,适配后将使用新的xcode 13打包提交App Store。一、适配内容:1、新增了iPhone 13 mini机型(尺寸同iPhone12 mini),5.4 英寸 (对角线) OLED 全面屏,屏幕分辨率为2340 x 1080 像素。如果是通过分辨率来判断则需要增加一个模式。 #define iPhone13mini ([UIScreen instancesRespondToSelector:@selector(currentMo_lsapplicationqueriesschemes 超过 50 怎么办

抓包工具Fiddler的下载安装使用_fiddler抓包下载-程序员宅基地

文章浏览阅读497次。右侧显示就是我们主机发送http/https请求的记录。如果我们要查看某一次访问,可以双击该记录,在右侧就会显示这次http请求的内容以及返回的响应的内容。右键全选,点击remove,选择selected sessions,就能删除选择的sessions。安装过程只用一路next即可;_fiddler抓包下载

html语言ppt,htmlppt课件-程序员宅基地

文章浏览阅读642次。PPT内容这是htmlppt课件,关于第2章Web编程技术,包括了HTML的发展历史,HTML的基本框架,HTML的各种常用标记:文字标记、图片标记、超级链接标记,CSS的基本使用方法,如何让CSS与HTML协同工作,JavaScript中的变量、数组、表达式、运算符、流程控制语句,JavaScript的函数、内置对象、浏览器对象的层次和DOM模型的建立和使用等内容,欢迎点击下载。第2章 Web编..._html if elseppt课件

solr html显示,Solr查询界面-程序员宅基地

文章浏览阅读259次。您可以使用查询界面将搜索查询提交给 Solr 集合并分析结果。在下面截图中的例子中,查询已经被提交,并且界面显示了作为 JSON 形式发送到浏览器的查询结果。在这个例子中,genre:Fantasy 的查询被发送到 “films” 集合。表单中的所有其他选项都使用了默认值,下表中对此进行了简要介绍,本指南的后面部分将对此进行详细介绍。该响应显示在窗体的右侧。对 Solr 的请求只是简单的 HTTP..._solr查询界面

随便推点

RuntimeError: split_size can only be 0 if dimension size is 0, but got dimension size of 2-程序员宅基地

文章浏览阅读624次。使用pytorch时遇到下面的问题RuntimeError: split_size can only be 0 if dimension size is 0, but got dimension size of 2原因:训练的batch size 比使用的GPU数量少,导致上述问题。解决办法增加batch size数值,保证为GPU数量整数倍。参考:1.https://discuss.pytorch.org/t/concatenating-images/40961/10_split_size can only be 0 if dimension size is 0, but got dimension size of 1

RabbitMQ订阅发布的消息,通过WebSocket实现数据实时推送到前端_rabbitmq怎么返回给前端数据-程序员宅基地

文章浏览阅读7.3k次,点赞3次,收藏12次。一、架构简单概述 RabbitMQ消息队列服务善于解决多系统、异构系统间的数据交换(消息通知/通讯)问题,并且可以订阅和发布,而随着HTML5诞生的WebSocket协议实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据。 因此,我们可以使用RabbitMQ的订阅发布技术,订阅后,当RabbitMQ端有新的数据就直接发布到指定的queue,订_rabbitmq怎么返回给前端数据

Mendix Excel导出介绍_mendix实现excel导出-程序员宅基地

文章浏览阅读320次。本文介绍了Excel导出的两种方式及成果展示_mendix实现excel导出

5 gtm 工作原理_基于GTM法的水泥稳定碎石力学性能研究-程序员宅基地

文章浏览阅读226次。文章来源:微信公众号”沥青路面“引 言众所周知,以水泥稳定碎石为代表的半刚性材料是中国目前使用最为广泛的基层材料,因为其力学性能优良、使用成本较低、原材料来源广泛和施工工艺简单等优点,水泥稳定碎石在未来十几年内仍将是中国使用最为广泛的基层材料。目前水泥稳定碎石在设计和施工方面存在一些问题,例如室内成型方式与实际道路受力状态存在一定差异;设计指标和施工检测指标相关性不足;对矿质石料级配的要求没有体现..._无侧限抗压强度与劈裂强度的的关系

黑科技,Python 脚本帮你找出微信上删除你好友的人_微信出现brandsessionholder-程序员宅基地

文章浏览阅读1.5k次。编者按:本文来自稀土掘金江昪编译自 Github:0x5e/wechat-deleted-friends “ 清理下[微笑],不用回。你的朋友圈没事也该清清了,打开设置,通用,功能,群助手,全选,把我的信息粘贴一下,就可以了,发送就知道谁把你删了,方便你清人,不清不知道 ,一清吓一跳。” 相信大家在微信上一定被上面的这段话刷过屏,群发消息应该算是微信上流传最广的找到删除好友的方法..._微信出现brandsessionholder

MySQL存储过程 游标循环的使用_存储过程 重复定义同名游标 会覆盖吗?-程序员宅基地

文章浏览阅读1.5k次。MySQL存储过程 游标循环的使用_存储过程 重复定义同名游标 会覆盖吗?

推荐文章

热门文章

相关标签