中断的读取方式
上升沿 下降沿 变电平
会分别在接收输入端口的
电平的上升段
电平的下降段
与电平的变化段
产生中断信号
f103上的可用中断
这取决于c8t6上保留的接口所可用的功能
中断在单片机硬件中的输入逻辑
STM32中断的使用感受
stm32f103c8t6的固件库函数
封装程度并不高
不论是
直接对应到不同的中断处理器的中断处理函数
还是
中断的数据结构体编译中
中断输入模式(定义中断输入线 )
与中断标志位
的分两个结构体定义
这里以PA4的中断输入为例
NVIC.h
#ifndef __NVIC_H
#define __NVIC_H
#include "sys.h"
extern u8 INT_MARK;//中断标志位
void KEYPAD4x4_INT_INIT (void);
#endif
NVIC.c
void KEYPAD4x4_INT_INIT (void){ //按键中断初始化
NVIC_InitTypeDef NVIC_InitStruct; //定义结构体变量
EXTI_InitTypeDef EXTI_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //启动GPIO时钟 (需要与复用时钟一同启动)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE);//配置端口中断需要启用复用时钟
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource4); //定义 GPIO 中断
EXTI_InitStruct.EXTI_Line=EXTI_Line4; //定义中断线
EXTI_InitStruct.EXTI_LineCmd=ENABLE; //中断使能
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt; //中断模式为 中断
//EXTI_Mode_Interrupt = 0x00, 中断模式
//EXTI_Mode_Event = 0x04 事件模式
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling; //取决于外围电路的输入方式,此处采用下降沿触发
//EXTI_Trigger_Rising = 0x08, 上升沿触发
//EXTI_Trigger_Falling = 0x0C, 下降沿触发
//EXTI_Trigger_Rising_Falling = 0x10 变化触发
EXTI_Init(& EXTI_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel=EXTI4_IRQn; //中断线
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //使能中断
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级 2
NVIC_InitStruct.NVIC_IRQChannelSubPriority=2; //子优先级 2
//注意在sys.c中设置优先级
/*
void NVIC_Configuration(void)
{ //嵌套中断向量控制器 的设置
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
}
*/
NVIC_Init(& NVIC_InitStruct);
}
void EXTI4_IRQHandler(void){
if(EXTI_GetITStatus(EXTI_Line4)!=RESET){//判断某个线上的中断是否发生
INT_MARK=1;//标志位置1,表示有按键中断
EXTI_ClearITPendingBit(EXTI_Line4); //清除 LINE 上的中断标志位
}
——————————————
而其结构体的定义为
stm32f10x_exti.c
typedef struct
{
uint32_t EXTI_Line; /*!< Specifies the EXTI lines to be enabled or disabled.
This parameter can be any combination of @ref EXTI_Lines */
EXTIMode_TypeDef EXTI_Mode; /*!< Specifies the mode for the EXTI lines.
This parameter can be a value of @ref EXTIMode_TypeDef */
EXTITrigger_TypeDef EXTI_Trigger; /*!< Specifies the trigger signal active edge for the EXTI lines.
This parameter can be a value of @ref EXTIMode_TypeDef */
FunctionalState EXTI_LineCmd; /*!< Specifies the new state of the selected EXTI lines.
This parameter can be set either to ENABLE or DISABLE */
}EXTI_InitTypeDef;
misc.h
typedef struct
{
uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled.
This parameter can be a value of @ref IRQn_Type
(For the complete STM32 Devices IRQ Channels list, please
refer to stm32f10x.h file) */
uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel
specified in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref NVIC_Priority_Table */
uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified
in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref NVIC_Priority_Table */
FunctionalState NVIC_IRQChannelCmd; /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
will be enabled or disabled.
This parameter can be set either to ENABLE or DISABLE */
} NVIC_InitTypeDef;
甚至可以直接通过其固件库的编译
看出其在硬件设计上的思路 甚至是设计细节。。。
极其繁琐
so,
my advice is to find a more reliable and well-packed head-fiile for NVIC and EXTI interrupt to use
or you need to
- 确定找到中断的输入端口(当然你在此之前就开启了GPIO时钟与复用时钟并定义了结构体变量)
然后对应上图表格分别设置 - EXTI
1 中断入口(中断所使用的标志位)(只能使用对应标志位,但此语句又必须要经过编译,可以理解为这样一句话“他要上厕所,所以他去厕所了”)
2 中断使能(你还需要在进厕所前打个卡申请一下)
3 设置中断的使用模式与触发模式(这个没什么好说的,根据需求弄) - NVIC
1 对应中断线的使用来对应确定哪个中断处理函数的使用(蹲下之前按照你是谁给你指定个坑位,不然就error炸坑)
2 中断线使能(蹲下之前再打个卡申请一下)
3 设置中断优先级(先看抢占优先级,再看子优先级) - 最后编译中断的读取函数,并在函数内改变标志位INT_MARK(终于,你蹲了下来,静静等待着括约肌的收缩。。。)
中断的编译就是如此复杂
让我不禁想吐槽
为什么要在软件中写两个一定绑定的结构体呢?
在两个绑定的结构体之上还要写几个一定绑定的结构体数据呢?
N***,等我把这几个中断的结构体一个一个自己全部编译完
程序都跑完了
H桥都过载了
LED灯珠都烧完了
人工智能都起义了
捏麻麻的我孙子都出生了
!!!
所以我只有,且只有这个建议
要么,自己写一个结构体,可以自动对中断内容进行设置并编译
还要么,直接上Github上找个能用的直接代替完事算了
我甚至觉得这东西就是拿来给初学者加深stm32了解程度的。。。当然也不一定,毕竟我也是初学者,等后面如果我有学习到这一相关部分并有了深入的的了解明白其编译的其他用心的话,我会继续更新(当然?也许?咕咕咕)
洋桃版使用实例
#include "stm32f10x.h" //STM32头文件
#include "sys.h"
#include "delay.h"
#include "relay.h"
#include "oled0561.h"
#include "KEYPAD4x4.h"
#include "NVIC.h"
int main (void){//主程序
u8 s;
delay_ms(500); //上电时等待其他器件就绪
RCC_Configuration(); //系统时钟初始化
RELAY_Init();//继电器初始化
I2C_Configuration();//I2C初始化
OLED0561_Init(); //OLED初始化
OLED_DISPLAY_8x16_BUFFER(0," YoungTalk "); //显示字符串
OLED_DISPLAY_8x16_BUFFER(3," KEYPAD4x4 TEST "); //显示字符串
INT_MARK=0;//标志位清0
NVIC_Configuration();//设置中断优先级
KEYPAD4x4_Init();//阵列键盘初始化
KEYPAD4x4_INT_INIT();//阵列键盘的中断初始化
u8 INT_TIME; //用于记录使用中断的次数
INT_TIME = 0;
while(1){
//其他程序内容
if( INT_TIME == 99) INT_TIME = 0;
OLED_DISPLAY_8x16_BUFFER(4,"times of INT");
OLED_DISPLAY_8x16(6,13*8,INT_TIME/10+0x30);//
OLED_DISPLAY_8x16(6,14*8,INT_TIME%10+0x30);//
if(INT_MARK){ //中断标志位为1表示有按键中断
INT_TIME++;
INT_MARK=0;//标志位清0
s=KEYPAD4x4_Read();//读出按键值
if(s!=0){ //如按键值不是0,也就是说有按键操作,则判断为真
//-------------------------"----------------"
OLED_DISPLAY_8x16_BUFFER(6," KEY NO. "); //显示字符串
OLED_DISPLAY_8x16(6,8*8,s/10+0x30);//
OLED_DISPLAY_8x16(6,9*8,s%10+0x30);//
}
}
}
}
总而言之,在程序中
外部中断使用的中心思想
就是
通过程序以某种方式去查询一个
可由外围硬件编程或改变的标记值
以此来更改CPU所处理的任务与线程
优先处理外围电路的请求