当前位置: 首页 > news >正文

【STM32】智能排队控制系统

1. 硬件准备

1.1 蜂鸣器

蜂鸣器的另一个应用——电动车报警系统

继电器,可以被形象地比作一个开关
能够通过控制小电流来打开或关闭大电流电路,实现电路的控制和信号的传递。
与普通的物理开关相比,继电器具有更高的可靠性和灵活性,能够应对复杂的电路控制需求

蜂鸣器GNDGND
I/OB5
VCC3V

1.2 继电器

继电器INB6
GNDGND
UCC5V

1.3 红外模块

模块中蓝色的电位器用于调节灵敏度,顺时针旋转,灵敏度变高,检测距离变长;逆时针越小,灵敏度变低,检测距离变短。
上电后电源指示灯(绿灯)亮。
当红外反射回来,OUT 输出低电平,输出指示灯(绿灯)亮
红外模块VCC3V3
GNDGND
OUTPB4
红外避障模块上的一对红外线发射与接收管,发射管发射出一定频率的红外线,当检测方向遇到障碍物时, 红外线反射回来被接收管接收,经过比较器(LM393)电路处理之后,信号输出接口输出低电平信号,同时绿色指示灯会亮起。
因为黑色能够吸收红外线(红外线不反射),而白色不行(红外线反射),所以除了避障可用作黑白线循迹、光电开关等等。

1.4 LCD1602

1.4.1 引脚配置

LCD1602GNDGND
VDD5V电源正极
V0通过电阻接地

液晶驱动电压,

调节对比度

RSPB1

寄存器选择:

1:数据寄存器

2:指令寄存器

RWPB2

读写操作选择:

1:读

2:写

EPB10

使能信号

D0PA0双向数据通信
D1PA1
D2PA2
D3PA3
D4PA4
D5PA5
D6PA6
D7PA7
BLA3V3背光正极
BLKGND背光负极
V0:液品显示器对比度调整端,接正电源时对比度最高,接地时对比度最低,对比度过高时会产生“鬼影,使用时可以通过电位器或电阻调整对比度。电阻小了全是黑块,电阻大了不显示。
RW:读写信号线,高电平时进行读操作,低电平时进行写操作。
RS RW 共同为低电平时可以写入指令成者显示地址;
RS 为低电平,RW 为高电平时可以读忙信号;
RS 为高电平,RW 为低电平时可以写入数据。
E:使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。

1.4.2 基本操作时序

LCD1602 的基本的操作分为以下四种:
状态字读操作:输入 RS=0RW=1E=1;输出:D0~7 读出为状态字;
数据读出操作:输入 RS=1RW=1E=1;输出:D0~7 读出为数据;
指令写入操作:输入 RS=0RW=0E=上升沿; 输出:无;
数据写入操作:输入 RS=1RW=0E=上升沿; 输出:无

读操作的时序图

当我们要写指令时候,RS 置为低电平,RW 置为低电平,E 置为低电平,然后将指令数据送到数据口D0~D7,延时 tsp1,让 LCD1602 准备接收数据,这时候将 E 拉高,产生一个上升沿,这时候指令就开始写入 LCD1602,延时一段时间,将 E 置为低电平。
写操作的时序图

当我们要写数据的时候,RS 置为高电平,RW 置为低电平,E 置为低电平,然后将指令数据送到数据口D0~D7,延时 tsp1,让 LCD1602 准备接收数据,这时候将 E 拉高,产生一个上升沿,这时候数据就开始写入 LCD1602,延时一段时间,将 E 置为低电平。
对比一下可以发现,写指令和写数据在时序上只是 RS 的不同,写指令 RS=0,写数据 RS=1

1.4.3 LCD1602显存地址

写入显示地址时要求最高位 D7 为高电平,也就是说,如果想你想
写入第一行第一个字符应该是:
00000000B00H+ 10000000B(80H) = 10000000B(80H)
写入第二行第一个字符应该是:
01000000B40H+ 10000000B(80H) = 11000000B(C0H)

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");}
}

http://www.dtcms.com/a/568997.html

相关文章:

  • AISaaS出海工具整理
  • 电商网站如何做精细化运营dw软件下载官方免费下载
  • 在线教程丨端侧TTS新SOTA!NeuTTS-Air基于0.5B模型实现3秒音频克隆
  • 测试开发话题10---自动化测试常用函数(2)
  • Auto CAD二次开发——镜像图形对象
  • 软考 关于23种设计模式
  • golang 网站开发 教程网站建设公司如何规避风险
  • 建设电子商务网站论文网站开发核心技术
  • nestjs集成grpc服务
  • Milvus:标量索引详解(十三)
  • 【仓颉纪元】仓颉学习深度实践:30 天从零基础到独立开发
  • RocketMQ【入门实践】
  • Harmony鸿蒙开发0基础入门到精通Day11--TypeScript篇
  • 网站做广告的好处软件定制开发平台
  • 从智能手表拆解看硬件与软件的魔法融合 -嵌入式开发
  • 【java基础语法】---- 综合训练
  • BKA-Transformer-LSTM多变量时间序列预测Matlab实现
  • 如何自己创造一个网站平台搬瓦工装WordPress
  • 数式Oinone亮相GOTC 2025开源集市,企业级产品化引擎冲击Gitee当日热门项目
  • 【产品研究】生物力学软件 SIMM 4.0 for Windows 用户手册总结
  • 更新公司网站内容需要山东住房和城乡建设局网站首页
  • Unity与Android原生交互开发入门篇 - 打开Android的设置
  • 如何查看Linux系统版本?
  • Python类和对象--生命周期方法(对象生命周期,内存管理机制-存储,垃圾回收)
  • PAIMON+STARROCKS 学习
  • *曲速引擎的核心思想
  • AI时代下医药项目管理效能提升与知识管理案例分享︱奥锐特药业研发中心主任庄守群
  • 路由器构建园区网
  • 陕西建设网站如何建立免费网站
  • 设计网站账号品牌策划公司广告语