• 一步一步点亮Led


    1.了解物理特性

    点亮LED的关键在于电压差

    2.查阅原理图了解板载LED的硬件接法

    方法:可以利用PDF文档的搜索功能(搜索LED即可,在底板搜索)

    可知:有4颗正极接3.3V,负极分别接SoC上面的引脚(即引脚低电平亮),另外一个开机常亮。

    3个SoC引脚是知道的,另外在核心板上查看pwmtout1可知引脚为GPD0_1,如下图

    GPD0表示端口号,后面的1是引脚号

    3.查阅数据手册

    当我们想要编程操控GPIO来操作LED时,需要通读一下数据手册关于GPIO的部分

    我们要操作的硬件为LED, 通过GPIO间接控制,实际要操作的设备是GPIO。

    3.1、GPJ0相关的寄存器如下

    其中,最主要的寄存器有:GPJ0_DAT, GPJ0CON

    3.2、以下为GPJ0CON寄存器:

    GPJ0这个端口的第一个引脚GPJ0_0对应寄存器GPJ0_CON的bit0~bit3, 点亮LED时应该将这个引脚配置成output模式。

    3.3、GPJ0DAT寄存器介绍

    GPJ0DAT[7:0]后面的7:0表示GPJ0对应的0~7引脚,后面的BIT[7:0]表示GPJ0DAT寄存器的bit0~bit7,从这里可以知道,
    GPJ0端口的每一个引脚分别对应GPJODAT寄存器的每一个bit位。
     
    3.4、总结
    根据以上,我们就知道如何点亮LED
    (1)操控GPJ0CON寄存器,选中为output模式。
    (2)操控GPJ0DAT寄存器,选择相应位为低电平。
     
    4.一步一步点亮le
    4.1、点亮led灯
     1 _start:
     2     // 第一步:把0x11111111写入0xE0200240(GPJ0CON)位置
     3     ldr r0, =0x11111111            // 从后面的=可以看出用的是ldr伪指令,因为需要编译器来判断这个数
     4     ldr r1, =0xE0200240            // 是合法立即数还是非法立即数。一般写代码都用ldr伪指令
     5     str r0, [r1]                // 寄存器间接寻址。功能是把r0中的数写入到r1中的数为地址的内存中去
     6 
     7     // 第二步:把0x0写入0xE0200244(GPJ0DAT)位置
     8     ldr r0, =0x0
     9     ldr r1, =0xE0200244
    10     str r0, [r1]                // 把0写入到GPJ0DAT寄存器中,引脚即输出低电平,LED点亮
    11 
    12 flag:                            // 这两行写了一个死循环。因为裸机程序是直接在CPU上运行的,CPU会
    13     b flag                        // 逐行运行裸机程序直到CPU断电关机。如果我们的程序所有的代码都
    14                                 // 执行完了CPU就会跑飞(跑飞以后是未定义的,所以千万不能让CPU
    15                                 // 跑飞),不让CPU跑飞的办法就是在我们整个程序执行完后添加死循环
    View Code

    4.2、改进代码1

     1 #define GPJ0CON    0xE0200240
     2 #define GPJ0DAT    0xE0200244
     3 
     4 .global _start                    // 把_start链接属性改为外部,这样其他文件就可以看见_start了
     5 _start:
     6     // 第一步:把所有引脚都设置为输出模式,代码不变
     7     ldr r0, =0x11111111            // 从后面的=可以看出用的是ldr伪指令,因为需要编译器来判断这个数
     8     ldr r1, =GPJ0CON            // 是合法立即数还是非法立即数。一般写代码都用ldr伪指令
     9     str r0, [r1]                // 寄存器间接寻址。功能是把r0中的数写入到r1中的数为地址的内存中去
    10 
    11     // 第二步:把中间LED(GPJ0_4)的输出设置为0,其余两颗设置为1,剩下的其他位不管
    12     ldr r0, =0x28
    13     ldr r1, =GPJ0DAT
    14     str r0, [r1]                // 把0写入到GPJ0DAT寄存器中,引脚即输出低电平,LED点亮
    15 
    16     b .                            // .代表当前这一句指令的地址,这个就是高大上的死循环
    View Code

    上述代码改进:

    (1)用宏定义来替换地址的数字

    (2)用b .来替换以前的死循环

    (3)加上.global _start(将_start的链接属性改为外部链接)

    改变:代码把4.1中点亮的led改为点亮中间的led。

    4.3、改进代码2

    在4.2中的缺陷:需要人为的计算0x28这个特定值,而且可读性不好。

    解决方案:在写代码时用位运算让编译器帮我们计算特定值。
     1 #define GPJ0CON    0xE0200240
     2 #define GPJ0DAT    0xE0200244
     3 
     4 .global _start                    // 把_start链接属性改为外部,这样其他文件就可以看见_start了
     5 _start:
     6     // 第一步:把所有引脚都设置为输出模式,代码不变
     7     ldr r0, =0x11111111            // 从后面的=可以看出用的是ldr伪指令,因为需要编译器来判断这个数
     8     ldr r1, =GPJ0CON            // 是合法立即数还是非法立即数。一般写代码都用ldr伪指令
     9     str r0, [r1]                // 寄存器间接寻址。功能是把r0中的数写入到r1中的数为地址的内存中去
    10 
    11     // 第二步:把中间LED(GPJ0_4)的输出设置为0,其余两颗设置为1,剩下的其他位不管
    12     //ldr r0, =((1<<3) | (1<<5))    // 等效于0b00101000,即0x28
    13     ldr r0, =((1<<3) | (0<<4) | (1<<5))    // 清清楚楚的看到哪个灭,哪个是亮
    14     ldr r1, =GPJ0DAT
    15     str r0, [r1]                // 把0写入到GPJ0DAT寄存器中,引脚即输出低电平,LED点亮
    16 
    17     b .                            // .代表当前这一句指令的地址,这个就是高大上的死循环
    View Code

    4.4、改进代码3

    加上延时函数和一些功能

     1 #define GPJ0CON    0xE0200240
     2 #define GPJ0DAT    0xE0200244
     3 
     4 .global _start                    // 把_start链接属性改为外部,这样其他文件就可以看见_start了
     5 _start:
     6     // 第一步:把所有引脚都设置为输出模式,代码不变
     7     ldr r0, =0x11111111            // 从后面的=可以看出用的是ldr伪指令,因为需要编译器来判断这个数
     8     ldr r1, =GPJ0CON            // 是合法立即数还是非法立即数。一般写代码都用ldr伪指令
     9     str r0, [r1]                // 寄存器间接寻址。功能是把r0中的数写入到r1中的数为地址的内存中去
    10 
    11     // 要实现流水灯,只要在主循环中实现1圈的流水显示效果即可
    12 flash:
    13     // 第1步:点亮LED1,其他熄灭
    14     //ldr r0, =((0<<3) | (1<<4) | (1<<5))    // 清清楚楚的看到哪个灭,哪个是亮
    15     ldr r0, =~(1<<3)
    16     ldr r1, =GPJ0DAT
    17     str r0, [r1]                // 把0写入到GPJ0DAT寄存器中,引脚即输出低电平,LED点亮
    18     // 然后延时
    19     bl delay                    // 使用bl进行函数调用
    20     
    21     // 第2步:点亮LED2,其他熄灭    
    22     ldr r0, =~(1<<4)
    23     ldr r1, =GPJ0DAT
    24     str r0, [r1]                // 把0写入到GPJ0DAT寄存器中,引脚即输出低电平,LED点亮
    25     // 然后延时
    26     bl delay                    // 使用bl进行函数调用
    27     
    28     // 第3步:点亮LED3,其他熄灭    
    29     ldr r0, =~(1<<5)
    30     ldr r1, =GPJ0DAT
    31     str r0, [r1]                // 把0写入到GPJ0DAT寄存器中,引脚即输出低电平,LED点亮
    32     // 然后延时
    33     bl delay                    // 使用bl进行函数调用
    34     
    35     b flash
    36 
    37 
    38 // 延时函数:函数名:delay
    39 delay:
    40     ldr r2, =9000000
    41     ldr r3, =0x0
    42 delay_loop:    
    43     sub r2, r2, #1                //r2 = r2 -1
    44     cmp r2, r3                    // cmp会影响Z标志位,如果r2等于r3则Z=1,下一句中eq就会成立
    45     bne delay_loop
    46     mov pc, lr                    // 函数调用返回
    View Code

    关键知识点:

    (1)B常用于不返回的跳转,比如跳到某个标号处,BL则用于子程序跳转(要返回,返回地地存于LR)

    (2)在子函数中一般用mov pc, lr 这句指令来用于调用返回

    (3)在延时函数中 

    cmp r2, r3     // cmp会影响Z标志位,如果r2等于r3则Z=1,下一句中eq就会成立

    bne delay_loop

    ne为条件后缀,成立则执行这条指令

    /********************************************************

     * 以上知识来自于朱老师物联网大讲堂

     *******************************************************/

  • 相关阅读:
    PHP分页类
    phpexcel 控制导出数据内容和行数
    phpexcel 导入 和 导出
    PHP无限极分类
    php 对查询结果集进行排序
    php 删除文件夹及文件夹内文件函数
    php 字符串截取函数
    php 获取用户登录的ip
    js layer页面层加载新网站
    分享到qq
  • 原文地址:https://www.cnblogs.com/zou27/p/5022460.html
Copyright © 2020-2023  润新知