基于STM32的铁路自动围栏系统设计

2024-03-07  

一、项目背景

随着城市规模的不断扩大和交通运输方式的日益发展,铁路与公路的交叉口已经成为常见的场景。然而,这些交叉口往往存在一定的安全隐患,因为有时不易发现列车行进的情况,导致公路上的车辆或行人可能会无意中闯入铁路区域,从而引发重大交通事故。

为了解决这个问题,当前开发了一款基于STM32的铁路自动围栏系统。该系统采用了STM32F103RCT6作为主控芯片,并使用步进电机来控制铁路围栏的开启和闭合。同时,系统还配备了红外感应器,以便能够及时监测到列车的通过情况。

当系统监测到有列车即将通过铁路交叉口时,公路信号灯会立刻变为红灯,蜂鸣器也会发出警报声音,以提醒行人和车辆注意安全。同时,铁路两侧的围栏也会自动关闭,在列车通过后再次打开。这样,就能有效地防止公路车辆和行人误闯铁路区域,保障了路人的安全。

image-20230517104342760

二、系统设计

2.1 硬件部分

STM32F103RCT6主铁路自动围栏系统的硬件部分主要包括:STM32F103RCT6主控芯片、步进电机、红外感应器、信号灯、蜂鸣器。 【1】STM32F103RCT6主控芯片是整个系统的核心,负责控制围栏的开启和闭合、监测红外感应器的状态、控制信号灯的变化以及控制蜂鸣器的报警声音。

【2】步进电机是用来控制铁路围栏的开启和闭合的设备,其动力来源为驱动芯片ULN2003。

【3】红外感应器是用来监测列车的通过情况,当感应到列车时输出高电平信号,否则输出低电平信号。

【4】信号灯则用来提示道路行人和车辆当前状态,红灯表示停止,绿灯表示通行。

【5】蜂鸣器则是用来发出报警声音,提醒行人和车辆注意安全。

2.2 软件部分

程序主要分为四部分:系统初始化、红外感应器检测、铁路围栏控制和信号灯控制。

【1】系统初始化主要是对硬件进行初始化,包括设置STM32的时钟、GPIO口的初始化等。

【2】红外感应器检测部分则是对红外感应器进行监测,当感应到列车时输出高电平信号,程序通过读取该信号实现对铁路围栏的控制和信号灯的变化。

【3】铁路围栏控制部分主要是通过对步进电机的控制来实现围栏的开启和闭合。

【4】信号灯控制部分则是通过对GPIO口的控制来实现信号灯的变化,当感应到列车时,将信号灯变为红色,否则为绿色。

三、核心代码实现

3.1 28BYJ48步进电机代码

以下是使用STM32F103RCT6驱动28BYJ-48步进电机实现正反转控制并封装成子函数调用的完整代码实现过程。

首先,需要定义相关引脚和变量:


#include "stm32f10x.h"

#define IN1_PIN GPIO_Pin_0

#define IN2_PIN GPIO_Pin_1

#define IN3_PIN GPIO_Pin_2

#define IN4_PIN GPIO_Pin_3

GPIO_InitTypeDef GPIO_InitStructure;

uint8_t step = 0;

然后,编写初始化GPIO的代码:


void init_GPIO(void)

{

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

  GPIO_InitStructure.GPIO_Pin = IN1_PIN | IN2_PIN | IN3_PIN | IN4_PIN;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

}

接着,编写正转和反转函数的代码:


void forward(void)

{

  switch(step)

   {

    case 0:

      GPIO_SetBits(GPIOA, IN1_PIN);

      GPIO_ResetBits(GPIOA, IN2_PIN | IN3_PIN | IN4_PIN);

      break;

    case 1:

      GPIO_SetBits(GPIOA, IN1_PIN | IN2_PIN);

      GPIO_ResetBits(GPIOA, IN3_PIN | IN4_PIN);

      break;

    case 2:

      GPIO_SetBits(GPIOA, IN2_PIN);

      GPIO_ResetBits(GPIOA, IN1_PIN | IN3_PIN | IN4_PIN);

      break;

    case 3:

      GPIO_SetBits(GPIOA, IN3_PIN | IN2_PIN);

      GPIO_ResetBits(GPIOA, IN1_PIN | IN4_PIN);

      break;

    case 4:

      GPIO_SetBits(GPIOA, IN3_PIN);

      GPIO_ResetBits(GPIOA, IN1_PIN | IN2_PIN | IN4_PIN);

      break;

    case 5:

      GPIO_SetBits(GPIOA, IN4_PIN | IN3_PIN);

      GPIO_ResetBits(GPIOA, IN1_PIN | IN2_PIN);

      break;

    case 6:

      GPIO_SetBits(GPIOA, IN4_PIN);

      GPIO_ResetBits(GPIOA, IN1_PIN | IN2_PIN | IN3_PIN);

      break;

    case 7:

      GPIO_SetBits(GPIOA, IN1_PIN | IN4_PIN);

      GPIO_ResetBits(GPIOA, IN2_PIN | IN3_PIN);

      break;

   }

  step++;

  if(step == 8)

   {

    step = 0;

   }

}

void backward(void)

