【开源】基于STM32的人员统控制系统

项目编号:STM32-T011

项目名称:基于STM32的人员统控制系统

【摘要】

        本设计基于STM32F103C8T6单片机,构建了一套人员统控制系统,实现了游客出入的实时统计与门禁管理。系统通过红外对管模块检测游客进出情况,自动将进出人数及在场人数显示在OLED屏幕上,保证统计的直观与准确。在进场时,游客需使用RFID射频卡进行身份验证,系统结合语音播报模块提示“欢迎光临”,并驱动舵机实现门禁开合,提升人机交互体验。为防止场馆超员,系统设定人数阈值,当在场人数超过预设值后,游客需刷两张RFID门票方可进入;若超过最大容量,门禁将不再开放,并通过语音播报提示人员已超限,确保安全有序管理。同时,系统通过WiFi模块与手机APP连接,管理人员可远程查看实时数据,并具备手动开门功能,以满足特殊情况的管理需求。该系统方案结构清晰、功能完整,不仅具备人数监测和门禁控制的基本能力,还融合了语音播报与远程控制功能,具有良好的应用价值,适用于景区、展馆等需要实时人数监管的场所。

【所用硬件】

1、STM32F103C8T6最小系统板

        STM32F103C8T6最小系统板是基于意法半导体(ST)Cortex-M3内核的微控制器开发板,核心芯片为STM32F103C8T6,主频72MHz,具有64KB Flash和20KB SRAM,满足中等复杂度的嵌入式应用需求。该板集成USB、USART、SPI、I2C等通信接口,支持多种外设扩展。最小系统板包含必要的外围电路,如8MHz晶振、复位电路、电源管理(3.3V稳压),并提供GPIO引脚引出,方便连接传感器、显示屏等模块。其低功耗、高性能特性使其广泛应用于智能硬件、工业控制等领域。在本设计中,它作为主控单元,负责数据采集、处理及外设控制,确保电子秤系统的稳定运行。

2、OLED显示模块

        OLED(有机发光二极管)显示屏模块是一种自发光显示器件,无需背光,具有高对比度、宽视角和快速响应的特点。本设计采用的OLED模块通常为0.96英寸或1.3英寸,分辨率为128×64像素,支持I2C或SPI通信协议,可直接与STM32等微控制器连接。其工作电压为3.3V~5V,功耗低,适合便携式设备。

3、轻触按键

        轻触按键(Tactile Switch)是一种瞬时接触式机械开关,通过按压触发导通,松开后自动复位。其结构简单、体积小巧,通常采用金属弹片或导电橡胶实现触点通断,具有手感清晰、寿命长(可达10万次以上操作)的特点。工作电压和电流范围宽(如12V/50mA),可直接与STM32等微控制器的GPIO引脚连接,需配合上拉/下拉电阻使用以避免信号浮动。

4、ESP8266-01S WIFI模块

        ESP8266-01S是一款基于ESP8266芯片的紧凑型无线通信模块,支持802.11 b/g/n协议,工作频率2.4GHz,内置32位Tensilica处理器和片上WiFi堆栈,可独立运行或作为从机与主控MCU(如STM32)协同工作。模块通过UART(AT指令)或SPI接口通信,支持STA(客户端)、AP(热点)和混合模式,便于接入互联网或组建本地无线网络。其Flash容量为1MB,提供GPIO引脚用于基础控制,工作电压3.3V,功耗低且成本低廉。

5、天问ASRPRO语音模块

        天问ASRPRO语音模块是一款集成度较高的离线语音识别与语音合成一体化模块,能够实现本地语音指令识别和实时语音播报功能。它内置多种常用语音指令库,支持用户自定义关键词,识别速度快且准确率高,不依赖网络即可运行,适合应用在对响应速度和稳定性要求较高的嵌入式系统中。模块采用串口通信方式,与单片机、STM32或其他主控设备连接简单,开发门槛低,用户只需通过指令配置即可完成识别与播报功能。

6、红外传感器

TCRT5000红外传感器是一种集发射与接收一体的光电传感器,主要由红外发射二极管和光敏三极管组成,能通过检测反射光的强弱来判断物体的存在与否或表面颜色的差异。该传感器对黑白反差较为敏感,因此常用于巡线小车、计数器以及接近检测等场合。它体积小巧,响应速度快,使用时只需配合简单的电路即可输出稳定信号,便于与单片机等控制器连接,具有低成本和易于集成的特点。

7、RFID射频模块

RFID模块是一种利用射频识别技术进行非接触式信息读取和传输的电子设备,它通过无线电信号与内置芯片的电子标签进行通信,实现身份识别和数据交换。该模块具有识别速度快、读写方便、抗干扰能力强等特点,常用于门禁系统、人员管理、物品追踪等应用场景,能够提高管理的智能化和自动化水平。

【系统框架图】

【软件流程图】

【核心代码展示】

