8、stm32单片机基于hal库实现智能排队控制系统

一、项目需求

(1)红外传感器检测有人通过并计数 

(2) 计数值显示在LCD1602

(3) 允许通过时,LED1闪烁,蜂鸣器不响,继电器不闭合;

(4) 不允许通过时, LED2 闪烁,蜂鸣器响,继电器闭合;
(5) 每次允许通过 5 个人,之后转为不允许通过, 3 秒后再转为允许通过

二、硬件清单

       (1) 继电器(模拟匣机)
       (2) 蜂鸣器
        (3)红外避障模块
        (4)LCD1602
        (5)上官二号
        (6)ST-Link
三、硬件接线

 四、项目框图

 五、状态机

状态机
状态机( State Machine )是一种用于描述系统行为或功能行为的数学模型。它通常包含一组状态、一组转
换条件以及动作执行。状态机通过在不同状态之间进行转换来模拟系统的行为。每个状态都代表系统的一个
特定配置或情况,而转换规则则定义了从一个状态转换到另一个状态的条件和动作。
状态机广泛应用于多个领域,包括但不限于计算机科学、电子工程、通信、自动化和机器人技术等。在计算
机科学中,状态机常用于描述软件系统的行为,特别是在硬件设计、编译器设计、网络协议以及用户界面交
互等方面。
状态机的主要特点包括:
1. 有限状态 :状态机通常具有有限数量的状态。这些状态可以是有序的、离散的或层次化的。 2. 转换条件 :状态之间的转换是基于特定条件触发的。当满足某个条件时,状态机会从当前状态转换到下
一个状态。
3. 动作执行 :在状态转换过程中,状态机可能会执行某些动作或操作。这些动作可以包括计算、数据更
新、输出信号等。
4. 确定性和非确定性 :状态机可以是确定性的(每个条件唯一对应一个转换)或非确定性的(一个条件可
能导致多个可能的转换)。
状态机的实现方式多种多样,可以使用编程语言中的条件语句、循环结构或专门的状态机库来实现。此外,
硬件设计领域中的有限状态机( Finite State Machine, FSM )也是状态机的一种重要应用。

 

 伪代码:

while(1)
{
if(state == 开心)
{
KTV();
撸串();
if(女朋友跟人跑了)
state = 郁闷;
}
else if(state == 郁闷)
{
抽烟();
嫩模();
if(交新女朋友了)
state = 开心;
else if(刷到良许直播)
state = 打鸡血;
}
else if(state == 打鸡血)
{
写bug();
改bug();
if(成功入行了)
state = 开心;
}
}

六、项目代码

 led.c

#include "led.h"
#include "sys.h"

//初始化GPIO函数
void led_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();                           // 使能GPIOB时钟
    
    //调用GPIO初始化函数
    gpio_initstruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;          // 两个LED对应的引脚
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;             // 推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP;                     // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;           // 高速
    HAL_GPIO_Init(GPIOB, &gpio_initstruct);
    //关闭LED
    led1_off();
    led2_off();
}

//点亮LED1的函数
void led1_on(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);   // 拉低LED1引脚,点亮LED1
}

//熄灭LED1的函数
void led1_off(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);     // 拉高LED1引脚,熄灭LED1
}

//翻转LED1状态的函数
void led1_toggle(void)
{
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
}

//点亮LED2的函数
void led2_on(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET);   // 拉低LED2引脚,点亮LED2
}

//熄灭LED2的函数
void led2_off(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);     // 拉高LED2引脚,熄灭LED2
}

//翻转LED2状态的函数
void led2_toggle(void)
{
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_9);
}

led.h

#ifndef __LED_H__
#define __LED_H__

void led_init(void);
void led1_on(void);
void led1_off(void);
void led1_toggle(void);
void led2_on(void);
void led2_off(void);
void led2_toggle(void);

#endif

beep.c

#include "beep.h"
#include "sys.h"

//初始化GPIO函数
void beep_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();                           // 使能GPIOB时钟
    
    //调用GPIO初始化函数
    gpio_initstruct.Pin = GPIO_PIN_5;                       // 蜂鸣器对应的引脚
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;             // 推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP;                     // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;           // 高速
    HAL_GPIO_Init(GPIOB, &gpio_initstruct);
    //关闭蜂鸣器
    beep_off();
}

//打开蜂鸣器的函数
void beep_on(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);   // 拉低蜂鸣器引脚,打开蜂鸣器
}

//关闭蜂鸣器的函数
void beep_off(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);     // 拉高蜂鸣器引脚,关闭蜂鸣器
}

beep.h

#ifndef __BEEP_H__
#define __BEEP_H__

void beep_init(void);
void beep_on(void);
void beep_off(void);

#endif

gate.c

#include "gate.h"
#include "sys.h"

//初始化GPIO函数
void gate_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();                           // 使能GPIOB时钟
    
    //调用GPIO初始化函数
    gpio_initstruct.Pin = GPIO_PIN_6;                       // 继电器对应的引脚
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;             // 推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP;                     // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;           // 高速
    HAL_GPIO_Init(GPIOB, &gpio_initstruct);
    //关闭LED
    gate_off();
}

