STM32按键中断学习记录

 

习惯了调程序遇到问题就在网上各种搜罗,常常能从大牛的记录或者回复中得到启发,没想到有一天自己也开始写博客记录下学习的点滴。

学习STM32的这一个月颇有点闭门造车的意思,因为周围没有学习这个开发板的朋友,遇到问题要么远程求助要么自己琢磨,感觉略苦逼,也容易造成不自信。。。最近一直断断续续得学习STM32里的中断实验,遇到了很多问题,今天总算是把程序调了出来,趁着现在内心扑腾的小火苗还在燃烧,先把按键中断实验记录下来。

 

我使用的开发板是淘宝购置的STM32奋斗板V3,是从朋友处得到的,因为我从来没有接触过硬件开发,导致这一个月里有近四分之一的时间是花在琢磨如何使用JTAG,让开发板和软件连接好上了,一开始甚至连短接线是啥都不知道。。更搞笑的是开发板有两种供电方式——DC5V和USB,朋友既没有给我电源也没有给我USB线,我以为只能用USB供电,那就需要一颗CR1220电池,在市里跑了一圈也没买着,歪打正着想着买个DC5V供电试试,还真搞定了。。现在想想真是汗啊,太幼稚了。。此外,这个月里还经历了JTAG固件损坏,尝试自己修复不得,又重新购置了一个JLINK这种事情。。。

 

我使用的开发软件是keil uv3,选择这么古老的版本是因为之前用的JLINK和keil软件的高级版本相连时总会报错说JLINK是山寨的不能使用,好在退回到UV3还是勉强可以配合工作的,也就一直没有更换软件了。

 

前面说得这些都是吐槽,下面开始进入正题。

 

对于STM32来说,中断的使用除了需要进行RCC的配置、GPIO的配置外,剩下的就是要进行NVIC向量中断控制器配置和EXTI中断配置,还有一定要记住将中断线和GPIO管脚相连,一开始我就忘了这茬。。。

 

中断实验里我使用到LED灯(PB.5),将按键K1的列扫描线(PC.5)作为中断输入,行扫描线(PE.2)也需要打开时钟,并对管脚初始化为推挽输出——这一点我其实还不是特别理解,之前程序没有调出来时,只对PC.5进行了初始化,PE.2没有管,一直都进不到中断服务程序,后来加上了对PE.2的初始化程序就正常了。

时钟初始化代码如下:

void RCC_Configuration(void)

{   

  SystemInit();

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOE, ENABLE);

}

APB2总线上控制了AFIO和GPIO管脚,APB1总线控制了TIM、WDG等。下面这个图是在uv3的Peripherals选项卡中APB Bridges选项中得到的,必须要在调试状态下才可以选择,可以查看相应的控制器时钟配置情况。

 

接下来就是配置GPIO。GPIO管脚的模式一定要正确~GPIO的管脚可以在Peripherals选项卡中的General Purpose IO选项中查看。

GPIO配置代码如下:

void GPIO_Configuration(void){  

  GPIO_InitTypeDef GPIO_InitStructure;

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED1  V6--PB5     

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//将PB.5配置为通用推挽输出

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//口线翻转速度为50MHz

  GPIO_Init(GPIOB, &GPIO_InitStructure);  

  

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;//K1 PE2 行扫描线     

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//按键配置成推挽输出

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//口线翻转速度为50MHz

  GPIO_Init(GPIOE, &GPIO_InitStructure);

 

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //K1 PC5 列扫描线——中断线   

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//配置成上拉输入

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//口线翻转速度为50MHz

  GPIO_Init(GPIOC, &GPIO_InitStructure);

}

中断向量控制器的配置:

void NVIC_Configuration(void)

{   

NVIC_InitTypeDef NVIC_InitStructure;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQn;//配置EXTI5~9线的中断向量

NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;

NVIC_Init(&NVIC_InitStructure);

}

中断初始化:

void EXTI_Configuration(void)

{   

EXTI_InitTypeDef EXTI_InitStructure;

EXTI_InitStructure.EXTI_Line=EXTI_Line5;

EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;

EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;

EXTI_InitStructure.EXTI_LineCmd=ENABLE;

EXTI_Init(&EXTI_InitStructure);

}

把PC.5设为EXTI中断线:

GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);

中断服务函数:(在stm32f10x_it.c中)

void EXTI9_5_IRQHandler(void)

{

if(EXTI_GetITStatus(EXTI_Line5)!=RESET)  //PC.5

it=1;//中断标志,全局变量

EXTI_ClearITPendingBit(EXTI_Line5);

}

}

 

主函数:

#include "stm32f10x.h"

#include "stm32f10x_exti.h"

#include "stm32f10x_rcc.h"

#include "misc.h"

#include "stdio.h"

uint32_t it=0;

unsigned char num=0;

void RCC_Configuration(void);

void GPIO_Configuration(void);

void NVIC_Configuration(void);

void EXTI_Configuration(void);

void Delay(__IO uint32_t nCount);

void numm(void);

int main(void)

{

  unsigned char a=0;

  RCC_Configuration();    //系统时钟配置

  GPIO_Configuration(); //GPIO端口配置

  NVIC_Configuration(); //向量中断控制器配置

  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);

  EXTI_Configuration();

  GPIO_SetBits(GPIOB, GPIO_Pin_5);    //LED1亮

  GPIO_ResetBits(GPIOE, GPIO_Pin_2); 

  while (1)

  {

   GPIO_ResetBits(GPIOE, GPIO_Pin_2); 

   numm();    //键盘扫描程序

if(num==1&&a==0){GPIO_ResetBits(GPIOB, GPIO_Pin_5);a=1;} //K1 按下作处理 复位--PB5=0 灭 置位--PB5=1 亮

else if(num==1&&a==1){GPIO_SetBits(GPIOB, GPIO_Pin_5);a=0;}

  }

}

void numm(void){

   num=0;

   if(it==1){     //按键按下标志 

      GPIO_ResetBits(GPIOE, GPIO_Pin_2);   //置PE2为0。  

  if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)==0){   //

   Delay(0xffff);   

if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)==0){   //按键消抖动

while(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)==0);//是否松开按键  

num=1;  //键值1 为K1按下

goto n_exit;

}

  }

 else ;

  n_exit:;

      it=0;

   } 

}

 

代码全贴上来了,进行了初始化以后就一直while(1)检测是否进中断,在中断服务函数里加了断点,进中断的话会跳到断点处,中断标志置位,再回到主函数,经过延时函数消抖,判断中断是否为真,再进行点灯灭灯操作。

 

写了一个多小时,感觉文章后半部分还不太详细,改天再修改。

 

相信付出一定会有收获!

 

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值