ARM裸机实验

 
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的地址。这句意思
 
是把这个地址值赋给r0.
mov r1,#0x15400  这句是把要传到GPBCON中的
值先赋给r1.
str r1,[r0]这句的意思就是把r1的值传给以r0中的值
为地址所指向的存储空间中,这就完成了设置
GPBCON的值。
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  unsigned  long
*)0x56000010)
#define GPBDAT  *((volatile  unsigned  long
*)0x56000014)
#define GPFCON  *((volatile  unsigned  long
*)0x56000050)
 
#define GPFDAT  *((volatile  unsigned  long
*)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

你可能感兴趣的:(ARM裸机实验)