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

【STM32】电动车报警系统

1. 功能需求

按下按键A,常响2秒,打开报警功能,此时当电动车(振动传感器)晃动时,蜂鸣器叫,若想关闭蜂鸣器,按下按键B,则关闭报警功能,蜂鸣器停止叫声。

电动车报警系统

2. 硬件准备

2.1 硬件介绍

433M无线收发模块、蜂鸣器、振动传感器、STM32开发板、绝缘线、STLINK、typeC

2.1.1 433M无线收发模块

无线收发模块 433MHz(或称RF433射频小模块)采用高频射频技术,并结合了全数字技术和 AVR 单片机,成为一种微型收发器。
遥控器上有四个按键,分别对应 433M 模块的四个数据位输出脚 D0D1D2D3。按下按
键发射信号,对应的引脚就会输出高电平
那么,433M 模块一般按照工作模式分类,有三种工作模式:
  1. M 点动:瞬态输出,相当于自复位开关的状态收到信息输出高电平,无信号时为低电平。
  2. T 锁存:上电时为低,收到信号输出高电平并锁定高,再次收到信号输出低并锁定低。
  3. L 自锁:上电时为低,收到信号输出高电平并锁定高,同时将其他输出置低。
比如我的模块是 M4 点动,「4」表示有4个按键,按一下按键 AD0 将输出一个高电平。

2.1.2 振动传感器

我用的是SW-18010P
接好 VCC GND,电源指示灯将被点亮。
当检测到震动时,板载指示灯点亮;震动停止,板载指示灯熄灭。
用螺丝刀转动「灵敏度调节电位器」可以调节灵敏度。大家可以将电位器旋到最左或最右,然后测试往哪边旋可以提高灵敏度。
SW-18015P 在无震动或者震动强度达不到设定阈值时,DO 口输出高电平;当外界震动强度超过设定阈值时,模块 D0 输出低电平

2.1.3 蜂鸣器

如何让蜂鸣器鸣响?将I/O引脚拉低即可。
模块工作电压:3.3V

2.2 引脚连接

433M无线收发模块GNDGND
5V5V
D0PB4
D1PA11
振动传感器VCC3V3
GNDGND
DOPA4
AO不接
蜂鸣器GNDGND
IOPB7
VCC3V3

3. 分步实现功能

先分别实现振动点灯功能、无线收发信号、蜂鸣器功能,再集成

3.1 振动点灯功能

3.1.1 准备好写过的led.c文件

#include "led.h"
#include "sys.h"//初始化GPIO函数
void led_init(void)
{GPIO_InitTypeDef gpio_initstruct;//打开时钟__HAL_RCC_GPIOB_CLK_ENABLE();                           // 使能GPIOB时钟//调用GPIO初始化函数gpio_initstruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;          // 两个LED对应的引脚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);//关闭LEDled1_off();led2_off();
}//点亮LED1的函数
void led1_on(void)
{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);   // 拉低LED1引脚,点亮LED1
}//熄灭LED1的函数
void led1_off(void)
{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);     // 拉高LED1引脚,熄灭LED1
}//翻转LED1状态的函数
void led1_toggle(void)
{HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
}//点亮LED2的函数
void led2_on(void)
{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET);   // 拉低LED2引脚,点亮LED2
}//熄灭LED2的函数
void led2_off(void)
{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);     // 拉高LED2引脚,熄灭LED2
}//翻转LED2状态的函数
void led2_toggle(void)
{HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_9);
}

3.1.2 写exti.c文件

第一步:进行初始化,写初始化函数

     写任何实验都必要的步骤       

  1. 打开时钟
  2. 调用GPIO初始化函数
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(GPIOA, &gpio_initstruct);HAL_NVIC_SetPriority(EXTI4_IRQn, 2, 0);                 // 设置EXTI0中断线的优先级HAL_NVIC_EnableIRQ(EXTI4_IRQn);                         // 使能中断
}

这里用到了中断,下次再详细讲中断,这次先简单了解一下~

 ①HAL_NVIC_SetPriority和HAL_NVIC_EnableIRQ都是中断配置函数

        HAL_NVIC_SetPriority是中断优先级配置,HAL_NVIC_EnableIRQ是中断使能配置

        设置中断分组 → 设置中断优先级 使能中断

②配置EXTI,其实就是按着顺序写实现中断功能

第二步:此时就剩中断服务函数EXTI4_IRQHandler没写了,为实现所需功能,一般会用到回调函数HAL_GPIO_EXTI_Callback,后面根据需要功能再写回调函数