//闭合继电器的函数
void gate_on(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);   // 拉低LED1引脚,点亮LED1
}

//松开继电器的函数
void gate_off(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);     // 拉高LED1引脚,熄灭LED1
}

//获取继电器状态的函数
uint8_t gate_status_get(void)
{
    return (uint8_t)HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6);
}

gate.h

#ifndef __GATE_H__
#define __GATE_H__

#include "stdint.h"

#define GATE_STATUS_ON     0
#define GATE_STATUS_OFF    1

void gate_init(void);
void gate_on(void);
void gate_off(void);
uint8_t gate_status_get(void);

#endif

lcd1602.c

#include "lcd1602.h"
#include "string.h"
#include <stdarg.h>
#include "delay.h"

// RS引脚定义
#define RS_GPIO_Port GPIOB
#define RS_GPIO_PIN GPIO_PIN_1
#define RS_HIGH     HAL_GPIO_WritePin(RS_GPIO_Port, RS_GPIO_PIN, GPIO_PIN_SET)
#define RS_LOW      HAL_GPIO_WritePin(RS_GPIO_Port, RS_GPIO_PIN, GPIO_PIN_RESET)

// RW引脚定义
#define RW_GPIO_Port GPIOB
#define RW_GPIO_PIN GPIO_PIN_2
#define RW_HIGH     HAL_GPIO_WritePin(RW_GPIO_Port, RW_GPIO_PIN, GPIO_PIN_SET)
#define RW_LOW      HAL_GPIO_WritePin(RW_GPIO_Port, RW_GPIO_PIN, GPIO_PIN_RESET)

// EN引脚定义
#define EN_GPIO_Port GPIOB
#define EN_GPIO_PIN GPIO_PIN_10
#define EN_HIGH     HAL_GPIO_WritePin(EN_GPIO_Port, EN_GPIO_PIN, GPIO_PIN_SET)
#define EN_LOW      HAL_GPIO_WritePin(EN_GPIO_Port, EN_GPIO_PIN, GPIO_PIN_RESET)

/**
 * @brief       LCD1602 GPIO初始化
 * @param       无
 * @retval      无
 */
void lcd1602_gpio_init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  //__HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

//  /*Configure GPIO pin Output Level */
//  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
//                          |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_SET);

//  /*Configure GPIO pin Output Level */
//  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10, GPIO_PIN_SET);

  /*Configure GPIO pins : PA0 PA1 PA2 PA3
                           PA4 PA5 PA6 PA7 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
                          |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PB1 PB2 PB10 */
  GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

/**
 * @brief       lcd开始工作
 * @param       无
 * @retval      无
 */
void lcd1602_start(void)
{
//(1)延时 15ms
    delay_ms(15);
//(2)写指令 38H(不检测忙信号) 
    lcd1602_write_cmd(0x38);
//(3)延时 5ms
    delay_ms(5);
//(4)检测忙信号(省略)
//(5)写指令 38H:显示模式设置
    lcd1602_write_cmd(0x38);
//(6)写指令 08H:显示关闭
    lcd1602_write_cmd(0x08);
//(7)写指令 01H:显示清屏
    lcd1602_write_cmd(0x01);
//(8)写指令 06H:显示光标移动设置
    lcd1602_write_cmd(0x06);
//(9)写指令 0CH:显示开及光标设置
    lcd1602_write_cmd(0x0c);
}

/**
 * @brief       LCD1602初始化
 * @param       无
 * @retval      无
 */
void lcd1602_init(void)
{
    lcd1602_gpio_init();
    lcd1602_start();
}

/**
 * @brief       写指令
* @param        cmd:指令
 * @retval      无
 */
void lcd1602_write_cmd(char cmd)
{
    RS_LOW;
    RW_LOW;
    EN_LOW;
    GPIOA->ODR = cmd;       //将一字节数据发到GPIOA 8个引脚
    delay_ms(5);
    EN_HIGH;
    delay_ms(5);
    EN_LOW;
}

/**
 * @brief       写数据
 * @param       dataShow:显示的字符
 * @retval      无
 */
void lcd1602_write_data(char dataShow)
{
    RS_HIGH;
    RW_LOW;
    EN_LOW;
    GPIOA->ODR = dataShow;   //将一字节数据发到GPIOA 8个引脚
    delay_ms(5);
    EN_HIGH;
    delay_ms(5);
    EN_LOW;
}

/**
 * @brief       画面右移
 * @param       无
 * @retval      无
 */
void lcd1602_right_move(void)
{
    for(int i=0;i < 16;i++){
        delay_ms(1000);
        lcd1602_write_cmd(0x18);            //画面右移一位 0x18
    }
}

/**
 * @brief       显示字符
 * @param       row: 显示行,col: 显示起始列,string:显示字符
 * @retval      无
 */
