C语言版——点亮LED灯,深入到栈

时间:2021-05-30 03:37:24

在上一篇进行了汇编语言的编写之后,我们采用C语言来编写程序,毕竟C语言才是我们使用最多的语言。

仅仅是点亮LED灯显然太过于简单,我们需要分析最后的反汇编,了解函数调用栈,深入C语言骨髓去分析代码,并且自己编写C语言的库函数版本,方便以后开发,同时也是对自己C语言封装能力的锻炼。

先贴韦老大的代码:

start.s:

.text
.global _start _start: /* 设置内存: sp 栈 */
ldr sp, = /* nand启动 */
// ldr sp, =0x40000000+4096 /* nor启动 */ /* 调用main */
bl main halt:
b halt

LED.c:

int main()
{
unsigned int *pGPFCON = (unsigned int *)0x56000050;
unsigned int *pGPFDAT = (unsigned int *)0x56000054;
/* 配置GPF4为输出引脚 */
*pGPFCON = 0x100; /* 设置GPF4输出0 */
*pGPFDAT = ; return ;
}

C语言操作,的传统IDE开发当中,我们只用从main函数开始写代码就行了,但是IDE隐藏了太多技术细节。

我们在arm嵌入式linux开发过程中,都需要自己来,这对初学者是不友好,但是对深入学习却是很有帮助的。

首先,第一点,nand flash启动,使用片内4k sram。

我们都知道,函数调用和局部变量的存储需要使用到一种叫做栈的数据结构。

这里说明,s3c2440,采用默认的栈生长方式,这也是我们最常见的方式,高地址往低地址生长。

要调用main函数,我们需要开辟栈,这里使用片内4k 内存作为栈。

看看反汇编:

led.elf:     file format elf32-littlearm

Disassembly of section .text:

 <_start>:
: e3a0da01 mov sp, # ; 0x1000
: eb000000 bl c <main> <halt>:
: eafffffe b <halt> 0000000c <main>:
c: e1a0c00d mov ip, sp
: e92dd800 stmdb sp!, {fp, ip, lr, pc}
: e24cb004 sub fp, ip, # ; 0x4
: e24dd008 sub sp, sp, # ; 0x8
1c: e3a03456 mov r3, # ; 0x56000000
: e2833050 add r3, r3, # ; 0x50
: e50b3010 str r3, [fp, #-]
: e3a03456 mov r3, # ; 0x56000000
2c: e2833054 add r3, r3, # ; 0x54
: e50b3014 str r3, [fp, #-]
: e51b2010 ldr r2, [fp, #-]
: e3a03c01 mov r3, # ; 0x100
3c: e5823000 str r3, [r2]
: e51b2014 ldr r2, [fp, #-]
: e3a03000 mov r3, # ; 0x0
: e5823000 str r3, [r2]
4c: e3a03000 mov r3, # ; 0x0
: e1a00003 mov r0, r3
: e24bd00c sub sp, fp, # ; 0xc
: e89da800 ldmia sp, {fp, sp, pc}
Disassembly of section .comment: <.comment>:
: cmpmi r3, # ; 0x0
: 4728203a undefined
: 2029554e eorcs r5, r9, lr, asr #
c: 2e342e33 mrccs , , r2, cr4, cr3, {}
: Address 0x10 is out of bounds.

说明:

<.comment>:在上面的反汇编当中,它不是汇编代码的一部分,是注解,给我们一些提示,便于我们阅读、理解的。在讲解这个汇编之前,我们需要先看一个arm寄存器的别名表。

C语言版——点亮LED灯,深入到栈

好,现在开始分析,其中最重要的也是新出现的两个指令:

stmdb,ldmia

详细介绍可以参见韦老大书籍P53,arm嵌入式系统开发P58。

简单说明,db表示事先递减方式,ia表示事后递增方式。

先对反汇编进行注解:

  led.elf:     file format elf32-littlearm

  Disassembly of section .text:

   <_start>:
: e3a0da01 mov sp, # ; 赋值4096给sp堆栈寄存器
: eb000000 bl c <main> ;跳转到main函数,同时保存main函数返回地址到lr寄存器,返回地址为下一条指令的地址,这里lr应为8 <halt>:
: eafffffe b <halt>;死循环 0000000c <main>:
c: e1a0c00d mov ip, sp;备份sp寄存器的值到ip,ip是r12寄存器的别名
  :    e92dd800     stmdb    sp!, {fp, ip, lr, pc}
; 这条指令需要重点讲解,首先,fp,ip,lr,pc分别对应寄存器:r11,r12,r14,r15
; stm指令多寄存器操作的时候,后面的寄存器从编号高的先开始存储,把后面几个寄存器的值写入sp所对应的内存块中,(注意和但寄存器操作区分开来)后缀db表示 先减后存储
; sp后面加了一个感叹号!,表示sp最后的值等于最后被修改的值,不加感叹号就算操作使sp更改过,sp也等于最初的值
; 首先操作r15,即pc,sp先减,sp=sp-4,此时sp=4092,pc等于当前指令地址加8,即此时pc=0x10+8=0x18,相当于把0x18写入sram地址4092
; 同理操作r14,即lr,sp=sp-4,lr=8,相当于把0x8写入4088地址
; r12,ip是等于4096的,上面的move指令,r11,fp的值此时未定
  :    e24cb004     sub    fp, ip, #    ; fp=ip-4=4092
: e24dd008 sub sp, sp, # ; sp=sp-8=4072
1c: e3a03456 mov r3, # ;#1442840576等于十六机制0x56000000,把这个数存放在r3中
: e2833050 add r3, r3, # ;r3=r3+80=0x56000050
: e50b3010 str r3, [fp, #-];fp-16=4076,把0x56000050放入内存4076中
: e3a03456 mov r3, # ; 0x56000000
2c: e2833054 add r3, r3, # ; r3=0x56000054
: e50b3014 str r3, [fp, #-];fp=fp-20=4072,把0x56000054放入内存4072中
: e51b2010 ldr r2, [fp, #-];r2=[fp-16=4076]=0x56000050
: e3a03c01 mov r3, #; r3==256=0x100
3c: e5823000 str r3, [r2];把0x100存入[0x56000050]
: e51b2014 ldr r2, [fp, #-];r2=[fp-20=4072]=0x56000054
: e3a03000 mov r3, # ; r3=0=0x0
: e5823000 str r3, [r2];把0x0存入0x56000054内存中
4c: e3a03000 mov r3, # ; r3=0x0
: e1a00003 mov r0, r3;r0=r3=0x0,这里编译器有点笨,可以直接r0给0的,这里对应return 0.
: e24bd00c sub sp, fp, # ; sp=fp-12=4080
  :    e89da800     ldmia    sp, {fp, sp, pc}
;恢复保存的现场,ldmia,事后增加,从sp所对应内存块中取出数据存放到后面的寄存器,高编号的寄存器放在高地址,低编号的寄存器
;放在低地址,此时sp=4080,从低地址往高地址开始恢复,这也符合ia后缀
;先恢复fp,此时4080地址存放的值,注意是值不是地址,等于4092,恰好就是等于fp,即一顿操作之后,fp还是等于原来的fp
;再恢复sp,sp=sp+4=4084,内存4084对应的值是4096,即一顿操作之后,sp又等于4096了;
;最后恢复pc,sp=sp+4=4088,内存4088对应的值是8,即一段操作之后,pc=8了,pc等于8意味着什么?意味着函数从main函数返回了,将去执行那个死循环halt

为了更好的理解函数入栈,让我们深入理解C语言底层汇编,画出内存示意图:

C语言版——点亮LED灯,深入到栈

你可能会说。0-4096不是4097了吗?这样问非常好,不放过任何有疑问的细节,但是,4096,可以是4096的开始,也可以是4095的结尾,这里表示的是4095的结尾,因为4096我们一来是要先减4的。上图的4096是没用使用到真正属于4096地址后扩4字节的,而是在刚好到达4096时,之前的内存。

到这里,终于完成了一大半,我们知道了函数入栈之后,似乎函数调用的参数传递,也要用到栈啊,那么我们继续挖掘汇编。这里又需要补充几点arm方面的知识。

C语言版——点亮LED灯,深入到栈

C语言版——点亮LED灯,深入到栈

C语言版——点亮LED灯,深入到栈

C语言版——点亮LED灯,深入到栈

现在编写汇编代码, 传递一个参数:

.text
.global _start _start: /* 设置内存: sp 栈 */
ldr sp, = /* nand启动 */
// ldr sp, =0x40000000+ /* nor启动 */ mov r0, #
bl led_on ldr r0, =
bl delay mov r0, #
bl led_on halt:
b halt

对应的c代码:

void delay(volatile int d)
{
while (d--);
} int led_on(int which)
{
unsigned int *pGPFCON = (unsigned int *)0x56000050;
unsigned int *pGPFDAT = (unsigned int *)0x56000054; if (which == )
{
/* 配置GPF4为输出引脚 */
*pGPFCON = 0x100;
}
else if (which == )
{
/* 配置GPF5为输出引脚 */
*pGPFCON = 0x400;
} /* 设置GPF4/5输出0 */
*pGPFDAT = ; return ;
}

上面汇编中,只对应一个参数,所以只用r0就可以达到函数参数传递的效果,汇编比较简单就不赘述了。

这个例子是为了让我们了解汇编通过寄存器传递函数参数,前提是必须先设置sp寄存器。

甚至不必编写main函数,当然不建议这样做,这样示例是为让你明白一点,main函数也是因为启动代码去调用了它,我们通过改写启动代码,可以没有main函数。

终于到了我们最熟悉的阶段了,编写C语言应用程序,一般来说,复杂的和可复用性更高的代码我们肯定是用C语言编写,全用汇编编写代码真是很慢而且麻烦,更不用说机器码编程了,但是了解它们对我们深入学习又十分有用,这或许就是arm对初学者不友好的原因吧,因为现在为止我们还没有大型项目需要编写复杂的Makefile,后面还有很多技能需要get,这也是在买了板子大半年了才真的开始上手的原因,需要花时间补习其他知识。

言归正传,如上面的C语言程序,虽然完成了要求,可是复用性太差,既然你觉得你C语言最熟悉,那么就请封装一个复用性高的代码出来看看吧。

我想使用复用性非常强的C代码,可以方便移植,快速开发,例如下面编写的mylib库函数:

#include "s3c2440_gpio.h"
int main(void)
{ Reset_gpio(OUT, GPIOF,GPIO_PinSource4);
Set_gpio(OUT, GPIOF,GPIO_PinSource5);
Reset_gpio(OUT, GPIOF,GPIO_PinSource6);
return ;
}

就是这样的代码,可以调用一个函数,达到指定IO输出高低电平或者设置模式。

s3c2440_gpio.c:

#include "s3c2440_gpio.h"

void Set_gpio(IOState new,GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_PinSource)
{
if(new==OUT)
{
//CON复位值为0,配置为输出
GPIO_InitStruct->CON |=<<GPIO_PinSource*;/*乘法优先级高于左移*/
//DAT复位值udf
GPIO_InitStruct->DAT |=(<<GPIO_PinSource);/*对应位清零,输出1*/
}
else if(new==IN)
{
//CON复位值为0,配置为输入
GPIO_InitStruct->CON &=(<<GPIO_PinSource*);/*乘法优先级高于左移*/
}
else
{
/*预留*/
}
} void Reset_gpio(IOState new,GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_PinSource)
{
if(new==OUT)
{
//CON复位值为0,配置为输出
GPIO_InitStruct->CON |=<<GPIO_PinSource*;/*乘法优先级高于左移*/
GPIO_InitStruct->DAT &=~(<<GPIO_PinSource);/*对应位清零,输出0,低电平*/
}
}

s3c2440_gpio.h:

#ifndef _S3C2440_GPIO_H_
#define _S3C2440_GPIO_H_
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
#define __IO volatile
typedef struct
{
__IO uint32_t CON;
__IO uint32_t DAT;
__IO uint32_t UP;
__IO uint32_t Reserved;
} GPIO_TypeDef; typedef enum
{
IN = ,
OUT = ,
EINT=
} IOState; #define GPIO_PinSource0 ((uint8_t)0x00)
#define GPIO_PinSource1 ((uint8_t)0x01)
#define GPIO_PinSource2 ((uint8_t)0x02)
#define GPIO_PinSource3 ((uint8_t)0x03)
#define GPIO_PinSource4 ((uint8_t)0x04)
#define GPIO_PinSource5 ((uint8_t)0x05)
#define GPIO_PinSource6 ((uint8_t)0x06)
#define GPIO_PinSource7 ((uint8_t)0x07) #define GPIOA_BASE (0x56000000)
#define GPIOB_BASE (0x56000010)
#define GPIOC_BASE (0x56000020)
#define GPIOD_BASE (0x56000030)
#define GPIOE_BASE (0x56000040)
#define GPIOF_BASE (0x56000050)
#define GPIOG_BASE (0x56000060)
#define GPIOH_BASE (0x56000070)
#define GPIOJ_BASE (0x560000d0) #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)
#define GPIOG ((GPIO_TypeDef *) GPIOG_BASE)
#define GPIOH ((GPIO_TypeDef *) GPIOH_BASE)
#define GPIOJ ((GPIO_TypeDef *) GPIOJ_BASE) void Set_gpio(IOState new,GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_PinSource);
void Reset_gpio(IOState new,GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_PinSource); #endif /*s3c2440_gpio.h*/

编写出这样的库函数需要有过库函数编程经验并且具备一定的C语言基础和思维。

再看看加了-g选项也就是调试信息的反汇编:

led.elf:     file format elf32-littlearm

Disassembly of section .text:

 <_start>:
.global _start _start: ldr sp,= //nandflash启动,设置栈
: e3a0da01 mov sp, # ; 0x1000
//调用main函数
bl main
: eb000000 bl c <main> <halt>: halt:
b halt
: eafffffe b <halt> 0000000c <main>:
#include "s3c2440_gpio.h"
int main(void)
{
c: e1a0c00d mov ip, sp
: e92dd800 stmdb sp!, {fp, ip, lr, pc}
: e24cb004 sub fp, ip, # ; 0x4 Reset_gpio(OUT, GPIOF,GPIO_PinSource4);
: e3a00001 mov r0, # ; 0x1
1c: e3a01456 mov r1, # ; 0x56000000
: e2811050 add r1, r1, # ; 0x50
: e3a02004 mov r2, # ; 0x4
: eb000042 bl <Reset_gpio>
Set_gpio(OUT, GPIOF,GPIO_PinSource5);
2c: e3a00001 mov r0, # ; 0x1
: e3a01456 mov r1, # ; 0x56000000
: e2811050 add r1, r1, # ; 0x50
: e3a02005 mov r2, # ; 0x5
3c: eb000007 bl <Set_gpio>
Reset_gpio(OUT, GPIOF,GPIO_PinSource6);
: e3a00001 mov r0, # ; 0x1
: e3a01456 mov r1, # ; 0x56000000
: e2811050 add r1, r1, # ; 0x50
4c: e3a02006 mov r2, # ; 0x6
: eb000038 bl <Reset_gpio>
return ;
: e3a03000 mov r3, # ; 0x0
}
: e1a00003 mov r0, r3
5c: e89da800 ldmia sp, {fp, sp, pc} <Set_gpio>:
#include "s3c2440_gpio.h" void Set_gpio(IOState new,GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_PinSource)
{
: e1a0c00d mov ip, sp
: e92dd800 stmdb sp!, {fp, ip, lr, pc}
: e24cb004 sub fp, ip, # ; 0x4
6c: e24dd00c sub sp, sp, # ; 0xc
: e50b0010 str r0, [fp, #-]
: e50b1014 str r1, [fp, #-]
: e1a03002 mov r3, r2
7c: e54b3016 strb r3, [fp, #-]
: e1a03443 mov r3, r3, asr #
: e54b3015 strb r3, [fp, #-]
if(new==OUT)
: e51b3010 ldr r3, [fp, #-]
8c: e3530001 cmp r3, # ; 0x1
: 1a000017 bne f4 <Set_gpio+0x94>
{
//CON复位值为0,配置为输出
GPIO_InitStruct->CON |=<<GPIO_PinSource*;/*乘法优先级高于左移*/
: e51b0014 ldr r0, [fp, #-]
: e51b1014 ldr r1, [fp, #-]
9c: e24b3016 sub r3, fp, # ; 0x16
a0: e5d32000 ldrb r2, [r3]
a4: e5d33001 ldrb r3, [r3, #]
a8: e1823403 orr r3, r2, r3, lsl #
ac: e1a02083 mov r2, r3, lsl #
b0: e3a03001 mov r3, # ; 0x1
b4: e1a02213 mov r2, r3, lsl r2
b8: e5913000 ldr r3, [r1]
bc: e1833002 orr r3, r3, r2
c0: e5803000 str r3, [r0]
//DAT复位值udf
GPIO_InitStruct->DAT |=(<<GPIO_PinSource);/*对应位清零,输出1*/
c4: e51b1014 ldr r1, [fp, #-]
c8: e51b0014 ldr r0, [fp, #-]
cc: e24b3016 sub r3, fp, # ; 0x16
d0: e5d32000 ldrb r2, [r3]
d4: e5d33001 ldrb r3, [r3, #]
d8: e1822403 orr r2, r2, r3, lsl #
dc: e3a03001 mov r3, # ; 0x1
e0: e1a02213 mov r2, r3, lsl r2
e4: e5903004 ldr r3, [r0, #]
e8: e1833002 orr r3, r3, r2
ec: e5813004 str r3, [r1, #]
f0: ea00000e b <Set_gpio+0xd0>
}
else if(new==IN)
f4: e51b3010 ldr r3, [fp, #-]
f8: e3530000 cmp r3, # ; 0x0
fc: 1a00000b bne <Set_gpio+0xd0>
{
//CON复位值为0,配置为输入
GPIO_InitStruct->CON &=(<<GPIO_PinSource*);/*乘法优先级高于左移*/
: e51b0014 ldr r0, [fp, #-]
: e51b1014 ldr r1, [fp, #-]
: e24b3016 sub r3, fp, # ; 0x16
10c: e5d32000 ldrb r2, [r3]
: e5d33001 ldrb r3, [r3, #]
: e1823403 orr r3, r2, r3, lsl #
: e1a02083 mov r2, r3, lsl #c: e3a03003 mov r3, # ; 0x3
: e1a02213 mov r2, r3, lsl r2
: e5913000 ldr r3, [r1]
: e0033002 and r3, r3, r2
12c: e5803000 str r3, [r0]
}
else
{
/*预留*/
}
}
: e24bd00c sub sp, fp, # ; 0xc
: e89da800 ldmia sp, {fp, sp, pc} <Reset_gpio>: void Reset_gpio(IOState new,GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_PinSource)
{
: e1a0c00d mov ip, sp
13c: e92dd800 stmdb sp!, {fp, ip, lr, pc}
: e24cb004 sub fp, ip, # ; 0x4
: e24dd00c sub sp, sp, # ; 0xc
: e50b0010 str r0, [fp, #-]
14c: e50b1014 str r1, [fp, #-]
: e1a03002 mov r3, r2
: e54b3016 strb r3, [fp, #-]
: e1a03443 mov r3, r3, asr #c: e54b3015 strb r3, [fp, #-]
if(new==OUT)
: e51b3010 ldr r3, [fp, #-]
: e3530001 cmp r3, # ; 0x1
: 1a000017 bne 1cc <Reset_gpio+0x94>
{
//CON复位值为0,配置为输出
GPIO_InitStruct->CON |=<<GPIO_PinSource*;/*乘法优先级高于左移*/
16c: e51b0014 ldr r0, [fp, #-]
: e51b1014 ldr r1, [fp, #-]
: e24b3016 sub r3, fp, # ; 0x16
: e5d32000 ldrb r2, [r3]
17c: e5d33001 ldrb r3, [r3, #]
: e1823403 orr r3, r2, r3, lsl #
: e1a02083 mov r2, r3, lsl #
: e3a03001 mov r3, # ; 0x1
18c: e1a02213 mov r2, r3, lsl r2
: e5913000 ldr r3, [r1]
: e1833002 orr r3, r3, r2
: e5803000 str r3, [r0]
GPIO_InitStruct->DAT &=~(<<GPIO_PinSource);/*对应位清零,输出0,低电平*/
19c: e51b0014 ldr r0, [fp, #-]
1a0: e51b1014 ldr r1, [fp, #-]
1a4: e24b3016 sub r3, fp, # ; 0x16
1a8: e5d32000 ldrb r2, [r3]
1ac: e5d33001 ldrb r3, [r3, #]
1b0: e1822403 orr r2, r2, r3, lsl #b4: e3a03001 mov r3, # ; 0x1
1b8: e1a03213 mov r3, r3, lsl r2
1bc: e1e02003 mvn r2, r3
1c0: e5913004 ldr r3, [r1, #]
1c4: e0033002 and r3, r3, r2
1c8: e5803004 str r3, [r0, #]
}
}
1cc: e24bd00c sub sp, fp, # ; 0xc
1d0: e89da800 ldmia sp, {fp, sp, pc}
Disassembly of section .comment: <.comment>:
: cmpmi r3, # ; 0x0
: 4728203a undefined
: 2029554e eorcs r5, r9, lr, asr #
c: 2e342e33 mrccs , , r2, cr4, cr3, {}
: smladxmi r0, r5, r0, r0
: 203a4343 eorcss r4, sl, r3, asr #
: 554e4728 strplb r4, [lr, #-]
1c: 2e332029 cdpcs , , cr2, cr3, cr9, {}
: 00352e34 eoreqs r2, r5, r4, lsr lr
Disassembly of section .debug_aranges: <.debug_aranges>:
: 0000001c andeq r0, r0, ip, lsl r0
: andeq r0, r0, r2
: andeq r0, r4, r0
...
: 0000000c andeq r0, r0, ip
...
: 0000001c andeq r0, r0, ip, lsl r0
: 003a0002 eoreqs r0, sl, r2
: andeq r0, r4, r0
2c: andeq r0, r0, r0
: 0000000c andeq r0, r0, ip
: andeq r0, r0, r4, asr r0
...
: 0000001c andeq r0, r0, ip, lsl r0
: 00c90002 sbceq r0, r9, r2
: andeq r0, r4, r0
4c: andeq r0, r0, r0
: andeq r0, r0, r0, rrx
: andeq r0, r0, r4, ror r1
...
Disassembly of section .debug_pubnames: <.debug_pubnames>:
: andeq r0, r0, r7, lsl r0
: 003a0002 eoreqs r0, sl, r2
: 008f0000 addeq r0, pc, r0
c: 006f0000 rsbeq r0, pc, r0
: 616d0000 cmnvs sp, r0
: 00006e69 andeq r6, r0, r9, ror #
: 2a000000 bcs <main+0x14>
1c: andeq r0, r0, # ; 0x0
: 0000c900 andeq ip, r0, r0, lsl #
: 0001c100 andeq ip, r1, r0, lsl #
: 00012e00 andeq r2, r1, r0, lsl #c: strvcbt r5, [r5], #-
: 6970675f ldmvsdb r0!, {r0, r1, r2, r3, r4, r6, r8, r9, sl, sp, lr}^
: 017b006f cmneq fp, pc, rrx
: ldrvsb r0, [r2]
3c: 5f746573 swipl 0x00746573
: 6f697067 swivs 0x00697067
: andeq r0, r0, r0
...
Disassembly of section .debug_info: <.debug_info>:
: andeq r0, r0, r6, lsr r0
: andeq r0, r0, r2
: tsteq r4, r0
...
: 0000000c andeq r0, r0, ip
: rsbvc r7, r1, # ; 0x73000000
1c: 00532e74 subeqs r2, r3, r4, ror lr
: 6d6f682f stcvsl , cr6, [pc, #-]!
: 68732f65 ldmvsda r3!, {r0, r2, r5, r6, r8, r9, sl, fp, sp}^
: rsbeq r7, r5, r1, ror #c: 20554e47 subcss r4, r5, r7, asr #
: eorcc r5, r0, # ; 0x4000001
: 0035312e eoreqs r3, r5, lr, lsr #
: 008b8001 addeq r8, fp, r1
3c: andeq r0, r2, r0
: andeq r0, r0, r4, lsl r0
: eoreqs r0, r6, r4, lsl #
: rsbeq r0, r0, r0
4c: 000c0000 andeq r0, ip, r0
: 4e470000 cdpmi , , cr0, cr7, cr0, {}
: subcs r2, r3, r5, asr r0
: 2e342e33 mrccs , , r2, cr4, cr3, {}
5c: 6d010035 stcvs , cr0, [r1, #-]
: 2e6e6961 cdpcs , , cr6, cr14, cr1, {}
: 682f0063 stmvsda pc!, {r0, r1, r5, r6}
: 2f656d6f swics 0x00656d6f
6c: rsbvc r6, r1, # ; 0x730000
: strvc r0, [r2, #-]
: 6769736e strvsb r7, [r9, -lr, ror #]!
: 2064656e rsbcs r6, r4, lr, ror #c: rsbvc r6, r1, # ; 0x630000
: andeq r0, r8, # ; 0x0
: 726f6873 rsbvc r6, pc, # ; 0x730000
: 6e752074 mrcvs , , r2, cr5, cr4, {}
8c: 6e676973 mcrvs , , r6, cr7, cr3, {}
: stmvsdb r0!, {r0, r2, r5, r6, sl, sp, lr}
: 0200746e andeq r7, r0, # ; 0x6e000000
: 6e750207 cdpvs , , cr0, cr5, cr7, {}
9c: 6e676973 mcrvs , , r6, cr7, cr3, {}
a0: stmvsdb r0!, {r0, r2, r5, r6, sl, sp, lr}
a4: 0400746e streq r7, [r0], #-
a8: 6d010307 stcvs , cr0, [r1, #-]
ac: 006e6961 rsbeq r6, lr, r1, ror #
b0: strhi r0, [r1, -r1, lsl #]
b4: 0c000000 stceq , cr0, [r0], {}
b8: andvs r0, r0, r0
bc: tsteq r0, r0
c0: 6e69025b mcrvs , , r0, cr9, cr11, {}
c4: streq r0, [r4, #-]
c8: 0001bd00 andeq fp, r1, r0, lsl #
cc: 4a000200 bmi 8d4 <Reset_gpio+0x79c>
d0: streq r0, [r0]
d4: 00006c01 andeq r6, r0, r1, lsl #
d8: 0001d400 andeq sp, r1, r0, lsl #
dc: andeq r6, r0, r0
e0: 554e4700 strplb r4, [lr, #-]
e4: teqcc r0, #- ; 0x80000000
e8: 352e342e strcc r3, [lr, #-]!
ec: cmncc r3, # ; 0x0
f0: ldrcct r3, [r4], #-
f4: 70675f30 rsbvc r5, r7, r0, lsr pc
f8: 632e6f69 teqvs lr, # ; 0x1a4
fc: 6f682f00 swivs 0x00682f00
: 732f656d teqvc pc, # ; 0x1b400000
: ldrvsb r6, [r2, #-]!
: 6e750200 cdpvs , , cr0, cr5, cr0, {}
10c: 6e676973 mcrvs , , r6, cr7, cr3, {}
: teqvs r0, # ; 0x65000000
: rsbeqs r6, r2, r8, ror #
: strvc r0, [r3, #-]
11c: 31746e69 cmncc r4, r9, ror #
: 00745f36 rsbeqs r5, r4, r6, lsr pc
: rsbeq r0, r1, r2, lsl #
: tstvc r2, # ; 0x0
12c: 74726f68 ldrvcbt r6, [r2], #-
: 736e7520 cmnvc lr, # ; 0x8000000
: 656e6769 strvsb r6, [lr, #-]!
: 6e692064 cdpvs , , cr2, cr9, cr4, {}
13c: smlsdxeq r2, r4, r0, r0
: 6e697503 cdpvs , , cr7, cr9, cr3, {}
: 5f323374 swipl 0x00323374
: streq r0, [r2, #-]
14c: andeq r0, r0, r7, lsl #
: 736e7502 cmnvc lr, # ; 0x800000
: 656e6769 strvsb r6, [lr, #-]!
: 6e692064 cdpvs , , cr2, cr9, cr4, {}
15c: smlsdxeq r4, r4, r0, r0
: 0000dc04 andeq sp, r0, r4, lsl #
: 0d021000 stceq , cr1, [r2]
: 4e4f4305 cdpmi , , cr4, cr15, cr5, {}
16c: dc090200 sfmle f0, , [r9], {}
: andeq r0, r0, # ; 0x0
: strmi r0, [r5], #-
: andeq r5, r0, # ; 0x41000000
17c: 0000e10a andeq lr, r0, sl, lsl #
: streqt r0, [r3], #-
: subeqs r5, r0, r5, lsl #
: 00e60b02 rsceq r0, r6, r2, lsl #c: tstcs r2, # ; 0x0
: ldrvsb r0, [r2, #-]
: undefined
: andeq r6, r0, # ; 0x65000000
19c: 0000eb0c andeq lr, r0, ip, lsl #a0: 0c230200 sfmeq f0, , [r3]
1a4: rsbeqs r0, r7, r0, lsl #a8: strvc r0, [r6, -r0]
1ac: streq r0, [r0], -r0
1b0: andeq r0, r0, r7, ror r0
1b4: andeq r7, r0, r6, lsl #b8: subpl r0, r7, r0, lsl #bc: 545f4f49 ldrplb r4, [pc], # ; 1c4 <Reset_gpio+0x8c>
1c0: strmibt r7, [r5], #-c4: andeq r6, r0, # ; 0x6500000
1c8: 0000970d andeq r9, r0, sp, lsl #cc: 011f0700 tsteq pc, r0, lsl #d0: andeq r0, r4, # ; 0x0
1d4: 4e490810 mcrmi , , r0, cr9, cr0, {}
1d8: 4f080000 swimi 0x00080000
1dc: tsteq r0, r5, asr r4
1e0: 4e494508 cdpmi , , cr4, cr9, cr8, {}
1e4: andeq r0, r2, r4, asr r0
1e8: 534f4903 cmppl pc, # ; 0xc000
1ec: ldrvsb r6, [r4, #-]!
1f0: ldreq r0, [r4], #-f4: stmeqdb r0, {r0}
1f8: andeq r0, r0, r5, ror r1
1fc: strvcbt r5, [r5], #-
: 6970675f ldmvsdb r0!, {r0, r1, r2, r3, r4, r6, r8, r9, sl, sp, lr}^
: 0401006f streq r0, [r1], #-
: andeq r6, r0, r1
20c: andeq r3, r1, r0, lsl #
: 0a5b0100 beq 16c0618 <__bss_end__+0x16b8444>
: 0077656e rsbeqs r6, r7, lr, ror #
: 011f0301 tsteq pc, r1, lsl #c: tstls r2, r0
: 000f0b70 andeq r0, pc, r0, ror fp
: tsteq r1, # ; 0x0
: andeq r0, r0, r5, ror r1
22c: 0b6c9102 bleq 1b2463c <__bss_end__+0x1b1c468>
: andeq r0, r0, r0
: subeqs r0, r1, r1, lsl #
: tstls r2, r0
23c: 040c006a streq r0, [ip], #-
: 000000f0 streqd r0, [r0], -r0
: 6552010d ldrvsb r0, [r2, #-]
: 5f746573 swipl 0x00746573
24c: 6f697067 swivs 0x00697067
: tsteq r8, r0, lsl #
: andeq r0, r0, r8, lsr r1
: 000001d4 ldreqd r0, [r0], -r4
25c: 6e0a5b01 fmacdvs d5, d10, d1
: tsteq r0, r5, ror #
: 00011f17 andeq r1, r1, r7, lsl pc
: addvcs r0, r1, r0, lsl #c: 00000f0b andeq r0, r0, fp, lsl #
: ldrvc r0, [r7, #-]
: andeq r0, r0, # ; 0x1
: 000b6c91 muleq fp, r1, ip
27c: tsteq r0, r0
: andeq r5, r0, r7, lsl r1
: 6a910200 bvs fe440a8c <__bss_end__+0xfe4388b8>
...
Disassembly of section .debug_abbrev: <.debug_abbrev>:
: andne r1, r0, r1, lsl #
: andne r1, r1, #- ; 0x80000001
: 1b080301 blne 200c14 <__bss_end__+0x1f8a40>
c: tstne r8, # ; 0x2000000
: andeq r0, r0, r5
: andne r1, r1, r1, lsl #
: tstne r1, r6, lsl #c: tstne r8, # ; 0x400000
: 1b08030b blne 200c54 <__bss_end__+0x1f8a80>
: andeq r0, r0, # ; 0x8
: stmeqda r3, {r2, r5}
2c: 0b3e0b0b bleq f82c60 <__bss_end__+0xf7aa8c>
: 2e030000 cdpcs , , cr0, cr3, cr0, {}
: 030c3f00 tsteq ip, # ; 0x0
: 3b0b3a08 blcc 2ce860 <__bss_end__+0x2c668c>
3c: 490c270b stmmidb ip, {r0, r1, r3, r8, r9, sl, sp}
: andne r1, r1, #- ; 0xc0000004
: 000a4001 andeq r4, sl, r1
: tstne r1, r0
4c: andne r1, r6, # ; 0x1
: strcs r1, [r1, #-]
: 030b1308 tsteq fp, # ; 0x20000000
: 00081b08 andeq r1, r8, r8, lsl #c: eoreq r0, r4, r0, lsl #
: 0b0b0803 bleq 2c2074 <__bss_end__+0x2b9ea0>
: 00000b3e andeq r0, r0, lr, lsr fp
: tsteq r0, # ; 0x300000
6c: 3b0b3a08 blcc 2ce894 <__bss_end__+0x2c66c0>
: 0013490b andeqs r4, r3, fp, lsl #
: tsteq r3, r0, lsl #
: 0b0b1301 bleq 2c4c84 <__bss_end__+0x2bcab0>
7c: 0b3b0b3a bleq ec2d6c <__bss_end__+0xebab98>
: 0d050000 stceq , cr0, [r5]
: 3a080300 bcc 200c8c <__bss_end__+0x1f8ab8>
: 490b3b0b stmmidb fp, {r0, r1, r3, r8, r9, fp, ip, sp}
8c: 000a3813 andeq r3, sl, r3, lsl r8
: eoreqs r0, r5, r0, lsl #
: andeq r1, r0, r9, asr #
: tsteq r1, r7, lsl #c: 3a0b0b13 bcc 2c2cf0 <__bss_end__+0x2bab1c>
a0: 000b3b0b andeq r3, fp, fp, lsl #
a4: eoreq r0, r8, r0, lsl #
a8: 0d1c0803 ldceq , cr0, [ip, #-]
ac: 2e090000 cdpcs , , cr0, cr9, cr0, {}
b0: 3f130101 swicc 0x00130101
b4: 3a08030c bcc 200cec <__bss_end__+0x1f8b18>
b8: 270b3b0b strcs r3, [fp, -fp, lsl #]
bc: 1201110c andne r1, r1, # ; 0x3
c0: 000a4001 andeq r4, sl, r1
c4: 00050a00 andeq r0, r5, r0, lsl #
c8: 0b3a0803 bleq e820dc <__bss_end__+0xe79f08>
cc: 13490b3b cmpne r9, # ; 0xec00
d0: 00000a02 andeq r0, r0, r2, lsl #
d4: 0300050b tsteq r0, # ; 0x2c00000
d8: 3b0b3a0e blcc 2ce918 <__bss_end__+0x2c6744>
dc: 0213490b andeqs r4, r3, # ; 0x2c000
e0: 0c00000a stceq , cr0, [r0], {}
e4: 0b0b000f bleq 2c0128 <__bss_end__+0x2b7f54>
e8: andeq r1, r0, r9, asr #
ec: 3f012e0d swicc 0x00012e0d
f0: 3a08030c bcc 200d28 <__bss_end__+0x1f8b54>
f4: 270b3b0b strcs r3, [fp, -fp, lsl #]
f8: 1201110c andne r1, r1, # ; 0x3
fc: 000a4001 andeq r4, sl, r1
...
Disassembly of section .debug_line: <.debug_line>:
: andeq r0, r0, r2, lsr r0
: 001b0002 andeqs r0, fp, r2
: tsteq r2, r0
c: 000a0efb streqd r0, [sl], -fp
: tsteq r1, r1, lsl #
: tsteq r0, r0
: cmnvs r4, r0, lsl #c: 532e7472 teqpl lr, # ; 0x72000000
: andeq r0, r0, r0
: andeq r0, r5, # ; 0x0
: andeq r0, r0, r0
2c: 2d010903 stccs , cr0, [r1, #-]
: 0002022e andeq r0, r2, lr, lsr #
: eoreqs r0, r2, r1, lsl #
: andeq r0, r2, r0
3c: 0000001a andeq r0, r0, sl, lsl r0
: 0efb0102 cdpeq , , cr0, cr11, cr2, {}
: 0101000a tsteq r1, sl
: andeq r0, r0, r1, lsl #c: 6d000100 stfvss f0, [r0]
: 2e6e6961 cdpcs , , cr6, cr14, cr1, {}
: andeq r0, r0, r3, rrx
: streq r0, [r0]
5c: 00000c02 andeq r0, r0, r2, lsl #
: 9c651100 stflse f1, [r5]
: 022c9c9c eoreq r9, ip, # ; 0x9c00
: tsteq r1, r4
6c: andeq r0, r0, r9, asr r0
: eoreqs r0, r4, r2
: tsteq r2, r0
: 000a0efb streqd r0, [sl], -fp
7c: tsteq r1, r1, lsl #
: tsteq r0, r0
: teqvs r3, # ; 0x0
: eorccs r3, r4, r2, lsr r4
8c: 6970675f ldmvsdb r0!, {r0, r1, r2, r3, r4, r6, r8, r9, sl, sp, lr}^
: 00632e6f rsbeq r2, r3, pc, ror #
: tstvc r0, # ; 0x0
: ldrcct r6, [r2], #-c: 675f3034 smmlarvs pc, r4, r0, r3
a0: 2e6f6970 mcrcs , , r6, cr15, cr0, {}
a4: andeq r0, r0, r8, rrx
a8: streq r0, [r0]
ac: andeq r6, r0, r2
b0: 3a081200 bcc 2048b8 <__bss_end__+0x1fc6e4>
b4: ldmeqda r3!, {r1, r2, r5, r6, fp}^
b8: smlsdxvc r8, r3, r6, r6
bc: 663a084a ldrvst r0, [sl], -sl, asr #
c0: tstvc r8, #- ; 0x80000000
c4: tsteq r0, r2, lsl #
c8: Address 0xc8 is out of bounds. Disassembly of section .debug_frame: <.debug_frame>:
: 0000000c andeq r0, r0, ip
: ffffffff swinv 0x00ffffff
: 7c010001 stcvc , cr0, [r1], {}
c: 000d0c0e andeq r0, sp, lr, lsl #
: 0000001c andeq r0, r0, ip, lsl r0
: andeq r0, r0, r0
: 0000000c andeq r0, r0, ip
1c: andeq r0, r0, r4, asr r0
: 440c0d44 strmi r0, [ip], #-
: 038d028e orreq r0, sp, #- ; 0xe0000008
: 0c44048b cfstrdeq mvd0, [r4], {}
2c: 0000040b andeq r0, r0, fp, lsl #
: 0000000c andeq r0, r0, ip
: ffffffff swinv 0x00ffffff
: 7c010001 stcvc , cr0, [r1], {}
3c: 000d0c0e andeq r0, sp, lr, lsl #
: 0000001c andeq r0, r0, ip, lsl r0
: andeq r0, r0, r0, lsr r0
: andeq r0, r0, r0, rrx
4c: 000000d8 ldreqd r0, [r0], -r8
: 440c0d44 strmi r0, [ip], #-
: 038d028e orreq r0, sp, #- ; 0xe0000008
: 0c44048b cfstrdeq mvd0, [r4], {}
5c: 0000040b andeq r0, r0, fp, lsl #
: 0000001c andeq r0, r0, ip, lsl r0
: andeq r0, r0, r0, lsr r0
: andeq r0, r0, r8, lsr r1
6c: 0000009c muleq r0, ip, r0
: 440c0d44 strmi r0, [ip], #-
: 038d028e orreq r0, sp, #- ; 0xe0000008
: 0c44048b cfstrdeq mvd0, [r4], {}
7c: 0000040b andeq r0, r0, fp, lsl #
Disassembly of section .debug_str: <.debug_str>:
: 4f495047 swimi 0x00495047
: 6e69505f mcrvs , , r5, cr9, cr15, {}
: 72756f53 rsbvcs r6, r5, # ; 0x14c
c: strmi r6, [r0, -r3, ror #]
: 5f4f4950 swipl 0x004f4950
: 74696e49 strvcbt r6, [r9], #-
: ldrvcb r7, [r2, #-]!
1c: Address 0x1c is out of bounds.

Makefile如下:

all:
arm-linux-gcc -c -g -o s3c2440_gpio.o s3c2440_gpio.c
arm-linux-gcc -c -g -o main.o main.c
arm-linux-gcc -c -g -o start.o start.S
arm-linux-ld -Ttext start.o main.o s3c2440_gpio.o -o led.elf
arm-linux-objcopy -O binary -S led.elf led.bin
arm-linux-objdump -S -D led.elf > led.dis
clean:
rm *.bin *.o *.elf *.dis

这个程序烧录进单板是可以点亮4和6的,但是这还存在一个潜在问题,看cpu手册:

C语言版——点亮LED灯,深入到栈

看门狗默认是打开的,所以程序运行一段时间会复位,但是上面没有加入LED闪烁,所以看不出来,现在更改启动文件的汇编,把看门狗关闭:

C语言版——点亮LED灯,深入到栈

上面的库函数还需要根据寄存器不断配置优化,我只是做出一个模子,这样给大家一个参考,就是通过一个通用的函数,给不同的引脚就让处理器做不同的事。

现在给出最终版(当然,库函数需要根据学习得深入不断优化):

包括关闭看门狗,自己写的输入输出设置库函数以及读取输入引脚库函数,这是根据以前STM32库函数开发经验,自己写库应用在s3c2440上。

启动汇编如上图所示,这里贴出c代码:

头文件:

#ifndef _S3C2440_GPIO_H_
#define _S3C2440_GPIO_H_
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
#define __IO volatile
typedef struct
{
__IO uint32_t CON;
__IO uint32_t DAT;
__IO uint32_t UP;
__IO uint32_t Reserved;
} GPIO_TypeDef; typedef enum
{
IN = ,
OUT = ,
EINT=
} IOState; typedef enum
{
Bit_RESET = ,
Bit_SET
}BitAction; #define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */
#define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */
#define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */
#define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */
#define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */
#define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */
#define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */
#define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */
#define GPIO_Pin_8 ((uint16_t)0x0100) /*!< Pin 8 selected */
#define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */
#define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */
#define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */
#define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */
#define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */
#define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */
#define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */
#define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */ #define GPIO_PinSource0 ((uint8_t)0x00)
#define GPIO_PinSource1 ((uint8_t)0x01)
#define GPIO_PinSource2 ((uint8_t)0x02)
#define GPIO_PinSource3 ((uint8_t)0x03)
#define GPIO_PinSource4 ((uint8_t)0x04)
#define GPIO_PinSource5 ((uint8_t)0x05)
#define GPIO_PinSource6 ((uint8_t)0x06)
#define GPIO_PinSource7 ((uint8_t)0x07) #define GPIOA_BASE (0x56000000)
#define GPIOB_BASE (0x56000010)
#define GPIOC_BASE (0x56000020)
#define GPIOD_BASE (0x56000030)
#define GPIOE_BASE (0x56000040)
#define GPIOF_BASE (0x56000050)
#define GPIOG_BASE (0x56000060)
#define GPIOH_BASE (0x56000070)
#define GPIOJ_BASE (0x560000d0) #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)
#define GPIOG ((GPIO_TypeDef *) GPIOG_BASE)
#define GPIOH ((GPIO_TypeDef *) GPIOH_BASE)
#define GPIOJ ((GPIO_TypeDef *) GPIOJ_BASE) void Set_gpio(IOState new,GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_PinSource);
void Reset_gpio(IOState new,GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_PinSource);
uint8_t ReadInput_gpio(GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_Pin);
#endif /*s3c2440_gpio.h*/

这里要分清楚GPIO是Pin还是PinSource。

源文件(增加读取输入电平):

#include "s3c2440_gpio.h"

/*设置输入输出属性,默认输出高电平
*new:out,in分别代表输出,输入
*GPIO_InitStruct:GPIO A-J
*GPIO_PinSource:0-7
*以上参数的宏定义可根据手册完善
*/
void Set_gpio(IOState new,GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_PinSource)
{
if(new==OUT)
{
//CON复位值为0,配置为输出
GPIO_InitStruct->CON |=<<GPIO_PinSource*;/*乘法优先级高于左移*/
//DAT复位值udf
GPIO_InitStruct->DAT |=(<<GPIO_PinSource);/*对应位清零,输出1*/
}
else if(new==IN)
{
//CON复位值为0,配置为输入
GPIO_InitStruct->CON &=(<<GPIO_PinSource*);/*乘法优先级高于左移*/
}
else
{
/*预留*/
}
} /*
*设置输出引脚输出低电平
*/
void Reset_gpio(IOState new,GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_PinSource)
{
if(new==OUT)
{
//CON复位值为0,配置为输出
GPIO_InitStruct->CON |=<<GPIO_PinSource*;/*乘法优先级高于左移*/
GPIO_InitStruct->DAT &=~(<<GPIO_PinSource);/*对应位清零,输出0,低电平*/
}
} /*
*读取输入引脚的电平,返回值为0或者1,0代表低电平,1代表高电平
*该函数本可以增加一个参数完成输入输出的读取,但是考虑到STM32也是分开的,故这里也分开实现
*输出引脚的电平读取库函数暂时没写,因为目前只用到输入引脚读取,后面需要时就完善,其原理是一样的,
*/
uint8_t ReadInput_gpio(GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_Pin)
{
uint8_t bitstatus = 0x00; if((GPIO_InitStruct->DAT & GPIO_Pin )!=(uint32_t)Bit_RESET)
{
bitstatus=(uint8_t)Bit_SET;
}
else
{
bitstatus = (uint8_t)Bit_RESET;
}
return bitstatus; }

main函数:

#include "s3c2440_gpio.h"

void Delay(uint32_t count)
{
while(count--);
}
int main(void)
{
//配置GPIOF 0,2,GPIOG 3为输入模式
Set_gpio(IN, GPIOF,GPIO_PinSource0);
Set_gpio(IN, GPIOF,GPIO_PinSource2);
Set_gpio(IN, GPIOG,GPIO_PinSource3);
//点亮LED1然后熄灭
Reset_gpio(OUT, GPIOF,GPIO_PinSource4);
Delay();
Set_gpio(OUT, GPIOF,GPIO_PinSource4);
Delay();
//点亮LED2然后熄灭
Reset_gpio(OUT, GPIOF,GPIO_PinSource5);
Delay();
Set_gpio(OUT, GPIOF,GPIO_PinSource5);
Delay();
//点亮LED3然后熄灭
Reset_gpio(OUT, GPIOF,GPIO_PinSource6);
Delay();
Set_gpio(OUT, GPIOF,GPIO_PinSource6);
Delay();
//熄灭三盏LED灯
Set_gpio(OUT, GPIOF,GPIO_PinSource5);
Set_gpio(OUT, GPIOF,GPIO_PinSource4); while ()
{
//如果按键3按下,则为低电平,就点亮LED3
if(ReadInput_gpio(GPIOF,GPIO_Pin_0))
{
Set_gpio(OUT, GPIOF,GPIO_PinSource6);
}
else
{
Reset_gpio(OUT, GPIOF,GPIO_PinSource6);
}
//如果按键2按下,则为低电平,就点亮LED2
if(ReadInput_gpio(GPIOF,GPIO_Pin_2))
{
Set_gpio(OUT, GPIOF,GPIO_PinSource5);
}
else
{
Reset_gpio(OUT, GPIOF,GPIO_PinSource5);
}
//如果按键1按下,则为低电平,就点亮LED1
if(ReadInput_gpio(GPIOG,GPIO_Pin_3))
{
Set_gpio(OUT, GPIOF,GPIO_PinSource4);
}
else
{
Reset_gpio(OUT, GPIOF,GPIO_PinSource4);
} }
return ;
}

原理图:

C语言版——点亮LED灯,深入到栈

外部电源上拉:

C语言版——点亮LED灯,深入到栈

EINT0->对应引脚GPF0

EINT2->对应引脚GPF2

EINT11->对应引脚GPG3

即,默认高电平,按键按下就低电平。

Makefile和之前一样,ok,这样是不是觉得方便多了?当然,这是建立在你熟练运用C语言的基础上的,不然是写不出库函数的。