void EXTI4_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
}void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{}

第三步:设立标志位,这一步需要和main.c配合看才能理解

实际上是检测到振动和没有振动的区别:检测到振动,标志位为1,无振动,标志位为0

在main.c中实现主功能,如果检测到振动,即vibrate_flag_get() == 1,那么就点亮LED1两秒然后熄灭,此时要把标志位置为0,vibrate_flag_set(0),否则标志位一直为1就没有区分的效果了

uint8_t vibrate_flag_get(void)
{uint8_t temp = vibrate_flag;vibrate_flag = FALSE;return temp;}void vibrate_flag_set(uint8_t value)
{vibrate_flag = value;
}

第四步:设立标志位后,怎么和振动传感器联系起来——回调函数

当振动传感器感受到振动时,PA4收到低电平,见“2.1.2 振动传感器”

用HAL_GPIO_ReadPin读PA4,如果是低电平0(GPIO_PIN_RESET),则标志位为1

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{//delay_ms(20);if (GPIO_Pin == GPIO_PIN_4){if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET)//led1_toggle();vibrate_flag = TRUE;}
}

3.1.3 写main.c

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "exti.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */led_init();                         /* 初始化LED灯 */exti_init();                        /* 初始化EXTI */while(1){ //如果检测到震动if(vibrate_flag_get() == TRUE){//那么就点亮LED1两秒,然后熄灭led1_on();delay_ms(2000);led1_off();vibrate_flag_set(FALSE);}}
}

别忘了补充.h文件的函数声明

3.2 无线收发信号功能

如果检测到A键按下,就翻转LED1状态;如果检测到B键按下,就翻转LED2状态

3.2.1 main.c

很容易理解,就是平常的初始化HAL库和一些函数、设置时钟,然后翻转灯的功能实现

可以扩展到电动车报警系统,翻转的把灯改为蜂鸣器就好了!

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "exti.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */led_init();                         /* 初始化LED灯 */exti_init();                        /* 初始化EXTI */while(1){ if(buttonA_flag_get() == TRUE)  //如果检测到A键按下led1_toggle();              //则翻转LED1状态if(buttonB_flag_get() ==  TRUE) //如果检测到B键按下led2_toggle();              //则翻转LED2状态}
}

3.2.2 exti.c

两个按键,在3.1.2的exti.c文件中只设置了一个中断,现在copy过来后,再加一个中断就好了

标志位也只设了一个,我们现在再加一个

等于都要3.1.2的双份的

#include "exti.h"
#include "sys.h"
#include "delay.h"
#include "led.h"uint8_t buttonA_flag = FALSE;                               // 按键A按下的标志位
uint8_t buttonB_flag = FALSE;                               // 按键B按下的标志位void exti_init(void)
{GPIO_InitTypeDef gpio_initstruct;//打开时钟__HAL_RCC_GPIOA_CLK_ENABLE();                           // 使能GPIOA时钟__HAL_RCC_GPIOB_CLK_ENABLE();//按键B中断配置gpio_initstruct.Pin = GPIO_PIN_12;                      // 按键B对应的引脚gpio_initstruct.Mode = GPIO_MODE_IT_RISING;             // 上升沿触发gpio_initstruct.Pull = GPIO_PULLDOWN;                   // 下拉HAL_GPIO_Init(GPIOA, &gpio_initstruct);HAL_NVIC_SetPriority(EXTI15_10_IRQn, 2, 0);             // 设置EXTI15_10中断线的优先级HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);                     // 使能中断//按键A中断配置gpio_initstruct.Pin = GPIO_PIN_5;                       // 按键A对应的引脚gpio_initstruct.Mode = GPIO_MODE_IT_RISING;             // 上升沿触发gpio_initstruct.Pull = GPIO_PULLDOWN;                   // 下拉HAL_GPIO_Init(GPIOB, &gpio_initstruct);HAL_NVIC_SetPriority(EXTI9_5_IRQn, 2, 0);               // 设置EXTI9_5中断线的优先级HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);                       // 使能中断
}void EXTI15_10_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
}void EXTI9_5_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_5);
}void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{//delay_ms(20);if (GPIO_Pin == GPIO_PIN_12)                                    //检测到B键按下{if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == GPIO_PIN_SET)//led2_toggle();buttonB_flag = TRUE;}else if (GPIO_Pin == GPIO_PIN_5)                                //检测到A键按下{if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5) == GPIO_PIN_SET)//led1_toggle();buttonA_flag = TRUE;}
}uint8_t buttonA_flag_get(void)
{uint8_t temp = buttonA_flag;buttonA_flag = FALSE;return temp;
}void buttonA_flag_set(uint8_t value)
{buttonA_flag = value;
}uint8_t buttonB_flag_get(void)
{uint8_t temp = buttonB_flag;buttonB_flag = FALSE;return temp;
}void buttonB_flag_set(uint8_t value)
{buttonB_flag = value;
}

