【STM32】智能排队控制系统
1. 硬件准备
1.1 蜂鸣器
蜂鸣器的另一个应用——电动车报警系统
| 蜂鸣器 | GND | GND |
| I/O | B5 | |
| VCC | 3V |
1.2 继电器

| 继电器 | IN | B6 |
| GND | GND | |
| UCC | 5V |
1.3 红外模块

| 红外模块 | VCC | 3V3 |
| GND | GND | |
| OUT | PB4 |
红外避障模块上的一对红外线发射与接收管,发射管发射出一定频率的红外线,当检测方向遇到障碍物时, 红外线反射回来被接收管接收,经过比较器(LM393)电路处理之后,信号输出接口输出低电平信号,同时绿色指示灯会亮起。因为黑色能够吸收红外线(红外线不反射),而白色不行(红外线反射),所以除了避障可用作黑白线循迹、光电开关等等。
1.4 LCD1602
1.4.1 引脚配置

| LCD1602 | GND | GND | |
| VDD | 5V | 电源正极 | |
| V0 | 通过电阻接地 | 液晶驱动电压, 调节对比度 | |
| RS | PB1 | 寄存器选择: 1:数据寄存器 2:指令寄存器 | |
| RW | PB2 | 读写操作选择: 1:读 2:写 | |
| E | PB10 | 使能信号 | |
| D0 | PA0 | 双向数据通信 | |
| D1 | PA1 | ||
| D2 | PA2 | ||
| D3 | PA3 | ||
| D4 | PA4 | ||
| D5 | PA5 | ||
| D6 | PA6 | ||
| D7 | PA7 | ||
| BLA | 3V3 | 背光正极 | |
| BLK | GND | 背光负极 |
V0:液品显示器对比度调整端,接正电源时对比度最高,接地时对比度最低,对比度过高时会产生“鬼影”,使用时可以通过电位器或电阻调整对比度。电阻小了全是黑块,电阻大了不显示。RW:读写信号线,高电平时进行读操作,低电平时进行写操作。当 RS 和 RW 共同为低电平时可以写入指令成者显示地址;当 RS 为低电平,RW 为高电平时可以读忙信号;当 RS 为高电平,RW 为低电平时可以写入数据。E:使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
1.4.2 基本操作时序
LCD1602 的基本的操作分为以下四种:状态字读操作:输入 RS=0、RW=1、E=1;输出:D0~7 读出为状态字;数据读出操作:输入 RS=1、RW=1、E=1;输出:D0~7 读出为数据;指令写入操作:输入 RS=0、RW=0、E=上升沿; 输出:无;数据写入操作:输入 RS=1、RW=0、E=上升沿; 输出:无
读操作的时序图
当我们要写指令时候,RS 置为低电平,RW 置为低电平,E 置为低电平,然后将指令数据送到数据口D0~D7,延时 tsp1,让 LCD1602 准备接收数据,这时候将 E 拉高,产生一个上升沿,这时候指令就开始写入 LCD1602,延时一段时间,将 E 置为低电平。
写操作的时序图当我们要写数据的时候,RS 置为高电平,RW 置为低电平,E 置为低电平,然后将指令数据送到数据口D0~D7,延时 tsp1,让 LCD1602 准备接收数据,这时候将 E 拉高,产生一个上升沿,这时候数据就开始写入 LCD1602,延时一段时间,将 E 置为低电平。
1.4.3 LCD1602显存地址

1.4.4 LCD1602字符表
字符表如下,和 ASCII 码相似,这就和我们写入字符时带来了方便
例如我想写入a,在ASCII 码中a是97,在LCD1602字符表中a也是97,就不用换算了

1.4.5 LCD1602上电初始化

