嵌入式GPIO接口及操作(二)

时间:2021-03-16 17:52:57

目标:C语言实现点亮LED灯

首先是main函数,并不特殊,它是被系统调用来执行的,main函数结束后要返回调用main函数的地址处,那么裸机程序,没有操作系统做这些工作,就要自己写调用main函数的程序了。
软件相关的初始化:
1、设置栈 2、设置main函数返回地址 3、调用main 4、清理工作

所谓设置栈就是将栈指针SP指向某块内存,在S3C2440中这块内存可以是片内SRAM,这样不用初始化内存了,如果指向SDRAM,那么首先要初始化SDRAM。
硬件相关的初始化:
a、关闭看门狗;b、初始化时钟;c、初始化SDRAM等
软件相关初始化和硬件相关初始化结合一起就是启动文件。

下面是用C语言写的代码
这一段代码是汇编语言,作用相当于启动文件,在这里为了简单,在硬件方面初始化只关闭了看门狗,软件方面初始化设置了栈。

crt.S

.text  
.
global _start
_start:
ldr r0,
=0x53000000 @看门狗地址
mov r1,#
0x0
str r1,[r0] @写入0,关闭看门狗
ldr sp,
=1024*4 @设置堆栈,注意不能大于4K

bl main
halt_loop:
b halt_loop

分析这段汇编程序,首先初始化硬件相关的,关闭看门狗,然后设置堆栈,在s3c2440不能大于4K,因为s3c2440片内SRAM只有4K,再然后就是调到main函数,用了bl指令,bl有两个功能,一是跳转,二是设置了返回地址,就是bl    main指令的下一条指令b hail_loop,所以在这里就初始化完返回地址了。
下面就实现c语言的main函数。

#define GPFCON  (*(volatile unsigned long *)0x56000050)  
#define GPFDAT (*(volatile unsigned long *)0x56000054)
int
main()
{
GPFCON
= 0x00000100;
GPFDAT
= 0x00000000;

return 0;
}

2、用C语言轮流点亮LED

#define GPFCON  (*(volatile unsigned long *)0x56000050)  
#define GPFDAT (*(volatile unsigned long *)0x56000054)
#define GPF4_out ( 1 << 4*2 )
#define GPF5_out ( 1 << 5*2 )
#define GPF6_out ( 1 << 6*2 )
void
delay(
volatile unsigned long dly)
{
for(;dly > 0;dly--);
}
int
main()
{
unsigned i
= 1;

GPFCON
= GPF4_out | GPF5_out | GPF6_out;
while(1)
{
GPFDAT
= ( ~( i << 4 ) );
i
*=2;
if( i == 8)
{
i
= 1;
}
delay(
30000);


}


return 0;
}

Makefile

CFLAGS := -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -ffreestanding  
led_on.bin:ctr.S main.c
arm
-linux-gcc $(CFLAGS) -c -o ctr.o ctr.S
arm
-linux-gcc $(CFLAGS) -c -o main.o main.c
arm
-linux-ld -Ttext 0x00000000 ctr.o main.o -o led_on.elf
arm
-linux-objcopy -O binary -S led_on.elf led_on.bin
arm
-linux-objdump -D -m arm led_on.elf>led_on.dis
clean:
rm
-f led_on.bin led_on.elf *.o led_on.dis

3、按键操作

#define GPFCON  (*(volatile unsigned long *)0x56000050)  
#define GPFDAT (*(volatile unsigned long *)0x56000054)
#define GPGCON (*(volatile unsigned long *)0x56000060)
#define GPGDAT (*(volatile unsigned long *)0x56000064)

#define GPF4_out ( 1 << 4*2 )
#define GPF5_out ( 1 << 5*2 )
#define GPF6_out ( 1 << 6*2 )

#define GPF4_msk ( 3 << ( 4*2 ) )
#define GPF5_msk ( 3 << ( 5*2 ) )
#define GPF6_msk ( 3 << ( 6*2 ) )

#define GPF0_in ( 0 << 0*2 )
#define GPF2_in ( 0 << 2*2 )
#define GPG3_in ( 0 << 3*2 )
#define GPF0_msk ( 3 << ( 0*2 ) )
#define GPF2_msk ( 3 << ( 2*2 ) )
#define GPG3_msk ( 3 << ( 3*2 ) )
int
main(
void )
{
unsigned
long ysdat;
GPFCON
&= ~( GPF4_msk | GPF5_msk | GPF6_msk );
GPFCON
|= GPF4_out |GPF5_out | GPF5_out;

GPFCON
&= ~( GPF0_msk | GPF2_msk );
GPFCON
|= GPF0_in |GPF2_in;

GPGCON
&= ~( GPG3_msk );
GPGCON
|= GPG3_in;

while(1)
{
ysdat
= GPFDAT;

if( ysdat & ( 1 << 0 ) )
{
GPFDAT
|= ( 1 << 4 );
}
else
{
GPFDAT
&= ~( 1 << 4 );
}

if( ysdat & ( 1 << 2 ) )
{
GPFDAT
|= ( 1 << 5 );
}
else
{
GPFDAT
&= ~( 1 << 5 );
}

ysdat
= GPGDAT;

if( ysdat & ( 1 << 3 ) )
{
GPFDAT
|= ( 1 << 6 );
}
else
{
GPFDAT
&= ~( 1 << 6 );
}

}

return 0;
}

Makefile

CFLAGS := -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -ffreestanding  
led_on.bin:ctr.S main.c
arm
-linux-gcc $(CFLAGS) -c -o ctr.o ctr.S
arm
-linux-gcc $(CFLAGS) -c -o main.o main.c
arm
-linux-ld -Ttext 0x00000000 ctr.o main.o -o led_on.elf
arm
-linux-objcopy -O binary -S led_on.elf led_on.bin
arm
-linux-objdump -D -m arm led_on.elf>led_on.dis
clean:
rm
-f led_on.bin led_on.elf *.o led_on.dis

通过嵌入式GPIO接口及操作(一)及这篇两个程序的练习,能够掌握对GPIO的操作,这是操作硬件的基本技能。