zoukankan      html  css  js  c++  java
  • 跟着韦老师学Linux学习笔记(一)-GPIO

    学编程,第一个程序肯定是“hello world”,学单片机或ARM,最初学的肯定是GPIO的操作。在这一节课里主要涉及到了点亮LED和按键控制LED。

    1、要想点亮一个LED,分以下几个步:

    ①、了解相关硬件

    ②、配置Gpio的相关寄存器

    ③、编写相关代码

    ④、编译下载

    2、一般来说,要想点亮LED,只需要控制相关的gpio口输出高电平或低电平就可以了。通过查看2440的原理图可以知道(如下图所示):

     

    3个LED的阴极经过1K的限流电阻连接到GPF4、GPF5和GPF6三个Gpio口上了。因此我们只要让PF4、GPF5和GPF6输出低电平,就能点亮LED,高电平熄灭LED。

    3、查看2440的DataSheet 可以知道,Gpio主要有三个寄存器需要设置,再本篇中分别是GPFCON、GPFDAT和GPFUP。

     

    其中:

         GPFCON是控制寄存器,主要是控制GPIO的功能,主要有输入、输出和中断三个功能。其中每个GPIO口有寄存器的两位来控制,00:输入,01:输出,10:中断,10:保留。

         GPFDAT是数据寄存器,主要是控制GPIO输出高电平还是低电平,0:低电平,1:高电平。

         GPFUP 是设置内部上拉电阻的寄存器,0:不设置上拉电阻,1:设置上拉电阻。

    4、编辑代码

    在教程中的第一个代码使用汇编语言编写的,代码非常简单。如下:

     1 .text
     2 .global _start
     3 _start:
     4 LDR    R0,=0x56000050
     5 MOV R1,#0x00000400
     6 STR    R1,[R0]    
     7 LDR    R0,=0x56000054    
     8 MOV    R1,#0x00000000
     9 STR    R1,[R0]
    10 MAIN_LOOP:
    11     B        MAIN_LOOP

     下面主要分一下这个代码:

    .text:这个是GCC编译器里面的一个关键词,它指定了后续编译出来的代码放在可执行代码段,是处理器开始执行代码的地方。

    .global _start 告诉编译器后续跟的是一个全局可见的名字(可能是变量,也可以是函数名),.global让 _start 符号成为可见的标识符,这样链接器就知道跳转到程序中的什么地方并开始执行。_start是一个函数的起始地址,也是编译、链接后程序的起始地址。由于程序是通过加载器来加载的,必须要找到 _start名字的函数,因此_start必须定义成全局的,以便存在于编译后的全局符合表中,供其它程序寻找到。

    _start是程序的起始地址

    LDR R0,=0x56000050

    MOV R1,#0x00000400

    STR R1,[R0]

    这三句主要实现了对GPFCON寄存器的设置,这里首先是把R0设为了GPFCON的寄存器地址,然后给R1赋值,最后把R1的值赋到以R0为地址的寄存器里,从而配置相应端口的功能。这里是0x00000400,正好是GPFCON的[11:10]设置为了01 ,即是GPF5位输出功能。

    LDR R0,=0x56000054                

    MOR R1,#0x00000000

    STR R1,[R0]

    这三句代码和上面类似,只要实现了GPFDAT输出低电平,这里是GPF5输出低电平,因为只有GPF5端口被设置为了输出功能。

    MAIN_LOOP:

               B MAIN_LOOP

    这句是个死循环没有什么太大意思。

    5、编译下载

    程序的编译命令时通过编写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

    arm-linux-gcc:

               -g:产生供gdb调试用的可执行文件

               -c:只编译不连接

               -o: 指定输出文件名。这里指定的是生成led_on.o

    arm-linux-ld:      

               -o:指定输出文件名。这里生成lec_on.elf。

               -Ttext: 设置代码段的起始地址:0x0000000。

    arm-linux-objcopy:

               -O: 输出的格式, binary指二进制文件。这里生成led_on.bin。

               -S: 不从源文件中复制重定位信息和符号信息到目标文件中

    Clean:

               是清除命令,清除make生成的文件,这里指的是清除led_on.bin 、led_on_elf以及所有的.o文件。*是通配符。

    然后我们linux环境下,执行make命令来编译文件生成可执行文件并下载到开发板上,可以观察到led2被点亮。开发板自带的有下载教程“如何烧写S3C2440裸板程序.pdf”。

    在接下来的视频教程中,主要讲解了如何用c语言来编写程序点亮led灯。用c程序来操作gpio口,首先要设置相关硬件,关看门狗,设置栈,这些功能是在汇编文件里编写的。

     1 .text
     2 .global _start
     3 _start:
     4                 ldr        r0, =0x53000000
     5                 mov        r1, #0x0
     6                 str        r1,[r0]                
     7                 ldr        sp, =1024*4
     8                 bl        main
     9 halt_loop:
    10                 b    halt_loop

    代码和上面的类似:

    ldr           r0, =0x53000000

    mov           r1, #0x0

    str           r1,[r0]   

    这三句代码是通过写0关闭看门狗,否则CPU会不断地重启。

    ldr           sp, =1024*4

    设置我们的堆栈空间的大小,这里设置为4K,因为2440的内部RAM只有4K。

    bl            main

    调用我们写的c函数

    接下来是个死循环。

    C函数:

    1 #define GPFCON (*(volatile unsigned long *) 0x56000050)
    2 #define GPFDAT (*(volatile unsigned long *) 0x56000054)
    3 int main()
    4 {
    5     GPFCON = 0x00000100;
    6     GPFDAT = 0x00000000;
    7     
    8     return 0;
    9 }

    在这里最重要的是GPFCON和GPFDAT这两个宏的定义,这是指向这两个寄存器地址的指针。

    例如:

    int a;

    int *p;

    p=&a;

    *p = 0x100;//这就是把变量a赋值为0x100

    在我们的程序中:

    地址是(volatile unsigned long *) 0x56000050,即是p=(volatile unsigned long *) 0x56000050,*p=(*(volatile unsigned long *) 0x56000050),GPFCON和GPFDAT两个宏的意思就是*p。

    其他就是往寄存器里赋值就行。

    编译下载:

    1 led_on_c.bin : crt0.S  led_on_c.c
    2     arm-linux-gcc -g -c -o crt0.o crt0.S
    3     arm-linux-gcc -g -c -o led_on_c.o led_on_c.c
    4     arm-linux-ld -Ttext 0x0000000 -g  crt0.o led_on_c.o -o led_on_c_elf
    5     arm-linux-objcopy -O binary -S led_on_c_elf led_on_c.bin
    6     arm-linux-objdump -D -m arm  led_on_c_elf > led_on_c.dis
    7 clean:
    8     rm -f led_on_c.dis led_on_c.bin led_on_c_elf *.o

    这个Makefile只是比前面多了一句:

    arm-linux-objdump -D -m arm  led_on_c_elf > led_on_c.dis

    只一句是用来生成反汇编代码的语句,

               -D:反汇编所有代码。

               -m:反汇编目标文件时使用的架构。这里是arm架构。

    下载如上。

    接下来的流水灯实验和按键控制led的实验,本质上与上面的c程序类似,重要点主要是涉及的位操作。

     1 #define    GPF4_out    (1<<(4*2))
     2 #define    GPF5_out    (1<<(5*2))
     3 #define    GPF6_out    (1<<(6*2))
     4 
     5 #define    GPF4_msk    (3<<(4*2))
     6 #define    GPF5_msk    (3<<(5*2))
     7 #define    GPF6_msk    (3<<(6*2))
     8         // LED1,LED2,LED4对应的3根引脚设为输出
     9         GPFCON &= ~(GPF4_msk | GPF5_msk | GPF6_msk); //对寄存器的相应位的清零操作。
    10         GPFCON |= GPF4_out | GPF5_out | GPF6_out;//对寄存器的相应位的赋值操作。

    位操作的好处是,清零时只清零相应位,赋值时也只赋值相应位,对其他为不产生影响,防止破坏程序。

    好了,第一节课的笔记到此为止,这也是第一次写博客,没什么太难的内容,只是上课的一些笔记(记性不好,还是写下来忘了方便查看)。再接再厉。

  • 相关阅读:
    Blazor Webassembly本地化的实现
    一分钟搞清C++中的指向常量的指针和常量型指针
    如何使新Edge和旧Edge并行使用
    Build 2020上公布的C# 9.0 新特性
    C# 8.0 新特性之二:接口默认实现
    如何用代码来快速批量下载人教社中小学电子教材
    三大常用数据库事务详解之三:事务运行模式
    三大常用关系型数据库事务详解之二:基本事务命令
    三大关系型数据库事务详解之一:基本概念
    自然语言处理学习笔记之一:概要
  • 原文地址:https://www.cnblogs.com/tianhaoyuan/p/6472263.html
Copyright © 2011-2022 走看看