实验(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汇编的条件执行码,这个比较常用,页贴上来供自己参考:
&