GPIO操作
Posted 游戏进行中
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GPIO操作相关的知识,希望对你有一定的参考价值。
1.1 硬件原理图
四个引脚接到LED上,跟别是GPF4,GPF5,GPF6和GPF7,前三个引脚分别控制三个LED,GPF7此引脚作为DM9000网卡的中断。
发光二极管的正极接3.3V电源,负极接在MCU上,当MCU的对应的引脚给一个低电平的时候,电路导通,发光二极管发光。
芯片手册,GPIO配置,如下图,控制LED的属于GPF管脚:
GPF的寄存器如下图:
- GPFCON:GPF管脚的控制寄存器
- GPFDAT:GPF管脚的数据寄存器
- GPFUP:GPF上拉使能的寄存器
GPF4-GPF6对应GPFCON寄存器的13—8位。
1.2 LED 操作
1.2.1 点亮一个 led 灯
(1)汇编编写
led_on.S
1 @****************************************************************************** 2 @ File:led_on.S 3 @ 功能:LED点灯程序,点亮LED1 4 @****************************************************************************** 5 6 .text 7 .global _start 8 _start: 9 LDR R0,=0x56000050 @ R0设为GPFCON寄存器。此寄存器 10 @ 用于选择端口B各引脚的功能: 11 @ 是输出、是输入、还是其他 12 MOV R1,#0x00000100 13 STR R1,[R0] @ 设置GPF4为输出口, 位[8:7]=0b01 14 LDR R0,=0x56000054 @ R0设为GPBDAT寄存器。此寄存器 15 @ 用于读/写端口B各引脚的数据 16 MOV R1,#0x00000000 @ 此值改为0x00000010, 17 @ 可让LED1熄灭 18 STR R1,[R0] @ GPF4输出0,LED1点亮 19 MAIN_LOOP: 20 B MAIN_LOOP
Makefile
1 led_on.bin : led_on.S 2 arm-linux-gcc -g -c -o led_on.o led_on.S 3 arm-linux-ld -Ttext 0x0000000 -g led_on.o -o led_on_elf 4 arm-linux-objcopy -O binary -S led_on_elf led_on.bin 5 clean: 6 rm -f led_on.bin led_on_elf *.o
make 执行编译,生成 led_on.bin。烧录到开发板
(2)用C语言编写
一个程序编译的时候会经过下面几个步骤:预处理、编译、汇编和链接。
编译就是将源程序编译成 .S
汇编就是将.S 编译成 .o
链接就是将多个 .o 链接成一个可执行程序
- 启动文件:
- 需要做硬件初始化
- 关看门狗
- 初始化时钟
- 初始化 SDRAM,若是 SRAM(内置) 不需要初始化,若是 SDRAM(外挂的),则首先要初始化 SDRAM
- 设置栈,即将 栈指针 sp 指向某块内存,
- 设置 main 函数的返回地址
- 调用 main 函数
- 清理工作
- 需要做硬件初始化
启动程序 crt0.S
1 @****************************************************************************** 2 @ File:crt0.S 3 @ 功能:通过它转入C程序 4 @****************************************************************************** 5 6 .text 7 .global _start 8 _start: 9 ldr r0, =0x53000000 @ WATCHDOG寄存器地址 10 mov r1, #0x0 11 str r1, [r0] @ 写入0,禁止WATCHDOG,否则CPU会不断重启 12 13 ldr sp, =1024*4 @ 设置堆栈,注意:不能大于4k, 因为现在可用的内存只有4K 14 @ nand flash中的代码在复位后会移到内部ram中,此ram只有4K 15 bl main @ 调用C程序中的main函数,bl 指令会调用 main 函数,并将返回地址保存在 lr 寄存器中 16 17 18 halt_loop: @ main 函数执行完之后,会返回到这里做清理工作,我们这里写的是进入死循环 19 b halt_loop
led_on.c
1 #define GPFCON (*(volatile unsigned long *)0x56000050) 2 #define GPFDAT (*(volatile unsigned long *)0x56000054) 3 4 int main() 5 { 6 GPFCON = 0x00000100; // 设置GPF4为输出口, 位[8:7]=0b01 7 GPFDAT = 0x00000000; // GPF4输出0,LED1点亮 8 }
Makefile
1 led_on.bin : crt0.S led_on.c 2 arm-linux-gcc -g -c -o crt0.o crt0.S 3 arm-linux-gcc -g -c -o led_on.o led_on.c 4 arm-linux-ld -Ttext 0x0000000 -g crt0.o led_on.o -o led_on_elf 5 arm-linux-objcopy -O binary -S led_on_elf led_on.bin 6 arm-linux-objdump -D -m arm led_on_elf > led_on.dis 7 clean: 8 rm -f led_on.dis led_on.bin led_on_elf *.o
1.2.2 点亮三个LED
除了 led_on.c 不一样之外,其余的和上面的 C语言编写的程序一样
led_on.c
1 #define GPFCON (*(volatile unsigned long *)0x56000050) 2 #define GPFDAT (*(volatile unsigned long *)0x56000054) 3 4 #define GPF4_out (1<<(4*2)) 5 #define GPF5_out (1<<(5*2)) 6 #define GPF6_out (1<<(6*2)) 7 8 void delay_ms(unsigned int val); 9 10 int main() 11 { 12 int i = 0; 13 GPFCON = GPF4_out|GPF5_out|GPF6_out; // 将LED1,2,4对应的GPF4/5/6三个引脚设为输出 14 15 while(1) 16 { 17 delay_ms(500); 18 GPFDAT = (~(i<<4)); // 根据i的值,点亮LED1,2,4 19 if(++i == 8) 20 i = 0; 21 } 22 23 return 0; 24 } 25 26 /* 对于12M 晶振来说的 */ 27 void delay_ms(unsigned int val) 28 { 29 unsigned int i; 30 31 while(val > 0) 32 { 33 for(i = 0; i < 187; ++i) 34 asm("nop"); 35 36 val--; 37 } 38 }
1.2.3 用按键控制LED
按键的原理图如下所示:
EINT0 和 EINT2 分别在 GPF0 和 GPF2 引脚上, EINT11 在 GPG3 引脚上
按键引脚需要去读,按键按下形成回路,所以按键的引脚设置为输入,当按键按下的时候,由于按键接地,则按键的引脚处为低电平0,弹起后被拉高为1
1 #define GPFCON (*(volatile unsigned long *)0x56000050) 2 #define GPFDAT (*(volatile unsigned long *)0x56000054) 3 4 #define GPGCON (*(volatile unsigned long *)0x56000060) 5 #define GPGDAT (*(volatile unsigned long *)0x56000064) 6 7 /* 8 * LED1,LED2,LED4对应GPF4、GPF5、GPF6 9 */ 10 #define GPF4_out (1<<(4*2)) 11 #define GPF5_out (1<<(5*2)) 12 #define GPF6_out (1<<(6*2)) 13 14 #define GPF4_msk (3<<(4*2)) 15 #define GPF5_msk (3<<(5*2)) 16 #define GPF6_msk (3<<(6*2)) 17 18 /* 19 * S2,S3,S4对应GPF0、GPF2、GPG3 20 */ 21 #define GPF0_in (0<<(0*2)) 22 #define GPF2_in (0<<(2*2)) 23 #define GPG3_in (0<<(3*2)) 24 25 #define GPF0_msk (3<<(0*2)) 26 #define GPF2_msk (3<<(2*2)) 27 #define GPG3_msk (3<<(3*2)) 28 29 int main() 30 { 31 unsigned long dwDat; 32 // LED1,LED2,LED4对应的3根引脚设为输出 33 GPFCON &= ~(GPF4_msk | GPF5_msk | GPF6_msk); 34 GPFCON |= GPF4_out | GPF5_out | GPF6_out; 35 36 // S2,S3对应的2根引脚设为输入 37 GPFCON &= ~(GPF0_msk | GPF2_msk); 38 GPFCON |= GPF0_in | GPF2_in; 39 40 // S4对应的引脚设为输入 41 GPGCON &= ~GPG3_msk; 42 GPGCON |= GPG3_in; 43 44 while(1){ 45 //若Kn为0(表示按下),则令LEDn为0(表示点亮) 46 dwDat = GPFDAT; // 读取GPF管脚电平状态 47 48 if (dwDat & (1<<0)) // S2没有按下 49 GPFDAT |= (1<<4); // LED1熄灭 50 else 51 GPFDAT &= ~(1<<4); // LED1点亮 52 53 if (dwDat & (1<<2)) // S3没有按下 54 GPFDAT |= (1<<5); // LED2熄灭 55 else 56 GPFDAT &= ~(1<<5); // LED2点亮 57 58 dwDat = GPGDAT; // 读取GPG管脚电平状态 59 60 if (dwDat & (1<<3)) // S4没有按下 61 GPFDAT |= (1<<6); // LED3熄灭 62 else 63 GPFDAT &= ~(1<<6); // LED3点亮 64 } 65 66 return 0; 67 }
以上是关于GPIO操作的主要内容,如果未能解决你的问题,请参考以下文章