本章目標:
5.1 GPIO硬件介紹
5.1.1 管腳相關的寄存器
5.1.2 怎麼使用軟件來訪問硬件
#define GPFCON (*(volatile unsigned long *) 0x56000050)
#define GPFDAT (*(volatile unsigned long *) 0x56000054)
#define GPF4_out (1 << 4*2)
GPFCON = GPF4_out; //GPF4引腳設爲輸出
GPFDAT &= ~(1 << 4); //GPF4輸出低電平
5.2 GPIO操作實例:LED和按鍵
5.2.1 硬件設計
5.2.2 程序設計及代碼詳解
.text
.global _start
_start:
LDR R0,=0x56000050 @R0設爲GPFCON寄存器
MOV R1, #0x00000100 @0b 01 0000 0000
STR R1,[R0] @設置GPF4爲輸出口,位[9:8] = 01
LDR R0,=0x56000054 @R0設置GPFDAT寄存器
MOV R1, #0x0000000 @此值改爲0x00000010(0001 0000)可以讓LED全熄滅
STR R1,[R0] @GPF4輸出0,點亮LED
MAIN_LOOP:
B MAIN_LOOP
led_on.bin:led_on.S @make指令比較led_on.bin和led_on.S的時間,決定是否執行下面的命令
arm-linux-gcc -g -c -o led_on.o led_on.S @編譯
arm-linux-ld -Ttext 0x0000 -g led_on.o -o led_on_elf @鏈接
arm-linux-objcopy -O binary -S led_on_elf led_on.bin @把ELF格式的可執行文件led_on_elf轉換成二進制格式文件led_on.bin
clean:
rm -f led_on.bin led_on_elf *.o
@************************************
@File:crt0.S
@功能:通過它轉入C程序
@************************************
.text
.global _start
_start:
ldr r0, =0x56000010 @WATCHDOG寄存器地址
mov r1, #0x0
str r1, [r0] @寫入0,禁止WATCHDOG
ldr sp, =1024*4 @設置堆棧,注意不能大於4k,因爲現在可用內存只有4kB
@NAND Flash中的代碼在復位後會移到內部ram(只有4kB)
bl main
halt_loop:
b halt_loop
int main()
{
GPFCON = GPF4_out; //GPF4引腳設爲輸出
GPFDAT &= ~(1 << 4); //GPF4輸出低電平
return 0;
}
led_on_c.bin:crt0.S led_on_c.c
arm-linux-gcc -g -c -o crt0.o crt0.S
arm-linux-gcc -g -c -o led_on_c.o led_on_c.c
arm-linux-ld -Ttext 0x0000000 -g crt0.o led_on_c.o -o led_on_c_elf
arm-linux-objcopy -O binary -S led_on_c_elf led_on_c.bin
arm-linux-objdump -D -m arm led_on_c_elf > led_on_c.dis
clean:
rm -f led_on_c.dis led_on_c.bin led_on_c_elf *.o
/*
* LED1,LED2,LED4對應GPF4、GPF5、GPF6
*/
/*
* S2,S3,S4對應GPF0、GPF2、GPG3
*/
int main()
{
unsigned long dwDat;
// LED1,LED2,LED4對應的3根引腳設爲輸出
GPFCON &= ~(GPF4_msk | GPF5_msk | GPF6_msk);
GPFCON |= GPF4_out | GPF5_out | GPF6_out;
// S2,S3對應的2根引腳設爲輸入
GPFCON &= ~(GPF0_msk | GPF2_msk);
GPFCON |= GPF0_in | GPF2_in;
// S4對應的引腳設爲輸入
GPGCON &= ~GPG3_msk;
GPGCON |= GPG3_in;
while(1){
//若Kn爲0(表示按下),則令LEDn爲0(表示點亮)
dwDat = GPFDAT; // 讀取GPF管腳電平狀態
if (dwDat & (1<<0)) // S2沒有按下
GPFDAT |= (1<<4); // LED1熄滅
else
GPFDAT &= ~(1<<4); // LED1點亮
if (dwDat & (1<<2)) // S3沒有按下
GPFDAT |= (1<<5); // LED2熄滅
else
GPFDAT &= ~(1<<5); // LED2點亮
dwDat = GPGDAT; // 讀取GPG管腳電平狀態
if (dwDat & (1<<3)) // S4沒有按下
GPFDAT |= (1<<6); // LED3熄滅
else
GPFDAT &= ~(1<<6); // LED3點亮
}
return 0;
}
5.2.3 實例測試
鏈接: https://pan.baidu.com/s/1kV24a9L 密碼: tfab