一、开发环境
1、硬件平台:FS2410
2、主机:Ubuntu 10.10
二、相关硬件原理图(按键与LED)
按键的接线资源:
KSCAN0 -> GPE11、 KSCAN1 -> GPG6、 KSCAN2 -> GPE13、 KSCAN3 -> GPG2
EINT0 -> GPF0、 EINT2 -> GPF2、 EINT11 -> GPG3、 EINT19 -> GPG11
三、程序设计相关原理
某个中断的产生表示,与它所对应的矩阵行的4个按键中,至少有一个按键被按住了。因此可以通过查看产生了哪个中断,来确定在矩阵的哪一行中发生了按键操作(按住或释放)。例如,如果产生了外部2号线中断(EINT2变为低电平),则表示K7、K8、K9和K15中至少有一个按键被按住了。这时候4个EINT端口应该通过GPIO配置寄存器被设置为外部中断端口,而且4个KSCAN端口的输出必须为低电平。
在确定按键操作所在行的位置之后,我们还得查看按键操作所在列的位置。此时要使用KSCAN端口组,同时将4个EINT端口配置为通用输入端口(而不是中断端口)。在4个KSCAN端口中,轮流将其中某一个端口的输出置为低电平,其他3个端口的输出置为高电平。这样逐列进行扫描,直到按键所在列的KSCAN端口输出为低电平,此时按键操作所在行的EINT管脚的输入端口的值会变成低电平。例如,在确认产生了外部2号中断之后,进行逐列扫描。若发现在KSCAN1为低电平时(其他端口输出均为高电平),GPF2(EINT2管脚的输入端口)变为低电平,则可以断定按键K8被按住了。
四、相关寄存器的配置信息见《ARM裸机——FS2410按键控制LED灯(查询方式)》
五、详细代码:
start.S:(启动代码)
.extern main
.text
.global _start
_start:
b Reset
HandleUndef:
b HandleUndef
HandleSWI:
b HandleSWI
HandlePrefetchAbort:
b HandlePrefetchAbort
HandleDataAbort:
b HandleDataAbort
HandleNotUsed:
b HandleNotUsed
b HandleIRQ
HandleFIQ:
b HandleFIQ
Reset:
mov r1, #0x53000000
mov r2, #0x0
str r2, [r1]
msr cpsr_c, #0xd2
ldr sp, =1024 * 3
msr cpsr_c, #0xdf
ldr sp, =1024 * 4
bl init_gpio
msr cpsr_c, #0x5f
ldr lr, =halt_loop
bl main
halt_loop:
b halt_loop
HandleIRQ:
sub lr, lr, #4
stmfd sp!, { r0-r12,lr }
bl light_on
ldmfd sp!, { r0-r12,pc }^
key.c:
#define SRCPND (*(volatile unsigned long *) 0x4a000000)
#define INTMOD (*(volatile unsigned long *) 0x4a000004)
#define INTMSK (*(volatile unsigned long *) 0x4a000008)
#define INTPND (*(volatile unsigned long *) 0x4a000010)
#define EXTINT2 (*(volatile unsigned long *) 0x56000090)
#define EINTMASK (*(volatile unsigned long *) 0x560000a4)
#define EINTPEND (*(volatile unsigned long *) 0x560000a8)
#define GPECON (*(volatile unsigned long *) 0x56000040)
#define GPEDAT (*(volatile unsigned long *) 0x56000044)
#define GPFCON (*(volatile unsigned long *) 0x56000050)
#define GPFDAT (*(volatile unsigned long *) 0x56000054)
#define GPGCON (*(volatile unsigned long *) 0x56000060)
#define GPE11_out (1 << 22)
#define GPF4_out (1 << 8)
#define GPF5_out (1 << 10)
#define GPF6_out (1 << 12)
#define GPF7_out (1 << 14)
#define GPG11_int (2 << 22)
void init_gpio(void) //初始化GPIO
{
GPFCON = GPF4_out | GPF5_out | GPF6_out | GPF7_out; //设置GPF4-GPF7为输出
GPFDAT |= 0xf0; //将4个LED熄灭
GPECON = GPE11_out; //GPE11设置为输出(KSCAN0)
GPEDAT &= ~(1 << 11); //设置GPE11输出0
GPGCON = GPG11_int; //GPG11设置为中断方式(EINT19)
EXTINT2 |= (1 << 13); //设置为下降沿触发
EINTMASK &= ~(1 << 19); //使能EINT19
INTMSK &= ~(1 << 5); //使能中断
}
void light_on(void) //设置灯亮
{
if((EINTPEND & (1 << 19)) && (SRCPND & (1 << 5))) //判断EINT19是否产生
{
GPFDAT &= ~(1 << 4); //点亮LED12
EINTPEND |= (1 << 19); //清除中断,注意清除中断的顺序
SRCPND = SRCPND;
INTPND = INTPND;
}
}
void wait(long long num) //延迟函数
{
for(; num > 0; num--);
}
int main(void) //设置LED9闪烁
{
while(1)
{
GPFDAT &= ~(1 << 7);
wait(200000);
GPFDAT |= 0xf0;
wait(200000);
}
return 0;
}
Makefile :
key.bin: start.S key.c
arm-none-linux-gnueabi-gcc -c start.S -o start.o
arm-none-linux-gnueabi-gcc -c key.c -o key.o
arm-none-linux-gnueabi-ld -Ttext 0x00000000 start.o key.o -o key
arm-none-linux-gnueabi-objcopy -O binary -S key key.bin
clean:
rm -f *.o key.bin key
在开发板的uboot上输入:
tftp 0 key.bin
go 0
实验现象:
LED9一直闪烁,按下按键后LED12灯亮