斯特云流量网站福州网站建设推广
基于STM32_HAL库的电动车报警器项目
文章目录
- 基于STM32_HAL库的电动车报警器项目
- 一、项目需求
- 二、硬件连接
- 三、项目实现
- 3.1 CubeMX配置:
- 3.2 代码实现:
一、项目需求
- 按下433M遥控器B按键,系统进入警戒模式,一旦检测到震动(小偷偷车)则警报响起,吓退小偷。
- 按下433M遥控器A按键,系统退出警戒模式,再怎么摇晃系统都不会报警,否则一直响的话车主会很尴尬😅
二、硬件连接
下面是具体的各模块与单片机之间的硬件连接,其中PA0、PA5、PA6是外部中断功能,PB7是GPIO输出:
三、项目实现
3.1 CubeMX配置:
-
配置Debug
-
打开RCC配置时钟,将高速时钟配置成Crystal/Ceramic Resonator
-
点击配置时钟选项,把时钟配置成高速外部时钟HSE,并且通过PLLCLK倍频到72MHZ,按下回车之后就为芯片内部的功能分配好了对应的时钟频率。
-
然后配置PB7为GPIO_Output模式,并且初始化为低电平,因为继电器模块是高电平触发的
-
配置PA0为外部中断引脚,并且配置为下降沿触发,连接外部的震动传感器
-
配置PA5和PA6为外部中断引脚,并且配置为上升沿触发,连接外部433M无线遥控的两个信号
-
打开NVIC,使能EXT0、EXT5、EXT6,并且设置“抢占优先级”为2级,本来之前我们的抢占优先级默认是0的,但是由于我们在代码的中断服务函数中使用了HAL_Delay()函数,程序初始化时默认把滴答定时器的中断优先级设为最低,其它中断源很容易打断它导致卡死,也就是说当HAL_Delay()函数在进行中的时候,如果又发生了震动触发了外部中断,就会又立刻执行这个中断处理程序,导致喇叭一直在响无法停下。所以我们只能:在 main 函数里使用以下函数提高滴答定时器的中断优先级(提升至0)
HAL_NVIC_SetPriority(SysTick_IRQn,0,0); //将 SysTick 定时器中断的抢占优先级和响应优先级都设置为 0(即最高优先级)
并且在CubeMX中将其他的中断优先级设置比滴答定时器优先级低,比如说:2
3.2 代码实现:
我们首先来看一下使用CubeMX生成的初始化代码:
/* main.c */
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK){Error_Handler();}
}
上面这段代码是由CubeMX生成的时钟相关的代码。
/* gpio.c */
void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);/*Configure GPIO pin : PA0 */GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*Configure GPIO pins : PA5 PA6 */GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*Configure GPIO pin : PB7 */GPIO_InitStruct.Pin = GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* EXTI interrupt init*/HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);HAL_NVIC_EnableIRQ(EXTI0_IRQn);HAL_NVIC_SetPriority(EXTI9_5_IRQn, 2, 0);HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);}
上面这段代码是由CubeMX配置生成的GPIO输出,以及外部中断初始化相关的代码。
/* stm32f1xx_it.c */
/*** @brief This function handles EXTI line0 interrupt.*/
void EXTI0_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}/*** @brief This function handles EXTI line[9:5] interrupts.*/
void EXTI9_5_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_5);HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6);
}
上面这段代码里面的两个函数,分别处理EXT0和EXT5&EXT6,他们都调用了HAL_GPIO_EXTI_IRQHandler
()函数,我们按下F12查看此函数:
/* stm32f1xx_hal_gpio.h */
/*** @brief This function handles EXTI interrupt request.* @param GPIO_Pin: Specifies the pins connected EXTI line* @retval None*/
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{/* EXTI line interrupt detected */if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u){__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);HAL_GPIO_EXTI_Callback(GPIO_Pin);}
}/*** @brief EXTI line detection callbacks.* @param GPIO_Pin: Specifies the pins connected EXTI line* @retval None*/
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{UNUSED(GPIO_Pin);
}
到这里我们终于看到外部中断处理函数了,我们只需要重新的写__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
就可以了,下面就是我们在main函数写的业务代码,从而实现我们的项目需求:
#include "main.h"
#include "gpio.h"#define J_ON 1 // 定义警报标志位
#define J_OFF 0 // 定义警报标志位void SystemClock_Config(void);/* 重写中断服务函数,如果检测到EXIT中断请求则进入该函数 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{static int mark = J_OFF; // 默认是取消警报标志// 一根线上可以接多个中断源,判断中断到底来自于哪一个switch(GPIO_Pin){ // 如果检测到PA0被拉低(小偷偷车)并且警报模式打开 case GPIO_PIN_0:if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET && mark == J_ON){// 将PB7拉低,继电器通电,喇叭一直响HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);}break;// 如果检测到PA5被拉高(按键B按下)设定为进入警报模式case GPIO_PIN_5: if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) == GPIO_PIN_SET){ // 将PB7拉低(警报提示)2秒后恢复电平(警报提示结束)表示进入警报模式HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);HAL_Delay(2000);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);// 同时将标志位设置为ONmark = J_ON;}break;// 如果检测到PA6被拉高(按键A按下)设定为取消警报模式case GPIO_PIN_6: if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6) == GPIO_PIN_SET){ // 将PB7拉低(警报提示)1秒后恢复电平(警报提示结束)表示取消警报模式HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);HAL_Delay(1000);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);// 同时将标志位设置为OFFmark = J_OFF; }break;}
}int main(void)
{HAL_Init();SystemClock_Config();HAL_NVIC_SetPriority(SysTick_IRQn,0,0); //将 SysTick 定时器中断的抢占优先级和响应优先级都设置为 0(即最高优先级)MX_GPIO_Init();while (1){}
}
我们把代码编译烧录进去就实现我们的整个项目。