草庐IT

FreeRTOS小项目实战------基于FreeRTOS和stm32的门禁系统

喝杯子的水 2023-08-01 原文

目录

收获

系统总体框架

程序框架

具体程序实现

工程文件网盘链接

收获

学习freertos的移植与裁剪,对任务间通信的认识更加深刻,加深了实时操作系统的理解,学习了as608指纹模块,rc522刷卡模块等模块的简单使用。

系统总体框架

该系统采用STM32F407ZGT6为主控芯片,在FreeRTOS下与分别通过as608指纹模块,RFID射频识别卡模块,LCD触屏模块以及esp8266WIFI模块完成解锁,配合显示模块,舵机,用蜂鸣器进行提示共同组成整个门禁系统,系统的整体框架图如下所示

首先指纹模块提前采取好需要识别的指纹到模块内置的芯片里面,将手指放到指纹识别模块上,系统会检测到指纹按下并且会采取当前的指纹图像与芯片内部的指纹图像进行识别,若识别成功,蜂鸣器响两下,并且LCD屏幕会显示指纹识别成功,舵机会转动180°模拟解锁成功,当指纹识别到的图像与模块存储的指纹识别不一致,则蜂鸣器会响3下,LCD屏幕会显示指纹识别失败,舵机不会转动。RFID射频识别功能是当使用者使用识别卡靠近RC522 RFID射频模块,此模块会识别到当前卡的卡号,若卡号与我写入的卡号一致则解锁成功,并且LCD屏幕会显示识别卡成功,舵机会转动180°模拟解锁成功;LCD触屏密码锁的功能是当使用者在屏幕输入密码,密码正确则解锁成功,并且LCD屏幕会显示指纹识别成功,舵机会转动180°模拟解锁成功。WIFI远程解锁则是ESP8266模块设置成AP+TCP服务器端,手机连接其热点并且在TCP客户端输入正确ip地址和端口号,输入正确的命令后解锁成功。当每一次解锁失败则会记录下这一次解锁失败,当累计3次后则舵机锁死。

程序框架

由此流程图可知,基于FreeRTOS操作系统下创建了一个开始任务和四个控制任务。任务与任务之间使用事件标志组进行通信,当TFTLCD屏幕触屏输入密码的时,当密码输入正确,则向舵机任务发送一个事件标志位;当指纹识别成功时,则向舵机任务发送一个事件标志位;当射频识别卡识别成功卡号时候;则向舵机任务发送一个事件标志位;当蓝牙从手机串口发生密码时,当密码识别成功,则向舵机任务发送一个事件标志位。舵机任务只要接收到其中一个事件标志位时候,舵机就会转动180°来模拟解锁成功。当如果每解锁失败一次之后,err全局变量加一,当err等于3的时候,则舵机任务被挂起。

具体程序实现

创建事件组

EventGroupHandle_t EventGroupHandler;	//事件标志组句柄
#define EVENTBIT_0	(1<<0)				//事件位
#define EVENTBIT_1	(1<<1)
#define EVENTBIT_2	(1<<2)
#define EVENTBIT_ALL	(EVENTBIT_0|EVENTBIT_1|EVENTBIT_2)

开始任务函数

//开始任务任务函数
void start_task(void *pvParameters)
{
	BaseType_t xReturn;
    taskENTER_CRITICAL();           //进入临界区
	
	
	EventGroupHandler=xEventGroupCreate();
	if(NULL!=EventGroupHandler)
		printf("EventGroupHandler事件创建成功\r\n");
		
	xReturn=xTaskCreate((TaskFunction_t )SG90_task,             
                (const char*    )"SG90_task",           
                (uint16_t       )SG90_STK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )SG90_TASK_PRIO,        
                (TaskHandle_t*  )&SG90Task_Handler);  
	if(xReturn==pdPASS)
		printf("SG90_TASK_PRIO任务创建成功\r\n");
	
	
    
    xReturn=xTaskCreate((TaskFunction_t )LCD_task,             
                (const char*    )"LCD_task",           
                (uint16_t       )LCD_STK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )LCD_TASK_PRIO,        
                (TaskHandle_t*  )&LCDTask_Handler); 
   if(xReturn==pdPASS)
		 printf("LCD_TASK_PRIO任务创建成功\r\n");	

   xReturn=xTaskCreate((TaskFunction_t )RFID_task,             
                (const char*    )"RFID_task",           
                (uint16_t       )RFID_STK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )RFID_TASK_PRIO,        
                (TaskHandle_t*  )&RFIDTask_Handler); 
   if(xReturn==pdPASS)
		 printf("RFID_TASK_PRIO任务创建成功\r\n");

   xReturn=xTaskCreate((TaskFunction_t )AS608_task,             
                (const char*    )"AS608_task",           
                (uint16_t       )AS608_STK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )AS608_TASK_PRIO,        
                (TaskHandle_t*  )&AS608Task_Handler); 
   if(xReturn==pdPASS)
		 printf("AS608_TASK_PRIO任务创建成功\r\n");
	 
	  xReturn=xTaskCreate((TaskFunction_t )ESP8266_task,             
                (const char*    )"ESP8266_task",           
                (uint16_t       )ESP8266_STK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )ESP8266_TASK_PRIO,        
                (TaskHandle_t*  )&ESP8266Task_Handler); 
   if(xReturn==pdPASS)
		 printf("ESP8266_TASK_PRIO任务创建成功\r\n");
	 
	 
	 
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

