第一课:GPIO操作——LED & 按键

来源:互联网 发布:苹果电脑office软件 编辑:程序博客网 时间:2024/06/05 20:13

前言

学习嵌入式已经快一年了,却是第一次正经的开始从ARM的裸板程序开始学习,有些汗颜……准备学习裸板程序的一部分,然后接着学习相应的设备驱动开发。第一次学博文,欢迎拍砖

第一课:GPIO操作——LED & 按键

环境:

软件:Ubuntu9.10 source insight3.5 oflash JTAG等驱动

硬件:ARM 2440 (韦东山配套教材)

参考教材:嵌入式Linux应用开发完全手册 韦东山著

一系列的环境搭建,操作步骤书中和视频教材解释也挺详细的

只是记录下学习过程的心得

按键点亮 LED     (C语言 )

最终文件: 

led_key.c :C程序文件,实现点亮led

crt0.s :裸板程序中的启动代码(汇编)

led_key.lds :连接脚本

Makefile :实现程序的预处理、编译、汇编和链接以及清除工作


实现: 

此处GPIO的操作需要:

1.判断key

2.点亮/灭led

a.配置功能:输出/输入/其他 key为输入,led引脚为输出功能

b.读key引脚,根据值来设置led引脚高电平LED熄灭,低电平LED点亮(参看电路图)


写程序之前先了解一下ARM2440的两种启动方式

1.Nand flash启动

a.在开发板上电启动的时候,CPU将Nand Flash开始的前4K数据复制到SRAM,即“Steppingstone”(此时内部RAM的起始地址为0);

b.CPU跳转地址0开始执行。

以上两步均为硬件执行

2.Nor flash启动

Nor flash可以像内存一样进行读操作,却不可想内存一样写

a.0地址指向Nor flash

b.CPU 从0地址取址执行

由于是裸板程序,因此需要在C语言文件之前实现一系列的初始化工作。

1)软件相关的初始化:

a.设置栈,即初始化SP指针,指向内存的某一块区域。如果是SRAM,可直接使用,如果是SDAM,还需要初始化(韦东山的板子都是直接映射到SRAM的,因此可以直接使用)

b.设置C语言中的main返回地址

c.调用main函数

(以上两步直接通过bl main可实现,返回地址保存到了LR寄存器)

d.清理工作

(通过死循环来实现的   

halt_loop : b halt_loop ) 

2)硬件初始化:

a.关看门狗,关中断

b.初始化时钟

c.初始化SDAM

(此次程序只关了看门狗)

这两步是由crt0.s来实现的,之后调用main函数


@******************************************************************************@ File:crt0.S@ 功能:通过它转入C程序@****************************************************************************** 
@.text部分是处理器开始执行代码的地方@.global关键字用来让一个符号对链接器可见,可以供其他链接对象模块使用@.global _start让_start符号成为链接器可见的标识符@这样链接器就知道跳转到程序中的什么地方并开始执行@linux寻找这个_start标签作为程序的默认进入点
@转载自:http://hi.baidu.com/ahauwangjie/item/10e988e740160ee5fb42baa5
.text.global _start_start:ldr r0,= 0x53000000;@watchdog寄存器地址mov r1,#0x0str r1,[r0]ldr sp,= 1024 * 4bl mainhalt_loop:b halt_loop

程序的具体实现:

//引脚定义#define GPFCON(*(volatile unsigned long *)0x56000050)#define GPFDAT(*(volatile unsigned long *)0x56000054)#define GPGCON (*(volatile unsigned long *)0x56000060)#define GPGDAT(*(volatile unsigned long *)0x56000064)//LED引脚初始化定义#define GPF4_MSK(3<<(4*2))#define GPF5_MSK(3<<(5*2))#define GPF6_MSK(3<<(6*2))//按键引脚初始化定义#define GPF0_MSK(3<<(0*2))#define GPF2_MSK(3<<(2*2))#define GPG3_MSK(3<<(3*2))//led引脚输出定义#define GPF4_out(1<<(4*2))#define GPF5_out(1<<(5*2))#define GPF6_out(1<<(6*2))int main(){unsigned long temp;//先将led相应引脚置0,其他位保留GPFCON &= ~(GPF4_MSK | GPF5_MSK |GPF6_MSK);//定义led引脚为输出GPFCON |= (GPF4_out | GPF5_out | GPF6_out);//定义按键引脚为输入GPFCON &= ~(GPF0_MSK | GPF2_MSK);GPGCON &= ~(GPG3_MSK);while(1){//读取key值temp = GPFDAT;//key值为0说明按键按下,为1表示没有按下if(temp & (1<<0))GPFDAT |= (1<<4);//熄灭ledelseGPFDAT &= ~(1<<4);//点亮ledif(temp & (1<<2))GPFDAT |= (1<<5);else GPFDAT &= ~(1<<5);temp = GPGDAT;if(temp & (1<<3))GPFDAT |= (1<<6);elseGPFDAT &= ~(1<<6);}return 0;}


led_key.lds:

SECTIONS {. = 0x00;  .text          :   { *(.text) }.rodata ALIGN(4) : {*(.rodata)}   .data ALIGN(4) : { *(.data) }  .bss ALIGN(4)  : { *(.bss)  *(COMMON) }}
关于连接脚本的细节,请参照相关文章:

http://blog.csdn.net/chepwavege/article/details/7401794

http://johnylai.i.sohu.com/blog/view/31725442.htm


Makefile:

led_key.bin : led_key.c crt0.s#依赖关系arm-linux-gcc -g -c -o crt0.o crt0.s#编译crt0.sarm-linux-gcc -g -c -o led_key.o led_key.c#编译led_key.carm-linux-ld -Tled_key.lds crt0.o led_key.o -o led_key_elf#通过连接脚本链接,生成led_key_elf文件arm-linux-objcopy -O binary -S led_key_elf led_key.bin#生成二进制可执行文件arm-linux-objdump -D -m arm led_key_elf > led_key.dis#生成反汇编文件clean:rm -f led_key_elf led_key.bin led_key.dis *.o *~#make clean

至此按键控制led的裸板程序写好,中间还有不少迷惑的地方,诸如Makefile中诸多参数的定义,连接脚本的编写,启动汇编程序的完善……