中断要发生需要三部分同时工作:
中断源
CPU使能中断
中断控制器的作用:
汇集各类中断信号并发给CPU。
中断处理过程:
1.中断控制器汇集各类中断信号并发给CPU。
2.CPU保存当前程序的运行环境(各个寄存器),调用中断服务程序ISR来处理中断
3.在ISR中通过读取中断控制器、外设相关寄存器来识别哪个中断,并处理。
4.清除中断:通过读写中断控制器和外设相关寄存器来实现。
5.最后恢复中断程序的运行环境(即2中保存的各个寄存器)。继续执行。
看一下中断控制器的内部结构框图,了解中断处理细节。
有些请求源是带sub寄存器的,有些则不带。
(1) 对于带sub寄存器的,中断源被触发之后,SUBSRCPND寄存器相应位被置1,如果没有被SUBMASK屏蔽的话,它在SRCPND的相应位也被置1,如果没有被MASK屏蔽的话或者FIQ的话,它将被进一步处理。
(2) 对于不带sub的,它在SRCPND的相应位被置1,如果没有被MASK屏蔽的话或者FIQ的话,它将被进一步处理。
(3) 对于一般中断,可能同时有几个中断被触发,未被INTMASK屏蔽的中断经比较后,选出优先级最高的中断,此中断再INTPND的相应位被置1,然后CPU进入中断模式进行处理。中断服务子程序通过读INTPND寄存器或者INTOFFSET寄存器来确定中断源。
清中断
指定中断源的中断服务程序中,必须通过清除 SRCPND 寄存器的相应位来正确的获得来自相同源的中断请求。如果从 ISR 中返回并且未清除相应位,则中断控制器的操作就好像其它中断请求已经从同一个源进入了。换句话说,如果 SRCPND 寄存器的指定位被设置为 1,其通常被认作一个有效中断请求正在等待服务。
清除相应位的时间依赖于用户的需要。如果希望收到来自相同冤源的其它有效请求,则应该首先清除相应位,并且接着使能中断。
可以通过写入一个数据到此寄存器来清除 SRCPND 寄存器的指定位。其只清除那些数据中被设置为 1 的相应位置的 SRCPND 位。那些数据中被设置为 0 的相应位置的位保持不变
就如 SRCPND 寄存器,必须在中断服务程序中清除了 SRCPND 寄存器后清除此寄存器。可以通过写入数据到此寄存器中来清除 INTPND 寄存器的指定位。只会清除数据中设置为 1 的相应 INTPND 寄存器位的位置。数据中设置为 0 的相应位的位置则保持不变。
可以通过写入数据到此寄存器来清除 SUBSRCPND 寄存器的指定位。只有数据中那些被设置为 1 的相应SUBSRCPND 寄存器的位的位置才能被清除。数据中那些被设置为 0 的相应位的位置则保持不变。
编程
对于特定的中断,不仅要设置中断控制器,还要进行其它设置。
外部中断:
设置中断源,让它能发出中断信号
设置中断控制器
设置CPU,CPSR的 I 位,是中断总开关
处理时要分辨中断源
处理完要清中断
汇编中的异常处理程序
.align 4
irq_eint:
ldr sp, =0x33d00000
/* 保护现场 */
stmdb sp!, {r0-r12,lr}
/* 处理异常 */
bl key_eint_isr
/* 恢复现场 */
ldmia sp!, {r0-r12,pc}^
相关C程序
/* 初始化中断控制器 */
void interrupt_init(void)
{
INTMSK &= ~(1<<0); /* Service available */
}
/* 初始化中断源,设置KEY为中断源 */
void key_eint_init(void)
{
GPFCON &= ~(3<<0);
GPFCON |= (2<<0);
EXTINT0 |= (7<<0); /* 设置双边沿触发 */
}
/* 按键外部中断处理函数 */
void key_eint_isr(void)
{
/* 中断处理 */
int val = GPFDAT;
if (val & (1<<4))
{
/* 当前状态是灭 */
GPFDAT &= ~(1<<4);
}
else
{
GPFDAT |= (1<<4);
}
/* 清中断 */
SRCPND |= (1<<0);
INTPND |= (1<<0);
}
设置时钟
设置初值
加载初值,启动Timer
设置自动加载
中断相关
对于定时器部分,还要参考S3C2440的定时器功能。不再细述。
具体代码如下
#include "timer.h"
extern flag;
void interrupt_init(void)
{
INTMSK &= ~(1<<10); /* Service available */
}
/* 定时器输入时钟频率 = PCLK / {预分频值+1} / {分频值} */
/* 31250 = 50000000/(99+1)/16 */
void timer_init(void)
{
TCFG0 = 99; //定时器0和1的预分频值为99
TCFG1 &= ~(0xf<<0);
TCFG1 |= (3<<0); //定时器1的分频值为1/16
TCNTB0 = 31250; //定时周期设为1s
TCON |= (1<<1); //手动更新
TCON &= ~(1<<1);
TCON |= ((1<<0) | (1<<3)); //开启自动重载,开启定时器
}
void timer_isr(void)
{
if (flag)
{
GPFDAT |= (1<<4);
GPFDAT |= (1<<5);
GPFDAT |= (1<<6);
flag = 0;
}
else
{
GPFDAT &= ~(1<<4);
GPFDAT &= ~(1<<5);
GPFDAT &= ~(1<<6);
flag = 1;
}
SRCPND |= (1<<10);
INTPND |= (1<<10);
}
上一篇:ARM的PWM定时器(S3C2440)
下一篇:ARM的异常(S3C2440)
设计资源 培训 开发板 精华推荐
- UC3845B 高性能电流模式 PWM 控制器的典型应用
- STC8H3K coreboard QFP48
- LTC2946IMS-1 6V 至 300V 高端电源、电荷和能量监视器的典型应用
- NCP1012 用于低待机功耗离线 SMPS 的自供电单片开关的典型应用
- 使用 ON Semiconductor 的 RC4190 的参考设计
- SPT7871 是一款单片 10 位双极型 ADC。由于其独特的架构,它可以以高达 100 MSPS 的速率对输入进行采样
- 具有 25uA 反向泄漏电流的 LT1956EGN 双源电源的典型应用电路
- 电梯到站提醒和故障自动警报
- LT6656BIS6-1.25、1.25V 扩展电源范围电压基准的典型应用
- DEVKIT-S12XE: 9S12XEP100 MCU评估开发板