舵机任务(利用舵机模拟门锁转动)

void SG90_task(void * pvParameters)
{
	 volatile EventBits_t EventValue;	
	while(1)
	{
		
		
		   EventValue=xEventGroupWaitBits(EventGroupHandler,EVENTBIT_ALL,pdTRUE,pdFALSE,portMAX_DELAY);
		   
				  printf("接收事件成功\r\n");
		      set_Angle(180);
			    delay_xms(1000);
			    delay_xms(1000);
			    set_Angle(0);
			    LCD_ShowString(80,150,260,16,16,"              ");

			vTaskDelay(100); //延时10ms,也就是10个时钟节拍
				
	}	
}

LCD触摸屏输入密码任务

void LCD_task(void * pvParameters)
{
  
//	sg90flag=GET_NUM();
	
	while(1)
	{
		 
			  if(sg90flag==1||GET_NUM())
				{
					 BEEP=1;
					 delay_xms(100);
					 BEEP=0;
				   printf("密码输入正确\r\n");
					 LCD_ShowString(80,150,260,16,16,"password match");
		       xEventGroupSetBits(EventGroupHandler,EVENTBIT_0);
	 
				}
        else
				{
					 BEEP=1;
					 delay_xms(50);
					 BEEP=0;
					 delay_xms(50);
					 BEEP=1;
					 delay_xms(50);
					 BEEP=0;
					delay_xms(50);
					 BEEP=1;
					 delay_xms(50);
					 BEEP=0;
					printf("密码输入错误\r\n");
					LCD_ShowString(80,150,260,16,16,"password error");
					err++;
					if(err==3)
					{
					  vTaskSuspend(SG90Task_Handler);
						printf("舵机任务挂起\r\n");
						LCD_ShowString(0,100,260,16,16,"Task has been suspended");
					}			
				}					
			vTaskDelay(100); //延时10ms,也就是10个时钟节拍
	}	
}

rc522识别卡任务

void RFID_task(void * pvParameters)
{
	
//	 rfidflag=shibieka();
   while(1)
	 {
	    if(rfidflag==1||shibieka())
			{
				   BEEP=1;
					 delay_xms(100);
					 BEEP=0;
				 Chinese_Show_two(30,50,16,16,0);
	       Chinese_Show_two(50,50,18,16,0);
	       Chinese_Show_two(70,50,20,16,0);
	       Chinese_Show_two(90,50,8,16,0);
	       Chinese_Show_two(110,50,10,16,0);
	       
				xEventGroupSetBits(EventGroupHandler,EVENTBIT_1);
				printf("识别卡号成功\r\n");
				
			
			}
			else if(shibieka()==0)
			{
				BEEP=1;
					 delay_xms(50);
					 BEEP=0;
					 delay_xms(50);
					 BEEP=1;
					 delay_xms(50);
					 BEEP=0;
					delay_xms(50);
					 BEEP=1;
					 delay_xms(50);
					 BEEP=0;
				Chinese_Show_two(90,50,12,16,0);
	      Chinese_Show_two(110,50,14,16,0);
			  printf("识别卡号失败\r\n");
				err++;
					if(err==3)
					{
					  vTaskSuspend(SG90Task_Handler);
						printf("舵机任务挂起\r\n");
						LCD_ShowString(0,100,260,16,16,"Task has been suspended");
					}
				
			
			}
			
	   vTaskDelay(100); //延时10ms,也就是10个时钟节拍
	 }

}

as608指纹识别任务

