基于STM32 实现排队系统,利用SysTick模拟多任务。(学习日记)

实验项目:

本次的实验项目没有难,就是把之前用过的模块整合了一下,大致的需求是

每次最多通过五人,允许通过时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中断服务函数中去添加任务的函数。

完结,整体感觉没有什么好讲的,都是一些很基础的东西。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

走下去-别回头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值