在上一篇进行了汇编语言的编写后,这一节采用C语言来编写,毕竟C语言才是我们使用最多的语言。
本节要点:
1)用C语言方式点亮LED灯;
2)分析反汇编代码;了解函数调用栈,深入的分析代码;
3)编写C语言的库函数版本,方便以后开发;
首先贴出一段代码:
start.s
.text .global _start _start: /* 设置内存: sp 栈 */ ldr sp, =4096 /* 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 = 0; return 0; }
在传统的IDE开发当中,我们只用从main函数开始写代码就行了,但是IDE隐藏了太多技术细节。
我们在arm嵌入式linux开发过程中,都需要自己来,这对初学者是不友好,但是对深入学习却很有帮助。
首先,nand flash启动,使用片内4K sram。
我们都知道,函数调用和局部变量的存储需要使用到一种叫做栈的数据结构。
说明:s3c2440,采用默认的栈生长方式,这也是我们最常见的方式,高地址往低地址生长。
要调用main函数,我们需要开辟栈,这里使用片内4K内存作为栈。
看一下反汇编:
led.elf: file format elf32-littlearm Disassembly of section .text: <_start>: 0: e3a0da01 mov sp, #4096 ; 0x1000 4: eb000000 bl c <main> <halt>: 8: eafffffe b 8 <halt> 0000000c <main>: c: e1a0c00d mov ip, sp 10: e92dd800 stmdb sp!, {fp, ip, lr, pc} 14: e24cb004 sub fp, ip, #4 ; 0x4 18: e24dd008 sub sp, sp, #8 ; 0x8 1c: e3a03456 mov r3, #1442840576 ; 0x56000000 20: e2833050 add r3, r3, #80 ; 0x50 24: e50b3010 str r3, [fp, #-16] 28: e3a03456 mov r3, #1442840576 ; 0x56000000 2c: e2833054 add r3, r3, #84 ; 0x54 30: e50b3014 str r3, [fp, #-20] 34: e51b2010 ldr r2, [fp, #-16] 38: e3a03c01 mov r3, #256 ; 0x100 3c: e5823000 str r3, [r2] 40: e51b2014 ldr r2, [fp, #-20] 44: e3a03000 mov r3, #0 ; 0x0 48: e5823000 str r3, [r2] 4c: e3a03000 mov r3, #0 ; 0x0 50: e1a00003 mov r0, r3 54: e24bd00c sub sp, fp, #12 ; 0xc 58: e89da800 ldmia sp, {fp, sp, pc} Disassembly of section .comment: <.comment>: 0: 43434700 cmpmi r3, #0 ; 0x0 4: 4728203a undefined 8: 2029554e eorcs r5, r9, lr, asr #10 c: 2e342e33 mrccs 14, 1, r2, cr4, cr3, {1} 10: Address 0x10 is out of bounds.
说明:
<.comment>:在上面的反汇编当中,它不是汇编代码的一部分,是注解,给我们一些提示,便于我们阅读、理解的。在讲解这个汇编之前,我们需要先看一个arm寄存器的别名表。
现在开始分析,其中最重要的也是新出现的两个指令:
stmdb,ldmia
简单说明,db表示事先递减方式,ia表示事后递增方式。
详细介绍可以参见 arm嵌入式系统开发P58。
先对反汇编进行注解:
led.elf: file format elf32-littlearm Disassembly of section .text: <_start>: 0: e3a0da01 mov sp, #4096 ; 赋值4096给sp堆栈寄存器 4: eb000000 bl c <main> ;跳转到main函数,同时保存main函数返回地址到lr寄存器,返回地址为下一条指令的地址,这里lr应为8 <halt>: 8: eafffffe b 8 <halt>;死循环 0000000c <main>: c: e1a0c00d mov ip, sp;备份sp寄存器的值到ip,ip是r12寄存器的别名
10: 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的值此时未定
14: e24cb004 sub fp, ip, #4 ; fp=ip-4=4092 18: e24dd008 sub sp, sp, #8 ; sp=sp-8=4072 1c: e3a03456 mov r3, #1442840576 ;#1442840576等于十六机制0x56000000,把这个数存放在r3中 20: e2833050 add r3, r3, #80 ;r3=r3+80=0x56000050 24: e50b3010 str r3, [fp, #-16];fp-16=4076,把0x56000050放入内存4076中 28: e3a03456 mov r3, #1442840576 ; 0x56000000 2c: e2833054 add r3, r3, #84 ; r3=0x56000054 30: e50b3014 str r3, [fp, #-20];fp=fp-20=4072,把0x56000054放入内存4072中 34: e51b2010 ldr r2, [fp, #-16];r2=[fp-16=4076]=0x56000050 38: e3a03c01 mov r3, #256; r3==256=0x100 3c: e5823000 str r3, [r2];把0x100存入[0x56000050] 40: e51b2014 ldr r2, [fp, #-20];r2=[fp-20=4072]=0x56000054 44: e3a03000 mov r3, #0 ; r3=0=0x0 48: e5823000 str r3, [r2];把0x0存入0x56000054内存中 4c: e3a03000 mov r3, #0 ; r3=0x0 50: e1a00003 mov r0, r3;r0=r3=0x0,这里编译器有点笨,可以直接r0给0的,这里对应return 0. 54: e24bd00c sub sp, fp, #12 ; sp=fp-12=4080
58: 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, =4096 /* nand启动 */ // ldr sp, =0x40000000+4096 /* nor启动 */ mov r0, #4 bl led_on ldr r0, =100000 bl delay mov r0, #5 bl led_on halt: b halt
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 == 4) { /* 配置GPF4为输出引脚 */ *pGPFCON = 0x100; } else if (which == 5) { /* 配置GPF5为输出引脚 */ *pGPFCON = 0x400; } /* 设置GPF4/5输出0 */ *pGPFDAT = 0; return 0; }
上面汇编中,只对应一个参数,所以只用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 0; }
就是这样的代码,可以调用一个函数,达到指定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 |=1<<GPIO_PinSource*2;/*乘法优先级高于左移*/ //DAT复位值udf GPIO_InitStruct->DAT |=(1<<GPIO_PinSource);/*对应位清零,输出1*/ } else if(new==IN) { //CON复位值为0,配置为输入 GPIO_InitStruct->CON &=(3<<GPIO_PinSource*2);/*乘法优先级高于左移*/ } else { /*预留*/ } } void Reset_gpio(IOState new,GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_PinSource) { if(new==OUT) { //CON复位值为0,配置为输出 GPIO_InitStruct->CON |=1<<GPIO_PinSource*2;/*乘法优先级高于左移*/ GPIO_InitStruct->DAT &=~(1<<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 = 0, OUT = 1, EINT=2 } 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,=4096 //nandflash启动,设置栈 0: e3a0da01 mov sp, #4096 ; 0x1000 //调用main函数 bl main 4: eb000000 bl c <main> <halt>: halt: b halt 8: eafffffe b 8 <halt> 0000000c <main>: #include "s3c2440_gpio.h" int main(void) { c: e1a0c00d mov ip, sp 10: e92dd800 stmdb sp!, {fp, ip, lr, pc} 14: e24cb004 sub fp, ip, #4 ; 0x4 Reset_gpio(OUT, GPIOF,GPIO_PinSource4); 18: e3a00001 mov r0, #1 ; 0x1 1c: e3a01456 mov r1, #1442840576 ; 0x56000000 20: e2811050 add r1, r1, #80 ; 0x50 24: e3a02004 mov r2, #4 ; 0x4 28: eb000042 bl 138 <Reset_gpio> Set_gpio(OUT, GPIOF,GPIO_PinSource5); 2c: e3a00001 mov r0, #1 ; 0x1 30: e3a01456 mov r1, #1442840576 ; 0x56000000 34: e2811050 add r1, r1, #80 ; 0x50 38: e3a02005 mov r2, #5 ; 0x5 3c: eb000007 bl 60 <Set_gpio> Reset_gpio(OUT, GPIOF,GPIO_PinSource6); 40: e3a00001 mov r0, #1 ; 0x1 44: e3a01456 mov r1, #1442840576 ; 0x56000000 48: e2811050 add r1, r1, #80 ; 0x50 4c: e3a02006 mov r2, #6 ; 0x6 50: eb000038 bl 138 <Reset_gpio> return 0; 54: e3a03000 mov r3, #0 ; 0x0 } 58: 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) { 60: e1a0c00d mov ip, sp 64: e92dd800 stmdb sp!, {fp, ip, lr, pc} 68: e24cb004 sub fp, ip, #4 ; 0x4 6c: e24dd00c sub sp, sp, #12 ; 0xc 70: e50b0010 str r0, [fp, #-16] 74: e50b1014 str r1, [fp, #-20] 78: e1a03002 mov r3, r2 7c: e54b3016 strb r3, [fp, #-22] 80: e1a03443 mov r3, r3, asr #8 84: e54b3015 strb r3, [fp, #-21] if(new==OUT) 88: e51b3010 ldr r3, [fp, #-16] 8c: e3530001 cmp r3, #1 ; 0x1 90: 1a000017 bne f4 <Set_gpio+0x94> { //CON复位值为0,配置为输出 GPIO_InitStruct->CON |=1<<GPIO_PinSource*2;/*乘法优先级高于左移*/ 94: e51b0014 ldr r0, [fp, #-20] 98: e51b1014 ldr r1, [fp, #-20] 9c: e24b3016 sub r3, fp, #22 ; 0x16 a0: e5d32000 ldrb r2, [r3] a4: e5d33001 ldrb r3, [r3, #1] a8: e1823403 orr r3, r2, r3, lsl #8 ac: e1a02083 mov r2, r3, lsl #1 b0: e3a03001 mov r3, #1 ; 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 |=(1<<GPIO_PinSource);/*对应位清零,输出1*/ c4: e51b1014 ldr r1, [fp, #-20] c8: e51b0014 ldr r0, [fp, #-20] cc: e24b3016 sub r3, fp, #22 ; 0x16 d0: e5d32000 ldrb r2, [r3] d4: e5d33001 ldrb r3, [r3, #1] d8: e1822403 orr r2, r2, r3, lsl #8 dc: e3a03001 mov r3, #1 ; 0x1 e0: e1a02213 mov r2, r3, lsl r2 e4: e5903004 ldr r3, [r0, #4] e8: e1833002 orr r3, r3, r2 ec: e5813004 str r3, [r1, #4] f0: ea00000e b 130 <Set_gpio+0xd0> } else if(new==IN) f4: e51b3010 ldr r3, [fp, #-16] f8: e3530000 cmp r3, #0 ; 0x0 fc: 1a00000b bne 130 <Set_gpio+0xd0> { //CON复位值为0,配置为输入 GPIO_InitStruct->CON &=(3<<GPIO_PinSource*2);/*乘法优先级高于左移*/ 100: e51b0014 ldr r0, [fp, #-20] 104: e51b1014 ldr r1, [fp, #-20] 108: e24b3016 sub r3, fp, #22 ; 0x16 10c: e5d32000 ldrb r2, [r3] 110: e5d33001 ldrb r3, [r3, #1] 114: e1823403 orr r3, r2, r3, lsl #8 118: e1a02083 mov r2, r3, lsl #1 11c: e3a03003 mov r3, #3 ; 0x3 120: e1a02213 mov r2, r3, lsl r2 124: e5913000 ldr r3, [r1] 128: e0033002 and r3, r3, r2 12c: e5803000 str r3, [r0] } else { /*预留*/ } } 130: e24bd00c sub sp, fp, #12 ; 0xc 134: e89da800 ldmia sp, {fp, sp, pc} <Reset_gpio>: void Reset_gpio(IOState new,GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_PinSource) { 138: e1a0c00d mov ip, sp 13c: e92dd800 stmdb sp!, {fp, ip, lr, pc} 140: e24cb004 sub fp, ip, #4 ; 0x4 144: e24dd00c sub sp, sp, #12 ; 0xc 148: e50b0010 str r0, [fp, #-16] 14c: e50b1014 str r1, [fp, #-20] 150: e1a03002 mov r3, r2 154: e54b3016 strb r3, [fp, #-22] 158: e1a03443 mov r3, r3, asr #8 15c: e54b3015 strb r3, [fp, #-21] if(new==OUT) 160: e51b3010 ldr r3, [fp, #-16] 164: e3530001 cmp r3, #1 ; 0x1 168: 1a000017 bne 1cc <Reset_gpio+0x94> { //CON复位值为0,配置为输出 GPIO_InitStruct->CON |=1<<GPIO_PinSource*2;/*乘法优先级高于左移*/ 16c: e51b0014 ldr r0, [fp, #-20] 170: e51b1014 ldr r1, [fp, #-20] 174: e24b3016 sub r3, fp, #22 ; 0x16 178: e5d32000 ldrb r2, [r3] 17c: e5d33001 ldrb r3, [r3, #1] 180: e1823403 orr r3, r2, r3, lsl #8 184: e1a02083 mov r2, r3, lsl #1 188: e3a03001 mov r3, #1 ; 0x1 18c: e1a02213 mov r2, r3, lsl r2 190: e5913000 ldr r3, [r1] 194: e1833002 orr r3, r3, r2 198: e5803000 str r3, [r0] GPIO_InitStruct->DAT &=~(1<<GPIO_PinSource);/*对应位清零,输出0,低电平*/ 19c: e51b0014 ldr r0, [fp, #-20] 1a0: e51b1014 ldr r1, [fp, #-20] 1a4: e24b3016 sub r3, fp, #22 ; 0x16 1a8: e5d32000 ldrb r2, [r3] 1ac: e5d33001 ldrb r3, [r3, #1] 1b0: e1822403 orr r2, r2, r3, lsl #8 1b4: e3a03001 mov r3, #1 ; 0x1 1b8: e1a03213 mov r3, r3, lsl r2 1bc: e1e02003 mvn r2, r3 1c0: e5913004 ldr r3, [r1, #4] 1c4: e0033002 and r3, r3, r2 1c8: e5803004 str r3, [r0, #4] } } 1cc: e24bd00c sub sp, fp, #12 ; 0xc 1d0: e89da800 ldmia sp, {fp, sp, pc} Disassembly of section .comment: <.comment>: 0: 43434700 cmpmi r3, #0 ; 0x0 4: 4728203a undefined 8: 2029554e eorcs r5, r9, lr, asr #10 c: 2e342e33 mrccs 14, 1, r2, cr4, cr3, {1} 10: 47000035 smladxmi r0, r5, r0, r0 14: 203a4343 eorcss r4, sl, r3, asr #6 18: 554e4728 strplb r4, [lr, #-1832] 1c: 2e332029 cdpcs 0, 3, cr2, cr3, cr9, {1} 20: 00352e34 eoreqs r2, r5, r4, lsr lr Disassembly of section .debug_aranges: <.debug_aranges>: 0: 0000001c andeq r0, r0, ip, lsl r0 4: 00000002 andeq r0, r0, r2 8: 00040000 andeq r0, r4, r0 ... 14: 0000000c andeq r0, r0, ip ... 20: 0000001c andeq r0, r0, ip, lsl r0 24: 003a0002 eoreqs r0, sl, r2 28: 00040000 andeq r0, r4, r0 2c: 00000000 andeq r0, r0, r0 30: 0000000c andeq r0, r0, ip 34: 00000054 andeq r0, r0, r4, asr r0 ... 40: 0000001c andeq r0, r0, ip, lsl r0 44: 00c90002 sbceq r0, r9, r2 48: 00040000 andeq r0, r4, r0 4c: 00000000 andeq r0, r0, r0 50: 00000060 andeq r0, r0, r0, rrx 54: 00000174 andeq r0, r0, r4, ror r1 ... Disassembly of section .debug_pubnames: <.debug_pubnames>: 0: 00000017 andeq r0, r0, r7, lsl r0 4: 003a0002 eoreqs r0, sl, r2 8: 008f0000 addeq r0, pc, r0 c: 006f0000 rsbeq r0, pc, r0 10: 616d0000 cmnvs sp, r0 14: 00006e69 andeq r6, r0, r9, ror #28 18: 2a000000 bcs 20 <main+0x14> 1c: 02000000 andeq r0, r0, #0 ; 0x0 20: 0000c900 andeq ip, r0, r0, lsl #18 24: 0001c100 andeq ip, r1, r0, lsl #2 28: 00012e00 andeq r2, r1, r0, lsl #28 2c: 74655300 strvcbt r5, [r5], #-768 30: 6970675f ldmvsdb r0!, {r0, r1, r2, r3, r4, r6, r8, r9, sl, sp, lr}^ 34: 017b006f cmneq fp, pc, rrx 38: 65520000 ldrvsb r0, [r2] 3c: 5f746573 swipl 0x00746573 40: 6f697067 swivs 0x00697067 44: 00000000 andeq r0, r0, r0 ... Disassembly of section .debug_info: <.debug_info>: 0: 00000036 andeq r0, r0, r6, lsr r0 4: 00000002 andeq r0, r0, r2 8: 01040000 tsteq r4, r0 ... 14: 0000000c andeq r0, r0, ip 18: 72617473 rsbvc r7, r1, #1929379840 ; 0x73000000 1c: 00532e74 subeqs r2, r3, r4, ror lr 20: 6d6f682f stcvsl 8, cr6, [pc, #-188]! 24: 68732f65 ldmvsda r3!, {r0, r2, r5, r6, r8, r9, sl, fp, sp}^ 28: 00657261 rsbeq r7, r5, r1, ror #4 2c: 20554e47 subcss r4, r5, r7, asr #28 30: 32205341 eorcc r5, r0, #67108865 ; 0x4000001 34: 0035312e eoreqs r3, r5, lr, lsr #2 38: 008b8001 addeq r8, fp, r1 3c: 00020000 andeq r0, r2, r0 40: 00000014 andeq r0, r0, r4, lsl r0 44: 00360104 eoreqs r0, r6, r4, lsl #2 48: 00600000 rsbeq r0, r0, r0 4c: 000c0000 andeq r0, ip, r0 50: 4e470000 cdpmi 0, 4, cr0, cr7, cr0, {0} 54: 20432055 subcs r2, r3, r5, asr r0 58: 2e342e33 mrccs 14, 1, r2, cr4, cr3, {1} 5c: 6d010035 stcvs 0, cr0, [r1, #-212] 60: 2e6e6961 cdpcs 9, 6, cr6, cr14, cr1, {3} 64: 682f0063 stmvsda pc!, {r0, r1, r5, r6} 68: 2f656d6f swics 0x00656d6f 6c: 72616873 rsbvc r6, r1, #7536640 ; 0x730000 70: 75020065 strvc r0, [r2, #-101] 74: 6769736e strvsb r7, [r9, -lr, ror #6]! 78: 2064656e rsbcs r6, r4, lr, ror #10 7c: 72616863 rsbvc r6, r1, #6488064 ; 0x630000 80: 02080100 andeq r0, r8, #0 ; 0x0 84: 726f6873 rsbvc r6, pc, #7536640 ; 0x730000 88: 6e752074 mrcvs 0, 3, r2, cr5, cr4, {3} 8c: 6e676973 mcrvs 9, 3, r6, cr7, cr3, {3} 90: 69206465 stmvsdb r0!, {r0, r2, r5, r6, sl, sp, lr} 94: 0200746e andeq r7, r0, #1845493760 ; 0x6e000000 98: 6e750207 cdpvs 2, 7, cr0, cr5, cr7, {0} 9c: 6e676973 mcrvs 9, 3, r6, cr7, cr3, {3} a0: 69206465 stmvsdb r0!, {r0, r2, r5, r6, sl, sp, lr} a4: 0400746e streq r7, [r0], #-1134 a8: 6d010307 stcvs 3, cr0, [r1, #-28] ac: 006e6961 rsbeq r6, lr, r1, ror #18 b0: 87010301 strhi r0, [r1, -r1, lsl #6] b4: 0c000000 stceq 0, cr0, [r0], {0} b8: 60000000 andvs r0, r0, r0 bc: 01000000 tsteq r0, r0 c0: 6e69025b mcrvs 2, 3, r0, cr9, cr11, {2} c4: 05040074 streq r0, [r4, #-116] c8: 0001bd00 andeq fp, r1, r0, lsl #26 cc: 4a000200 bmi 8d4 <Reset_gpio+0x79c> d0: 04000000 streq r0, [r0] d4: 00006c01 andeq r6, r0, r1, lsl #24 d8: 0001d400 andeq sp, r1, r0, lsl #8 dc: 00006000 andeq r6, r0, r0 e0: 554e4700 strplb r4, [lr, #-1792] e4: 33204320 teqcc r0, #-2147483648 ; 0x80000000 e8: 352e342e strcc r3, [lr, #-1070]! ec: 33730100 cmncc r3, #0 ; 0x0 f0: 34343263 ldrcct r3, [r4], #-611 f4: 70675f30 rsbvc r5, r7, r0, lsr pc f8: 632e6f69 teqvs lr, #420 ; 0x1a4 fc: 6f682f00 swivs 0x00682f00 100: 732f656d teqvc pc, #457179136 ; 0x1b400000 104: 65726168 ldrvsb r6, [r2, #-360]! 108: 6e750200 cdpvs 2, 7, cr0, cr5, cr0, {0} 10c: 6e676973 mcrvs 9, 3, r6, cr7, cr3, {3} 110: 63206465 teqvs r0, #1694498816 ; 0x65000000 114: 00726168 rsbeqs r6, r2, r8, ror #2 118: 75030801 strvc r0, [r3, #-2049] 11c: 31746e69 cmncc r4, r9, ror #28 120: 00745f36 rsbeqs r5, r4, r6, lsr pc 124: 00610402 rsbeq r0, r1, r2, lsl #8 128: 73020000 tstvc r2, #0 ; 0x0 12c: 74726f68 ldrvcbt r6, [r2], #-3944 130: 736e7520 cmnvc lr, #134217728 ; 0x8000000 134: 656e6769 strvsb r6, [lr, #-1897]! 138: 6e692064 cdpvs 0, 6, cr2, cr9, cr4, {3} 13c: 07020074 smlsdxeq r2, r4, r0, r0 140: 6e697503 cdpvs 5, 6, cr7, cr9, cr3, {0} 144: 5f323374 swipl 0x00323374 148: 05020074 streq r0, [r2, #-116] 14c: 00000087 andeq r0, r0, r7, lsl #1 150: 736e7502 cmnvc lr, #8388608 ; 0x800000 154: 656e6769 strvsb r6, [lr, #-1897]! 158: 6e692064 cdpvs 0, 6, cr2, cr9, cr4, {3} 15c: 07040074 smlsdxeq r4, r4, r0, r0 160: 0000dc04 andeq sp, r0, r4, lsl #24 164: 0d021000 stceq 0, cr1, [r2] 168: 4e4f4305 cdpmi 3, 4, cr4, cr15, cr5, {0} 16c: dc090200 sfmle f0, 4, [r9], {0} 170: 02000000 andeq r0, r0, #0 ; 0x0 174: 44050023 strmi r0, [r5], #-35 178: 02005441 andeq r5, r0, #1090519040 ; 0x41000000 17c: 0000e10a andeq lr, r0, sl, lsl #2 180: 04230200 streqt r0, [r3], #-512 184: 00505505 subeqs r5, r0, r5, lsl #10 188: 00e60b02 rsceq r0, r6, r2, lsl #22 18c: 23020000 tstcs r2, #0 ; 0x0 190: 65520508 ldrvsb r0, [r2, #-1288] 194: 76726573 undefined 198: 02006465 andeq r6, r0, #1694498816 ; 0x65000000 19c: 0000eb0c andeq lr, r0, ip, lsl #22 1a0: 0c230200 sfmeq f0, 4, [r3] 1a4: 00770600 rsbeqs r0, r7, r0, lsl #12 1a8: 77060000 strvc r0, [r6, -r0] 1ac: 06000000 streq r0, [r0], -r0 1b0: 00000077 andeq r0, r0, r7, ror r0 1b4: 00007706 andeq r7, r0, r6, lsl #14 1b8: 50470300 subpl r0, r7, r0, lsl #6 1bc: 545f4f49 ldrplb r4, [pc], #3913 ; 1c4 <Reset_gpio+0x8c> 1c0: 44657079 strmibt r7, [r5], #-121 1c4: 02006665 andeq r6, r0, #105906176 ; 0x6500000 1c8: 0000970d andeq r9, r0, sp, lsl #14 1cc: 011f0700 tsteq pc, r0, lsl #14 1d0: 02040000 andeq r0, r4, #0 ; 0x0 1d4: 4e490810 mcrmi 8, 2, r0, cr9, cr0, {0} 1d8: 4f080000 swimi 0x00080000 1dc: 01005455 tsteq r0, r5, asr r4 1e0: 4e494508 cdpmi 5, 4, cr4, cr9, cr8, {0} 1e4: 00020054 andeq r0, r2, r4, asr r0 1e8: 534f4903 cmppl pc, #49152 ; 0xc000 1ec: 65746174 ldrvsb r6, [r4, #-372]! 1f0: 04140200 ldreq r0, [r4], #-512 1f4: 09000001 stmeqdb r0, {r0} 1f8: 00000175 andeq r0, r0, r5, ror r1 1fc: 74655301 strvcbt r5, [r5], #-769 200: 6970675f ldmvsdb r0!, {r0, r1, r2, r3, r4, r6, r8, r9, sl, sp, lr}^ 204: 0401006f streq r0, [r1], #-111 208: 00006001 andeq r6, r0, r1 20c: 00013800 andeq r3, r1, r0, lsl #16 210: 0a5b0100 beq 16c0618 <__bss_end__+0x16b8444> 214: 0077656e rsbeqs r6, r7, lr, ror #10 218: 011f0301 tsteq pc, r1, lsl #6 21c: 91020000 tstls r2, r0 220: 000f0b70 andeq r0, pc, r0, ror fp 224: 03010000 tsteq r1, #0 ; 0x0 228: 00000175 andeq r0, r0, r5, ror r1 22c: 0b6c9102 bleq 1b2463c <__bss_end__+0x1b1c468> 230: 00000000 andeq r0, r0, r0 234: 00510301 subeqs r0, r1, r1, lsl #6 238: 91020000 tstls r2, r0 23c: 040c006a streq r0, [ip], #-106 240: 000000f0 streqd r0, [r0], -r0 244: 6552010d ldrvsb r0, [r2, #-269] 248: 5f746573 swipl 0x00746573 24c: 6f697067 swivs 0x00697067 250: 01180100 tsteq r8, r0, lsl #2 254: 00000138 andeq r0, r0, r8, lsr r1 258: 000001d4 ldreqd r0, [r0], -r4 25c: 6e0a5b01 fmacdvs d5, d10, d1 260: 01007765 tsteq r0, r5, ror #14 264: 00011f17 andeq r1, r1, r7, lsl pc 268: 70910200 addvcs r0, r1, r0, lsl #4 26c: 00000f0b andeq r0, r0, fp, lsl #30 270: 75170100 ldrvc r0, [r7, #-256] 274: 02000001 andeq r0, r0, #1 ; 0x1 278: 000b6c91 muleq fp, r1, ip 27c: 01000000 tsteq r0, r0 280: 00005117 andeq r5, r0, r7, lsl r1 284: 6a910200 bvs fe440a8c <__bss_end__+0xfe4388b8> ... Disassembly of section .debug_abbrev: <.debug_abbrev>: 0: 10001101 andne r1, r0, r1, lsl #2 4: 12011106 andne r1, r1, #-2147483647 ; 0x80000001 8: 1b080301 blne 200c14 <__bss_end__+0x1f8a40> c: 13082508 tstne r8, #33554432 ; 0x2000000 10: 00000005 andeq r0, r0, r5 14: 10011101 andne r1, r1, r1, lsl #2 18: 11011206 tstne r1, r6, lsl #4 1c: 13082501 tstne r8, #4194304 ; 0x400000 20: 1b08030b blne 200c54 <__bss_end__+0x1f8a80> 24: 02000008 andeq r0, r0, #8 ; 0x8 28: 08030024 stmeqda r3, {r2, r5} 2c: 0b3e0b0b bleq f82c60 <__bss_end__+0xf7aa8c> 30: 2e030000 cdpcs 0, 0, cr0, cr3, cr0, {0} 34: 030c3f00 tsteq ip, #0 ; 0x0 38: 3b0b3a08 blcc 2ce860 <__bss_end__+0x2c668c> 3c: 490c270b stmmidb ip, {r0, r1, r3, r8, r9, sl, sp} 40: 12011113 andne r1, r1, #-1073741820 ; 0xc0000004 44: 000a4001 andeq r4, sl, r1 48: 11010000 tstne r1, r0 4c: 12061001 andne r1, r6, #1 ; 0x1 50: 25011101 strcs r1, [r1, #-257] 54: 030b1308 tsteq fp, #536870912 ; 0x20000000 58: 00081b08 andeq r1, r8, r8, lsl #22 5c: 00240200 eoreq r0, r4, r0, lsl #4 60: 0b0b0803 bleq 2c2074 <__bss_end__+0x2b9ea0> 64: 00000b3e andeq r0, r0, lr, lsr fp 68: 03001603 tsteq r0, #3145728 ; 0x300000 6c: 3b0b3a08 blcc 2ce894 <__bss_end__+0x2c66c0> 70: 0013490b andeqs r4, r3, fp, lsl #18 74: 01130400 tsteq r3, r0, lsl #8 78: 0b0b1301 bleq 2c4c84 <__bss_end__+0x2bcab0> 7c: 0b3b0b3a bleq ec2d6c <__bss_end__+0xebab98> 80: 0d050000 stceq 0, cr0, [r5] 84: 3a080300 bcc 200c8c <__bss_end__+0x1f8ab8> 88: 490b3b0b stmmidb fp, {r0, r1, r3, r8, r9, fp, ip, sp} 8c: 000a3813 andeq r3, sl, r3, lsl r8 90: 00350600 eoreqs r0, r5, r0, lsl #12 94: 00001349 andeq r1, r0, r9, asr #6 98: 01010407 tsteq r1, r7, lsl #8 9c: 3a0b0b13 bcc 2c2cf0 <__bss_end__+0x2bab1c> a0: 000b3b0b andeq r3, fp, fp, lsl #22 a4: 00280800 eoreq r0, r8, r0, lsl #16 a8: 0d1c0803 ldceq 8, cr0, [ip, #-12] ac: 2e090000 cdpcs 0, 0, cr0, cr9, cr0, {0} b0: 3f130101 swicc 0x00130101 b4: 3a08030c bcc 200cec <__bss_end__+0x1f8b18> b8: 270b3b0b strcs r3, [fp, -fp, lsl #22] bc: 1201110c andne r1, r1, #3 ; 0x3 c0: 000a4001 andeq r4, sl, r1 c4: 00050a00 andeq r0, r5, r0, lsl #20 c8: 0b3a0803 bleq e820dc <__bss_end__+0xe79f08> cc: 13490b3b cmpne r9, #60416 ; 0xec00 d0: 00000a02 andeq r0, r0, r2, lsl #20 d4: 0300050b tsteq r0, #46137344 ; 0x2c00000 d8: 3b0b3a0e blcc 2ce918 <__bss_end__+0x2c6744> dc: 0213490b andeqs r4, r3, #180224 ; 0x2c000 e0: 0c00000a stceq 0, cr0, [r0], {10} e4: 0b0b000f bleq 2c0128 <__bss_end__+0x2b7f54> e8: 00001349 andeq r1, r0, r9, asr #6 ec: 3f012e0d swicc 0x00012e0d f0: 3a08030c bcc 200d28 <__bss_end__+0x1f8b54> f4: 270b3b0b strcs r3, [fp, -fp, lsl #22] f8: 1201110c andne r1, r1, #3 ; 0x3 fc: 000a4001 andeq r4, sl, r1 ... Disassembly of section .debug_line: <.debug_line>: 0: 00000032 andeq r0, r0, r2, lsr r0 4: 001b0002 andeqs r0, fp, r2 8: 01020000 tsteq r2, r0 c: 000a0efb streqd r0, [sl], -fp 10: 01010101 tsteq r1, r1, lsl #2 14: 01000000 tsteq r0, r0 18: 61747300 cmnvs r4, r0, lsl #6 1c: 532e7472 teqpl lr, #1912602624 ; 0x72000000 20: 00000000 andeq r0, r0, r0 24: 02050000 andeq r0, r5, #0 ; 0x0 28: 00000000 andeq r0, r0, r0 2c: 2d010903 stccs 9, cr0, [r1, #-12] 30: 0002022e andeq r0, r2, lr, lsr #4 34: 00320101 eoreqs r0, r2, r1, lsl #2 38: 00020000 andeq r0, r2, r0 3c: 0000001a andeq r0, r0, sl, lsl r0 40: 0efb0102 cdpeq 1, 15, cr0, cr11, cr2, {0} 44: 0101000a tsteq r1, sl 48: 00000101 andeq r0, r0, r1, lsl #2 4c: 6d000100 stfvss f0, [r0] 50: 2e6e6961 cdpcs 9, 6, cr6, cr14, cr1, {3} 54: 00000063 andeq r0, r0, r3, rrx 58: 05000000 streq r0, [r0] 5c: 00000c02 andeq r0, r0, r2, lsl #24 60: 9c651100 stflse f1, [r5] 64: 022c9c9c eoreq r9, ip, #39936 ; 0x9c00 68: 01010004 tsteq r1, r4 6c: 00000059 andeq r0, r0, r9, asr r0 70: 00340002 eoreqs r0, r4, r2 74: 01020000 tsteq r2, r0 78: 000a0efb streqd r0, [sl], -fp 7c: 01010101 tsteq r1, r1, lsl #2 80: 01000000 tsteq r0, r0 84: 63337300 teqvs r3, #0 ; 0x0 88: 30343432 eorccs r3, r4, r2, lsr r4 8c: 6970675f ldmvsdb r0!, {r0, r1, r2, r3, r4, r6, r8, r9, sl, sp, lr}^ 90: 00632e6f rsbeq r2, r3, pc, ror #28 94: 73000000 tstvc r0, #0 ; 0x0 98: 34326333 ldrcct r6, [r2], #-819 9c: 675f3034 smmlarvs pc, r4, r0, r3 a0: 2e6f6970 mcrcs 9, 3, r6, cr15, cr0, {3} a4: 00000068 andeq r0, r0, r8, rrx a8: 05000000 streq r0, [r0] ac: 00006002 andeq r6, r0, r2 b0: 3a081200 bcc 2048b8 <__bss_end__+0x1fc6e4> b4: 08730866 ldmeqda r3!, {r1, r2, r5, r6, fp}^ b8: 77086673 smlsdxvc r8, r3, r6, r6 bc: 663a084a ldrvst r0, [sl], -sl, asr #16 c0: 73087208 tstvc r8, #-2147483648 ; 0x80000000 c4: 01000402 tsteq r0, r2, lsl #8 c8: Address 0xc8 is out of bounds. Disassembly of section .debug_frame: <.debug_frame>: 0: 0000000c andeq r0, r0, ip 4: ffffffff swinv 0x00ffffff 8: 7c010001 stcvc 0, cr0, [r1], {1} c: 000d0c0e andeq r0, sp, lr, lsl #24 10: 0000001c andeq r0, r0, ip, lsl r0 14: 00000000 andeq r0, r0, r0 18: 0000000c andeq r0, r0, ip 1c: 00000054 andeq r0, r0, r4, asr r0 20: 440c0d44 strmi r0, [ip], #-3396 24: 038d028e orreq r0, sp, #-536870904 ; 0xe0000008 28: 0c44048b cfstrdeq mvd0, [r4], {139} 2c: 0000040b andeq r0, r0, fp, lsl #8 30: 0000000c andeq r0, r0, ip 34: ffffffff swinv 0x00ffffff 38: 7c010001 stcvc 0, cr0, [r1], {1} 3c: 000d0c0e andeq r0, sp, lr, lsl #24 40: 0000001c andeq r0, r0, ip, lsl r0 44: 00000030 andeq r0, r0, r0, lsr r0 48: 00000060 andeq r0, r0, r0, rrx 4c: 000000d8 ldreqd r0, [r0], -r8 50: 440c0d44 strmi r0, [ip], #-3396 54: 038d028e orreq r0, sp, #-536870904 ; 0xe0000008 58: 0c44048b cfstrdeq mvd0, [r4], {139} 5c: 0000040b andeq r0, r0, fp, lsl #8 60: 0000001c andeq r0, r0, ip, lsl r0 64: 00000030 andeq r0, r0, r0, lsr r0 68: 00000138 andeq r0, r0, r8, lsr r1 6c: 0000009c muleq r0, ip, r0 70: 440c0d44 strmi r0, [ip], #-3396 74: 038d028e orreq r0, sp, #-536870904 ; 0xe0000008 78: 0c44048b cfstrdeq mvd0, [r4], {139} 7c: 0000040b andeq r0, r0, fp, lsl #8 Disassembly of section .debug_str: <.debug_str>: 0: 4f495047 swimi 0x00495047 4: 6e69505f mcrvs 0, 3, r5, cr9, cr15, {2} 8: 72756f53 rsbvcs r6, r5, #332 ; 0x14c c: 47006563 strmi r6, [r0, -r3, ror #10] 10: 5f4f4950 swipl 0x004f4950 14: 74696e49 strvcbt r6, [r9], #-3657 18: 75727453 ldrvcb r7, [r2, #-1107]! 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 0 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 = 0, OUT = 1, EINT=2 } IOState; typedef enum { Bit_RESET = 0, 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 |=1<<GPIO_PinSource*2;/*乘法优先级高于左移*/ //DAT复位值udf GPIO_InitStruct->DAT |=(1<<GPIO_PinSource);/*对应位清零,输出1*/ } else if(new==IN) { //CON复位值为0,配置为输入 GPIO_InitStruct->CON &=(3<<GPIO_PinSource*2);/*乘法优先级高于左移*/ } else { /*预留*/ } } /* *设置输出引脚输出低电平 */ void Reset_gpio(IOState new,GPIO_TypeDef* GPIO_InitStruct,uint16_t GPIO_PinSource) { if(new==OUT) { //CON复位值为0,配置为输出 GPIO_InitStruct->CON |=1<<GPIO_PinSource*2;/*乘法优先级高于左移*/ GPIO_InitStruct->DAT &=~(1<<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; }
#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(100000); Set_gpio(OUT, GPIOF,GPIO_PinSource4); Delay(100000); //点亮LED2然后熄灭 Reset_gpio(OUT, GPIOF,GPIO_PinSource5); Delay(100000); Set_gpio(OUT, GPIOF,GPIO_PinSource5); Delay(100000); //点亮LED3然后熄灭 Reset_gpio(OUT, GPIOF,GPIO_PinSource6); Delay(100000); Set_gpio(OUT, GPIOF,GPIO_PinSource6); Delay(100000); //熄灭三盏LED灯 Set_gpio(OUT, GPIOF,GPIO_PinSource5); Set_gpio(OUT, GPIOF,GPIO_PinSource4); while (1) { //如果按键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 0; }
原理图:
外部电源上拉:
EINT0->对应引脚GPF0
EINT2->对应引脚GPF2
EINT11->对应引脚GPG3
即,默认高电平,按键按下就低电平。
Makefile和之前一样,ok,这样是不是觉得方便多了?当然,这是建立在你熟练运用C语言的基础上的,不然是写不出库函数的。