GPIO操作之C语言篇 分类: 嵌入式开发学习 2014-06-29 09:26 248人阅读 评论(0) 收藏

1:主要内容

   在嵌入式开发中,一般使用汇编语言做一些芯片初始化工作,当对程序效率要求很高时,也有时会使用汇编语言,但汇编语言相对较难阅读和理解。因此,我们希望我们以后的实验在初始化完芯片相关功能后使用C语言进行编程,方便大家阅读及理解。这一篇的内容主要是讲解使用C语言来控制LED灯闪烁。

2:相关要点

1,在通用PC机上写程序都有一个叫做main的函数,是程序的总入口。在嵌入式开发时,怎么从汇编语言跳转到C语言?在跳转之前需要设置哪些东西?

2:,在ARM体系中,汇编和C语言之间相互调用时参数如何传递?

关于上面的两个疑问,我不在这里详细分析。我给出参考资料,大家自行参考,思索。

针对问题1: ucos在s3c2410上运行过程整体剖析之基础知识-c语言和堆栈

针对问题2:参见资料 ATPCS.pdf

3:实验源码

initsystem.s
@******************************************************************************
@ 文件名  :initsystem.s
@ 功    能:初始化系统并copy代码
@ 
@ 作者    :张连聘
@ 创建时间:2014-06-22
@******************************************************************************

.text
.global _start

			
			@声明常量
			.equ   DATA_DST,0x40000000  @目的地址
			.equ   DATA_SRC,0x80000000  @源地址
	
@引入外部标号
			.extern  main
			.extern	 start_copy_addr
			
_start:

 
				
					LDR PC,  ResetAddr
		 
ResetAddr: .word  ResetInit

ResetInit:

					LDR R0,=DATA_DST  			@RO 指向目的地址
					LDR R1,=start_copy_addr 	        @R1 指向源地址
					MOV R10,#128     			@复制的个数为128*8*4=4K
CopyLoop:   		<span style="white-space:pre">		</span>LDMIA R1!,{R2-R9}			@从R1指定的内存地址处装载数据到R2--R9中
					STMIA R0!,{R2-R9}			@把R2--R9的数据复制到R0指定的内存中
					SUBS  R10,R10,#1
					BNE   CopyLoop
					LDR   SP,=0X40000000+1024*64            @设置堆栈指针,LPC2220内部有64KRAM,设置SP指针指向最高地址
					
					LDR PC,=main                            @调用C语言的main函数
HaltLoop:
					B HaltLoop
.end

main.c
/******************************************************************************
* 文件名  :main.c
* 功    能:利用P2.28控制led灯闪烁
* 
* 作者    :张连聘
* 创建时间:2014-06-25
*******************************************************************************/

//定义一些控制寄存器地址

#define IO2DIR   (*(volatile unsigned long *)0xE0028028)  //IO2输入、输出配置寄存器
#define IO2SET   (*(volatile unsigned long *)0xE0028024)  //IO2输出1控制寄存器
#define IO2CLR   (*(volatile unsigned long *)0xE002802C)  //IO2输出0控制寄存器

#define LEDCON   (1<<28)                                  

void Delay(int ms);
void main(void)
{
	
	IO2DIR = LEDCON;    //配置P2.28为输出口
	while (1)
	{
		IO2SET = LEDCON; //点亮LED灯
		Delay(6666);
		IO2CLR = LEDCON; //熄灭LED灯
		Delay(6666);	
	}
}
/******************************************************************************
* 名    称:Delay
* 功    能:软件延时
* 入口参数:ms 
* 出口参数:无
******************************************************************************/
void Delay(int ms)
{
	int i,j;
	for(i=0;i<10;i++)
		for(j=0;j<ms;j++)
		;
}




	

led_control.lds
/*
* led_control 的链接脚本。
*
*
*/

 MEMORY
{
   rom (rx)  : ORIGIN = 0x80000000, LENGTH = 2M
   ram (!rx) : ORIGIN = 0x40000000, LENGTH = 2M
}
ENTRY(_start)
SECTIONS
{

	. = 0x80000000 ;
	.init : 
	{	
		initsystem.o(.text)
		start_copy_addr = . ;
	} >rom
	. = 0x40000000 ;
	.main :
	AT (ADDR(.init)+SIZEOF(.init))
	{	
		main.o(.text)
	} >ram


	
	
}

makefile
control_led.bin:main.c initsystem.s
	arm-linux-gcc -g -c -o main.o main.c
	arm-linux-gcc -g -c -o initsystem.o initsystem.s
	arm-linux-ld -Tled_control.lds -nostdlib -g  main.o initsystem.o -o control_led_elf
	arm-linux-objcopy -O binary -S control_led_elf  control_led.bin
clean:
	rm -f control_led.bin control_led_elf *.o


4:源码重点分析

我们在main.c里定义了一个main函数,那我们在汇编代码里怎么引用呐?
.extern  main        声明在另一个文件中定义了main函数。然后LDR PC,=main  跳转到main函数。这里说明一下,之所以不能使用BL指令跳转,是因为启动代码执行的地址在0X80000000 ,而启动代码将main函数代码copy到0X40000000。Bl的跳转范围没有这么大。还有,这个main函数完全可以更改为其他函数,只是一个普通的函数名称。
LDR   SP,=0X40000000+1024*64       使用这条指令,是设置SP堆栈指针的位置。这里讲堆栈指针设置在了LPC2220这款芯片的内部RAM的最顶端。默认的ARM处理器是递减堆栈。

5:总结

由上面的实验可见,PC机编程时的main函数只是一个普通的函数名称,只不过他们底层设置好了,调用main函数,所以我们一般说普通PC机程序总入口是main函数。其实,在main函数之前已经做了很多工作。

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted on 2014-06-29 09:26  张连聘  阅读(201)  评论(0编辑  收藏  举报

导航