写点什么

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

作者:DS小龙哥
  • 2023-06-19
    重庆
  • 本文字数:4518 字

    阅读完需:约 15 分钟

一、项目背景

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


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


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


二、系统设计

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 作为主控芯片,使用步进电机控制铁路围栏的开启和闭合,使用红外感应器来监测列车的通过情况。在公路与铁路的交叉路口,若在远处感应到有列车即将通过,则公路信号灯变为红灯,蜂鸣器报警,铁路两侧围栏自动闭合;直至感应到列车彻底离开,公路信号灯变为绿灯,蜂鸣器关闭,围栏打开。系统具有结构简单、性能可靠等优点,在实际应用中取得了良好的效果。

发布于: 2023-06-19阅读数: 15
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022-01-06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
基于STM32的铁路自动围栏系统设计_6月优质更文活动_DS小龙哥_InfoQ写作社区