实验项目:
本次的实验项目没有难,就是把之前用过的模块整合了一下,大致的需求是
每次最多通过五人,允许通过时led1闪烁,蜂鸣器不响,门开,不允许通过时,led2闪烁
门关。
硬件:
LCD1602 STM32 红外模块
ST-Link 蜂鸣器 继电器
硬件接线
(注)led的io口根据自己实际的进行更改。
代码
led.c
#include "led.h"
#include "sys.h"
//初始化GPIO函数
void led_init(void)
{
//打开时钟
__HAL_RCC_GPIOB_CLK_ENABLE();
//调用gpio初始化函数
GPIO_InitTypeDef LED1 ;
LED1.Pin = GPIO_PIN_8|GPIO_PIN_9;
LED1.Mode = GPIO_MODE_OUTPUT_PP;
LED1.Pull = GPIO_PULLUP;
LED1.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB,&LED1);
//关闭led
led1_off();
//点亮led2
led2_on();
}
//点亮led函数
void led1_on(void)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
}
//点亮led2函数
void led2_on(void)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
}
//熄灭led函数
void led1_off(void)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
}
void led2_off(void)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);
}
//反转个状态
void led_toggle(void)
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
}
void led2_toggle(void)
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
}
led.h
#ifndef __LED_H__
#define __LED_H__
//初始化GPIO函数
void led_init(void);
//点亮led函数
void led1_on(void);
void led2_on(void);
//熄灭led函数
void led1_off(void);
void led2_off(void);
//反转个状态
void led_toggle(void);
void led2_toggle(void);
#endif
蜂鸣器相关代码:beep.c
#include "beep.h"
#include "sys.h"
//gpio初始化
void GPIO_Init()
{
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef GPIO_Struct;
GPIO_Struct.Pin = GPIO_PIN_5;
GPIO_Struct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_Struct.Pull = GPIO_PULLUP;
GPIO_Struct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB,&GPIO_Struct);
}
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 GPIO_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相关代码:lcd1602.c
#include "lcd1602.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);
//EA引脚
#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_GPIO_init(void)
{
//A组初始化
GPIO_InitTypeDef gpio_struct;
__HAL_RCC_GPIOA_CLK_ENABLE();
gpio_struct.Mode = GPIO_MODE_OUTPUT_PP;
gpio_struct.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_struct.Pull = GPIO_PULLUP;
gpio_struct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&gpio_struct);
//B组初始化
__HAL_RCC_GPIOB_CLK_ENABLE();
gpio_struct.Mode = GPIO_MODE_OUTPUT_PP;
gpio_struct.Pin = GPIO_PIN_1 | GPIO_PIN_2 |GPIO_PIN_10;
gpio_struct.Pull = GPIO_PULLUP;
gpio_struct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB,&gpio_struct);
}
void lcd1602_start(void)
{
delay_ms(15);
lcd1602_wirte_cmd(0x38);
delay_ms(5);
lcd1602_wirte_cmd(0x38);
lcd1602_wirte_cmd(0x08);
lcd1602_wirte_cmd(0x01);
lcd1602_wirte_cmd(0x06);
lcd1602_wirte_cmd(0x0C);
}
void lcd1602_init(void)
{
//初始化gpio口
lcd1602_GPIO_init();
//上电初始化
lcd1602_start();
}
void lcd1602_wirte_cmd(char cmd)
{
RS_LOW;
RW_LOW;
EN_LOW;
GPIOA->ODR = cmd;
delay_ms(5);
EN_HIGH;
delay_ms(5);
EN_LOW;
}
void lcd1602_wirte_data(char dataShow)
{
RS_HIGH;
RW_LOW;
EN_LOW;
GPIOA->ODR = dataShow;
delay_ms(5);
EN_HIGH;
delay_ms(5);
EN_LOW;
}
void lcd1602_show_char(void)
{
//在哪里显示
lcd1602_wirte_cmd(0x80 + 0x02);
//显示什么?
lcd1602_wirte_data('L');
}
void lcd1602_show_line(char row, char col,char *string)
{
switch(row)
{
case 1:
lcd1602_wirte_cmd(0x80 + col);
while(*string)
{
lcd1602_wirte_data(*string);
string++;
}
break;
case 2:
lcd1602_wirte_cmd(0x80 + 0x40 + col);
while(*string)
{
lcd1602_wirte_data(*string);
string++;
}
break;
}
}
lcd1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
#include "sys.h"
void lcd1602_GPIO_init(void);
void lcd1602_start(void);
void lcd1602_init(void);
void lcd1602_wirte_data(char dataShow);
void lcd1602_wirte_cmd(char cmd);
void lcd1602_show_char(void);
void lcd1602_show_line(char row, char col,char *string);
#endif
延时代码:delay.c
#include "delay.h"
/**
* @brief 微秒级延时
* @param nus 延时时长,范围:0~233015
* @retval 无
*/
void delay_us(uint32_t nus)
{
uint32_t ticks;
uint32_t tcnt = 0,told, tnow;
uint32_t reload = SysTick->LOAD;
ticks = nus * 72;
told = SysTick->VAL;
while(1)
{
tnow = SysTick->VAL;
if( tnow != told)
{
if( tnow < told)
{
tcnt += told - tnow;
}
else
{
tcnt += reload - ( tnow - told);
}
told = tnow;
if(tcnt >= ticks)
{
break;
}
}
}
}
/**
* @brief 毫秒级延时
* @param nms 延时时长,范围:0~4294967295
* @retval 无
*/
void delay_ms(uint32_t nms)
{
while(nms--)
delay_us(1000);
}
/**
* @brief 秒级延时
* @param ns 延时时长,范围:0~4294967295
* @retval 无
*/
void delay_s(uint32_t ns)
{
while(ns--)
delay_ms(1000);
}
/**
* @brief 重写HAL_Delay函数
* @param nms 延时时长,范围:0~4294967295
* @retval 无
*/
void HAL_Delay(uint32_t nms)
{
delay_ms(nms);
}
delay.h
#ifndef __DELAY_H__
#define __DELAY_H__
#include "sys.h"
void delay_ms(uint32_t nms); /* 延时nms */
void delay_us(uint32_t nus); /* 延时nus */
void delay_s(uint32_t ns); /* 延时ns */
void HAL_Delay(uint32_t nms); /* 延时nms */
#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
任务相关代码:tasks.c
#include "tasks.h"
#include "led.h"
#include "beep.h"
#include "gate.h"
#include "exti.h"
#include "lcd1602.h"
#include "stdio.h"
enum
{
PASS_STATE,
WAIT_STATE
} ;
uint32_t led1_task1_cnt = 0;
uint32_t led2_task2_cnt = 0;
uint32_t passenger = 0;
uint8_t led1_task_flag = 0;
uint8_t led2_task2_flag = 0;
uint8_t state = PASS_STATE;
uint32_t Timer_cnt = 0;
uint8_t Timer_flag = 0;
char message[16] = {0};
void systick_isr(void)
{
//允许通行
if(state == PASS_STATE)
{
//LED1以1秒的频率闪烁
if(led1_task1_cnt < 1000)
{
led1_task1_cnt++;
}else{
led1_task_flag = 1;
led1_task1_cnt = 0;
}
//LED2不闪烁
led2_off();
//蜂鸣器不响
beep_off();
//开门
gate_off();
}
//不允许通行
else if(state == WAIT_STATE)
{
//LED1不闪
led1_off();
//LED2以200ms的频率闪烁
if(led2_task2_cnt < 200)
{
led2_task2_cnt++;
}else{
led2_task2_flag = 1;
led2_task2_cnt = 0;
}
//蜂鸣器响
beep_on();
//关门
gate_on();
//计时三秒
if(Timer_cnt < 3000)
{
Timer_cnt++;
}else{
Timer_flag = 1;
Timer_cnt = 0;
//允许通行
state = PASS_STATE;
}
}
}
void timer_task1()
{
if(Timer_flag == 1)
{
lcd1602_show_line(1,1,"PASS...");
}
}
void led1_task1(void)
{
if(led1_task_flag == 1)
{
led_toggle();
led1_task_flag = 0;
}
else
return;
}
void led2_task2(void)
{
if(led2_task2_flag == 1)
{
led2_toggle();
led2_task2_flag = 0;
}
else
return;
}
void sensor_task(void)
{
//检测有人通过
if(Ia_flag_get() == TRUE && state == PASS_STATE)
{
//计数+1
passenger++;
//显示状态
sprintf(message,"pass...%02d/05",passenger);
lcd1602_show_line(1,1,message);
}
//如果通过的人数超过五个
if(passenger >= 5)
{
//计数清0;
passenger = 0;
//进入不允许通行状态
state = WAIT_STATE;
//lcd显示
lcd1602_show_line(1,1,"wait...00/05");
}
}
tasks.h
#ifndef __TASKS_H__
#define __TASKS_H__
#include "sys.h"
void systick_isr(void);
void led1_task1(void);
void led2_task2(void);
void sensor_task(void);
#endif
main函数:main.c
#include "sys.h"
#include "led.h"
#include "delay.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();
gate_init();
GPIO_Init();
exti_init();
lcd1602_GPIO_init();
//lcd1602_show_line(2,1,"CHEN");
while(1)
{
led1_task1();
led2_task2();
led2_task2();
}
}
由于使用了SysTick来模拟多任务,所以记得在SysTick中断服务函数中去添加任务的函数。
完结,整体感觉没有什么好讲的,都是一些很基础的东西。