0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何组合一排LED并使它们闪烁序列

454398 来源:wv 2019-10-25 09:36 次阅读

步骤1:材料

对于此项目,您将需要

Raspberry pi 3

七个LEDs

七个220欧姆电阻

一个10k欧姆电阻

一个按钮

您还需要计算机设置程序才能以裸机方式处理raspberry pi 3。查看我以前的指导,以了解如何为使用pi裸机设置环境。

此项目从开始到结束大概需要3-4个小时。

好,我们开始吧!!!!

步骤2:电路

要构建此模块,我们需要一行6个LED分别连接到GPIO 20-25。我们还需要一个连接到GPIO 27的指示灯。该指示灯将向我们指示是否已按下按钮。最后,我们需要连接按钮。按钮的一侧将连接到3.3v,另一侧连接到下拉引脚。我们将使用GPIO 17连接到按钮。 GPIO 17将成为我们的输入引脚。 GPIO 17连接到一个10k欧姆的电阻,该电阻连接到地(GND)。我们这样做是为了确保GPIO 17始终设置为低电平。如果不是,则该引脚有可能在高点和低点之间放弃,从而给我们带来随机的结果。为了避免这种情况,我们可以使用电阻较大的电阻将引脚下拉至0v。

在面包板上设置电路是一个简单的过程。请遵循上面的电路图。将引线的短边连接到GND,将长边连接到220欧姆电阻。对其他5个不同的led重复此操作。这样一来,您总共应该连接六个LED。从一端开始,将第一个LED的正极连接到GPIO 20,然后将下一个引脚连接到GPIO 21,依此类推。..最后一个LED应该连接到GPIO 25。

对于指示灯led连接led的短端连接到GND,长端连接到220 ohm电阻,然后将电阻连接到GPIO 17。

将按钮连接到试验板。我使用的按钮上有四个连接。我们将只使用底部的两个。将一端连接到正极轨,另一端连接到10k欧姆电阻。将GPIO 17连接到10k电阻。按下按钮时,它将GPIO 17连接至将引脚设置为高电平的正极。

将3.3v引脚连接至正极,并将GND引脚连接至负极。

最后将正轨和负轨连接在一起,以便可以使用两侧。

步骤3:代码:简介

编码部分是从上一个闪烁的项目中已经学到的东西建立的。

该项目中的两个新事物是,我们设置了堆栈框架的使用方式,以便我们可以模拟高级功能,并进行设置使用系统时钟等待特定毫秒数的等待函数。

堆栈是一种常见的编程结构。它实际上是一个地址序列,可用于临时存储内容。堆栈具有两个基本功能

您可以将项目推入堆栈顶部

,也可以将项目从堆栈顶部弹出

可以按不同的版本设置堆栈,但是对于该项目,我们将坚持默认配置。当您将某些东西推入堆栈时,它会放在顶部。当下一件物品被推入堆栈时,新物品将成为顶部,而旧物品将位于其下方。希望您以前曾经使用过堆栈,如果没有的话,可以在网上找到更多更深入的解释。幸运的是,Arm有一个push和pop指令,因此使用堆栈很容易组装。

我们将要探索的第二件事是访问系统计时器,这样我们可以将程序延迟一定的时间。

第4步:代码:堆栈/堆栈框架

设置要使用的堆栈就像一行代码一样简单。由于链接器的设置方式(kernel.ld),我们在编译时将所有代码插入0x8000之后。因此,我们需要将此值移到sp寄存器中。

mov sp,#0x8000

将其添加到代码顶部并使用堆栈应该没问题。

现在进入堆栈框架。堆栈框架基本上是当我们预留堆栈的一部分以用于过程调用时。这使我们能够实现高级语言(如Java和C ++)使用的功能。这些语言使用堆栈来跟踪函数调用。我们可以在汇编中做同样的事情。

堆栈框架:

要将函数调用模拟为高级语言,我们将保留寄存器我们想通过将它们放置在堆栈上来使用,然后如果需要将其用于变量,我们还可以在堆栈中预留本地内存。在函数末尾,我们必须破坏堆栈帧并将堆栈重置为以前的状态。