#include "app_task.h"
#include "main.h"
#include "m5310a.h"
#include "delay.h"
#include "usart.h"
#include "timer.h"
#include "esp8266.h"
#include "io.h"
#include "led.h"
#include "oled.h"
#include "sim800l.h"
#include "rtc.h"
#include "Encoder.h"
#include "beep.h"
#include "mpu6050.h"
#include "inv_mpu.h"
#include "adc.h"
#include "key.h"
#include "dth11.h"
#include "ds18b20.h"
#include "PAJ7620.h"
#include "max30102.h"
#include "stm32f10x_adc.h"
#include "HCSR04.h"
#include "rfid.h"

u8 str[100];
OLED oled;
USER user;

TaskControlBlock TaskList[MAX_TASKS] = {0};
uint8_t RegisteredTasks = 0; // 已注册任务数
uint32_t SystemTick = 0;     // 系统时间基准

// 任务注册函数
int8_t Task_Register(uint8_t id, uint32_t interval, void (*task_func)(void *), void *param)
{
    if (RegisteredTasks >= MAX_TASKS)
        return -1;

    TaskList[RegisteredTasks].TaskID = id;
    TaskList[RegisteredTasks].PollingInterval = interval;
    TaskList[RegisteredTasks].TimerCounter = 0;
    TaskList[RegisteredTasks].RunFlag = 0;
    TaskList[RegisteredTasks].EnableFlag = 1;
    TaskList[RegisteredTasks].TaskHook = task_func;
    TaskList[RegisteredTasks].TaskParam = param;
    TaskList[RegisteredTasks].Delay = 0;
    RegisteredTasks++;
    return 0;
}

// 任务使能控制
void Task_Enable(uint8_t id, uint8_t enable)
{
    for (int i = 0; i < RegisteredTasks; i++)
    {
        if (TaskList[i].TaskID == id)
        {
            TaskList[i].EnableFlag = enable;
            break;
        }
    }
}

/**
 * @brief LED闪烁任务
 *
 * @param pt
 */
void Led_Task(void *pt)
{
    LED1 = !LED1;
}

/**
 * @brief 按键任务
 *
 * @param pt
 */
void Key_Task(void *pt)
{
    switch (KEY_Scan(0))
    {
    case KEY1_PRICE:
    {
        if(oled.page == PAGE_1)
        {
            if(oled.x < 4) oled.x++;
            if(oled.x == 4) oled.x=1;
        }
    };
    break;

    case KEY2_PRICE:
    {
        if(oled.page == PAGE_1)
        {
            if(oled.x == 2)
            {
                if(user.people_value < user.max_people) user.people_value++;
            }
            else if(oled.x == 3)
            {
                if(user.max_people < 100) user.max_people++;
            }
        }
        
    };
    break;

    case KEY3_PRICE:
    {
        if(oled.page == PAGE_1)
        {
            if(oled.x == 2)
            {
                if(user.people_value > 0) user.people_value--;
            }
            else if(oled.x == 3)
            {
                if(user.max_people > user.people_value) user.max_people--;
            }
            
        }
        
    };
    break;

    case KEY4_PRICE:
    {
        user.door_flag = 1;
    };
    break;
    }
}

/**
 * @brief OLED显示任务
 *
 * @param pt
 */
void OLED_Task(void *pt)
{
    if (oled.page == PAGE_1)
    {
        /**人员控制系统 */
        OLED_ShowChinese(16, 0, 35, 16, 1);
        OLED_ShowChinese(32, 0, 36, 16, 1);
        OLED_ShowChinese(48, 0, 37, 16, 1);
        OLED_ShowChinese(64, 0, 38, 16, 1);
        OLED_ShowChinese(80, 0, 39, 16, 1);
        OLED_ShowChinese(96, 0, 40, 16, 1);

        /**人数: */
        OLED_ShowChinese(0, 16, 41, 16, 1);
        OLED_ShowChinese(16, 16, 42, 16, 1);
        OLED_ShowChinese(32, 16, 43, 16, 1);
        sprintf(str,"%3d",user.people_cnt);
        OLED_ShowString(48,16,str,16,1);

        /**人数阈值: */
        OLED_ShowChinese(0, 32, 41, 16, 1);
        OLED_ShowChinese(16, 32, 42, 16, 1);
        OLED_ShowChinese(32, 32, 44, 16, 1);
        OLED_ShowChinese(48, 32, 45, 16, 1);
        OLED_ShowChinese(64, 32, 50, 16, 1);
        sprintf(str,"%3d",user.people_value);
        if(oled.x == 2)
        {
            OLED_ShowString(80,32,str,16,0);
        }
        else
        {
            OLED_ShowString(80,32,str,16,1);
        }
        
        

        /**最大人数: */
        OLED_ShowChinese(0, 48, 46, 16, 1);
        OLED_ShowChinese(16, 48, 47, 16, 1);
        OLED_ShowChinese(32, 48, 48, 16, 1);
        OLED_ShowChinese(48, 48, 49, 16, 1);
        OLED_ShowChinese(64, 48, 50, 16, 1);
        sprintf(str,"%3d",user.max_people);
        if(oled.x == 3)
        {
            OLED_ShowString(80,48,str,16,0);
        }
        else
        {
            OLED_ShowString(80,48,str,16,1);
        }
        

    }
    else if(oled.page == PAGE_TIP)
    {
        /**人员已超 */
        OLED_ShowChinese(32, 16, 51, 16, 1);
        OLED_ShowChinese(48, 16, 52, 16, 1);
        OLED_ShowChinese(64, 16, 53, 16, 1);
        OLED_ShowChinese(80, 16, 54, 16, 1);

        /**需要刷卡 次 */
        OLED_ShowChinese(16, 32, 56, 16, 1);
        OLED_ShowChinese(32, 32, 57, 16, 1);
        OLED_ShowChinese(48, 32, 58, 16, 1);
        OLED_ShowChinese(64, 32, 59, 16, 1);
        OLED_ShowChinese(96, 32, 60, 16, 1);
        sprintf(str,"%d",user.card_cnt);
        OLED_ShowString(80,32,str,16,1);

    }

    OLED_Refresh();
}


