实验(2)、通过按键按灯

知识点储备:

1、阅读s3c2440数据手册,掌握s3c2440 I/O口特性,掌握对GPnCON、GPnDAT、GPBUP三个特殊功能寄存器的使用方法。

2、阅读开发板电路图,了解实验电路。

实验步骤:

(1)按照程序清单编写代码

(2)将所有代码放在一个文件夹,用win7的Source Insight新建工程,并查看代码

(3)将文件夹放入linux中,编译,一旦出现错误,根据提示的错误文件行数,到Source Insight中找到改行,调试错误

(4)用DNW下载bin镜像文件,然后拨码开关开到NandFlash中运行代码,观察现象

(5)本实验采用的汇编语言是基于GNU标准的,请在ADS软件下重新编写基于ADS的汇编,详见附录。利用ADS做工程,需要对其做详细配置,比如CPU体系架构,运行地址,生成文件格式等等,详细的配置请参阅天嵌开发板光盘中的“裸奔三部曲(全书)20110101.pdf”的附录103-116页,请完整配置一遍,本实验需提交两种版本代码,分别运行。

实验描述:以轮询而非中断的方式进行按键扫描

实验须知:#define GPBCON (*(volatile unsigned long *)0x56000010)的解读:表示GPBCON为地址是0x56000010的寄存器的内容

一、编写键按灯程序。

1、找出控制4个LED对应的IO引脚,分别为:GPB5\6\7\8,4个按键对应的IO引脚,分别为:GPF0\1\2\4(K4右\k1上\k3下\k2左),具体可查阅开发板电路图。每次按下一键对应的一个LED亮,如按下K2,对应的LED2亮,以此类推。

//在TQ2440_V2核心板原理图.pdf文件中,可以看到GPB5\6\7\8;

2、写程序如下:crt0.S、key_led.c、makefile

(1)crt0.S程序如下:

.text

.global _start

_start:

ldr r0,=0x53000000 @WATCHDOG定时器控制寄存器地址

mov r1, #0x0

str r1,[r0] @写入0,禁止WATCHDOG,否则CPU会不断重启

ldr sp,=1024*4 @设置堆栈,注意:不能大于4k,因为现在可用的内存只有4K

@nand flash中的代码在复位后会移到内部ram中,此ram只有4K

bl main @调用C程序中的main函数

halt_loop:

b halt_loop

(2)键按灯程序

key_led.c程序如下:

#define GPBCON (*(volatile unsigned long *)0x56000010)

#define GPBDAT (*(volatile unsigned long *)0x56000014)

#define GPFCON (*(volatile unsigned long *)0x56000050)

#define GPFDAT (*(volatile unsigned long *)0x56000054)

#define GPB5_out (1<<(5*2))

#define GPB6_out (1<<(6*2))

#define GPB7_out (1<<(7*2))

#define GPB8_out (1<<(8*2))

#define GPF1_in ~(3<<(1*2))

#define GPF4_in ~(3<<(4*2))

#define GPF2_in ~(3<<(2*2))

#define GPF0_in ~(3<<(0*2))

int main()

{

unsigned long dwDat;

GPBCON = GPB5_out | GPB6_out | GPB7_out | GPB8_out ;

GPFCON = GPF1_in & GPF2_in & GPF4_in & GPF0_in;

while(1)

{

dwDat = GPFDAT;

if (dwDat & (1<<1))

GPBDAT |= (1<<5);

else

GPBDAT &= ~(1<<5);

if (dwDat & (1<<4))

GPBDAT |= (1<<6);

else

GPBDAT &= ~(1<<6);

if (dwDat & (1<<2))

GPBDAT |= (1<<7);

else

GPBDAT &= ~(1<<7);

if (dwDat & (1<<0))

GPBDAT |= (1<<8);

else

GPBDAT &= ~(1<<8);

}

return 0;

}

(3)makefile文件如下:

key_led.bin : crt0.S key_led.c

arm-linux-gcc -nostdlib -g -c -o crt0.o crt0.S

arm-linux-gcc -nostdlib -g -c -o key_led.o key_led.c

arm-linux-ld -Ttext 0x0000000 -g crt0.o key_led.o -o key_led_elf

arm-linux-objcopy -O binary -S key_led_elf key_led.bin

arm-linux-objdump -D -m arm key_led_elf > key_led.dis

clean:

rm -f key_led.dis key_led.bin key_led_elf *.o

Q&A

(1)请根据s3c2440数据手册,查找GPFCON,GPFDAT的地址,并用实验中的编程方法,为这两个寄存器下的内容编写宏,类似于#define GPBCON (*(volatile unsigned long *)0x56000010)

(2)结合电路图和程序,请问LED灯的接法是共阴还是共阳接法?

(3) volatile关键字的作用?

(4)按照实例代码,四个按键中哪个优先级最高?

附录:从ADS到GCC

在ARM开发过程中,由于ADS编译器和arm-linux-gcc编译器的差别,导致ADS下的汇编与ARM-Linux汇编略有不同,实现相同功能的汇编,两者需要做转换,整理如下:
1、修改伪指令

如arm-linux汇编头:

.text

.global _start

_start:

修改为ads版本:

(TAB)AREAnand1,CODE,READONLY

(TAB)ENTRY

注意ADS中汇编命令前都必须加上tab 键,如上方代码中“AREA”和“ENTRY”前面都有tab空格,否则编译出错。

2、修改段标号

去掉arm-linux汇编中的:号即可在ads中使用。

如:

halt_loop:

b halt_loop

修改为ads版本:注,标号顶格

halt_loop

(TAB)b halt_loop

3、ads需要加上ENTRY和END指令表示程序入口和结束标志

如:

(TAB)AREAnand1,CODE,READONLY

(TAB)ENTRY

…………

(TAB)END

4、ADS中的C语言混编

与arm-linux汇编不同,ads下的汇编调用C语言的函数时需要指定IMPORT

切记注意在IMPORT前面加tab键空格。否则可能出现下面的错误

arm汇编的条件执行码,这个比较常用,页贴上来供自己参考:

&

results matching ""

    No results matching ""

    results matching ""

      No results matching ""