通常,如果函数需要返回任何内容,则应将其放在r0中。/p》

如果函数接受参数,则应将其放在函数分支的前面。

堆栈框架:SETUP

我们通过设置堆栈框架开始该功能。

push {r7,lr}

mov r7,sp

push {}

ldr,[r7,#8] @第一个参数与r7的偏移量为#8

然后我们通过清理堆栈框架来结束堆栈框架

pop

pop {r7,lr}

。此过程使我们无需更改任何寄存器即可调用函数。它还允许在函数内调用函数,因为堆栈框架将始终保留lr,因此允许进行多个级别的函数调用。

=======================================

stack frame visual

=======================================

0x0 | 《=sp

---------------------------------------

0x4 |

---------------------------------------

0x8 |

---------------------------------------

0x12|

---------------------------------------

0x16|

---------------------------------------

0x20|

---------------------------------------

0x24|

---------------------------------------

0x28|

======================================= Example Function with one argument.

_______________________________________ push {r1} @argument r1=0x1234

b ex_func =======================================

stack frame visual

=======================================

0x0 | 0x1234 《=sp The argument is pushed onto the stack

---------------------------------------

0x4 |

---------------------------------------

0x8 |

---------------------------------------

0x12|

---------------------------------------

0x16|

---------------------------------------

0x20|

---------------------------------------

0x24|

---------------------------------------

0x28|

======================================= ex_func:

push {r7,lr}

mov r7,sp @r7 will equal 0x8

=======================================

stack frame visual

=======================================

0x0 | 0x1234 The argument is pushed onto the stack

---------------------------------------

0x4 | lr

---------------------------------------

0x8 | r7 《=sp

---------------------------------------

0x12|

---------------------------------------

0x16|

---------------------------------------

0x20|

---------------------------------------

0x24|

---------------------------------------

0x28|

======================================= push {r1-r3} @using r1,r2,and r3 so we preserve them

=======================================

stack frame visual

=======================================

0x0 | 0x1234 The argument is pushed onto the stack

---------------------------------------

0x4 | lr

---------------------------------------

0x8 | r7

---------------------------------------

0x12| r3 saved register

---------------------------------------

0x16| r2 saved register

---------------------------------------

0x20| r1 《=sp saved register

---------------------------------------

0x24|

---------------------------------------

0x28|

=======================================

pop r1,[r7,#8] @remember r7=0x8, the old sp. To access the argument at 0x0 we need to go up by 8

@thats why we do [r7,#8] which is the same as putting the value at 0x0 (0x1234) into r1 sub sp,sp,#8 @moves sp down to create local memory

=======================================

stack frame visual

=======================================

0x0 | 0x1234 The argument is pushed onto the stack

---------------------------------------

0x4 | lr

---------------------------------------

0x8 | r7

---------------------------------------

0x12| r3 saved register

---------------------------------------

0x16| r2 saved register

---------------------------------------

0x20| r1 saved register

---------------------------------------

0x24| empty

---------------------------------------

0x28| empty 《=sp

======================================= To end the function we need to move the value to be returned if any into ro

步骤5:代码:系统计时器

要使用系统计时器设置延迟,我将其编写在一个单独的文件中,因此也可以在以后的项目中使用。为此,我们基本上需要访问计时器并获取初始时间戳。一旦有了,我们将再次访问时间戳。我们将从最初的时间戳中减去第二个时间戳,并将其与所需的值进行比较。

算法非常简单,最困难的部分是访问正确的寄存器。

计时器的基地址为0x3f003000

计时器的lo字的偏移量为0x4

计时器的高位字的偏移量为0x8

尝试编写自己的等待函数!如果需要参考,请附上我的代码。

步骤6:代码:获取输入

对于该项目,我使用了GPLEV0寄存器。本质上,它保持引脚0-31的状态。我们正在使用GPIO 17作为输入。要将此引脚设置为输入,我们必须访问FSEL1寄存器并清除GPIO 17专用的三位。

GPLEV0偏移量0x34

FSEL1偏移量0x04

通过掩码将GPIO 17设置为输入0xFF1FFFFF

我们还需要将位20-27设置为输出。

FSEL2偏移量0x08

将掩码设置为20到27以输出0x249249

由于我们使用的是输出,我们还需要访问GPSET0寄存器以打开引脚,而GPCLR0寄存器以关闭引脚

GPSET0偏移量0x1c

GPCLR0偏移量0x28

由于等待功能以微秒为单位,因此您可以使用以下几个值

半秒0x7a120 = 500,000微秒= 1/2秒

四分之一秒0x3d090 = 250,000微秒= 1/4秒

秒的八分之一0x1e848 = 125,000微秒= 1/8秒

好,让我们开始编码!

mov r0, @return

上面的代码设置了我们的代码,因此它可以正常运行。

Then we need to undo the stack frame

下一步我设置基址的地址和我们将要使用的偏移量。

Get rid of local memory created

在这里,我设置了一些以后将要使用的有用符号。

add sp,sp,#8

=======================================

stack frame visual

=======================================

0x0 | 0x1234 The argument is pushed onto the stack

---------------------------------------

0x4 | lr

---------------------------------------

0x8 | r7

---------------------------------------

0x12| r3 saved register

---------------------------------------

0x16| r2 saved register

---------------------------------------

0x20| r1 《=sp saved register

---------------------------------------

0x24| empty

---------------------------------------

0x28| empty

=======================================

出于可读性考虑,我为寄存器的目的设置了一些符号。

Replace saved registers

要将此引脚设置为输入,首先要获得适当的偏移,然后再加载掩码;最后,我将掩码写回到寄存器中。

pop {r1-r3}

=======================================

stack frame visual

=======================================

0x0 | 0x1234 The argument is pushed onto the stack

---------------------------------------

0x4 | lr

---------------------------------------

0x8 | r7 《=sp

---------------------------------------

0x12| r3

---------------------------------------

0x16| r2

---------------------------------------

0x20| r1

---------------------------------------

0x24| empty

---------------------------------------

0x28| empty

=======================================

我做的和输入一样,只是使用了不同的偏移量和掩码。

Replace r7 and link register

接下来,我开始主程序循环。我首先描述我要程序执行的操作。

pop {r7,lr}

=======================================

stack frame visual

=======================================

0x0 | 0x1234 The argument is pushed onto the stack

---------------------------------------

0x4 | lr 《=sp

---------------------------------------

0x8 | r7

---------------------------------------

0x12| r3

---------------------------------------

0x16| r2

---------------------------------------

0x20| r1

---------------------------------------

0x24| empty

---------------------------------------

0x28| empty

=======================================

我以一个小的等待值开始循环。

Finally, we need to clean up after the argument

add sp,sp,#4

=======================================

stack frame visual

=======================================

0x0 | 0x1234 《=sp

---------------------------------------

0x4 | lr

---------------------------------------

0x8 | r7

---------------------------------------

0x12| r3

---------------------------------------

0x16| r2

---------------------------------------

0x20| r1

---------------------------------------

0x24| empty

---------------------------------------

0x28| empty

=======================================

mov pc,lr Return

在这里,我正在检查引脚17的状态,该函数将返回r0中指定引脚的状态。我的所有功能都将在末尾列出。

Notice that nothing is overwritten in the stack. We simply move the stack pointer back to it‘s original place.

我检查返回值,然后跳转到一个功能,该功能可以打开指示灯并循环或关闭指示灯

如果按下该按钮,它将GPIO17连接到3.3v,因此将其设置为高电平。因此,如果按下按钮,输入功能将返回1,从而指示器打开并且LED的环路上升,从GPIO20到GPIO 26接通。

基本上就是这样。接下来,我将介绍在input_loop中调用的函数。

步骤7:代码:函数定义

首先,我们有get输入

b main

.section .text

main:

mov sp,#0x8000

我的函数有一个参数,即GPIO引脚的编号。该功能使用引脚号创建一个掩码来测试GPLEV0中的位。 tst执行逻辑“与”并设置标志。如果and返回true,则未设置零标志。

r1:0000_1000

r2:0000_1000

tst r2,r1

结果:未设置零标志

结果返回到r0。

.equ BASE_ADDR,0x3f200000 @Base address

.equ GPFSEL0, 0x0

.equ GPFSEL1, 0x04 @FSEL1 register offset | use to select GPIO 10-19 and set input/output/alt func

.equ GPFSEL2, 0x08 @FSEL2 register offset | use to select GPIO 20-29 and set input/output/alt func

.equ GPSET0, 0x1c @GPSET0 register offset| use to set GPIO’s logic level high(3.3v)

.equ GPCLR0, 0x28 @GPCLR0 register offset| use to set GPIO‘s logic level low(0v)

.equ GPLEV0, 0x34 @GPIO level offset | use to read current level of pin(on/off)[high/low]{3.3v/0v}

接下来,我有两个函数可以打开指示器并关闭指示灯。当指示灯打开时,该功能将分支并通过GPIO引脚循环。当指示灯熄灭时,该功能将通过GPIO引脚分支和向下循环。

.equ CLEAR_BITS21_23,0xFF1FFFFF @mask to clear bits 21 through 23 | use to set GPIO 17 to input

.equ SET_20_27,0x249249 @mask to set bits 20 through 27 | use to set GPIO 20-27 to output

.equ SET_BIT27,0x8000000 @mask to set bits 27 | use to set GPIO 27 to high(3.3v) or low(0v) GPIO 27 is indicator light

.equ half_second, 0x7a120 @hex value for half a second in microseconds

.equ quarter_second, 0x3d090 @hex value for quarter of a second in microseconds

.equ eighth_second,0x1e848 @hex value for eigth of a second in microseconds

前两个功能设置向上或向下循环功能。他们只是确保在循环开始之前将计数器设置为正确的数字。 loop_up和loop_down函数在本质上彼此相同。一个循环通过以GPIO 20开头并以GPIO 26结尾的引脚,然后循环通过以GPIO 26开头并以GPIO 20结尾的引脚。

循环位置i或j移入r0和然后调用turn_on函数。这会根据传递到r0的数字打开一个引脚。然后,循环将等待八分之一秒,然后再关闭引脚并递增或递减计数器。

base .req r1 @Sets symbol base to refer to r1: can use base and r1 interchangeably base《=》r1

ldr base,=BASE_ADDR @base = 0x3f20000, load base with the base address of peripheralsoffset .req r2 @Sets symbol offset to refer to r2: can use offset and r2 interchangeably offset《=》r2

mask .req r3 @Sets symbol mask to refer to r3 mask《=》r3

i .req r4 @Sets symbol i to refer to r4 i《=》r4

j .req r5 @Sets symbol j to refer to r5 j《=》r5

return .req r0 @return 《=》 r0

turn_on和turn_of函数。

步骤8:将它们放在一起。

现在,您已经编写了所有代码文件,您需要生成一个二进制kernel.img。我设置了一个简单的makefile,将其吐出来。只需下载它,然后将第4行的代码变量更改为文件名即可。

如果您无法使代码正常工作,请下载并编译我的代码,然后将kernel.img放到pi上。如果可以,那么如果不返回电路步骤并尝试重建电路,则代码可能存在问题。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • led
    led
    +关注

    关注

    242

    文章

    23173

    浏览量

    658791
  • 树莓派
    +关注

    关注

    116

    文章

    1701

    浏览量

    105559
收藏 人收藏

    评论

    相关推荐

    负载管的闪烁噪声和热噪声的区别

    负载管的闪烁噪声和热噪声是两种不同的噪声类型,它们在电子设备中的表现和影响各有特点。 闪烁噪声(1/f噪声) 定义 : 闪烁噪声,也称为1/f噪声或粉红噪声,是
    的头像 发表于 10-10 11:19 385次阅读

    继电器组合组合架的作用

    继电器组合组合架是电气控制系统中的重要组成部分,它们在电路中起到保护、控制和信号传递的作用。继电器组合组合架的设计和应用对于确保电气系统
    的头像 发表于 09-27 14:35 464次阅读

    文全了解麦克风阵列

    什么是麦克风阵列? 想象一下一个小型音响部队在你面前,它们站成一排,用不同的麦克风捕捉声音。这就是麦克风阵列的基本概念。麦克风阵列由多个麦克风组成,按照特定的布局排列在起,用来捕捉和
    的头像 发表于 09-03 16:03 1154次阅读
    <b class='flag-5'>一</b>文全了解麦克风阵列

    【「时间序列与机器学习」阅读体验】全书概览与时间序列概述

    它们都试图从数据中获取信息、发现模式,某种程度上预测未来的数据。2.多维时间序列 多维时间序列是指在同时间点上收集的多个相关变量的观测
    发表于 08-07 23:03

    闪烁发光二极管的工作原理及应用电路

    闪烁发光二极管,简称闪烁LED,是种能够自主发出闪烁光线的LED。它的工作原理与普通
    的头像 发表于 06-08 11:39 2711次阅读
    <b class='flag-5'>闪烁</b>发光二极管的工作原理及应用电路

    时间序列分析的异常检测综述

    时间序列是在不同时点记录个或多个变量值的数据。例如,每天访问网站的人数、每月城市的 average 温度、每小时的股票价格等。时间序列非常重要,因为它们允许我们分析过去,理解现在,
    的头像 发表于 03-11 09:36 601次阅读
    时间<b class='flag-5'>序列</b>分析的异常检测综述

    5050RGB三合一LED WS2850B数据手册

    电子发烧友网站提供《5050RGB三合一LED WS2850B数据手册.pdf》资料免费下载
    发表于 03-07 18:16 1次下载

    多杆合一、多感合一的智慧灯杆新发展模式

    智慧灯杆在城市建设中的作用愈发重要,实现多杆合一、多感合一,促进城市智能化、便捷化、绿色化发展已迫在眉睫!
    的头像 发表于 03-06 17:05 447次阅读
    多杆<b class='flag-5'>合一</b>、多感<b class='flag-5'>合一</b>的智慧灯杆新发展模式

    如何将LED连接到Arduino板使其闪烁

     在本快速入门指南中,您将学习如何将 LED 连接到 Arduino 板使其闪烁
    的头像 发表于 02-11 10:53 2097次阅读
    如何将<b class='flag-5'>LED</b>连接到Arduino板<b class='flag-5'>并</b>使其<b class='flag-5'>闪烁</b>

    使用GTM中断实现LED的500ms间隔的闪烁LED没有闪烁的原因?

    计数值大小,每当等于500时LED电平就翻转次。但实际的运行结果,LED并没有闪烁,更奇怪的是把计数值的判断 和LED翻转的代码直接放在G
    发表于 02-02 12:14

    LED灯关灯后闪烁的解决方法

    LED灯以其亮度大、耗能低、寿命长等特点,逐步霸占当今电灯市场。般来说,LED灯是很难发生问题的,在LED灯的问题中,不外乎三种毛病:灯不亮、灯变暗、关灯后
    发表于 02-01 16:40 1871次阅读

    三星电子推出全球首款商用透明Micro LED

    三星电子推出了全球首款商用透明Micro LED。在Micro LED展厅的中央,安装了211英寸透明Micro LED,给人种在大型足球场第一排
    发表于 01-17 11:41 440次阅读

    VD6283TX环境光传感器(2)----移植闪烁频率代码

    100 Hz或120 Hz的闪烁频率。为了消除这种可见闪烁减少其对人体的潜在影响,许多LED灯采用了脉冲宽度调制(PWM)的调光方法,从而实现更高的
    的头像 发表于 12-28 10:17 549次阅读
    VD6283TX环境光传感器(2)----移植<b class='flag-5'>闪烁</b>频率代码

    什么是电阻?电阻的识别技巧介绍

    电阻,也称为集成电阻或网络电阻器,是种将多个电阻集中封装在起的电阻器件。它们个引脚都连到
    的头像 发表于 12-14 10:10 1680次阅读

    LED闪烁的原因 LED闪烁故障解决方法

    LED闪烁的原因 LED闪烁故障解决方法 LED闪烁是指在正常使用过程中,
    的头像 发表于 12-11 15:31 7694次阅读