led.c不变,补充.h文件就可尝试运行了

3.3 蜂鸣器功能

这个是最简单的,上面的会了,这个一看就懂了

beep.c

#include "beep.h"
#include "sys.h"void beep_init(void)
{GPIO_InitTypeDef gpio_initstruct;__HAL_RCC_GPIOB_CLK_ENABLE();gpio_initstruct.Pin=GPIO_PIN_8 ;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);void beep_off(void);}void beep_on(void)
{HAL_GPIO_WritePin(GPIOB , GPIO_PIN_8, GPIO_PIN_RESET);}
void beep_off(void)
{HAL_GPIO_WritePin(GPIOB , GPIO_PIN_8, GPIO_PIN_SET);}

main.c

#include "sys.h"
#include "uart1.h"
#include "delay.h"
#include "beep.h"int main()
{HAL_Init();stm32_clock_init(RCC_PLL_MUL9);beep_init();beep_off();//while(1)
//{
//	beep_on();
//	delay_ms(500);
//	beep_off();
//	delay_ms(500);
//}}

4. 整体功能实现

4.1 思路

4.2 代码

led.c

#include "led.h"
#include "sys.h"//初始化GPIO函数
void led_init(void)
{GPIO_InitTypeDef gpio_initstruct;//打开时钟__HAL_RCC_GPIOB_CLK_ENABLE();                           // 使能GPIOB时钟//调用GPIO初始化函数gpio_initstruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;          // 两个LED对应的引脚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);//关闭LEDled1_off();led2_off();
}//点亮LED1的函数
void led1_on(void)
{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);   // 拉低LED1引脚,点亮LED1
}//熄灭LED1的函数
void led1_off(void)
{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);     // 拉高LED1引脚,熄灭LED1
}//翻转LED1状态的函数
void led1_toggle(void)
{HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
}//点亮LED2的函数
void led2_on(void)
{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET);   // 拉低LED2引脚,点亮LED2
}//熄灭LED2的函数
void led2_off(void)
{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);     // 拉高LED2引脚,熄灭LED2
}//翻转LED2状态的函数
void led2_toggle(void)
{HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_9);
}

exti.c

#include "exti.h"
#include "sys.h"
#include "delay.h"
#include "led.h"uint8_t buttonA_flag = FALSE;                               // 按键A按下的标志位
uint8_t buttonB_flag = FALSE;                               // 按键B按下的标志位
uint8_t vibrate_flag = FALSE;                               // 检测到震动标志位void exti_init(void)
{GPIO_InitTypeDef gpio_initstruct;//打开时钟__HAL_RCC_GPIOA_CLK_ENABLE();                           // 使能GPIOA时钟__HAL_RCC_GPIOB_CLK_ENABLE();//按键B中断配置gpio_initstruct.Pin = GPIO_PIN_12;                      // 按键B对应的引脚gpio_initstruct.Mode = GPIO_MODE_IT_RISING;             // 上升沿触发gpio_initstruct.Pull = GPIO_PULLDOWN;                   // 下拉HAL_GPIO_Init(GPIOA, &gpio_initstruct);HAL_NVIC_SetPriority(EXTI15_10_IRQn, 2, 0);             // 设置EXTI15_10中断线的优先级HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);                     // 使能中断//按键A中断配置gpio_initstruct.Pin = GPIO_PIN_5;                       // 按键A对应的引脚gpio_initstruct.Mode = GPIO_MODE_IT_RISING;             // 上升沿触发gpio_initstruct.Pull = GPIO_PULLDOWN;                   // 下拉HAL_GPIO_Init(GPIOB, &gpio_initstruct);HAL_NVIC_SetPriority(EXTI9_5_IRQn, 2, 0);               // 设置EXTI9_5中断线的优先级HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);                       // 使能中断//震动传感器中断配置gpio_initstruct.Pin = GPIO_PIN_4;                       // 震动传感器对应的引脚gpio_initstruct.Mode = GPIO_MODE_IT_FALLING;            // 下降沿触发gpio_initstruct.Pull = GPIO_PULLUP;                     // 上拉HAL_GPIO_Init(GPIOA, &gpio_initstruct);HAL_NVIC_SetPriority(EXTI4_IRQn, 2, 0);                 // 设置EXTI0中断线的优先级HAL_NVIC_EnableIRQ(EXTI4_IRQn);                         // 使能中断
}void EXTI15_10_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
}void EXTI9_5_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_5);
}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_12)                                    //检测到B键按下{if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == GPIO_PIN_SET)//led2_toggle();buttonB_flag = TRUE;}else if (GPIO_Pin == GPIO_PIN_5)                                //检测到A键按下{if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5) == GPIO_PIN_SET)//led1_toggle();buttonA_flag = TRUE;}else if (GPIO_Pin == GPIO_PIN_4)                                //检测到震动{if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET)//led1_toggle();vibrate_flag = TRUE;}
}uint8_t buttonA_flag_get(void)
{uint8_t temp = buttonA_flag;buttonA_flag = FALSE;return temp;
}void buttonA_flag_set(uint8_t value)
{buttonA_flag = value;
}uint8_t buttonB_flag_get(void)
{uint8_t temp = buttonB_flag;buttonB_flag = FALSE;return temp;
}void buttonB_flag_set(uint8_t value)
{buttonB_flag = value;
}uint8_t vibrate_flag_get(void)
{uint8_t temp = vibrate_flag;vibrate_flag = FALSE;return temp;}void vibrate_flag_set(uint8_t value)
{vibrate_flag = value;
}

