千家信息网

06-GPIO实验

发表于:2024-11-28 作者:千家信息网编辑
千家信息网最后更新 2024年11月28日, GPIO(General Purpose I/O Ports)意思为通用输入/输出端口,通俗地说,就是一些引脚,可以通过它们输出高低电平、或者通过它们读入引脚的状态──是高电平还是低电平。 三星 S
千家信息网最后更新 2024年11月28日06-GPIO实验

 GPIO(General Purpose I/O Ports)意思为通用输入/输出端口,通俗地说,就是一些引脚,可以通过它们输出高低电平、或者通过它们读入引脚的状态──是高电平还是低电平。
 三星 S3C2440,有130个I/O端口,分为A-J九组,可以通过设置寄存器来确定某个引脚用于输入、输出还是特殊功能。在这里通过四个实验介绍GPIO的简单使用。
1、通过汇编语言点亮LED灯
 首先需要看原理图,知道LED与芯片引脚的关系。
   
 由原理图可知,2440引脚作为输出引脚与LED灯连接,要使LED灯点亮,配置相关寄存器为输出引脚,且将该引脚输出低电平即可点亮LED灯。查看2440芯片手册,GPB组引脚控制寄存器地址为:0x56000010,数据寄存器地址为:0x56000014。点亮LED1的汇编代码为:

.text.global _start_start:             LDR     R0,=0x56000010  @ R0设为GPBCON寄存器。此寄存器用于选择端口B各引脚的功能: 是输出、是输入、还是其他        MOV     R1,#0x00000400                STR     R1,[R0]                    @ 设置GPB5为输出口, 位[11:10]=0b01        LDR     R0,=0x56000014     @ R0设为GPBDAT寄存器。此寄存器用于读/写端口B各引脚的数据        MOV     R1,#0x00000000      @ 此值改为0x00000020,可让LED1熄灭        STR     R1,[R0]             @ GPB5输出0,LED1点亮MAIN_LOOP:        B       MAIN_LOOP

其Makefile为:

led_on.bin : led_on.S    arm-linux-gcc -g -c -o led_on.o led_on.S    arm-linux-ld -Ttext 0x0000000 -g led_on.o -o led_on_elf    arm-linux-objcopy -O binary -S led_on_elf led_on.binclean:    rm -f   led_on.bin led_on_elf *.o

编译后下载到TQ2440开发板后效果:led_1点亮

2、通过C语言点亮LED灯
 在使用C语言点亮LED灯时,首先需要进行硬件相关初始化与软件相关初始化。硬件相关有:关看门狗、初始化时钟、初始化SDRAM等,而对于点亮LED灯实验,只需要关闭看门狗即可;软件方面,需要设置返回地址,即设置栈、调用main函数等。首先,汇编代码部分:

 .text.global _start_start:            ldr      r0, =0x53000000     @ WATCHDOG寄存器地址            mov   r1, #0x0                                 str      r1, [r0]                     @ 写入0,禁止WATCHDOG,否则CPU会不断重启            ldr     sp, =1024*4         @ 设置堆栈,注意:不能大于4k, 因为现在可用的内存只有4K,nand flash中的代码在复位后会移到内部ram中,此ram只有4K            bl      main                      @ 调用C程序中的main函数halt_loop:            b       halt_loop

C语言部分:

#define GPBCON      (*(volatile unsigned long *)0x56000010)#define GPBDAT      (*(volatile unsigned long *)0x56000014)int main(){    GPBCON = 0x00000400;    // 设置GPB5为输出口, 位[11:10]=0b01    GPBDAT = 0x00000000;    // GPB5输出0,LED1点亮    return 0;}

Makefile代码为:

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.disclean:    rm -f led_on_c.dis led_on_c.bin led_on_c_elf *.o

编译后下载到TQ2440开发板后效果:led_1点亮

3、通过按键控制LED灯点亮
 通过按键控制LED灯时,首先看原理图,了解按键与2440芯片连接的引脚关系。

 使用汇编完成相关初始化,跳转到main函数中,C程序部分通过按键实现LED灯的亮与灭。
