很多情况下,要实现一个嵌入式程序,用到某一功能或者某一个硬件资源时,我经常拿厂家或者是其他人给提供的代码,参考其中的配置代码段部分,只去修改实现成我需要的功能就好。相信大家也和我有相似的经历吧!?从工程的角度来说,这没问题。但是理论上总感觉少了点什么,今天以外部中断的寄存器配置为例,进一步讲解中断源是如何进入CPU中,CPU又如何处理中断信号的,这一过程。单纯学术的角度,具体涉及到哪些寄存器、填写什么值,就不细述了。这里用的单片机是FS4412多核ARM芯片。
中断的实现过程(程序的角度)
中断发生后,硬件自动跳转到异常向量表中对应异常类型的位置,然后进行处理。处理过程,先进行现场保护(数据进栈操作),然后根据处理中断函数,根据中断号进行特定的中断处理,等中断程序处理完后,还要恢复中断前的现场(数据出栈操作)。
对中断源的处理过程(硬件的角度)这个过程涉及到我们要讲的中断初始化配置,从图中可以看到,一个外部中断信号需要经过这么多步骤才能到达ARM内核。
首先,外部中断信号需经过GPIO管脚进入CPU内部,然后再内部经使能-->分发-->分发使能-->cpu接口-->接口使能和优先级-->ARM内核 过五关 斩六将 终于到达ARM内核,然后产生中断标志位,再执行之前讲到的中断实现(程序实现)。
中断初始化配置单片机有内置外设,GPIO属于外围功能模块,中断控制器GIC属于内部外设。由于中断源从IO口进入到中断控制器GIC,才能进入ARM内核。我们需要同时配置这两块资源。
- #define GPX1CON (*(volatile unsigned int *)0x11000c20)
- #define EXT_INT41CON (*(volatile int *)0x11000E04)
- #define EXT_INT41_MASK (*(volatile int *)0x11000F04)
- #define ICDISER1_CPU0 (*(volatile int *)0x10490104)
- #define ICDIPTR14_CPU0 (*(volatile int *)0x10490838)
- #define ICDDCR (*(volatile int *)0x10490000)
- #define ICCICR_CPU0 (*(volatile int *)0x10480000)
- #define ICCPMR_CPU0 (*(volatile int *)0x10480004)
- #define EXT_INT41_PEND (*(volatile int *)0x11000f44)
- #define ICCIAR_CPU0 (*(volatile int *)0x1048000C)
- #define ICCEOIR_CPU0 (*(volatile int *)0x10480010)
- #define ICDICPR1_CPU0 (*(volatile int *)0x10490284)
-
-
-
- void interrupt_init(void)
- {
- //-----外: 配置管脚的工作模式
- GPX1CON = (GPX1CON & ~(0xF<<4))|(0xF<<4); //配置 GPX1_1为中断模式
-
- EXT_INT41CON = (EXT_INT41CON & ~(0x7<<4))|(0x2<<4); //设置GPX1_1的触发方式为 下降沿触
-
- EXT_INT41_MASK = EXT_INT41_MASK & (~0x02); //GPX1_1 中断使能
-
-
-
- //-----内: 功能块设置
- ICDISER1_CPU0 = ICDISER1_CPU0 | (1<<25); //EINT9 (GPX1_1) GIC中断使能
- ICDIPTR14_CPU0 = 0x01010101; //参考例子背景,用默认设置
- ICDDCR = ICDDCR|1; //GIC 分发总使能
- ICCICR_CPU0 = 1; // CPU0 中断使能
- ICCPMR_CPU0 = 0XFF; //设置CPU0的优先级门槛为最低
-
- }
复制代码
注:外部中断配置过程:
- 1配置中断
- 1、 分配中断向量表:
- /* Set the Vector Table base location at 0x20000000 */
- NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
- 2、 设置中断优先级:
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设置中断优先级
- 3、 初始化外部中断:
- /*允许EXTI4中断 */
- NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQChannel; //中断通道
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PreemptionPriorityValue;//强占优先级
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //次优先级
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //通道中断使能
- NVIC_Init(&NVIC_InitStructure); //初始化中断
- 注意:如果我们配置的外部针脚为PA4,或PB4,或PC4,PD4等,那么采用的外部中断也必须是EXTI4,同样,如果外部中断针脚是PA1,PB1,PC1,PD1 那么中断就要用EXTI1,其他类推。
-
- 2配置GPIO针脚作为外部中断的触发事件
- 1、 选择IO针脚
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
- 注意,如果的针脚是端口的4号针脚,配置的中断一定是EXTI4
- 2、 配置针脚为输入
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- 3、 初始化针脚
- GPIO_Init(GPIOD,&GPIO_InitStructure);
-
-
- 3配置EXTI线,使中断线和IO针脚线连接上
- 1、 将EXTI线连接到IO端口上
- 将EXTI线4连接到端口GPIOD的第4个针脚上
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource4);
- 注意:如果配置的针脚是4号,那么参数必须是GPIO_PinSource4
- 如果配置的针脚是3号,那么参数必须是GPIO_PinSource3
- 2、配置中断边沿
- /*配置EXTI线0上出现下降沿,则产生中断*/
- EXTI_InitStructure.EXTI_Line = EXTI_Line4;
- 注意:如果配置的4号针脚,那么EXTI_Line4是必须的
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
- EXTI_InitStructure.EXTI_LineCmd = ENABLE; //中断线使能
- EXTI_Init(&EXTI_InitStructure); //初始化中断
- EXTI_GenerateSWInterrupt(EXTI_Line4); //EXTI_Line4中断允许
-
- 到此中断配置完成,可以写中断处理函数。
- 举例:
- 配置函数
- /*************************************************************************
- * 函数名 NVIC_Configration
- * 描述 配置各个中断寄存器
- * 输入 无
- * 输出 无
- * 返回值 无
- ****************************************************************************/
- void NVIC_Configration(void)
- {
- NVIC_InitTypeDef NVIC_InitStructure;
- //#ifdef VECT_TAB_RAM
- /* Set the Vector Table base location at 0x20000000 */
- NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
- //#else /* VECT_TAB_FLASH */
- /* Set the Vector Table base location at 0x08000000 */
- //NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
- //#endif
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设置中断优先级
- /*允许EXTI4中断 */
- NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQChannel;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PreemptionPriorityValue;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- /*允许EXTI9中断*/
- NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- /*配置SysTick处理优先级:优先级以及子优先级*/
-
- }
-
- /************************************************************************
- * 函数名 :GPIO_Configuration(void)
- * 描述 :配置TIM2阵脚
- * 输入 :无
- * 输出 :无
- * 返回 :无
- ************************************************************************/
- void GPIO_Configuration(void){
- /* GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOA,&GPIO_InitStructure); */
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
- GPIO_Init(GPIOC,&GPIO_InitStructure);
-
- /*配置GPIOD的第一个管角为浮动输入*/
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_Init(GPIOD,&GPIO_InitStructure);
-
- /*配置GPIOB的第9个管脚为浮动输入*/
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_Init(GPIOB,&GPIO_InitStructure);
- }
-
-
- /**************************************************************
- * 函数 SysTick_Configuration
- * 描述 设置SysTick
- * 输入 无
- * 输出 无
- * 返回值 无
- ***************************************************************/
- void SysTick_Configuration(void)
- {
- /*配置 HCLK 时钟做为SysTick 时钟源*/
- SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //系统时钟8分频 72MHz
-
- NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 8,2);
- /*SysTick Interrupt each 1000Hz with HCLK equal to 72MHz*/
- SysTick_SetReload(9000);//中断周期1ms
- /*Enable the SysTick Interrupt */
- SysTick_ITConfig(ENABLE);//打开中断
- SysTick_CounterCmd(SysTick_Counter_Enable);
- SysTick_CounterCmd(SysTick_Counter_Clear);
- }
-
-
- /******************************************************************************
- * 函数名 EXTI_Configuration
- * 描述 配置EXTI线
- * 输入 无
- * 输出 无
- * 返回值 无
- ******************************************************************************/
- void EXTI_Configuration(void){
-
- /*将EXTI线0连接到PA0*/
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource4);
- /*配置EXTI线0上出现下降沿,则产生中断*/
- EXTI_InitStructure.EXTI_Line = EXTI_Line4;
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
- EXTI_InitStructure.EXTI_LineCmd = ENABLE;
- EXTI_Init(&EXTI_InitStructure);
- EXTI_GenerateSWInterrupt(EXTI_Line4);
-
- /*将EXTI线9连接到PB9上*/
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource9);
- /*将EXTI线9上出现下降沿产生中断*/
- EXTI_InitStructure.EXTI_Line = EXTI_Line9;
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
- EXTI_InitStructure.EXTI_LineCmd = ENABLE;
- EXTI_Init(&EXTI_InitStructure);
- EXTI_GenerateSWInterrupt(EXTI_Line9);
- }
-
- 中断函数:
- void EXTI4_IRQHandler(void)
- {
- if(EXTI_GetITStatus(EXTI_Line4)!= RESET){
- EXTI_ClearITPendingBit(EXTI_Line4);
- if(Ledflag == 0){
- Ledflag = 1;
- GPIOC->ODR |= 0X00000080;
- }
- else{
- Ledflag = 0;
- GPIOC->ODR &= 0XFFFFFF7F;
- }
- }
- }
-
复制代码
|