2. 分功能实现
2.1 蜂鸣器实验
回顾一下点灯实验,我们只需要把灯改成蜂鸣器就好了
不管任何实验,第一步肯定是初始化xxx
第一步:初始化蜂鸣器(假设把蜂鸣器接到PB7引脚)
初始化GPIO
配置GPIO
设置默认蜂鸣器关
第二步:写所需要函数
打开蜂鸣器(引脚接到低电平时蜂鸣器响)
关闭蜂鸣器
蜂鸣器状态获取(这一个往往在与别的硬件功能一块实现时使用)
#include "alarm.h"
#include "sys.h"//初始化GPIO函数
void alarm_init(void)
{GPIO_InitTypeDef gpio_initstruct;//打开时钟__HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟//调用GPIO初始化函数gpio_initstruct.Pin = GPIO_PIN_7; // LED1对应的引脚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);//关闭LEDalarm_off();
}//点亮LED1的函数
void alarm_on(void)
{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET); // 拉低LED1引脚,点亮LED1
}//熄灭LED1的函数
void alarm_off(void)
{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET); // 拉高LED1引脚,熄灭LED1
}
//蜂鸣器状态
uint8_t alarm_status_get(void)
{return HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7);}
以上写在alarm.c,别忘了头文件alarm.h补充函数声明
若使用uint8_t,需要添加#include "stdint.h"t头文件
#ifndef __ALARM_H__
#define __ALARM_H__
#define ALARM_STATUS_ON 0
#define ALARM_STATUS_OFF 1
#include "stdint.h"void alarm_init(void);
void alarm_on(void);
void alarm_off(void);
uint8_t alarm_status_get(void);#endif
2.2 继电器实验
同蜂鸣器
2.3 红外模块实验
.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_GPIOA_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_get();ia_flag = FALSE;return temp;}void ia_flag_set(uint8_t value)
{ia_flag = value;
}
.h
#ifndef __EXTI_H__
#define __EXTI_H__#include "stdint.h"#define TRUE 1
#define FALSE 0void exti_init(void);
uint8_t ia_flag_get(void);
void ia_flag_set(uint8_t value);#endif
2.4 LCD1602显示实验
第一步:初始化LCD1602
void lcd1602_init(void)
{lcd1602_gpio_init();//GPIO初始化lcd1602_start();//上电初始化
}
①初始化GPIO,并配置GPIO
void lcd1602_gpio_init(void)
{GPIO_InitTypeDef gpio_initstruct;__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();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.Speed=GPIO_SPEED_FREQ_HIGH;gpio_initstruct.Pull=GPIO_PULLUP;HAL_GPIO_Init(GPIOA,&gpio_initstruct);gpio_initstruct.Pin=GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10;gpio_initstruct.Mode=GPIO_MODE_OUTPUT_PP;gpio_initstruct.Speed=GPIO_SPEED_FREQ_HIGH;gpio_initstruct.Pull=GPIO_PULLUP;HAL_GPIO_Init(GPIOB,&gpio_initstruct);
}
② LCD1602上电初始化
把1.4.5的图拿过来了,对应着写代码
void lcd1602_start(void)
{delay_ms(15);lcd1602_write_cmd(0x38);delay_ms(5);lcd1602_write_cmd(0x38);lcd1602_write_cmd(0x08);lcd1602_write_cmd(0x01);lcd1602_write_cmd(0x06);lcd1602_write_cmd(0x0C);
};
void lcd1602_write_cmd(char cmd)
{RS_LOW;RW_LOW;EN_LOW;GPIOA->ODR=cmd;delay_ms(5);EN_HIGH;delay_ms(5);EN_LOW;};
引脚太多,就定义了一下,以后改着方便
//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);
第二步:写所需要函数
①写入数据
void lcd1602_write_data(char datashow)
{RS_HIGH;RW_LOW;EN_LOW;GPIOA->ODR=datashow;delay_ms(5);EN_HIGH;delay_ms(5);EN_LOW;
};
②显示数据
显示字符(这里假设显示字符B)
第一行第一个是0x80,想在第一行第二个位置显示B,就是0x80+0x02
void lcd1602_show_char(void)
{//在哪里显示lcd1602_write_cmd(0x80+0x02);//显示什么lcd1602_write_data('B');
}
显示字符串(一共2行)
void lcd1602_show_line(char row,char col,char*string)
{switch(row){case 1:lcd1602_write_cmd(0x80+col);while (*string){lcd1602_write_data(*string);string++;}break;case 2:lcd1602_write_cmd(0x80+0x40+col);while (*string){lcd1602_write_data(*string);string++;}break;}
}
3. 整合起来
3.1 智能排队控制系统框架


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
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 0void exti_init(void);
uint8_t ia_flag_get(void);
void ia_flag_set(uint8_t value);#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);//关闭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);
}
gate.h
#ifndef __GATE_H__
#define __GATE_H__#include "stdint.h"#define GATE_STATUS_ON 0
#define GATE_STATUS_OFF 1void 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 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;}
}
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
led.c和led.h和之前文章的一样
task.c
#include "tasks.h"
#include "led.h"uint32_t led1_task_cnt = 0;
uint32_t led2_task_cnt = 0;uint8_t led1_task_flag = 0;
uint8_t led2_task_flag = 0;void systick_isr(void)
{if (led1_task_cnt < 1000)led1_task_cnt++;else{led1_task_flag = 1;led1_task_cnt = 0;}if (led2_task_cnt < 200)led2_task_cnt++;else{led2_task_flag = 1;led2_task_cnt = 0;}
}void task1(void)
{if(led1_task_flag == 0)return;led1_task_flag = 0;led1_toggle();
}void task2(void)
{if(led2_task_flag == 0)return;led2_task_flag = 0;led2_toggle();
}
task.h
#ifndef __TASKS_H__
#define __TASKS_H__#include "sys.h"void systick_isr(void);
void task1(void);
void task2(void);#endif
main.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, "Bai, Come on");}
3.2 教你写出代码
在3.1中各部分还是独立的,现在通过状态机使它们能配合彼此工作

开始正式实现功能了,main函数里使用多线程
main.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, 1, "PASS...");while(1){ led1_task();led2_task();sensor_task();}
}
在task.c中实现状态机

根据这个图,我们得有允许通行状态PASS_STATE和不允许通行状态WAIT_STATE,一般用枚举的方法表示(enum),然后这部分补充代码完全按照上图进行功能实现,代码有详细注释
#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){//计数加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, "WAIT...00/05");}
}