汇编代码:

.text.global _start_start:            ldr     r0, =0x53000000     @ WATCHDOG寄存器地址            mov     r1, #0x0                                 str   r1, [r0]              @ 写入0,禁止WATCHDOG,否则CPU会不断重启             ldr     sp, =1024*4         @ 设置堆栈,注意:不能大于4k, 因为现在可用的内存只有4K,nand flash中的代码在复位后会移到内部ram中,此ram只有4K            bl      main                @ 调用C程序中的main函数halt_loop:            b       halt_loop
C语言代码:
#define GPFCON      (*(volatile unsigned long *)0x56000050)#define GPFDAT      (*(volatile unsigned long *)0x56000054)#define GPBCON      (*(volatile unsigned long *)0x56000010)#define GPBDAT      (*(volatile unsigned long *)0x56000014)/* * LED1,LED2,LED3、LED4对应GPB5、GPB6、GPB7、GPB8 */#define GPB5_out    (1<<(5*2))#define GPB6_out    (1<<(6*2))#define GPB7_out    (1<<(7*2))#define GPB8_out    (1<<(8*2))#define GPB5_msk    (3<<(5*2))#define GPB6_msk    (3<<(6*2))#define GPB7_msk    (3<<(7*2))#define GPB8_msk    (3<<(8*2))/* * K1,K2,K3,K4对应GPF1、GPF4、GPF2、GPF0 */#define GPF0_in     (0<<(0*2))#define GPF1_in     (0<<(1*2))#define GPF2_in     (0<<(2*2))#define GPF4_in     (0<<(4*2))#define GPF0_msk    (3<<(0*2))#define GPF1_msk    (3<<(1*2))#define GPF2_msk    (3<<(2*2))#define GPF4_msk    (3<<(4*2))int main(){        unsigned long dwDat;        // LED1,LED2,LED3,LED4对应的4根引脚设为输出        GPBCON &= ~(GPB5_msk | GPB6_msk | GPB7_msk | GPB8_msk);        GPBCON |= GPB5_out | GPB6_out | GPB7_out | GPB8_out;        // K1,K2,K3,K4对应的4根引脚设为输入        GPFCON &= ~(GPF0_msk | GPF1_msk | GPF2_msk | GPF4_msk);        GPFCON |= GPF0_in | GPF1_in | GPF2_in | GPF4_in;        while(1){            //若Kn为0(表示按下),则令LEDn为0(表示点亮)            dwDat = GPFDAT;             // 读取GPF管脚电平状态            if (dwDat & (1<<1))        // K1没有按下                GPBDAT |= (1<<5);       // LED1熄灭            else                    GPBDAT &= ~(1<<5);      // LED1点亮            if (dwDat & (1<<4))         // K2没有按下                GPBDAT |= (1<<6);       // LED2熄灭            else                    GPBDAT &= ~(1<<6);      // LED2点亮            if (dwDat & (1<<2))        // K3没有按下                GPBDAT |= (1<<7);       // LED3熄灭            else                    GPBDAT &= ~(1<<7);      // LED3点亮            if (dwDat & (1<<0))         // K4没有按下                GPBDAT |= (1<<8);       // LED4熄灭            else                    GPBDAT &= ~(1<<8);      // LED4点亮    }    return 0;}
Makefile:
    key_led.bin : crt0.S  key_led.c    arm-linux-gcc -g -c -o crt0.o crt0.S    arm-linux-gcc -g -c -o key_led.o key_led.c    arm-linux-ld -Ttext 0x0000000 -g  crt0.o key_led.o -o key_led_elf    arm-linux-objcopy -O binary -S key_led_elf key_led.bin    arm-linux-objdump -D -m arm  key_led_elf > key_led.disclean:    rm -f   key_led.dis key_led.bin key_led_elf *.o

编译后下载到TQ2440开发板后效果:
     

4、通过延时循环点亮LED灯
 与使用点亮一盏LED灯类似,通过循环与延时函数即可完成另LED循环闪烁的效果。

实验源码

0