stm32f051k8ux连接stm32nbiot板子,我要用超声波传感器检测距离,若距离过近则亮灯闪烁提醒,并启动继电器,代码该如何写?
好了,如果前面不太彻底明白的话也没关系,搬砖的只需要记住在哪里搬,搬去哪里,怎么搬就行了,至于这块砖是怎么生产的就不需要了解了。进入正题
在配置每个中断的时候一般有4个步骤:
1、结合当前使用的外设,确定自己需要的中断源(单片机外设)。比如单片机用于通信的固件外设(I2C,SPI,USART等)有发送完成,接收完成中断。GPIO引脚也可设置上升沿,下降沿中断。定时器的计时中断。。。所有的中断类型参看stm32f10x.h 这个头文件IRQn_Type 这个枚举定义。
2、 初始化 NVIC_InitTypeDef 结构体,配置中断优先级分组,设置抢占优先级和子优先级,使能中断请求。参看固件库文件 misc.h:
typedef struct
{
uint8_t NVIC_IRQChannel; //用来设置中断源
uint8_t NVIC_IRQChannelPreemptionPriority; //抢占优先级(主优先级)
uint8_t NVIC_IRQChannelSubPriority; //子优先级
FunctionalState NVIC_IRQChannelCmd; //中断使能( ENABLE)或者失能( DISABLE)
} NVIC_InitTypeDef;
此结构体配置完后,使用库函数
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);配置NVIC。
3、 编写中断服务函数,在固件库启动文件 startup_stm32f10x_md.s 中预先为每个中断都写了一个中断服务函数,只是这些中断函数都是为空,为的只是初始化中断向量表:
WWDG_IRQHandler
PVD_IRQHandler
TAMPER_IRQHandler
RTC_IRQHandler
FLASH_IRQHandler
RCC_IRQHandler
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
DMA1_Channel1_IRQHandler
DMA1_Channel2_IRQHandler
DMA1_Channel3_IRQHandler
DMA1_Channel4_IRQHandler
DMA1_Channel5_IRQHandler
DMA1_Channel6_IRQHandler
DMA1_Channel7_IRQHandler
ADC1_2_IRQHandler
USB_HP_CAN1_TX_IRQHandler
USB_LP_CAN1_RX0_IRQHandler
CAN1_RX1_IRQHandler
CAN1_SCE_IRQHandler
EXTI9_5_IRQHandler
TIM1_BRK_IRQHandler
TIM1_UP_IRQHandler
TIM1_TRG_COM_IRQHandler
TIM1_CC_IRQHandler
TIM2_IRQHandler
TIM3_IRQHandler
TIM4_IRQHandler
I2C1_EV_IRQHandler
I2C1_ER_IRQHandler
I2C2_EV_IRQHandler
I2C2_ER_IRQHandler
SPI1_IRQHandler
SPI2_IRQHandler
USART1_IRQHandler
USART2_IRQHandler
USART3_IRQHandler
EXTI15_10_IRQHandler
RTCAlarm_IRQHandler
USBWakeUp_IRQHandler
TIM8_BRK_IRQHandler
TIM8_UP_IRQHandler
TIM8_TRG_COM_IRQHandler
TIM8_CC_IRQHandler
ADC3_IRQHandler
FSMC_IRQHandler
SDIO_IRQHandler
TIM5_IRQHandler
SPI3_IRQHandler
UART4_IRQHandler
UART5_IRQHandler
TIM6_IRQHandler
TIM7_IRQHandler
DMA2_Channel1_IRQHandler
DMA2_Channel2_IRQHandler
DMA2_Channel3_IRQHandler
DMA2_Channel4_5_IRQHandler
实际的中断服务函数都需要我们重新编写, 放在 stm32f10x_it.c 这个库文件中,可以看到那里面已经有了一些写好的系统中断的服务函数,我们只需跟着在文件末尾继续写就行了。中断服务函数的函数名必须跟启动文件里面预先设置的一样,如果写错,系统就在中断向量表中找不到中断服务函数的入口,直接跳转到启动文件里面预先写好的空函数,实现不了中断。 注意:中断服务函数里不应该处理耗时的操作!
4.使能外设的某个中断,具体由此外设的相关中断使能函数控制,在此外设的固件库文件找到函数原型:
void xxx_ITConfig(xxx_TypeDef* xxx, uint16_t xxx_IT, FunctionalState NewState);
针对该问题,可以采取以下几步解决:
配置超声波传感器的GPIO引脚和外部中断,使其能够检测到距离变化并产生对应的中断信号。
在中断响应函数中,编写LED闪烁和继电器启动的代码。具体来说,可以通过调用HAL库提供的相应函数来控制LED的状态翻转,并且通过GPIO引脚控制继电器的启动或停止。
下面是代码实现的详细步骤:
配置GPIO引脚和外部中断。在STM32CubeMX工具中,找到对应的GPIO引脚和外部中断,将它们的状态设为输入模式,并使能对应的中断。具体地,可以在工具中选择Pinout视图,在需要配置的GPIO引脚上右键单击,在弹出的上下文菜单中选择"GPIO_EXTI Interrupt"来使能外部中断。然后,在Configuration视图中,选择NVIC Configuration,使能相应的中断,并设置中断优先级。
在编写中断响应函数中,调用HAL库提供的相应函数来控制LED的状态翻转,并通过GPIO引脚控制继电器的启动或停止。具体来说,可以在编写时间中断回调函数中,判断引发中断的GPIO引脚是否是超声波传感器所连接的引脚。如果是,则调用HAL库提供的相应函数来控制LED翻转和继电器的启动或停止。例如:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_1) // 如果是超声波传感器引脚产生的中断
{
// 闪烁LED灯
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
// 控制继电器
if(distance < THRESHOLD_DISTANCE) // 距离太近
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // 启动继电器
}
else // 距离正常
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // 停止继电器
}
}
}
其中,GPIOA和GPIOB是HAL库中定义的GPIO组,GPIO_PIN_5和GPIO_PIN_0是对应的引脚编号。distance是一个全局变量,表示从超声波传感器检测到的距离,THRESHOLD_DISTANCE是一个常量,表示允许的最小距离阈值。
需要注意的是,如果在回调函数中进行了一些比较耗时的操作,可能会影响整个系统的稳定性,因此需要尽量保证回调函数的响应时间尽可能短。如果需要进行比较复杂的操作,可以考虑使用一个标记变量来指示需要在主循环中执行一些特殊操作。
while(1) {
// 发送超声波信号
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
HAL_Delay(10);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
// 等待超声波回波
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2) == GPIO_PIN_RESET);
uint32_t t1 = HAL_GetTick();
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2) == GPIO_PIN_SET);
uint32_t t2 = HAL_GetTick();
// 计算距离
distance = (t2 - t1) * 34 / 1000 / 2;
}
其中,GPIO_PIN_1是用来产生超声波信号的引脚,GPIO_PIN_2是用来检测超声波回波的引脚。在产生超声波信号时,需要将GPIO_PIN_1引脚电平拉高10ms,然后再将其拉低。在检测超声波回波时,可以通过HAL库提供的函数HAL_GetTick()来获取当前的系统时间戳。
需要注意的是,由于超声波在空气中的传播速度是约为340m/s,因此可以通过计算回波的时间差来近似计算出距离。具体来说,回波的时间差Δt等于超声波来回的时间,因此距离d等于Δt * 340 / 2,其中因子2是因为超声波是往返传播的。
综上所述,可以通过以上步骤来在STM32F051K8UX开发板上实现连接超声波传感器,检测距离并控制LED灯和继电器的功能。