- start.s
cpp
preserve8
area reset, code, readonly
code32
entry
ldr pc, =start
nop
nop
nop
nop
nop
ldr pc, =interrupt_handler
nop
start
ldr sp, =0x40001000
mrs r0, cpsr
bic r0, r0, #0x1F
orr r0, r0, #0x12;IRQ
bic r0, r0, #(1 << 7);打开IRQ中断允许
msr cpsr_c, r0
ldr sp, =0x40001000
sub sp, sp, #1024
mrs r0, cpsr
bic r0, r0, #0x1F
orr r0, r0, #0x10 ;User
msr cpsr_c, r0
ldr sp, =0x40001000
sub sp, sp, #2048
import main
b main
interrupt_handler
sub lr, lr, #4
stmfd sp!, {r0-r12, lr}
import do_interrupt
bl do_interrupt
ldmfd sp!, {r0-r12, pc}^
finished
b finished
end
- main.c------timer4是一个纯粹的定时器
cpp
#include <s3c2440.h>
#include "led.h"
#include "key.h"
#include "interrupt.h"
void init_wdt(void) //初始化看门狗,禁止启动,关闭看门狗
{
WTCON &= ~(1 << 0);
}
void delay(unsigned int n)
{
while (n--);
}
void init_clk(void)
{
unsigned int t = MPLLCON; //将PCLK频率存入变量设置好再进行修改,防止频率修改中途器件因为频率过高而短路
t &= ~((0xff << 12) | (0x3f << 4) | (3 << 0)); //利用锁相环将12MHz倍频
t |= ((127 << 12) | (2 << 4) | (1 << 0)); //配置fclk频率大约为400Mhz
CLKDIVN |= ((2 << 1) | (1 << 0));//分频,配置HCLK为100MHz,HCLK为50MHz
MPLLCON = t;//将所有频率配置好再进行设置,防止器件被烧坏
}
void timer4_handler(void)
{
static unsigned int n = 0;
++n;
if (n > 1000) //定时器中断触发次数次数
{
ledAllNor();
n = 0;
}
}
void init_timer4(void)
{
TCFG0 |= (24 << 8); //配置定时器 4 预分频值25 50/25=2MHz
TCFG1 &= ~(0x0f << 16);// 选择 PWM 定时器 4 的选通输入1/2 2/2=1MHz
TCNTB4 = 1000;//设置定时器 4 的计数缓冲器的值为1000 ,1000减到0触发一次定时器中断
TCON |= (1 << 22); //自动重载
TCON |= (1 << 21); // 定时器 4 的手动更新
TCON &= ~(1 << 21);// 定时器 4 的手动更新复位
INTMOD &= ~(1 << IRQ_INT_TIMER4);//配置定时器4中断为IRQ模式
INTMSK &= ~(1 << IRQ_INT_TIMER4);//让定时器中断处于可服务模式
TCON |= (1 << 20);//启动定时器4
register_irq(IRQ_INT_TIMER4, timer4_handler);//注册定时器中断处理函数
}
int main(void)
{
init_wdt();
init_led();
init_key();
init_clk();
init_timer4();
while (1)
{
// ledAllNor();
// delay(0xffff);
}
}
- led.h
cpp
#ifndef _LED_H_
#define _LED_H_
extern void init_led(void);
extern void ledon(unsigned int n);
extern void ledAllOn(void);
extern void ledAllOff(void);
extern void ledAllNor(void);
extern void ledoff(unsigned int n);
#endif
- led.c
cpp
#include <s3c2440.h>
#include "led.h"
#include "key.h"
#include "interrupt.h"
void init_led(void) //初始化led ,输出模式
{
GPBCON &= ~((3 << 10) | (3 << 12) | (3 << 14) | (3 << 16));
GPBCON |= ((1 << 10) | (1 << 12) | (1 << 14) | (1 << 16));
ledAllOff();
}
void ledon(unsigned int n)
{
if (n < 1 || n > 4)
{
return;
}
GPBDAT &= ~(1 << (n + 4));
}
void ledAllOn(void)
{
GPBDAT &= ~(0x0f << 5);
}
void ledAllOff(void)
{
GPBDAT |= (0x0f << 5);
}
void ledAllNor(void)
{
GPBDAT ^= (0x0f << 5);
}
void ledoff(unsigned int n)
{
if (n < 1 || n > 4)
{
return;
}
GPBDAT |= (1 << (n + 4));
}
- key.h
cpp
#ifndef _KEY_H_
#define _KEY_H_
extern void init_key(void);
extern void key_handler(void);
#endif
- key.c
cpp
#include <s3c2440.h>
#include "led.h"
#include "key.h"
#include "interrupt.h"
void init_key(void) //按键中断EINT 8 11 13 14 15 19
{
INTMOD &= ~(1 << IRQ_EINT8_23);//EINT8_23设置为IRQ 中断模式 (INTMOD ) 寄存器
INTMSK &= ~(1 << IRQ_EINT8_23);//EINT8_23设置为可服务 中断屏蔽 (INTMSK ) 寄存器
GPGCON &= ~((3 << 0) | (3 << 6) | (3 << 10) | (3 << 12) | (3 << 14) | (3 << 22));
GPGCON |= ((1 << 1) | (1 << 7) | (1 << 11) | (1 << 13) | (1 << 15) | (1 << 23));//按键改为触发外部中断模式
GPGUP |= ((1 << 0) | (1 << 11));//禁止附加上拉电阻
EXTINT1 |= ((2 << 0) | (2 << 12) | (2 << 20) | (2 << 28)); //为外部中断配置信号触发方式
EXTINT1 |= ((1 << 3) | (1 << 15) | (1 << 23) | (1 << 27) | ((unsigned int)1 << 31));//下降沿触发+信号滤波
EXTINT2 |= ((2 << 12) | (1 << 15));
EINTMASK &= ~((1 << 8) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19));
register_irq(IRQ_EINT8_23, key_handler);//注册由enit8_23导致产生的中断函数
}
void key_handler(void)
{
if (EINTPEND & (1 << 8))//判断具体是哪个子中断源引发中断
{
ledAllNor();
}
else if (EINTPEND & (1 << 11))
{
ledAllNor();
}
else if (EINTPEND & (1 << 13))
{
ledon(1);
}
else if (EINTPEND & (1 << 14))
{
ledon(2);
}
else if (EINTPEND & (1 << 15))
{
ledon(3);
}
else if (EINTPEND & (1 << 19))
{
ledon(4);
}
EINTPEND = EINTPEND;
}
- interrupt.h
cpp
#ifndef _INTERRUPT_H_
#define _INTERRUPT_H_
typedef void (*irq_handler)(void);
#define IRQ_EINT8_23 5
#define IRQ_INT_TIMER4 14
extern void do_interrupt(void);
extern void register_irq(int irq_num, irq_handler handler);
#endif
- interrupt.c
cpp
#include <s3c2440.h>
#include "led.h"
#include "key.h"
#include "interrupt.h"
static irq_handler handler_vector[60];//static防止别人去修改,只能在本interrupt.c文件中使用
void do_interrupt(void)
{
int n = INTOFFSET;
handler_vector[n]();
SRCPND = SRCPND;//先清src
INTPND = INTPND;//置位
}
void register_irq(int irq_num, irq_handler handler)
{
handler_vector[irq_num] = handler;
}
-
中断执行流程
-
中断源发出中断请求
-
CPU查询中断是否被运行、以及中断是否被屏蔽
-
CPU考察中断优先级
-
CPU保护现场
-
执行中断服务函数
-
恢复现场
-
外部中断是带有sub寄存器的子请求源
-
对pend寄存器写1是清零
pend寄存器0未请求 1请求,但写1清零
-
串口中断带sub子寄存器
-
判断中断源
pend 给1是0 给0是1
srcpnd
intpnd
-
s3c2440是递减寄存器
-
定时器没有子中断源
PLL锁相环:倍频,使频率升高
MPLL:给主板倍频(不要修改MPLL)
UPLL:给USB倍频
分频器:分频,将频率升高
FCLK分频器
重点
p
m
s
7-20