{

  switch(step)

   {

    case 0:

      GPIO_SetBits(GPIOA, IN1_PIN | IN4_PIN);

      GPIO_ResetBits(GPIOA, IN2_PIN | IN3_PIN);

      break;

    case 1:

      GPIO_SetBits(GPIOA, IN4_PIN);

      GPIO_ResetBits(GPIOA, IN1_PIN | IN2_PIN | IN3_PIN);

      break;

    case 2:

      GPIO_SetBits(GPIOA, IN3_PIN | IN4_PIN);

      GPIO_ResetBits(GPIOA, IN1_PIN | IN2_PIN);

      break;

    case 3:

      GPIO_SetBits(GPIOA, IN3_PIN);

      GPIO_ResetBits(GPIOA, IN1_PIN | IN2_PIN | IN4_PIN);

      break;

    case 4:

      GPIO_SetBits(GPIOA, IN2_PIN | IN3_PIN);

      GPIO_ResetBits(GPIOA, IN1_PIN | IN4_PIN);

      break;

    case 5:

      GPIO_SetBits(GPIOA, IN2_PIN);

      GPIO_ResetBits(GPIOA, IN1_PIN | IN3_PIN | IN4_PIN);

      break;

    case 6:

      GPIO_SetBits(GPIOA, IN1_PIN | IN2_PIN);

      GPIO_ResetBits(GPIOA, IN3_PIN | IN4_PIN);

      break;

    case 7:

      GPIO_SetBits(GPIOA, IN1_PIN);

      GPIO_ResetBits(GPIOA, IN2_PIN | IN3_PIN | IN4_PIN);

      break;

   }

  step--;

  if(step == -1)

   {

    step = 7;

   }

}

最后,可以封装正转和反转函数成子函数:


void rotate_motor(int steps, int direction)

{

  int i = 0;

  for(i = 0; i < steps; i++)

     {

         if(direction == 0)

         {

             forward();

         }

         else if(direction == 1)

     {

         backward();

     }

 }

 

 void motor_stop(void)

 {

     GPIO_ResetBits(GPIOA, IN1_PIN | IN2_PIN | IN3_PIN | IN4_PIN);

 }

最后,可以在主函数中使用这些封装好的子函数:


int main(void)

{

  init_GPIO();

  // 正转200步

  rotate_motor(200, 0);

  // 反转100步

  rotate_motor(100, 1);

  // 停止电机

  motor_stop();

  while (1);

}

3.2 蜂鸣器报警代码

#include "stm32f10x.h"

#define BUZZER_GPIO_PIN GPIO_Pin_7 

#define BUZZER_GPIO_PORT GPIOC

void buzzer_init(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

  GPIO_InitStructure.GPIO_Pin = BUZZER_GPIO_PIN;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(BUZZER_GPIO_PORT, &GPIO_InitStructure);

}

void buzzer_on(void)

{

  GPIO_SetBits(BUZZER_GPIO_PORT, BUZZER_GPIO_PIN); // Buzzer on

}

void buzzer_off(void)

{

  GPIO_ResetBits(BUZZER_GPIO_PORT, BUZZER_GPIO_PIN); // Buzzer off

}

3.3 红外感应器代码

#include "stm32f10x.h"

#define IR_GPIO_PIN GPIO_Pin_1 

#define IR_GPIO_PORT GPIOA

void ir_init(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

  EXTI_InitTypeDef EXTI_InitStructure;

  NVIC_InitTypeDef NVIC_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

  GPIO_InitStructure.GPIO_Pin = IR_GPIO_PIN;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // 下拉输入模式

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(IR_GPIO_PORT, &GPIO_InitStructure);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);

  EXTI_InitStructure.EXTI_Line = EXTI_Line1; // 对应中断线 EXTI1

  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; // 上升沿和下降沿触发

  EXTI_InitStructure.EXTI_LineCmd = ENABLE;

  EXTI_Init(&EXTI_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; // 中断向量

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; // 抢占优先级2

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; // 响应优先级3

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

}

void EXTI1_IRQHandler(void)

{

  if (EXTI_GetITStatus(EXTI_Line1) != RESET)

   {

    // Do something when IR sensor detects the train

    EXTI_ClearITPendingBit(EXTI_Line1);

   }

}

3.4 信号灯控制代码

#include "stm32f10x.h"

#define LED_GREEN_GPIO_PIN GPIO_Pin_6 

#define LED_GREEN_GPIO_PORT GPIOB

#define LED_RED_GPIO_PIN GPIO_Pin_7 

#define LED_RED_GPIO_PORT GPIOB

void led_init(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

  GPIO_InitStructure.GPIO_Pin = LED_GREEN_GPIO_PIN | LED_RED_GPIO_PIN;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(GPIOB, &GPIO_InitStructure);

}

void led_green_on(void)

{

  GPIO_SetBits(LED_GREEN_GPIO_PORT, LED_GREEN_GPIO_PIN); // Green LED on

}

void led_green_off(void)

{

  GPIO_ResetBits(LED_GREEN_GPIO_PORT, LED_GREEN_GPIO_PIN); // Green LED off

}

void led_red_on(void)

{

  GPIO_SetBits(LED_RED_GPIO_PORT, LED_RED_GPIO_PIN); // Red LED on

}

void led_red_off(void)

{

  GPIO_ResetBits(LED_RED_GPIO_PORT, LED_RED_GPIO_PIN); // Red LED off

}

四、总结

当前设计的这种基于STM32的铁路自动围栏系统,通过对铁路交叉口进行有效的监测和控制,实现了对过往车辆和行人的有效防护。该系统采用STM32F103RCT6作为主控芯片,使用步进电机控制铁路围栏的开启和闭合,使用红外感应器来监测列车的通过情况。在公路与铁路的交叉路口,若在远处感应到有列车即将通过,则公路信号灯变为红灯,蜂鸣器报警,铁路两侧围栏自动闭合;直至感应到列车彻底离开,公路信号灯变为绿灯,蜂鸣器关闭,围栏打开。系统具有结构简单、性能可靠等优点,在实际应用中取得了良好的效果。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。