在上一篇进行了汇编语言的编写之后,我们采用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寄存器的别名表。

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

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语言底层汇编,画出内存示意图:

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

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

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

.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手册:

看门狗默认是打开的,所以程序运行一段时间会复位,但是上面没有加入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 ;
}

原理图:

外部电源上拉:

EINT0->对应引脚GPF0

EINT2->对应引脚GPF2

EINT11->对应引脚GPG3

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

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

C语言版——点亮LED灯,深入到栈的更多相关文章

  1. 第7章 使用寄存器点亮LED灯

    第7章     使用寄存器点亮LED灯 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  2. 第7章 使用寄存器点亮LED灯—零死角玩转STM32-F429系列

    第7章     使用寄存器点亮LED灯 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  3. STM32F4 阿波罗寄存器点亮LED灯

    学习步骤: 使用寄存器点亮LED灯,需要进行如下的步骤,LED灯属于外设部分,首先需要开启外设的时钟使能,然后LED灯是PB1口,(芯片是正点原子的阿波罗),接着定义GPIOB口的输出模式,为上拉.推 ...

  4. 第二章之S5PV210在BL1中点亮LED灯

    1,u-boot中第一个入口在./arch/arm/cpu/armv7/start.S 翻到153行:如下图 前面都是进行一些基本设置,不用管. cpu_init_cp15设置协处理器, cpu_in ...

  5. 字符型设备驱动程序-first-printf以及点亮LED灯(三)

    根据  字符型设备驱动程序-first-printf以及点亮LED灯(二) 学习 修改函数 中的printf 为 printk. #include <linux/module.h> /* ...

  6. JZ2440开发板:用按键点亮LED灯(学习笔记)

    本文是对韦东山嵌入式第一期学习的记录之一,如有您需要查找的信息,可以继续往下阅读. 想要用按键点亮LED灯,就需要知道按键和LED灯的相关信息,这样才可以进行之后的操作.阅读JZ2440的原理图,可以 ...

  7. 30个物联网传感器小实验:三行代码点亮LED灯

    30个物联网传感器小实验:三行代码点亮LED灯 三行代码点亮LED灯 LED灯闪烁 LED灯调亮度 LED淡入淡出 不写一行代码点亮LED灯 全彩RGB灯 面包板 30个物联网传感器小实验:三行代码点 ...

  8. Raspberry PI 系列 —— 裸机点亮LED灯

    Raspberry PI 系列 -- 裸机点亮LED灯 背景 近期刚买了Raspberry PI B+,配置执行了官方提供的Raspbian系统,折腾了一周Linux系统,感觉没啥意思,于是就试着想了 ...

  9. 树莓派点亮LED灯需要几行代码?3行。小孩子都能学会

    目录 点亮LED灯 硬件连接 代码 闪烁的LED灯 呼吸灯 其他 点亮LED灯 硬件连接 找一个LED灯,连接如上图,注意长短引脚,经过这些年的狂轰乱炸,大家对于这个应该不漠视,毕竟Arduino都进 ...

随机推荐

  1. dubbo 学习(5) dubbo多协议和多注册中心

    转载 http://blog.csdn.net/songjinbin/article/details/49498431 一.配置dubbo多协议模式 1.默认协议 Dubbo缺省协议采用单一长连接和N ...

  2. ML之监督学习算法之分类算法一 ——— 决策树算法

    一.概述 决策树(decision tree)的一个重要任务是为了数据中所蕴含的知识信息,因此决策树可以使用不熟悉的数据集合,并从中提取出一系列规则,在这些机器根据数据创建规则时,就是机器学习的过程. ...

  3. c#代码 天气接口 一分钟搞懂你的博客为什么没人看 看完python这段爬虫代码,java流泪了c#沉默了 图片二进制转换与存入数据库相关 C#7.0--引用返回值和引用局部变量 JS直接调用C#后台方法(ajax调用) Linq To Json SqlServer 递归查询

    天气预报的程序.程序并不难. 看到这个需求第一个想法就是只要找到合适天气预报接口一切都是小意思,说干就干,立马跟学生沟通价格. ​ ​不过谈报价的过程中,差点没让我一口老血喷键盘上,话说我们程序猿的人 ...

  4. Oracle 12C -- top-n查询新特性

    Oracle 12C -- top-n查询新特性在12C中,增加了一些新的特性.可以指定返回结果集的指定数量的行.或按照百分比返回行. SQL> select count(*) from emp ...

  5. 【转】AlphaGo与人工智能

    AlphaGo与人工智能 在之前的一篇文章中我指出,自动驾驶所需要的“视觉识别能力”和“常识判断能力”,对于机器来说是非常困难的问题.至今没有任何机器可以在视觉方面达到驴的水平,更不要说和人比.可是最 ...

  6. elasticsearch 小试牛刀

  7. 并发测试 JavaDemo

    https://github.com/oldratlee/fucking-java-concurrency /** * @author Jerry Lee */ public class Testee ...

  8. C#基础课程之三循环语句

    for循环: ; i < ; i++) { Console.WriteLine("执行"+i+"次"); } while循环: while (true) ...

  9. IOS App 后台运行

    使用block的另一个用处是可以让程序在后台较长久的运行.在以前,当app被按home键退出后,app仅有最多5秒钟的时候做一些保存或清理资源的工作.但是应用可以调用UIApplication的beg ...

  10. Modelsim se仿真Xilinx IPcore

    Modelsim se仿真Xilinx IPcore 方法:先写好do文件常规框架,根据modelsim报错再添加ise IP核库仿真文件.注:记得添加并仿真glbl.v全局控制仿真文件到sim/is ...