STM32中断的食用感受
stm32f103c8t6固件库函数
的中断部分
封装程度并不高
不论是
直接对应到不同的中断处理器的中断处理函数
还是
中断的数据结构体编译中
中断输入模式(定义中断输入线 )
与中断标志位
分两个结构体的定义
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;
这种完全基于硬件思路布局
而丝毫不考虑软件部分易用性
所编译的的库函数
使用起来十分智障
这里以PA4的中断输入为例
基于以上库文件的编译,一般的编译过程大致如下
NVIC.c
extern u8 INT_MARK;//设置中断标志位
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 上的中断标志位
}
——————————————
以上编译过程大致可以解读成:
- 确定找到中断的输入端口(当然你在此之前就开启了GPIO时钟与复用时钟并定义了结构体变量)
然后对应上图表格分别设置 - EXTI
1 中断入口(中断所使用的标志位)(只能使用对应标志位,但此语句又必须要经过编译
(可以理解为这样一句话“他要上厕所,所以他去厕所了”)
2 中断使能(你还需要在进厕所前打个卡申请一下)
3 设置中断的使用模式与触发模式(这个没什么好说的,根据需求弄) - NVIC
1 对应中断线的使用来对应确定哪个中断处理函数的使用(蹲下之前按照你是谁给你指定个坑位,不然就error炸坑)
2 中断线使能(蹲下之前再打个卡申请一下)
3 设置中断优先级(先看抢占优先级,再看子优先级) - 最后编译中断的读取函数,并在函数内改变标志位INT_MARK(终于,你蹲了下来,静静等待着括约肌的收缩。。。)
你甚至可以通过以上的编译过程中
看出其在芯片内部设计上的布局思路
极其繁琐
中断的编译就是如此复杂
让我不禁去想
一个面向使用者,力求简化的对象
为什么要在对象中写两个一定绑定的结构体呢?
为什么在两个绑定的结构体之上还要写几个一定绑定的结构体数据呢?
为什么这些东西还非要使用者一一输入呢?
MMD,等我把这几个中断的结构体一个一个自己全部编译完,找到坑位蹲下来
主程序都跑完了
H桥都过载了
LED灯珠都烧完了
人工智能都起义了
捏麻麻的我孙子都出生了
恶灵的B印子都结好了
和平都蓄满了
我骨灰盒都上天了
!@¥%#&
所以我只有,且只有这个建议
直接上Github上找个能用的直接代替完事算了
just to find a more reliable and well-packed head-fiile for NVIC and EXTI interrupt to use
后记:
我甚至觉得这东西就是拿来给初学者加深stm32了解程度的。。。
当然也不一定,毕竟我也是初学者,等后面如果我有学习到这一相关部分并有了深入的的了解明白其编译的其他用心的话,我会继续更新(当然?也许?咕咕咕)