一、原理
需要一个震动感应器来感应是否产生震动,然后把这个震动感应器作为GPIO输入,单片机来读取这个输入是否产生震动。如果产生震动,我们就可以把一个GPIO作为输出口,将它连接到一个灯上,然后输出高低电平。
后续根据情况再优化这个设计。
二、硬件
1、一个震动感应器
2、一个单片机
3、继电器
4、led灯
三、接口说明
我用的霸道的板子,这里我把PB6作为输入,PB7作为输出。
查找PB6、PB7挂载的总线:
四、源代码
bsp_ganying.h
#ifndef _BSP_GANYING_H
#define _BSP_GANYING_H
#include "stm32f10x.h"
void lightIn(void);
void lightOut(void);
#define GPIO_LIGHT_CLK RCC_APB2Periph_GPIOB
#define GPIO_IN_RORT GPIOB
#define GPIO_OUT_RORT GPIOB
#define GPIO_LIGHT_PIN_IN GPIO_Pin_6
#define GPIO_LIGHT_PIN_OUT GPIO_Pin_7
#endif /*_BSP_GANYING_H*/
bsp_ganying.c
#include "bsp_ganying.h"
void lightIn(void)
{
GPIO_InitTypeDef gpioConfig_IN;
RCC_APB2PeriphClockCmd(GPIO_LIGHT_CLK, ENABLE);
gpioConfig_IN.GPIO_Pin = GPIO_LIGHT_PIN_IN;
gpioConfig_IN.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIO_IN_RORT, &gpioConfig_IN);
}
void lightOut(void)
{
GPIO_InitTypeDef gpioConfig_OUT;
RCC_APB2PeriphClockCmd(GPIO_LIGHT_CLK,ENABLE);
gpioConfig_OUT.GPIO_Pin = GPIO_LIGHT_PIN_OUT;
gpioConfig_OUT.GPIO_Mode = GPIO_Mode_Out_PP;
gpioConfig_OUT.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIO_OUT_RORT, &gpioConfig_OUT);
}
main.c
#include "bsp_ganying.h"
#include "stm32f10x.h"
void delay(uint16_t nCount)
{
uint16_t nTime = 0;
while(nCount--)
{
nTime= 12000;
while(nTime--);
}
}
int main(void)
{
lightIn();
lightOut();
GPIO_SetBits(GPIO_OUT_RORT,GPIO_LIGHT_PIN_OUT);
while(1)
{
if(GPIO_ReadInputDataBit(GPIO_IN_RORT, GPIO_LIGHT_PIN_IN) == 0)
{
GPIO_ResetBits(GPIO_OUT_RORT,GPIO_LIGHT_PIN_OUT);
delay(1000);
GPIO_SetBits(GPIO_OUT_RORT,GPIO_LIGHT_PIN_OUT);
}else
{
GPIO_SetBits(GPIO_OUT_RORT,GPIO_LIGHT_PIN_OUT);
}
}
}
这样就能看到一个现象,我们下载到班子以后。当我们触碰这个震动感应器的时候,我们作为输出的GPIO口连接的灯,就会亮一秒,然后熄灭,我们继续触碰这个震动感应器,又会亮一秒。
但是这个程序是不是while有一大堆循环,比较消耗cpu,所以我们可以优化改为中断模式,在产生中断的时候进行输出。
五、中断配置
因为我们GPIOB使我们的输入也是我们的输出端口,所以我们配置外部中断的时候要选择复用端口。
因为之前说过,5-9共用一个EXTI,所以这里要注意一下。
bsp_exti.h
#ifndef _BSP_GANYING_H
#define _BSP_GANYING_H
#include "stm32f10x.h"
#include "bsp_ganying.h"
#define GPIO_IN_RORT GPIOB
#define GPIO_LIGHT_CLK RCC_APB2Periph_GPIOB
#define GPIO_LIGHT_PIN_IN GPIO_Pin_6
void extiConfig(void);
#endif /*_BSP_GANYING_H*/
bsp_exti.c
#include "bsp_exti.h"
#include "bsp_ganying.h"
void extiConfig()
{
EXTI_InitTypeDef extiConfig;
GPIO_InitTypeDef gpioConfig_IN;
NVIC_InitTypeDef nvicConfig;
RCC_APB2PeriphClockCmd(GPIO_LIGHT_CLK, ENABLE);
//选择复用端口,因GPIOB是输入也是输出
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource6);
//配置GPIO
gpioConfig_IN.GPIO_Pin = GPIO_LIGHT_PIN_IN;
gpioConfig_IN.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIO_IN_RORT, &gpioConfig_IN);
//配置EXTI
extiConfig.EXTI_Line = EXTI_Line6;
extiConfig.EXTI_Mode = EXTI_Mode_Interrupt;
extiConfig.EXTI_Trigger = EXTI_Trigger_Falling;
extiConfig.EXTI_LineCmd = ENABLE;
EXTI_Init(&extiConfig);
//配置嵌套NVIC函数
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //优先级组
nvicConfig.NVIC_IRQChannel = EXTI9_5_IRQn; //配置中断源,共用5-9
nvicConfig.NVIC_IRQChannelPreemptionPriority = 1;
nvicConfig.NVIC_IRQChannelSubPriority = 1;
nvicConfig.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvicConfig);
}
配置中断函数
void EXTI9_5_IRQHandler(void)
{
/*确保是否产生了 EXTI Line0 中断*/
if( EXTI_GetITStatus(EXTI_Line6) != RESET)
{
GPIO_ResetBits(GPIO_OUT_RORT,GPIO_LIGHT_PIN_OUT);
delay(1000);
GPIO_SetBits(GPIO_OUT_RORT,GPIO_LIGHT_PIN_OUT);
}
/*清除中断标志*/
EXTI_ClearITPendingBit(EXTI_Line6);
}
六、完整代码
链接:https://pan.baidu.com/s/1PIHp4xLzLwlMv4zkvLP_kA
提取码:e4lr
项目主要是让自己熟悉调库的步骤,中断的基本原理,和一些坑。