ARM开发板mini2440的按键控制LED小程序

本文转载自:http://bbs.eeworld.com.cn/viewthread.php?tid=86691

 

mini2440是当前最经济的arm9开发板了,目前就是500多元一块,麻雀虽小,重要的那几个部件也还算齐全,用它来做计算机系统底层的学习工具很合适。而且关于s3c2410/2440系列的教程资料和经验文章在网上很多,大家遇到问题时多google一下也能快速地解决。

先拿一个最初步的LED控制程序上手吧。我的实验开发环境是基于ubuntu9.04系统。

控制硬件的行为,说到底就是设置其对应的寄存器。mini2440开发板有四个LED灯(下图黄色部分,得把LED屏先取下来才能看到,用螺丝刀取下四角的四颗螺丝),还有六个按键(很小,在cmos电池的旁边排成两列,下图红色圈住的部分),我们可以通过配置这些硬件对应的寄存器的值(根据映射在内存空间的地址),来控制它们。例如,四个LED灯有一个配置寄存器(在mini2440板上对应标称为GPBCON)和一个数据寄存器(对应标称为GPBDAT),这两个寄存器都是32bit的整数数值。

mini2440开发板布局图

 

四个LED灯分别使用GPBCON寄存上的4组“2bit位”来配置其是否是输出状态,例如,LED1使用第11、12bit,LED2使用第13、14bit,LED3使用第15、16bit,LED4使用第17、18bit。当把这两位(从高位到低位的顺序看,即[bit12、bit11]这样为一组)设置为00则表示输入状态,01(对于LED1就是bit12为0,bit11为1)表示输出状态,10为特殊功能,11保留待用。GPBDAT寄存器的其中4个bit对应着4个LED灯的数值状态。第6个比特对应LED1,第7个比特对应LED2,第8个比特对应LED3,第9个比特对应LED4。在这样的布局下,我们习惯把LED1对应的某些GPBCON位称为GPBCON5,LED2对应的称为GPBCON6,LED3对应的称为GPBCON7 … 以此类推。因为GPBCON&(0×1<<2*5)不为0表示LED1使用的第11、12位处于输入状态,GPBCON&(0×1<<2*6)不为0表示LED2使用的第13、14位处于输入状态…同理,GPBCON &= ~(0×3<<2*5)即设置LED1为输入状态,GPBCON &= ~(0×3<<2*6)即设置LED2为输入状态… 类似的,GPBDAT对应LED1为GPBDAT5(1<<5),对应LED2为GPBDAT6(1<<6)…

mini2440按键对应GPG分布

mini2440按键对应GPG分布

六个按键使用的是是GPGCON寄存器上的4组“2bit位”来配置其是否处于输入状态,例如,(参照上图中六个按键布局,是根据按键在CMOS电池上方(北部)的布局画的),右上的按键对应GPGCON的第23、24比特,左下的按键对应GPGCON的第1、2比特。GPGDAT寄存器的其中6个比特,对应着6个按键的数值状态。与LED同样地,我们习惯称这几个按键为GPG11、GPG7、GPG6、GPG5、GPG3、GPG0。GPGDAT11、GPGDAT7等等依次对应六个按键。

我们着重关注的是寄存器的输入状态和输出状态。如前所述,将GPBCON的第14位设置为0,第13位设置为1,就表示LED2被设置为输出状态。此时,如果GPBDAT的第7个bit(GPBDAT6)为0(低电平),那么LED2就被点亮,如果GPBDAT6为1(高电平),那么LED2就处于熄灭状态。将GPGCON11的值设置为00(也就是令右上角按键输入状态),则如果这个按键按下,GPGDAT11的值为0(低电平),如果未被按下,则GPGDAT11的值为1(高电平)。
则这里有一个疑问是,LED的输入状态以及按键的输出状态应该是不会在任何场景出现的,应该是没有任何用处的吧。

有了上面这些基础,我们就可以很容易地写出按键控制LED点亮或熄灭的程序了。我写的测试的程序可在这里下载,很简单,有很清楚的注释说明,就不在这里解释了。这个头文件在今后的程序中也可以复用。

程序写完了,怎么跑在没有操作系统的开发板上?没有操作系统也就是说我们目前没有一个可以自启动并被引导的正常运转在cpu和内存的程序,所以我们要自己做这些 –引导我们的程序运转起来。我们要用的方法是,将程序烧入Nandflash,然后使用从Nandflash启动来直接运行我们的程序。使用Nandflash时,s3c2440会将Nandflash的最开始4k的内容加载到SDRAM内存中自动运行,而我们目前的小程序的可运行bin格式的size远远未到4K的大小,所以,我们就将程序放入Nandflash的开始处然后从Nanflash启动系统就可以了。

在我们平时为linux或windows编译C程序时,编译器会自动为我们的C代码链接接一个初始化程序运行环境的小程序,crt0.S文件就是这个程序的汇编格式,在各种操作系统以及其编译器都会有对应的文件。我们的2440目前没有跑操作系统,所以我们要自己写一个crt0.S文件:

.text
.global _start
_start:
ldr     r0, =0×56000010     @ 获取WATCHDOG寄存器·
mov     r1, #0×0
str   r1, [r0]              @ 关闭WATCHDOG,这样就不用“喂狗”防止CPU复位了

ldr     sp, =1024*4         @ 设置程序的栈指针,我们的程序从Nandflash中开始运行,一开始只能有4k的大小