/**  
 * @brief RFID卡读取任务
 * 
 * @param pt 
 */
void RFID_Task(void *pt)
{
    RC522_Handel();
    if(ID_Num == 2)
    {
        ID_Num = 0;
        if(user.people_cnt<user.people_value)
        {
            user.door_flag = 1;
        }
        else if(user.people_cnt<user.max_people)
        {
            if(user.card_cnt == 2)
            {
                oled.page = PAGE_TIP;
                OLED_Clear();
            }
            if(user.card_cnt == 1)
            {
                user.door_flag = 1;
                OLED_Clear();
                oled.page = PAGE_1;
            }
            user.card_cnt--;
        }
        else
        {
            user.door_flag = 1;
        }
    }
}


/**
 * @brief 红外检测任务
 * 
 * @param pt 
 */
void HongWai_Task(void *pt)
{
    static u8 flag1=0,flage2=0;
    if(user.door_flag == 1)
    {
        if((HongWai_In == 0 && flag1 == 0) || (user.card_cnt == 1 && flag1 == 0))
        {
            flag1 = 1;
            if(user.people_cnt<user.max_people)
            {
                if(user.people_cnt<user.people_value)
                {
                    user.people_cnt++;
                    Servo_SetAngle_PB0(90); 
                    Usart_SendString(USART1,"OK",strlen("OK"));
                }
                else if(user.people_cnt<user.max_people)
                {
                    user.card_cnt = 2;
                    user.people_cnt++;
                    Servo_SetAngle_PB0(90); 
                    Usart_SendString(USART1,"OK",strlen("OK"));
                }
    
                
            }
            else
            {
                Usart_SendString(USART1,"NO",strlen("NO"));
            }
        }
        else if(HongWai_In == 1 && flag1 == 1)
        {
            user.door_flag=0;
            flag1 = 0;
            Servo_SetAngle_PB0(0); 
        }
    }

    if(HongWai_Out == 0 && flage2 == 0)
    {
        flage2 = 1;
        user.motor_flag = 1;
        if(user.people_cnt > 0) user.people_cnt--;
        Servo_SetAngle_PB0(90); 
    }
    else if(HongWai_Out == 1 && flage2 == 1)
    {
        flage2 = 0;
        Servo_SetAngle_PB0(0); 
        
    }
    

}


void ESP8266_Task(void *pt)
{
    sprintf(str,"#%d#%d#%d#",user.people_cnt,user.people_value,user.max_people);
    ESP8266_SendData(str);
}



void Task_Init(void)
{
    Task_Register(1, 1000, Led_Task, NULL);
    Task_Register(2, 1, Key_Task, NULL);
    Task_Register(3, 200, OLED_Task, NULL);
    Task_Register(4, 1000, RFID_Task, NULL);
    Task_Register(5, 200, HongWai_Task, NULL);
    Task_Register(6, 2000, ESP8266_Task, NULL);
}

void Task_Run(void)
{
    for (int i = 0; i < RegisteredTasks; i++)
    {
        if (TaskList[i].RunFlag && TaskList[i].EnableFlag)
        {
            // 执行任务函数
            if (TaskList[i].TaskHook != NULL)
            {
                TaskList[i].TaskHook(TaskList[i].TaskParam);
            }
            // 清除运行标志
            TaskList[i].RunFlag = 0;
        }
    }
}

void TaskTime(void)
{
    static u32 tick_time = 0;
    tick_time++;
    // 遍历任务列表更新计数器
    for (int i = 0; i < RegisteredTasks; i++)
    {
        if (TaskList[i].EnableFlag)
        {
            TaskList[i].TimerCounter++;

            // 达到时间间隔时设置运行标志
            if (TaskList[i].TimerCounter >= TaskList[i].PollingInterval)
            {
                TaskList[i].RunFlag = 1;
                TaskList[i].TimerCounter = 0;
            }
        }
    }
}

【原理图】

【硬件实物图】

【实物演示】

人员统控制系统

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值