void lcd1602_show_line(char row, char col, char *string)
{
    switch(row){
    case 1:
        lcd1602_write_cmd(0x80+col);        //最高位 D7 为高电平
        while(*string){
            lcd1602_write_data(*string);
            string++;
        }
        break;
    
    case 2:
        lcd1602_write_cmd(0x80+0x40+col);
        while(*string){
            lcd1602_write_data(*string);
            string++;
        }
        break;
    }
}

lcd1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__

#include <stdint.h>


void lcd1602_init(void);
void lcd1602_write_cmd(char cmd);
void lcd1602_write_data(char dataShow);
void lcd1602_show_line(char row, char col, char *string);
void lcd1602_right_move(void);


#endif

exti.c

#include "exti.h"
#include "sys.h"
#include "delay.h"
#include "led.h"

uint8_t ia_flag = FALSE;                               // 检测到震动标志位

void exti_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();                           // 使能GPIOA时钟
    
    //调用GPIO初始化函数
    gpio_initstruct.Pin = GPIO_PIN_4;                       // 震动传感器对应的引脚
    gpio_initstruct.Mode = GPIO_MODE_IT_FALLING;            // 下降沿触发
    gpio_initstruct.Pull = GPIO_PULLUP;                     // 上拉
    HAL_GPIO_Init(GPIOB, &gpio_initstruct);
    
    HAL_NVIC_SetPriority(EXTI4_IRQn, 2, 0);                 // 设置EXTI0中断线的优先级
    HAL_NVIC_EnableIRQ(EXTI4_IRQn);                         // 使能中断
}

void EXTI4_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    delay_ms(20);
    if (GPIO_Pin == GPIO_PIN_4)
    {
        if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4) == GPIO_PIN_RESET)
            //led1_toggle();
            ia_flag = TRUE;
    }
}

uint8_t ia_flag_get(void)
{
    uint8_t temp = ia_flag;
    ia_flag = FALSE;
    return temp;
    
}

void ia_flag_set(uint8_t value)
{
    ia_flag = value;
}

exti.h

#ifndef __EXTI_H__
#define __EXTI_H__

#include "stdint.h"

#define TRUE    1
#define FALSE   0

void exti_init(void);
uint8_t ia_flag_get(void);
void ia_flag_set(uint8_t value);

#endif

task.c

#include "tasks.h"
#include "led.h"
#include "beep.h"
#include "exti.h"
#include "lcd1602.h"
#include "gate.h"
#include "stdio.h"

enum
{
    PASS_STATE,
    WAIT_STATE
};

uint32_t led1_task_cnt = 0;
uint32_t led2_task_cnt = 0;
uint32_t wait_cnt = 0;
uint32_t passenger = 0;

uint8_t led1_task_flag = 0;
uint8_t led2_task_flag = 0;
uint8_t state = PASS_STATE;

char message[16] = {0};

void systick_isr(void)
{
    //如果处于允许通行的状态
    if(state == PASS_STATE)
    {
        //LED1以1秒的频率闪烁
        if (led1_task_cnt < 1000)
            led1_task_cnt++;
        else
        {
            led1_task_flag = 1;
            led1_task_cnt = 0;
        }
        //LED2不闪烁
        led2_off();
        //蜂鸣器不响
        beep_off();
        //开门
        gate_off();
    }
    //如果处于不允许通行的状态
    else if(state == WAIT_STATE)
    {
        //LED2以200ms的频率闪烁
        if (led2_task_cnt < 200)
            led2_task_cnt++;
        else
        {
            led2_task_flag = 1;
            led2_task_cnt = 0;
        }
        //LED1不闪
        led1_off();
        //蜂鸣器响
        beep_on();
        //关门
        gate_on();
        //计时3秒,之后
        if(wait_cnt < 3000)
            wait_cnt++;
        else
        {
            wait_cnt = 0;
            //进入允许通行状态
            state = PASS_STATE;
            //LCD显示状态
            lcd1602_show_line(1, 1, "PASS...");
        }
    }
}

void led1_task(void)
{
    if(led1_task_flag == 0)
        return;
    
    led1_task_flag = 0;
    
    led1_toggle();
}

void led2_task(void)
{
    if(led2_task_flag == 0)
        return;
    
    led2_task_flag = 0;
    
    led2_toggle();
}

void sensor_task(void)
{
    //如果检测到有人通过
    if(ia_flag_get() == TRUE && state == PASS_STATE)
    {
        //计数加1
        passenger++;
        //LCD显示状态
        sprintf(message, "PASS...%02d/05", passenger);
        lcd1602_show_line(1, 1, message);
        
    }

    //如果通过的人数超过5个
    if(passenger >= 5)
    {
        //计数清零
        passenger = 0;
        //进入不允许通行状态
        state = WAIT_STATE;
        //LCD显示状态
        lcd1602_show_line(1, 1, "WAIT...00/05");
    }
}

 task.h

#ifndef __TASKS_H__
#define __TASKS_H__

#include "sys.h"

void systick_isr(void);
void led1_task(void);
void led2_task(void);
void sensor_task(void);

#endif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值