从零开始学习stm32(三)
思考:如何实现以下功能?
- 串口回显
- LED循环闪烁(间隔1秒)
- 任务1与任务2不会互相干扰
中断
系统停止当前正在运行的程序转到其他服务,可能是程序接受了比自身优先级高的请求,或者是人为设置中断,中断时属于正常现象。
硬中断
由硬件产生
软件中断
软中断是由当前正在运行的进程所产生。
中断处理过程
- 当异常中断发生时,系统处理完当前指令后,将跳转到相应的异常中断程序处执行。
- 异常中断程序处理完成后,程序返回到发生中断指令的下一条指令处执行。
- 进入异常中断时,要保存呗中断的程序执行现场,在从异常中断处理程序退出时,要恢复被中断的程序的执行现场。
EXTI基本概念
中断产生的根本原因
单片机系统正在运行时,往往时一个单纯的封闭系统。但有些时候需要外部干预,因此可通过中断的方式进行。
中断和事件
** 中断时软件级,stm32中断线路产生的输入信号到NVIC,在执行中断服务函数。
** 事件时硬件级的,stm32事件线产生后回传输一个脉冲信号给其他外设使用。
事件机制提供了一个完全由硬件自动完成触发到产生结果的通道,不需要软件参与,降低了CPU负荷,节省了中断资源,提高了相应速度,是利用硬件来提升CPU芯片处理事件能力的一个有效方法。
** 中断相应函数
-
一种处理中断相应的函数,遵行特定原型声明的c函数,运行在中断上下文。
-
中断处理函数不能被阻塞,其内部的程序必须运行非常快
-
告诉硬件已经收到了它发出的中断,中断服务程序通常分为两半,上半部:只执行哪些可以很快执行的代码,如向硬件确认已收到中断号等。下半部:执行中断触发需要完成的其他工作
-
执行在中断上下文中的代码注意事项,中断上下文的代码不能进入休眠,中断处理程序应该尽快结束。
中断原理
外部信号从输入线管脚进入。
经过边沿检测电路
通过或门中断挂起请求寄存器,如果中断屏蔽寄存器对应位为0,则该请求信号不能传输到与门另一端,实现中断屏蔽
第三节
NVIC基本概念
内嵌向量中断控制器--------与内核紧密相连,内核外设
中断优先级
包括两个优先级:抢占优先级和子优先级
所有的优先级可编程的中断源都需要指定这两种优先级。
抢占优先级:决定是否可以产生中断嵌套
子优先级:决定中断响应顺序
若两种优先级一样,则看中断源在中断向量表中的偏移量,偏移量小的先响应。
NVIC寄存器
- NVIC_ISERx/NVIC_ICERx 中断使能(设置/清除)寄存器
- NVIC_ISPRx /NVIC_ICPRx中断挂起设置/清除寄存器
- NVIC_IABRx 激活位寄存器
- NVIC_IPRx 中断优先级寄存器
- NVIC_STIR 软件触发中断寄存器
外部中断思路
- 根据原理图确定相应的外部中断信号线
- 配置外部中断
- 选择EXTI的信号源
- 选择EXTI类型:中断、事件
- 选择EXTI的触发模式:上升沿、下降沿
- EXTI使能
代码
头文件
//key.h
typedef enum{
PRESS,RESS
}KEY_orp;
typedef enum {
CHECK,INTERRUPT
}MODE;
#define KEY_MODE INTERRUPT
extern void key_exit_init(void);
extern void key_nvic_init(void);
extern void KEY_Init(MODE mode);
extern void delay_us(u8 time);
extern u8 key_read(void);
extern u8 flag;
c文件
//key.c
#include<stm32f10x_rcc.h>
#include<stm32f10x_gpio.h>
#include<stm32f10x_rcc.h>
#include<stm32f10x_exti.h>
#include<misc.h>
#include<key.h>
//PB12,KEY高电平有效
//当按键不被按下的时候,它一直稳定在低电平--下拉
void delay_us(u8 time){
while(time--){
int i = 1000;
while(i--);
}
}
void key_exit_init(void){
EXTI_InitTypeDef KEY_exit;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12);
KEY_exit.EXTI_Line = EXTI_Line12;
KEY_exit.EXTI_Mode = EXTI_Mode_Interrupt;
KEY_exit.EXTI_Trigger = EXTI_Trigger_Rising;
KEY_exit.EXTI_LineCmd = ENABLE;
EXTI_Init(&KEY_exit);
}
void key_nvic_init(void){
NVIC_InitTypeDef key_nvic;
key_nvic.NVIC_IRQChannel = EXTI15_10_IRQn;
key_nvic.NVIC_IRQChannelSubPriority = 0;
key_nvic.NVIC_IRQChannelPreemptionPriority = 1;
key_nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&key_nvic);
}
void KEY_Init(MODE mode){
GPIO_InitTypeDef KEY;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//结构体初始化
KEY.GPIO_Mode = GPIO_Mode_IPD;
KEY.GPIO_Pin = GPIO_Pin_12;
//GPIO初始化
GPIO_Init(GPIOB, &KEY);
if (INTERRUPT == mode){
key_exit_init();
key_nvic_init();
}else{}
}
//读取按键
u8 key_read(void){
u8 result = 0;
delay_us(10);
result = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);
//按键去抖
if (result == PRESS){
return 0;
}else{
return 1;
}
}
u8 flag = 0;
void EXTI15_10_IRQHandler(void){
if (SET == EXTI_GetITStatus(EXTI_Line12)){
flag = !flag;
}
EXTI_ClearITPendingBit(EXTI_Line12);
}