STM32第二天之外部中断及系统定时器

1.中断优先级

1.在 NVIC 有一个专门的寄存器:中断优先级寄存器 NVIC_IPRx,用来配置外部中断的优先级,IPR 宽度为 8bit,原则上每个外部中断可配置的优先级为 0~255。

2.数值越小,优先级越高。 在 F103 中,只使用了高 4bit,用于表达优先级的这 4bit,又被分组成抢占优先级和子优先级

3.如果有多个中断同时响应,抢占 优先级高的就会抢占抢占优先级低的优先得到执行,如果抢占优先级相同,就比较子优先级。如 果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,优先级越高。

1.优先级分组

2.在配置每个中断的时候一般有 3 个编程要点:

1. 使能外设某个中断,这个具体由每个外设的相关中断使能位控制。比如串口有发送完成中 断,接收完成中断,这两个中断都由串口控制寄存器的相关中断使能位控制。

2. 初始化 NVIC_InitTypeDef 结构体,配置中断优先级分组,设置抢占优先级和子优先级,使 能中断请求。NVIC_InitTypeDef 结构体在固件库头文件 misc.h 中定义。

typedef struct {
    uint8_t NVIC_IRQChannel; // 中断源
    uint8_t NVIC_IRQChannelPreemptionPriority; // 抢占优先级
    uint8_t NVIC_IRQChannelSubPriority; // 子优先级
    FunctionalState NVIC_IRQChannelCmd; // 中断使能或者失能
 } NVIC_InitTypeDef;
//NVIC_IROChannel:用来设置中断源,不同的中断中断源不一样,且不可写错,即使写错了程序
也不会报错,只会导致不响应中断。具体的成员配置可参考 stm32f10x.h 头文件里面的 IRQn_Type
结构体定义,这个结构体包含了所有的中断源。

 3. 编写中断服务函数

启动文件 startup_stm32f10x_hd.s 中我们预先为每个中断都写了一个中断服务函数,只是这些 中断函数都是为空,为的只是初始化中断向量表。实际的中断服务函数都需要我们重新编写,为 了方便管理我们把中断服务函数统一写在 stm32f10x_it.c 这个库文件中。 关于中断服务函数的函数名必须跟启动文件里面预先设置的一样,如果写错,系统就在中断向量 表中找不到中断服务函数的入口,直接跳转到启动文件里面预先写好的空函数,并且在里面无限 循环,实现不了中断。

 4.外部中断EXTI

1.原理框图

编号 1 是输入线,EXTI 控制器有 19 个中断/事件输入线,这些输入线可以通过寄存器设置 为任意一个 GPIO,也可以是一些外设的事件。输入线 一般是存在电平变化的信号

编号 2 是一个边沿检测电路,它会根据上升沿触发选择寄存器 (EXTI_RTSR) 和下降沿触发 选择寄存器 (EXTI_FTSR) 对应位的设置来控制信号触发。边沿检测电路以输入线作为信号 输入端,如果检测到有边沿跳变就输出有效信号 1 给编号 3 电路,否则输出无效信号 0。

编号 3 电路实际就是一个或门电路,它一个输入来自编号 2 电路,另外一个输入来自软件 中断事件寄存器 (EXTI_SWIER)。EXTI_SWIER 允许我们通过程序控制就可以启动中断/事 件线。我们知道或门的作用就是有 1 就为 1,所以这两个输入随 便一个有有效信号 1 就可以输出 1 给编号 4 和编号 6 电路。

编号 4 电路是一个与门电路,它一个输入是编号 3 电路,另外一个输入来自中断屏蔽寄存 器 (EXTI_IMR)。与门电路要求输入都为 1 才输出 1,导致的结果是如果 EXTI_IMR 设置为 0 时,那不管编号 3 电路的输出信号是 1 还是 0,最终编号 4 电路输出的信号都为 0;如果 EXTI_IMR 设置为 1 时,最终编号 4 电路输出的信号才由编号 3 电路的输出信号决定,这 样我们可以简单的控制 EXTI_IMR 来实现是否产生中断的目的。编号 4 电路输出的信号会 被保存到挂起寄存器 (EXTI_PR) 内,如果确定编号 4 电路输出为 1 就会把 EXTI_PR 对应位 置 1。

编号 5 是将 EXTI_PR 寄存器内容输出到 NVIC 内,从而实现系统中断事件控制。

2.编程要点

1) 初始化用来产生中断的 GPIO;

2) 初始化 EXTI;

3) 配置 NVIC;

4) 编写中断服务函数;

/*配置NVIC寄存器*/
static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 配置NVIC为优先级组1 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  
  /* 配置中断源:配置两个中断源 */
  NVIC_InitStructure.NVIC_IRQChannel =  EXTI0_IRQn|EXTI15_10_IRQn;
  /* 配置抢占优先级 */
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 配置子优先级 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断通道 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  
  NVIC_Init(&NVIC_InitStructure);
}

 /**
  * @brief  配置 IO为EXTI中断口,并设置中断优先级
  * @param  无
  * @retval 无
  */
void EXTI_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure; 
	EXTI_InitTypeDef EXTI_InitStructure;

	/*开启按键GPIO口的时钟,AFIO为外部中断的时钟*/
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
												
	/* 配置 NVIC 中断*/
	NVIC_Configuration();
	
/*--------------------------KEY1配置-----------------------------*/
	/* 选择按键用到的GPIO */	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  /* 配置为浮空输入 */	
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

	/* 选择EXTI的信号源 */
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); 
  EXTI_InitStructure.EXTI_Line = EXTI_Line0;
	
	/* EXTI为中断模式 */
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	/* 上升沿中断 */
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  /* 使能中断 */	
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
	
  /*--------------------------KEY2配置-----------------------------*/
	/* 选择按键用到的GPIO */	
  GPIO_InitStructure.GPIO_Pin = KEY2_INT_GPIO_PIN;
  /* 配置为浮空输入 */	
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);

	/* 选择EXTI的信号源 */
  GPIO_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE, KEY2_INT_EXTI_PINSOURCE); 
  EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE;
	
	/* EXTI为中断模式 */
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	/* 下降沿中断 */
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  /* 使能中断 */	
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
}
void EXTI0_IRQHandler(void)
 {
 //确保是否产生了 EXTI Line 中断
 if (EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) {
 // LED1 取反
 LED1_TOGGLE;
 //清除中断标志位
 EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);
}
 }

 

当中断发生时,对应的中断服务函数就会被执行,我们可以在中断服务函数实现一些控制。
一般为确保中断确实发生,我们会在中断服务函数中调用中断标志位状态读取函数读取外设中
断标志位并判断标志位状态。
EXTI_GetITStatus 函数用来获取 EXTI 的中断标志位状态,如果 EXTI 线有中断发生函数返回
“SET”否则返回“RESET”。实际上,EXTI_GetITStatus 函数是通过读取 EXTI_PR 寄存器值来判
断 EXTI 线状态的。
中断服务函数我们让 LED1 翻转其状态,执行任务后需要调用 EXTI_ClearITPendingBit 函数清除 EXTI 线的中断标志位

5.系统定时器

 主要作用产生精准延时,使用AHBCLK作为时钟源。常用ms延时和us延时,

最大不能超过重装载寄存器的值 2^ 24,当重装载寄存器的值递减到 0 的时候产生中断, 然后重装载寄存器的值又重新装载往下递减计数,以此循环往复

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值