项目:智能排队控制系统
1.项目需求
1.红外传感器检测有人通过并计数;
2.计数值显示在LCD1602
3.允许通过时,LED1闪烁,蜂鸣器不响,继电器不合,
4.不允许通过时,LED2闪烁蜂鸣器响,继电器闭合;
5.每次允许通过5人,之后转为不允许通过,3秒后再转为允许通过
2.硬件清单
- 继电器
- 蜂鸣器
- 红外避障模式
- LCD1062
- STM32
- ST-Link
3.硬件连接
STM32 | LCD1602 | 继电器 | 蜂鸣器 | 红外 |
---|---|---|---|---|
GND | GND | |||
5V | VDD | |||
GND | v0 | |||
B1 | RS | |||
B2 | RW | |||
B10 | E | |||
A0 | D0 | |||
A1 | D1 | |||
A2 | D2 | |||
A3 | D3 | |||
A4 | D4 | |||
A5 | D5 | |||
A6 | D6 | |||
A7 | D7 | |||
3.3V | BLA | VCC | VCC | VCC |
GND | BLK | GND | GND | GND |
B4 | OUT | |||
B5 | I/O | |||
B6 | IN |
4.项目框图
5.状态机
6.代码
6.1led.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);//关闭LEDled1_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);
}
6.2tasks.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;//LCD1602显示状态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){//计数+1passenger++;//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,"WAIL...00/05");}}
6.3beep.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); // 拉高蜂鸣器引脚,关闭蜂鸣器
}
6.4exti.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;
}
6.5gate.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);//关闭LEDgate_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);
}
6.6 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 PA3PA4 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)延时 15msdelay_ms(15);
//(2)写指令 38H(不检测忙信号) lcd1602_write_cmd(0x38);
//(3)延时 5msdelay_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;}
}
6.6main.c
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "tasks.h"
#include "gate.h"
#include "beep.h"
#include "exti.h"
#include "lcd1602.h"int main(void)
{HAL_Init(); /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */led_init(); /* 初始化LED灯 */gate_init(); /* 初始化继电器 */beep_init(); /* 初始化蜂鸣器 */exti_init(); /* 初始化红外传感器 */lcd1602_init(); /* 初始化LCD1602 */lcd1602_show_line(1,2,"PASS...");while(1){ sensor_task();led1_task();led2_task();}
}