目录
1.项目概述
该项目非常适合初学stm32的小白进行尝试,本项目运用了stm32常用的外设如io,中断,也用到了常用的模块,有继电器模块,振动传感器,相信尝试完这个项目之后小白们都可以顺利入门stm32.
2.材料准备
1.stm32F103c8t6最最小系统板
2.震动传感器模块
3.一路继电器模块
3.接线图
4.GPIO相关配置
首先我们先回顾一下GPIO相关的配置,震动传感器的输出引脚产生震动输出低电平,没有震动是高电平。我们首先选择一个单片机的引脚连接振动传感器的引脚,这里我们就选PA1这个引脚。
从下面的系统结构图可以看出,GPIOA是搭载在APB2总线下的,因此我们需要开启APB2的时钟。
我们在固件库中找到APB2的使能函数配置使能就可以了。
配置好就是这个样子
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
接着我们配置GPIO的功能
固件库需要我们配置引脚编号,速度,模式三个参数。我们分别配置成PA1,50,10M。
**
* @brief GPIO Init structure definition
*/
typedef struct
{
uint16_t GPIO_Pin; /*!< Specifies the GPIO pins to be configured.
This parameter can be any value of @ref GPIO_pins_define */
GPIOSpeed_TypeDef GPIO_Speed; /*!< Specifies the speed for the selected pins.
This parameter can be a value of @ref GPIOSpeed_TypeDef */
GPIOMode_TypeDef GPIO_Mode; /*!< Specifies the operating mode for the selected pins.
This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;
shake.c(配置震动传感器)
#include "shake.h"
#include "stm32f10x.h"
void Shake_Init(void)
{
GPIO_InitTypeDef shake_init; //这里结构体的定义要在时钟之前,不然会报错
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
shake_init.GPIO_Mode =GPIO_Mode_IPD;
shake_init.GPIO_Pin =GPIO_Pin_1;
shake_init.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&shake_init);
}
relay.c(配置继电器)
#include "relay.h"
#include "stm32f10x.h"
void Relay_Init(void)
{
GPIO_InitTypeDef Relay_init;//ʹÄÜGPIOAµÄʱÖÓ
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );、
Relay_init.GPIO_Mode =GPIO_Mode_IPU ;
Relay_init.GPIO_Pin =GPIO_Pin_5;
Relay_init.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init( GPIOA, &Relay_init );
}
5.中断相关配置
如何配置中断:
1. 初始化用来中断的GPIO口
2. 初始化EXTI
3. 配置NVIC(中断优先级) 配置中断的优先级,中断嵌套
4.编写中断服务函数
中断简介
stm32总共有20条中断线,而0-15是我们GPIO的,其它的是特殊功能的中断线。我们只关心GPIO的中断线即可。
选择好中断先后我们通过输入线进入,接着经过边沿检测电路,边沿检测这里又分了,上升沿触发检测(0变化到1的过程),下降沿触发检测(1变化到0的过程).......。由于我们震动传感器至少高低电平的变化,因此我们只需关注是上升沿触发检测还是下降沿触发检测。配置完边沿检测后我们会来到NVIC中断控制器,它其实也是一个外设,只不过是内核的外设,跟配置exti是一样的都是配置结构体。
配置EXTI
首先来回顾一下EXTI的结构体成员有哪些。
typedef struct
{
uint32_t EXTI_Line; //EXTI选择中断线/事件线选择
EXTIMode_TypeDef EXTI_Mode; //EXTI模式选择,可选择为中断模式/产生事件
EXTITrigger_TypeDef EXTI_Trigger; //EXTI边沿触发事件,可选择为上升沿触发,下降沿触发,
上升沿下降沿都触发
FunctionalState EXTI_LineCmd; //控制是否使能EXTI线
}EXTI_InitTypeDef;
配置NVIC
typedef struct
{
uint8_t NVIC_IRQChannel; //设置中断通道
uint8_t NVIC_IRQChannelPreemptionPriority; //设置抢占优先级
uint8_t NVIC_IRQChannelSubPriority; //设置子优先级
FunctionalState NVIC_IRQChannelCmd; //是否使能NVIC
} NVIC_InitTypeDef;
这里要注意:在配置之前抢占优先级还需定义优先级组,不同的组别优先级也是不一样的,组别的数字越小说明优先级越高。比较的时候先是比较抢占优先级,谁的数字越小谁的优先级就高。 如果抢占优先级数字一样, 那么我们就去比较子优先级,比较方法和抢占优先级是一样的,如抢占优先级和子优先级一样, 那么会比较中断的序号,同样也是序号数越小优先级越高。
exti.c(配置中断)
#include "stm32f10x.h"
#include "exti.h"
void exti_Init(void)
{
// 1.配置GPIO
GPIO_InitTypeDef shake_init;
EXTI_InitTypeDef exti_init;
NVIC_InitTypeDef nvic_init;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig( GPIO_PortSourceGPIOA, GPIO_PinSource1);
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2);
shake_init.GPIO_Mode =GPIO_Mode_IPD;
shake_init.GPIO_Pin =GPIO_Pin_1;
shake_init.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&shake_init);
//2.配置EXTI外部中断
exti_init.EXTI_Line = EXTI_Line1 ; //设置中断通道
exti_init.EXTI_LineCmd = ENABLE;
exti_init.EXTI_Mode =EXTI_Mode_Interrupt;
exti_init.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_Init(&exti_init);
//3.配置NVIC中断控制器
nvic_init.NVIC_IRQChannel =EXTI1_IRQn; //设置中断通道
nvic_init.NVIC_IRQChannelPreemptionPriority =1;//设置抢占优先级
nvic_init.NVIC_IRQChannelSubPriority =1; //设置子优先级
nvic_init.NVIC_IRQChannelCmd=ENABLE; //使能
NVIC_Init(&nvic_init);
}
编写中断服务函数:
main.c
#include "stm32f10x.h"
#include "relay.h"
#include "shake.h"
#include "exti.h"
void delay(uint16_t time)
{
uint16_t i=0;
while(time--)
{
i=16000;
while(i--);
}
}
int main()
{
Shake_Init();
Relay_Init();
void EXTI1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1 != RESET)) //判断是否发送中断
{
GPIO_SetBits(GPIOA, GPIO_Pin_5); //打开继电器,开灯
delay(1000);
GPIO_ResetBits(GPIOA, GPIO_Pin_5); //关闭继电器,关灯
}
}
6.项目总结
这个项目实现起来比较简单,帮助初学者体验了一把软硬件结合的快感,也熟悉了stm32的一些基本的外设,我本人也是从这个小项目入坑stm32的,希望对大家有所帮助。