bl      main                @ 跳到main函数去执行我们的代码
halt_loop:
b       halt_loop

代码准备ok,接下来就可以开始准备编译了,如果你还没有交叉编译环境,可以在这里下载交叉编译器(86M),然后解压到一个目录下,再把该目录添加到你的linux系统的PATH环境变量中即可。你可以在终端命令行输入$PATH来检查是否安装成功。(需要重启系统)

然后,再创建一个Makefile文件:

led_on_c.bin : crt0.S  led_key.c
arm-linux-gcc -g -c -o crt0.o crt0.S     #编译crt0.S文件 得到crt0.o程序
arm-linux-gcc -g -c -o led_key.o led_key.c       #编译led_key.c文件,得到led_key.o文件
arm-linux-ld -Ttext 0×0000000 -g  crt0.o led_key.o -o led_key_elf   #将crto.o和led_key.o链接为led_key_elf并将代码段放在0地址
arm-linux-objcopy -O binary -S led_key_elf led_key.bin    #将led_key_elf转为二进制bin文件
arm-linux-objdump -D -m arm  led_key_elf > led_key.dis    #这一行是将led_key_elf文件反汇编为汇编文件,并将转化的汇编放在led_key.dis文件中,可以省略
clean:
rm -f led_key.dis led_key.bin led_key_elf *.o   #清除编译现场

这一切准备就绪之后,就可以将上述文件(2440_GPX.h , led_key.c , crt0.S , Makefile)放在一个文件夹下,在命令行终端进入该目录后输入make命令,就可以开始编译,一切顺利的话,就可以得到led_key.bin文件,这就是我们要烧入Nandflash的文件。

首先,用随机附带的Jtag小板将开发板的JTag口和PC并口连接起来,然后将mini2440的启动选择开关拨到使用Nandflash启动的一边,然后拨动电源开关给电。使用Jflash-s3c2440程序将刚刚编译的bin文件烧写入NandFlash中(进入Jflash-s3c2440的所在目录,然后输入“sudo ./Jflash-s3c2440 bin文件位置加文件名    /t=5” 回车),根据命令行的提示,先选0(表示烧写2440的nandflash),再选0(表示从0地址开始烧写),等待一会烧写完成之后再次出现提示符,此时输入2(表示完成退出)。举例如下:

adreaman@adreaman-laptop:~/Jflash$ sudo ./Jflash-s3c2440  ~/s3c2440/temp/led_key/led_key.bin /t=5

+————————————+
|     SEC JTAG FLASH for 2440+
|     modified by Quasar 2003.9.22+
+————————————+
> flashType=5
> S3C2440X(ID=0×0032409d) is detected.

[K9S1208 NAND Flash JTAG Programmer]
K9S1208 is detected. ID=0xec76
0:K9S1208 Program      1:K9S1208 Pr BlkPage   2:Exit
Select the function to test :0

[SMC(K9S1208V0M) NAND Flash Writing Program]

Source size:0h~37fh

Available target block number: 0~4095
Input target block number:0
target start block number     =0
target size        (0×4000*n) =0×4000
STATUS:Epppppppppppppppppppppppppppppppp
0:K9S1208 Program      1:K9S1208 Pr BlkPage   2:Exit
Select the function to test :2
adreaman@adreaman-laptop:~/Jflash$

到这里,大功告成,拨动开发板电源重启开发板,按动按键,看看是不是像我们的设计一样。Enjoy it!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mini2440是一款常见的嵌入式开发板,它的主板上有4个LED灯,分别是LED1、LED2、LED3和LED4。这些LED灯的控制引脚分别对应GPF4、GPF5、GPF6和GPF7。以下是使用C语言控制Mini2440LED灯的示例代码: ``` #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <fcntl.h> #include <sys/mman.h> #define LED1 4 #define LED2 5 #define LED3 6 #define LED4 7 unsigned int *gpfcon; unsigned int *gpfdat; void led_init(void) { int fd; fd = open("/dev/mem", O_RDWR | O_SYNC); if (fd == -1) { printf("open /dev/mem failed.\n"); exit(-1); } gpfcon = (unsigned int *)mmap(NULL, 16, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x56000050); if (gpfcon == MAP_FAILED) { printf("mmap failed.\n"); exit(-1); } gpfdat = gpfcon + 1; *gpfcon &= ~((0x3 << (LED1*2)) | (0x3 << (LED2*2)) | (0x3 << (LED3*2)) | (0x3 << (LED4*2))); *gpfcon |= ((0x1 << (LED1*2)) | (0x1 << (LED2*2)) | (0x1 << (LED3*2)) | (0x1 << (LED4*2))); } void led_on(int led) { *gpfdat &= ~(1 << led); } void led_off(int led) { *gpfdat |= (1 << led); } int main(int argc, char **argv) { led_init(); while (1) { led_on(LED1); sleep(1); led_off(LED1); sleep(1); } return 0; } ``` 这段代码中,我们首先通过`mmap()`函数来映射物理地址到虚拟地址空间,然后设置LED灯的控制引脚为输出模式,并控制LED灯的亮灭状态。在`led_init()`函数中,我们将LED灯的控制引脚设置为输出模式,并将LED灯全部关闭。在`led_on()`和`led_off()`函数中,我们分别控制LED灯的亮和灭。在`main()`函数中,我们通过循环不断控制LED1的亮灭状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值