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
    +关注

    关注

    244

    文章

    24715

    浏览量

    692425
  • 树莓派
    +关注

    关注

    122

    文章

    2082

    浏览量

    110753
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    RT1176 定制板 – 重置后 LED 闪烁应用程序不运行怎么解决?

    简单的 LED 闪烁项目。 将 GPIO 配置为输出,使用 SysTick 每 1 秒切换次。 Used MCUXpresso 配置工具 25.06 to configure th
    发表于 04-06 07:54

    如何使用 VisionFive 使 LED 在 PWM 频率下闪烁

    使用 VisionFive 使 LED 在 PWM 频率下闪烁
    发表于 03-27 08:09

    如何使用 VisionFive GPIO 使 LED 闪烁

    使用 VisionFive GPIO 使 LED 闪烁
    发表于 03-27 07:48

    交换机上的SFP口不只是“插光纤”:从数据中心到工业现场的实战解析

    在很多中高端交换机上,我们都能看到一排排纤薄的SFP插槽。它们并非装饰,而是构建高速、可靠网络的核心物理接口 。本文将抛开枯燥的参数表,从真实应用场景出发,看看SFP光模块如何赋能各行业数字化转型。
    的头像 发表于 02-24 15:57 575次阅读
    交换机上的SFP口不只是“插光纤”:从数据中心到工业现场的实战解析

    运行 debian 69 红色电源 LED 旁边的绿色闪烁 LED 是什么意思?

    运行 debian 69 红色电源 LED 旁边的绿色闪烁 LED 是什么意思?
    发表于 02-03 07:52

    探索MAX25603:汽车组合大灯的理想LED控制器

    探索MAX25603:汽车组合大灯的理想LED控制器 在汽车照明领域,款性能卓越的LED控制器对于实现高效、稳定且多功能的照明系统至关重要。今天,我们就来深入了解
    的头像 发表于 01-30 16:10 255次阅读

    合科泰教你如何焊接简单LED闪烁电路

    你是否曾好奇那些闪烁LED灯背后的原理?今天教你用5分钟焊接个简单的LED闪烁电路,无需编程,只需
    的头像 发表于 01-07 17:28 1317次阅读
    合科泰教你如何焊接简单<b class='flag-5'>LED</b><b class='flag-5'>闪烁</b>电路

    FP8013在便携设备LED驱动中的应用设计:攻克低压差条件下的亮度衰减与闪烁问题

    你是否经常遇到,单节锂电池供电的手电筒或头灯,在电量消耗到定程度后,灯光就开始闪烁或明显变暗?  ” “这问题的根本原因,在于“低压差”应用导致。当电池电压持续降低,导致输入与输出之间的压差收窄至临界点时,传统驱动芯片便无
    的头像 发表于 12-23 15:37 1076次阅读
    FP8013在便携设备<b class='flag-5'>LED</b>驱动中的应用设计:攻克低压差条件下的亮度衰减与<b class='flag-5'>闪烁</b>问题

    【瑞萨RA6E2地奇星开发板试用】串口下载烧录程序使LED闪烁频率变慢

    成功后会给出提示,如是下载失败,尝试按下复位按键。成功下载如下图所示: 下载烧录的程序使LED闪烁频率变慢如下图所示: 详细代码如下图: 详细见视频。至此我们的串口下载成功。
    发表于 12-06 01:47

    基于芯源CW32 MCU的LED闪烁示例及代码分析

    最近我在项目中使用了芯源的CW32 MCU,这是款非常适合物联网和低功耗应用的微控制器。在初步学习和使用中,我做了个简单的LED闪烁实验,通过这篇帖子给大家分享
    发表于 12-04 06:52

    不止是变身,鸿蒙二合一1+1&amp;gt;2的秘密

    鸿蒙二合一,才是真的二合一
    的头像 发表于 11-26 15:05 4495次阅读
    不止是变身,鸿蒙二<b class='flag-5'>合一</b>1+1&amp;gt;2的秘密

    LP5560可编程单LED驱动器数据手册总结

    LP5560 是款可编程 LED 驱动器,可生成各种闪烁序列,每个序列最多三个不同长度的脉冲。闪烁
    的头像 发表于 08-29 11:07 1320次阅读
    LP5560可编程单<b class='flag-5'>LED</b>驱动器数据手册总结

    【创龙TLT113-MiniEVM开发板试用体验】T113开发板LED闪烁控制终极教程

    前言 本教程专为创龙TLT113-MiniEVM开发板编写,提供多种LED闪烁控制方法。无论您是嵌入式开发新手还是有经验工程师,都能找到适合您的解决方案。教程包含Shell脚本、C语言程序、系统服务
    发表于 08-06 13:56

    银月光655nm VCSEL+460nm LED合一光源,赋能生发设备新升级

    深圳市银月光科技推出655nm VCSEL+460nm LED合一光源,融合高效光束与杀菌抑炎功能,助力高端生发设备,提升产品竞争力。
    的头像 发表于 08-05 18:12 1098次阅读

    5050 RGBW 四合一全彩 LED 灯珠

    20mA*4 功能性5050 RGBW 四合一全彩 LED 灯珠是种集成了红(Red)、绿(Green)、蓝(Blue)和白(White)四种颜色 LED 芯片的照明元件。这种灯珠因
    发表于 06-27 10:02