习惯了调程序遇到问题就在网上各种搜罗,常常能从大牛的记录或者回复中得到启发,没想到有一天自己也开始写博客记录下学习的点滴。
学习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)检测是否进中断,在中断服务函数里加了断点,进中断的话会跳到断点处,中断标志置位,再回到主函数,经过延时函数消抖,判断中断是否为真,再进行点灯灭灯操作。
写了一个多小时,感觉文章后半部分还不太详细,改天再修改。
相信付出一定会有收获!
上一篇:STM32外部中断及定时器编程示例
下一篇:STM32 外部中断使用方法总结
推荐阅读最新更新时间:2024-03-16 16:05