alarm.c

#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;                       // 继电器对应的引脚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();
}//闭合继电器的函数
void alarm_on(void)
{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);   // 拉低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 (uint8_t)HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7);
}

main.c

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "exti.h"
#include "alarm.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */led_init();                         /* 初始化LED灯 */exti_init();                        /* 初始化EXTI */alarm_init();                       /* 初始化继电器 */uint8_t alert_mode = FALSE;         //警戒模式标志while(1){ //A按键是否按下?if(buttonA_flag_get() == TRUE){alarm_on();delay_ms(2000);alarm_off();alert_mode = TRUE;}//B按键是否按下?if(buttonB_flag_get() == TRUE){if(alarm_status_get() == ALARM_STATUS_ON)alarm_off();else{alarm_on();delay_ms(1000);alarm_off();}alert_mode = FALSE;}//如果处于警戒模式if(alert_mode == TRUE){if(vibrate_flag_get() == TRUE)alarm_on();}elsevibrate_flag_set(FALSE);}
}

————下一篇:详细学习中断————

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

相关文章:

  • linux kernel struct clk_init_data结构浅解
  • ▲各类通信算法的FPGA开发学习教程——总目录
  • 2025企业秋招:AI笔试监考如何重塑秋招公平性?
  • Rust开发之常用标准库Trait实践(Display、From/Into)
  • XML与HTML
  • 太原做网站需要多少钱网页设计网站怎么放到域名里
  • 网站开发 费用怎么用PS做网站广告图
  • 算法专题十八:FloodFill算法(使用dfs)
  • 【11408学习记录】考研数学速成:n维随机变量分布函数详解(从定义到边缘分布一网打尽)
  • 网络安全应用题3:网络攻击与防范
  • 做网站设计赚钱吗做攻略的网站好
  • 用react和ant.d做的网站例子宣传推广方式
  • 网店网站设计php网站开发教学
  • 鸿蒙元服务深度实践:跨端唤醒与状态共享的设计模式
  • 【Linux】信号机制详解:进程间通信的核心
  • 当一家车企出现在AI顶会
  • 解锁AI交互新范式:MCP(Model Context Protocol)如何重塑模型上下文管理
  • 保定 网站制作网站策划ppt
  • C#知识学习-019(泛型类型约束关键字)
  • ioDraw实测:AI加持的全能图表工具,免费又好用?
  • GD32F407VE天空星开发板的188数码管
  • 时硕科技,隐形冠军的修炼之道
  • 普通企业网站建设嘉兴网站建设搭建
  • 论文网站开发贵州城乡住房建设网站
  • 计算机毕业设计 基于Python的电商用户行为分析系统 Django 大数据毕业设计 Hadoop毕业设计选题【附源码+文档报告+安装调试】
  • EtherNet/IP转EtherNet/IP协议转换网关驱动:欧姆龙与罗克韦尔PLC通讯配置完整案例
  • 天津网站建设价位邵东建设公司网站哪家好
  • 鸿蒙Flutter三方库适配指南:07.插件开发
  • 从大厂到中小公司,活下去的五个生存法则
  • Flink State Checkpointing