void AS608_task(void *pvParameters)
{
  while(1)
	{
		if(PS_Sta)	 //检测PS_Sta状态,如果有手指按下
		{
		   if(press_FR()==1)
			{
				 BEEP=1;
				 delay_xms(100);
				 BEEP=0;
				 Chinese_Show_two(30,25,0,16,0);
	       Chinese_Show_two(50,25,2,16,0);
	       Chinese_Show_two(70,25,4,16,0);
	       Chinese_Show_two(90,25,6,16,0);
	       Chinese_Show_two(110,25,8,16,0);
	       Chinese_Show_two(130,25,10,16,0);
				 xEventGroupSetBits(EventGroupHandler,EVENTBIT_2);
			   printf("指纹识别成功");
				 
				 
			
			}
			else if(press_FR()==0)
			{
				BEEP=1;
					 delay_xms(50);
					 BEEP=0;
					 delay_xms(50);
					 BEEP=1;
					 delay_xms(50);
					 BEEP=0;
					delay_xms(50);
					 BEEP=1;
					 delay_xms(50);
					 BEEP=0;
				Chinese_Show_two(110,25,12,16,0);
	      Chinese_Show_two(130,25,14,16,0);
			  printf("指纹识别失败");
				err++;
					if(err==3)
					{
					  vTaskSuspend(SG90Task_Handler);
						printf("舵机任务挂起\r\n");
						LCD_ShowString(0,100,260,16,16,"Task has been suspended");
					}
			
			}
			     
		}
		vTaskDelay(100);
	}
}

esp8266任务

void ESP8266_task(void *pvParameters)
{

  while(1)
	{
	   if(USART3_RX_STA)
		{
			if(strstr((const char*)USART3_RX_BUF,"on"))
			{
				 BEEP=1;
				 delay_xms(100);
				 BEEP=0;
			   printf("开门成功\r\n");
				 xEventGroupSetBits(EventGroupHandler,EVENTBIT_0);
				 memset(USART3_RX_BUF,0,sizeof(USART3_RX_BUF));
			}				
				
			if(!strstr((const char*)USART3_RX_BUF,"on"))
			{
			  printf("密码错误\r\n");
				memset(USART3_RX_BUF,0,sizeof(USART3_RX_BUF));
			}				
	
			USART3_RX_STA=0;
//			continue;
		}
		vTaskDelay(100);	
	}
}

工程文件网盘链接

链接:https://pan.baidu.com/s/1d_hQY91rDy5VRq5E4HCYZg 
提取码:dpfr

有关FreeRTOS小项目实战------基于FreeRTOS和stm32的门禁系统的更多相关文章

  1. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  2. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  3. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  4. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  5. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  6. ruby-on-rails - (Ruby,Rails) 基于角色的身份验证和用户管理...? - 2

    我正在寻找用于Rails的优质管理插件。似乎大多数现有的插件/gem(例如“restful_authentication”、“acts_as_authenticated”)都围绕着self注册等展开。但是,我正在寻找一种功能齐全的基于管理/管理角色的解决方案——但不是简单地附加到另一个非基于角色的解决方案。如果我找不到,我想我会自己动手......只是不想重新发明轮子。 最佳答案 RyanBates最近做了两个关于授权的railscast(注意身份验证和授权之间的区别;身份验证检查用户是否如她所说的那样,授权检查用户是否有权访问资源

  7. ruby - 在 Rakefile 中动态生成 Rake 测试任务(基于现有的测试文件) - 2

    我正在根据Rakefile中的现有测试文件动态生成测试任务。假设您有各种以模式命名的单元测试文件test_.rb.所以我正在做的是创建一个以“测试”命名空间内的文件名命名的任务。使用下面的代码,我可以用raketest:调用所有测试require'rake/testtask'task:default=>'test:all'namespace:testdodesc"Runalltests"Rake::TestTask.new(:all)do|t|t.test_files=FileList['test_*.rb']endFileList['test_*.rb'].eachdo|task|n

  8. ruby - 如何使用 Ruby 基于字母数字字符串生成颜色? - 2

    我想要像“嘿那里”这样的东西变成,例如,#316583。我希望将任意长度的字符串“归结”为十六进制颜色。我不知道从哪里开始。我在想,每个字符串的MD5散列都是不同的-但如何将该散列转换为十六进制颜色数字? 最佳答案 你可以只取几位前几位:require'digest/md5'color=Digest::MD5.hexdigest('Mytext')[0..5] 关于ruby-如何使用Ruby基于字母数字字符串生成颜色?,我们在StackOverflow上找到一个类似的问题:

  9. 【自动驾驶环境感知项目】——基于Paddle3D的点云障碍物检测 - 2

    文章目录1.自动驾驶实战:基于Paddle3D的点云障碍物检测1.1环境信息1.2准备点云数据1.3安装Paddle3D1.4模型训练1.5模型评估1.6模型导出1.7模型部署效果附录show_lidar_pred_on_image.py1.自动驾驶实战:基于Paddle3D的点云障碍物检测项目地址——自动驾驶实战:基于Paddle3D的点云障碍物检测课程地址——自动驾驶感知系统揭秘1.1环境信息硬件信息CPU:2核AI加速卡:v100总显存:16GB总内存:16GB总硬盘:100GB环境配置Python:3.7.4框架信息框架版本:PaddlePaddle2.4.0(项目默认框架版本为2.3

  10. STM32的HAL和LL库区别和性能对比 - 2

    LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L

随机推荐