ARM 裸机实验之用按键
控制 LED 灯
嵌入式可以说是一门很复杂的学科,要想学透并不
容易,初学者可以从裸机实验开始学起,所以我为大
家准备了一些裸机实验,供大家学习参考,高手就不
用看了,呵呵额。。。。。
想当初我学嵌入式时,觉的有点单片机的基础,学
起 ARM 来应该不难,没想到事实并不是我想的那样,
单片机相比 ARM 来说差的远了,呵呵,也并不是说
ARM 很不好学,只要找到合适的方法,肯下功夫,一
段时间之后,你就会收到满意的效果的,好了,进入
主题。。。。。。。
主机操作系统:linux redhat9.0
目标板 :TQ2440
ARM: S3C2440
SDRAM:64M
NOR FLASH : 2M
NAND FLASH:256M
记得当初刚开始学的时候,总是想先弄明白 ARM
是通过什么方式控制它的 IO 端口的,现在我还是先从
这方面开始讲起吧。。。。。。
通过三星公司 S3C2440 的数据手册可知,它有 9 组
GPIO 端口,分别是 GPA-GPJ(没有 GPI),
它的每组端口的输入和输出都是通过配置相关的寄
存器来实现的,比如说 GPB 这一组,GPB 共有 11 个
IO 端 口 GPB0-GPB10 , 相 应 的 控 制 寄 存 器 为
GPBCON、GPBDAT、GPBUP。
GPBCON 用来设置 GPB 端口是用来输出还是输入
还是用来做第二功能,GPBDAT 则是控制 IO 口的输
出电平或从中得到输入电平,GPBUP 是决定各个端口
是否使用上拉电阻功能。
正因为这样给了我们很大方便,使得我们通过修改
寄存器就可以控制端口。下面就来看看我们的程序吧。
首先说要实现的功能:用开发板上的 4 个按键来控
制 4 个 LED 灯的亮灭,哪个键按下,相应的灯就亮起,
键松开,灯就灭掉。
电路连接情况:4 个按键分别接的是 GPF0、GPF1、
GPF2、GPF4
4 个 LED 灯分别接的是 GPB5 、GPB6、
GPB7、GPB8
先来一个简单的程序,让 4 个 LED 灯全亮,看一下
整个程序的流程:
.text
.global start
_start:
ldr r0,=0x56000010
mov r1,#0x15400
str r1,[r0]
ldr r0,=0x56000014
mov r1,#0x0
str r1,[r0]
main_loop:
b main_loop
整个程序只有几行,下面咱们来一行一行分析:
ldr r0,=0x56000010 查看 S3C2440 数据手册可知其中
0x56000010 就是寄存器 GPBCON 的地址。这句意思
值先赋给 r1.
mov r1,#0x15400 这句是把要传到 GPBCON 中的
str r1,[r0]这句的意思就是把 r1 的值传给以 r0 中的值
为 地 址 所 指 向 的 存 储 空 间 中 , 这 就 完 成 了 设 置
GPBCON 的值。
是把这个地址值赋给 r0.
ldr r0,=0x56000014
mov r1,#0x0
str r1,[r0]
后面这三行
就是给控制 GPB 端口高低电平的寄存器赋值,使引脚
都输出低电平,根据电路图,这时 4 个 LED 灯就会全
部点亮了。
这是源程序,放到 linux 系统里面,在同一文件夹下还
要 编 写 Makefile 文 件 , 这 样 编 译 起 来 比 较 省 事 。
Makefile 文件内容如下:
led.bin:led.S
arm-linux-gcc -g -c -o led.o led.S
arm-linux-ld -Ttext 0x0000000 -g led.o -o led_elf
arm-linux-objcopy -O binary -S led_elf led.bin
clean:
rm -f led.bin led_elf *.o
这里暂不介绍 Makefile 文件的写法,以后会有专门章
节讲解的。
下面是通过按键控制 LED 灯亮灭的程序,程序分为两
部分,由于我们打算用 C 语言编写,所以要先用汇编
语言做一下初始化工作,包括关闭看门狗和设置堆栈。
汇编语言程序:
.text
.global start
_start:
ldr r0,=0x53000000
mov r1,#0 ;关闭看门狗
str r1,[r0]
ldr sp,=1024*4 ;设置堆栈
bl main ;跳转到 main 函数
main_loop:
bl main_loop
保存为 :led2.S
C 语言程序:
/*定义各个端口寄存器,GPB 用于 LED 灯的输出控制,
GPF 用于按键的输入控制*/
#define GPBCON *((volatile
*)0x56000010)
#define GPBDAT *((volatile
*)0x56000014)
#define GPFCON *((volatile
*)0x56000050)
unsigned
unsigned
unsigned
long
long
long
unsigned
long
#define GPFDAT *((volatile
*)0x56000054)
/*初始化各个端口寄存器*/
void IO_init()
{
GPBCON=0x55<<10;//将 GPB5-8 端口设为输出,用
于控制 LED 灯的两灭
GPBDAT=0x0f<<5;//初始化 LED 灯,使其初始状态
//GPF 初始状态即为输入,可取默认值,
为熄灭
不做更改
}
void LED1()
{
//////////////////////////////////在死循环中依次查询各个按
键的状态,若键按下,相应的灯亮,若抬起,灭
while(1)
{
if(!(GPFDAT&0x02))
GPBDAT=GPBDAT&~(0x01<<5);
else
GPBDAT=GPBDAT|(0x01<<5);
if(!(GPFDAT&0x10))
GPBDAT=GPBDAT&~(0x01<<6);
else
GPBDAT=GPBDAT|(0x01<<6);
if(!(GPFDAT&0x04))
GPBDAT=GPBDAT&~(0x01<<7);
else
GPBDAT=GPBDAT|(0x01<<7);
if(!(GPFDAT&0x01))
GPBDAT=GPBDAT&~(0x01<<8);
else
GPBDAT=GPBDAT|(0X01<<8);
}
}
/////////////////////////C 语言主函数
void main()
{
IO_init();
LED1();
}
保存为 main.c
如果上面那个让 LED 灯全亮的程序大家能理解的话,
那这个程序也很好理解,它只不过是多了对 GPF 几个
端口的电平读取,然后根据电平判断某个按键是否被
按下,来决定让哪个 LED 灯点亮或是熄灭。
这个程序的功能是某个按键按下 LED 灯就点亮,
等按键松开 LED 灯就熄灭,如果你能将这个程序理解
了的话,为了加深印象,你可自己试着做做改动,比
如某个按键按下后它控制的 LED 灯点亮,直到有另一
个按键按下它才会熄灭,相应的 LED 灯又会点亮。
下面是本程序的 Makefile 文件:
led2.bin:led2.S main.c
arm-linux-gcc -g -c -o led2.o led2.S
arm-linux-gcc -g -c -o main.o main.c
arm-linux-ld -Ttext 0x0000000 -g led2.o main.o -o
led2_elf
arm-linux-objcopy -O binary -S led2_elf led2.bin
arm-linux-objdump -D -m arm led2_elf > led2.dis
clean:
rm -f led2_elf
*.o led2.dis