中断方式一:外部中断
步骤:
1.系统上电初始化
2.系统时钟参数设置–同前
3.引脚设置
//***********gpio.c
#include "gpio.h"
void GPIOConfiguration()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);//用PA0作数字输出引脚
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);
//用PA1作外部中断输入引脚
}
//***********gpio.h略
4.开中断,等触发
//***********nvic.c
#include "nvic.h"
void NVICConfiguation()
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//外部中断线
EXTI_InitStructure.EXTI_Line=EXTI_Line1;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);
//内部中断向量表
#ifdef VECT_TAB_RAM
NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
#else
NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);
#endif
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//***********nvic.h略
对misc.h的解释:
STM32 V3.5版本的库函数中没有原来版本中单独对于NVIC(中断向量嵌套)的外设驱动,把NVIC的外设驱动放在了misc.c中,实际上是代替原来的stm32f10x_nvic.c.
NVIC即嵌套中断向量控制器.
关于优先级别移步
http://www.cnblogs.com/dyllove98/archive/2013/08/01/3230973.html
http://bbs.ednchina.com/BLOG_ARTICLE_3009999.HTM
对于不同的外部中断请求,分类如下:
EXTI_InitStructure.EXTI_Line=EXTI_LineN;
这个就是选择不同的外部中断线N
EXTI16接到PVD输出
EXTI17接到RTC闹钟事件
EXTI18连接到USB唤醒事件(这三个没画出来)
5.进入中断服务子程序并返回
同时在stm32f10x_it.c里面添加中断服务函数,并将其在stm32f10x_it.h里面声明。
void EXTI1_IRQHandler()
{
extern vu16 BreakFlag;
if(EXTI_GetFlagStatus(EXTI_Line1)!=RESET)
{
GPIO_SetBits(GPIOA,GPIO_Pin_0);
//*********可添加其他代码,这里我们将自己的程序放在中断服务子函数当中来,也可以用全局变量进行传递到主函数当中,进行编程.下面将用到这种方法.
Delay(4000);
Delay(4000);
EXTI_ClearITPendingBit(EXTI_Line1); //软件清除中断
}
else
{;}
}
注:关于中断服务子函数的函数名可参考启动文件
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
主函数main() 如下:
#include "stm32f10x.h"
#include "gpio.h"
#include "rcc.h"
#include "nvic.h"
vu16 BreakFlag;
extern void Delay(vu32 nCount)
{
for(;nCount>0;nCount--)
;
}
int main()
{
#ifdef DEBUG
debug();
#endif
for(;;);
}
中断方式二:采用定时器产生中断
STM32定时器简介:
挂线时钟分频(来自于系统时钟方框图):
注:只要是使用默认的函数配置时钟,无论是TIM1-TIM8,定时器的内部计数频率均为72MHz(STM32F103内部8M的内部震荡,经过倍频后最高可以达到72M.就是默认晶振 8M 的时候,推荐的 CPU 频率选择)。尽管APB1最高只能是36MHz,但是当预分频值为2时,可以让APB1挂线的低速定时器时钟变为72MHz。
打开system_stm32f10x.c,如果系统时钟设置为72MHz,系统会运行
#elif defined SYSCLK_FREQ_72MHz
/**
* @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2
* and PCLK1 prescalers.
* @note This function should be used only after reset.
* @param None
* @retval None
*/
static void SetSysClockTo72(void)
里面有
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
//AHB总线时钟,由系统时钟SYSCLK 分频得到,一般不分频,等于系统时钟
//PCLK2对应APB2外设,PCLK2=72MHz
//PCLK1对应APB1外设,PCLK1=36MHz.但是图下面的一个框这样解释,如果APB1的预分频系数=1,则频率不变,否则频率*2,所以后来TIM的时钟频率又自动变成之前的两倍,又72MHz。
//查头文件,RCC_CFGR_PPRE2类似
#define RCC_CFGR_PPRE1_DIV1 ((uint32_t)0x00000000) /*!< HCLK not divided */
#define RCC_CFGR_PPRE1_DIV2 ((uint32_t)0x00000400) /*!< HCLK divided by 2 */
#define RCC_CFGR_PPRE1_DIV4 ((uint32_t)0x00000500) /*!< HCLK divided by 4 */
#define RCC_CFGR_PPRE1_DIV8 ((uint32_t)0x00000600) /*!< HCLK divided by 8 */
#define RCC_CFGR_PPRE1_DIV16 ((uint32_t)0x00000700) /*!< HCLK divided by 16 */
下面先采用通用定时器
这里CK_PSC即是挂线时钟,经过我们设定的TIM_Init()之后,即设定里面的TIM_Prescaler值,输出为我们所需要的实际定时器时钟CK_CNT,要使得CK_CNT有效,TIM1_CR1.CEN必须=1.
且在计数器可以产生
a.更新事件(上溢,下溢)
b.触发事件(输出比较和输入捕获)
/********************************************************************
实现结果:利用通用定时器TIM2产生中断,定时1s,发生中断的时候LED灯点亮,
且延迟若干时间,同时用户可自行添加其他的程序.
定时时间=(1/定时器时钟频率)*周期
********************************************************************/
1)引脚配置值搞PA0即可,其他去掉。
2)添加TIM2定时器时钟使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
3)外部中断不用,中断向量表通道要改成
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
4)添加stm32f10x_tim.h到FWlib,并自建time.c(和time.h)
#include "time.h"
void TIM2_Configuration()
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
//采用内部时钟给TIM2提供时钟源
//TIM_InternalClockConfig(TIM2);
TIM_TimeBaseStructure.TIM_Period=2000;
TIM_TimeBaseStructure.TIM_Prescaler=0x8c9f;
//预分频系数为36000-1,这样计数器时钟为72MHz/36000 = 2kHz
TIM_TimeBaseStructure.TIM_ClockDivision=0;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM2,TIM_IT_CC1,ENABLE);//ʹÄÜTIM2ͨµÀ1ÖжÏ
TIM_Cmd(TIM2,ENABLE);
}
5)中断服务函数
当有TIM2的无论哪个中断(事件)触发中断发生那么就会进入这个函数 TIM2_IRQHandler()
而更新事件的中断判断要依靠以下语句:if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
最后别忘了TIM_ClearITPendingBit(TIM32, TIM_FLAG_Update).