分类 树莓派 下的文章

树莓派是一个很棒的游戏平台。在我们的系列文章的第九篇中学习如何开始使用树莓派。

回到我们关于树莓派入门系列文章的第五篇,我提到 Minecraft 是一种教孩子们使用游戏平台进行编程的方法。作为一个不错的游戏平台,今天我们将讨论在树莓派上使用或者不使用模拟器来玩游戏的方式。

使用模拟器玩游戏

模拟器是一种能让你在树莓派上玩不同系统、不同年代游戏的软件。在如今众多的模拟器中,RetroPi 是树莓派中最受欢迎的。你可以用它来玩 Apple II、Amiga、Atari 2600、Commodore 64、Game Boy Advance 和其他许多游戏。

如果 RetroPi 听起来有趣,请阅读这些说明开始使用,玩得开心!

原生 Linux 游戏

树莓派的操作系统 Raspbian 上也有很多原生 Linux 游戏。“Make Use Of” 有一篇关于如何在树莓派上玩 10 个老经典游戏,如 Doom 和 Nuke Dukem 3D 的文章。

你也可以将树莓派用作游戏服务器。例如,你可以在树莓派上安装 Terraria、Minecraft 和 QuakeWorld 服务器。


via: https://opensource.com/article/19/3/play-games-raspberry-pi

作者:Anderson Silva 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

欢迎进入输入课程系列。在本系列,你将会学会如何使用键盘接收输入给树莓派。我们将会从揭示输入开始本课,然后转向更传统的文本提示符。

这是第一堂输入课,会教授一些关于驱动和链接的理论,同样也包含键盘的知识,最后以在屏幕上显示文本结束。

1、开始

希望你已经完成了 OK 系列课程,这会对你完成屏幕系列课程很有帮助。很多 OK 课程上的文件会被使用而不会做解释。如果你没有这些文件,或者希望使用一个正确的实现,可以从该堂课的下载页下载模板。如果你使用你自己的实现,请删除调用了 SetGraphicsAddress 之后全部的代码。

2、USB

如你所知,树莓派 B 型有两个 USB 接口,通常用来连接一个鼠标和一个键盘。这是一个非常好的设计决策,USB 是一个非常通用的接口,很多种设备都可以使用它。这就很容易为它设计新外设,很容易为它编写设备驱动,而且通过 USB 集线器可以非常容易扩展。还能更好吗?当然是不能,实际上对一个操作系统开发者来说,这就是我们的噩梦。USB 标准太大了。我是说真的,在你思考如何连接设备之前,它的文档将近 700 页。

USB 标准的设计目的是通过复杂的软件来简化硬件交互。

我和很多爱好操作系统的开发者谈过这些,而他们全部都说几句话:不要抱怨。“实现这个需要花费很久时间”,“你不可能写出关于 USB 的教程”,“收益太小了”。在很多方面,他们是对的,我不可能写出一个关于 USB 标准的教程,那得花费几周时间。我同样不能教授如何为全部所有的设备编写外设驱动,所以使用自己写的驱动是没什么用的。然而,即便不能做到最好,我仍然可以获取一个正常工作的 USB 驱动,拿一个键盘驱动,然后教授如何在操作系统中使用它们。我开始寻找可以运行在一个甚至不知道文件是什么的操作系统的自由驱动,但是我一个都找不到,它们都太高层了,所以我尝试写一个。大家说的都对,这耗费了我几周时间。然而我可以高兴的说我做的这些工作没有获取操作系统以外的帮助,并且可以和鼠标和键盘通信。这绝不是完整的、高效的,或者正确的,但是它能工作。驱动是以 C 编写的,而且有兴趣的可以在下载页找到全部源代码。

所以,这一个教程不会是 USB 标准的课程(一点也没有)。实际上我们将会看到如何使用其他人的代码。

3、链接

既然我们要引进外部代码到操作系统,我们就需要谈一谈 链接 linking 。链接是一种过程,可以在程序或者操作系统中链接函数。这意味着当一个程序生成之后,我们不必要编写每一个函数(几乎可以肯定,实际上并非如此)。链接就是我们做的用来把我们程序和别人代码中的函数连结在一起。这个实际上已经在我们的操作系统进行了,因为链接器把所有不同的文件链接在一起,每个都是分开编译的。

链接允许我们制作可重用的代码库,所有人都可以在他们的程序中使用。

有两种链接方式:静态和动态。静态链接就像我们在制作自己的操作系统时进行的。链接器找到全部函数的地址,然后在链接结束前,将这些地址都写入代码中。动态链接是在程序“完成”之后。当程序加载后,动态链接器检查程序,然后在操作系统的库找到所有不在程序里的函数。这就是我们的操作系统最终应该能够完成的一项工作,但是现在所有东西都将是静态链接的。

程序经常调用调用库,这些库会调用其它的库,直到最终调用了我们写的操作系统的库。

我编写的 USB 驱动程序适合静态编译。这意味着我给你的是每个文件的编译后的代码,然后链接器找到你的代码中的那些没有实现的函数,就将这些函数链接到我的代码。在本课的 下载页 是一个 makefile 和我的 USB 驱动,这是接下来需要的。下载并使用这个 makefile 替换你的代码中的 makefile, 同事将驱动放在和这个 makefile 相同的文件夹。

4、键盘

为了将输入传给我们的操作系统,我们需要在某种程度上理解键盘是如何实际工作的。键盘有两种按键:普通键和修饰键。普通按键是字母、数字、功能键,等等。它们构成了键盘上几乎全部按键。修饰键是多达 8 个的特殊键。它们是左 shift、右 shift、左 ctrl、右 ctrl、左 alt、右 alt、左 GUI 和右 GUI。键盘可以检测出所有的组合中那个修饰键被按下了,以及最多 6 个普通键。每次一个按钮变化了(例如,是按下了还是释放了),键盘就会报告给电脑。通常,键盘也会有 3 个 LED 灯,分别指示大写锁定,数字键锁定,和滚动锁定,这些都是由电脑控制的,而不是键盘自己。键盘也可能有更多的灯,比如电源、静音,等等。

对于标准 USB 键盘,有一个按键值的表,每个键盘按键都一个唯一的数字,每个可能的 LED 也类似。下面的表格列出了前 126 个值。

表 4.1 USB 键盘值

序号描述序号描述序号描述序号描述
4aA5bB6cC7dD
8eE9fF10gG11hH
12iI13jJ14kK15lL
16mM17nN18oO19pP
20qQ21rR22sS23tT
24uU25vV26wW27xX
28yY29zZ301!312@
323#334$345%356^
367&378*389(390)
40ReturnEnter41Escape42DeleteBackspace43Tab
44Spacebar45-_46=+47[{
48]}49\ 和 ``50#~51;:
52'"53`~54,<55.>
56/?57Caps Lock58F159F2
60F361F462F563F6
64F765F866F967F10
68F1169F1270Print Screen71Scroll Lock
72Pause73Insert74Home75Page Up
76Delete forward77End78Page Down79Right Arrow
80Left Arrow81Down Arrow82Up Arrow83Num Lock
84小键盘 /85小键盘 *86小键盘 -87小键盘 +
88小键盘 Enter89小键盘 1End90小键盘 2Down Arrow91小键盘 3Page Down
92小键盘 4Left Arrow93小键盘 594小键盘 6Right Arrow95小键盘 7Home
96小键盘 8Up Arrow97小键盘 9Page Up98小键盘 0Insert99小键盘 .Delete
100\ 和 ``101Application102Power103小键盘 =
104F13105F14106F15107F16
108F17109F18110F19111F20
112F21113F22114F23115F24
116Execute117Help118Menu119Select
120Stop121Again122Undo123Cut
124Copy125Paste126Find127Mute
128Volume Up129Volume Down

完全列表可以在HID 页表 1.12的 53 页,第 10 节找到。

5、车轮后的螺母

通常,当你使用其他人的代码,他们会提供一份自己代码的总结,描述代码都做了什么,粗略介绍了是如何工作的,以及什么情况下会出错。下面是一个使用我的 USB 驱动的相关步骤要求。

这些总结和代码的描述组成了一个 API - 应用程序产品接口。

表 5.1 CSUD 中和键盘相关的函数

函数参数返回值描述
UsbInitialiser0 是结果码这个方法是一个集多种功能于一身的方法,它加载 USB 驱动程序,枚举所有设备并尝试与它们通信。这种方法通常需要大约一秒钟的时间来执行,但是如果插入几个 USB 集线器,执行时间会明显更长。在此方法完成之后,键盘驱动程序中的方法就可用了,不管是否确实插入了键盘。返回代码如下解释。
UsbCheckForChange本质上提供与 UsbInitialise 相同的效果,但不提供相同的一次初始化。该方法递归地检查每个连接的集线器上的每个端口,如果已经添加了新设备,则添加它们。如果没有更改,这应该是非常快的,但是如果连接了多个设备的集线器,则可能需要几秒钟的时间。
KeyboardCountr0 是计数返回当前连接并检测到的键盘数量。UsbCheckForChange 可能会对此进行更新。默认情况下最多支持 4 个键盘。可以通过这个驱动程序访问多达这么多的键盘。
KeyboardGetAddressr0 是索引r0 是地址检索给定键盘的地址。所有其他函数都需要一个键盘地址,以便知道要访问哪个键盘。因此,要与键盘通信,首先要检查计数,然后检索地址,然后使用其他方法。注意,在调用 UsbCheckForChange 之后,此方法返回的键盘顺序可能会改变。
KeyboardPollr0 是地址r0 是结果码从键盘读取当前键状态。这是通过直接轮询设备来操作的,与最佳实践相反。这意味着,如果没有频繁地调用此方法,可能会错过一个按键。所有读取方法只返回上次轮询时的值。
KeyboardGetModifiersr0 是地址r0 是修饰键状态检索上次轮询时修饰键的状态。这是两边的 shift 键、alt 键和 GUI 键。这回作为一个位字段返回,这样,位 0 中的 1 表示左控件被保留,位 1 表示左 shift,位 2 表示左 alt ,位 3 表示左 GUI,位 4 到 7 表示前面几个键的右版本。如果有问题,r0 包含 0。
KeyboardGetKeyDownCountr0 是地址r0 是计数检索当前按下键盘的键数。这排除了修饰键。这通常不能超过 6。如果有错误,这个方法返回 0。
KeyboardGetKeyDownr0 是地址,r1 键号r0 是扫描码检索特定按下键的扫描码(见表 4.1)。通常,要计算出哪些键是按下的,可以调用 KeyboardGetKeyDownCount,然后多次调用 KeyboardGetKeyDown ,将 r1 的值递增,以确定哪些键是按下的。如果有问题,返回 0。可以(但不建议这样做)在不调用 KeyboardGetKeyDownCount 的情况下调用此方法将 0 解释为没有按下的键。注意,顺序或扫描代码可以随机更改(有些键盘按数字排序,有些键盘按时间排序,没有任何保证)。
KeyboardGetKeyIsDownr0 是地址,r1 扫描码r0 是状态除了 KeyboardGetKeyDown 之外,还可以检查按下的键中是否有特定的扫描码。如果没有,返回 0;如果有,返回一个非零值。当检测特定的扫描码(例如寻找 ctrl+c)时更快。出错时,返回 0。
KeyboardGetLedSupportr0 是地址r0 是 LED检查特定键盘支持哪些 LED。第 0 位代表数字锁定,第 1 位代表大写锁定,第 2 位代表滚动锁定,第 3 位代表合成,第 4 位代表假名,第 5 位代表电源,第 6 位代表 Shift ,第 7 位代表静音。根据 USB 标准,这些 LED 都不是自动更新的(例如,当检测到大写锁定扫描代码时,必须手动设置大写锁定 LED)。
KeyboardSetLedsr0 是地址, r1 是 LEDr0 是结果码试图打开/关闭键盘上指定的 LED 灯。查看下面的结果代码值。参见 KeyboardGetLedSupport 获取 LED 的值。

有几种方法返回“返回值”。这些都是 C 代码的老生常谈了,就是用数字代表函数调用发生了什么。通常情况, 0 总是代表操作成功。下面的是驱动用到的返回值。

返回值是一种处理错误的简单方法,但是通常更优雅的解决途径会出现于更高层次的代码。

表 5.2 - CSUD 返回值

代码描述
0方法成功完成。
-2参数:函数调用了无效参数。
-4设备:设备没有正确响应请求。
-5不匹配:驱动不适用于这个请求或者设备。
-6编译器:驱动没有正确编译,或者被破坏了。
-7内存:驱动用尽了内存。
-8超时:设备没有在预期的时间内响应请求。
-9断开连接:被请求的设备断开连接,或者不能使用。

驱动的通常用法如下:

  1. 调用 UsbInitialise
  2. 调用 UsbCheckForChange
  3. 调用 KeyboardCount
  4. 如果返回 0,重复步骤 2。
  5. 针对你支持的每个键盘:

    1. 调用 KeyboardGetAddress
    2. 调用 KeybordGetKeyDownCount
    3. 针对每个按下的按键:

      1. 检查它是否已经被按下了
      2. 保存按下的按键
    4. 针对每个保存的按键:

      1. 检查按键是否被释放了
      2. 如果释放了就删除
  6. 根据按下/释放的案件执行操作
  7. 重复步骤 2

最后,你可以对键盘做所有你想做的任何事了,而这些方法应该允许你访问键盘的全部功能。在接下来的两节课,我们将会着眼于完成文本终端的输入部分,类似于大部分的命令行电脑,以及命令的解释。为了做这些,我们将需要在更有用的形式下得到一个键盘输入。你可能注意到我的驱动是(故意的)没有太大帮助,因为它并没有方法来判断是否一个按键刚刚按下或释放了,它只有方法来判断当前那个按键是按下的。这就意味着我们需要自己编写这些方法。

6、可用更新

首先,让我们实现一个 KeyboardUpdate 方法,检查第一个键盘,并使用轮询方法来获取当前的输入,以及保存最后一个输入来对比。然后我们可以使用这个数据和其它方法来将扫描码转换成按键。这个方法应该按照下面的说明准确操作:

重复检查更新被称为“轮询”。这是针对驱动 IO 中断而言的,这种情况下设备在准备好后会发一个信号。
  1. 提取一个保存好的键盘地址(初始值为 0)。
  2. 如果不是 0 ,进入步骤 9.
  3. 调用 UsbCheckForChange 检测新键盘。
  4. 调用 KeyboardCount 检测有几个键盘在线。
  5. 如果返回 0,意味着没有键盘可以让我们操作,只能退出了。
  6. 调用 KeyboardGetAddress 参数是 0,获取第一个键盘的地址。
  7. 保存这个地址。
  8. 如果这个值是 0,那么退出,这里应该有些问题。
  9. 调用 KeyboardGetKeyDown 6 次,获取每次按键按下的值并保存。
  10. 调用 KeyboardPoll
  11. 如果返回值非 0,进入步骤 3。这里应该有些问题(比如键盘断开连接)。

要保存上面提到的值,我们将需要下面 .data 段的值。

.section .data
.align 2
KeyboardAddress:
.int 0
KeyboardOldDown:
.rept 6
.hword 0
.endr
.hword num 直接将半字的常数插入文件。
.rept num [commands] .endr 复制 `commands` 命令到输出 num 次。

试着自己实现这个方法。对此,我的实现如下:

1、我们加载键盘的地址。

.section .text
.globl KeyboardUpdate
KeyboardUpdate:
push {r4,r5,lr}

kbd .req r4
ldr r0,=KeyboardAddress
ldr kbd,[r0]

2、如果地址非 0,就说明我们有一个键盘。调用 UsbCheckForChanges 慢,所以如果一切正常,我们要避免调用这个函数。

teq kbd,#0
bne haveKeyboard$

3、如果我们一个键盘都没有,我们就必须检查新设备。

getKeyboard$:
bl UsbCheckForChange

4、如果有新键盘添加,我们就会看到这个。

bl KeyboardCount

5、如果没有键盘,我们就没有键盘地址。

teq r0,#0
ldreq r1,=KeyboardAddress
streq r0,[r1]
beq return$

6、让我们获取第一个键盘的地址。你可能想要支持更多键盘。

mov r0,#0
bl KeyboardGetAddress

7、保存键盘地址。

ldr r1,=KeyboardAddress
str r0,[r1]

8、如果我们没有键盘地址,这里就没有其它活要做了。

teq r0,#0
beq return$
mov kbd,r0

9、循环查询全部按键,在 KeyboardOldDown 保存下来。如果我们询问的太多了,返回 0 也是正确的。

saveKeys$:
  mov r0,kbd
  mov r1,r5
  bl KeyboardGetKeyDown
  
  ldr r1,=KeyboardOldDown
  add r1,r5,lsl #1
  strh r0,[r1]
  add r5,#1
  cmp r5,#6
  blt saveKeys$

10、现在我们得到了新的按键。

mov r0,kbd
bl KeyboardPoll

11、最后我们要检查 KeyboardOldDown 是否工作了。如果没工作,那么我们可能是断开连接了。

teq r0,#0
bne getKeyboard$

return$:
pop {r4,r5,pc}
.unreq kbd

有了我们新的 KeyboardUpdate 方法,检查输入变得简单,固定周期调用这个方法就行,而它甚至可以检查键盘是否断开连接,等等。这是一个有用的方法,因为我们实际的按键处理会根据条件不同而有所差别,所以能够用一个函数调以它的原始方式获取当前的输入是可行的。下一个方法我们希望它是 KeyboardGetChar,简单的返回下一个按下的按钮的 ASCII 字符,或者如果没有按键按下就返回 0。这可以扩展到支持如果它按下一个特定时间当做多次按下按键,也支持锁定键和修饰键。

如果我们有一个 KeyWasDown 方法可以使这个方法有用起来,如果给定的扫描代码不在 KeyboardOldDown 值中,它只返回 0,否则返回一个非零值。你可以自己尝试一下。与往常一样,可以在下载页面找到解决方案。

7、查找表

KeyboardGetChar 方法如果写得不好,可能会非常复杂。有 100 多种扫描码,每种代码都有不同的效果,这取决于 shift 键或其他修饰符的存在与否。并不是所有的键都可以转换成一个字符。对于一些字符,多个键可以生成相同的字符。在有如此多可能性的情况下,一个有用的技巧是查找表。查找表与物理意义上的查找表非常相似,它是一个值及其结果的表。对于一些有限的函数,推导出答案的最简单方法就是预先计算每个答案,然后通过检索返回正确的答案。在这种情况下,我们可以在内存中建立一个序列的值,序列中第 n 个值就是扫描代码 n 的 ASCII 字符代码。这意味着如果一个键被按下,我们的方法只需要检测到,然后从表中检索它的值。此外,我们可以为当按住 shift 键时的值单独创建一个表,这样按下 shift 键就可以简单地换个我们用的表。

在编程的许多领域,程序越大,速度越快。查找表很大,但是速度很快。有些问题可以通过查找表和普通函数的组合来解决。

.section .data 命令之后,复制下面的表:

.align 3
KeysNormal:
    .byte 0x0, 0x0, 0x0, 0x0, 'a', 'b', 'c', 'd'
    .byte 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'
    .byte 'm', 'n', 'o', 'p', 'q', 'r', 's', 't'
    .byte 'u', 'v', 'w', 'x', 'y', 'z', '1', '2'
    .byte '3', '4', '5', '6', '7', '8', '9', '0'
    .byte '\n', 0x0, '\b', '\t', ' ', '-', '=', '['
    .byte ']', '\\\', '#', ';', '\'', '`', ',', '.'
    .byte '/', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, '/', '*', '-', '+'
    .byte '\n', '1', '2', '3', '4', '5', '6', '7'
    .byte '8', '9', '0', '.', '\\\', 0x0, 0x0, '='

.align 3
KeysShift:
    .byte 0x0, 0x0, 0x0, 0x0, 'A', 'B', 'C', 'D'
    .byte 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L'
    .byte 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'
    .byte 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '"'
    .byte '£', '$', '%', '^', '&', '*', '(', ')'
    .byte '\n', 0x0, '\b', '\t', ' ', '_', '+', '{'
    .byte '}', '|', '~', ':', '@', '¬', '<', '>'
    .byte '?', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, '/', '*', '-', '+'
    .byte '\n', '1', '2', '3', '4', '5', '6', '7'
    .byte '8', '9', '0', '.', '|', 0x0, 0x0, '='

这些表直接将前 104 个扫描码映射到 ASCII 字符作为一个字节表。我们还有一个单独的表来描述 shift 键对这些扫描码的影响。我使用 ASCII null 字符(0)表示所有没有直接映射的 ASCII 键(例如功能键)。退格映射到 ASCII 退格字符(8 表示 \b),enter 映射到 ASCII 新行字符(10 表示 \n), tab 映射到 ASCII 水平制表符(9 表示 \t)。

.byte num 直接插入字节常量 num 到文件。

.

大部分的汇编器和编译器识别转义序列;如 \t 这样的字符序列会插入该特殊字符。

KeyboardGetChar 方法需要做以下工作:

  1. 检查 KeyboardAddress 是否返回 0。如果是,则返回 0。
  2. 调用 KeyboardGetKeyDown 最多 6 次。每次:

    1. 如果按键是 0,跳出循环。
    2. 调用 KeyWasDown。 如果返回是,处理下一个按键。
    3. 如果扫描码超过 103,进入下一个按键。
    4. 调用 KeyboardGetModifiers
    5. 如果 shift 是被按着的,就加载 KeysShift 的地址,否则加载 KeysNormal 的地址。
    6. 从表中读出 ASCII 码值。
    7. 如果是 0,进行下一个按键,否则返回 ASCII 码值并退出。
  3. 返回 0。

试着自己实现。我的实现展示在下面:

1、简单的检查我们是否有键盘。

.globl KeyboardGetChar
KeyboardGetChar:
ldr r0,=KeyboardAddress
ldr r1,[r0]
teq r1,#0
moveq r0,#0
moveq pc,lr

2、r5 将会保存按键的索引,r4 保存键盘的地址。

push {r4,r5,r6,lr}
kbd .req r4
key .req r6
mov r4,r1
mov r5,#0
keyLoop$:
  mov r0,kbd
  mov r1,r5
  bl KeyboardGetKeyDown

2.1、 如果扫描码是 0,它要么意味着有错,要么说明没有更多按键了。

teq r0,#0
beq keyLoopBreak$

2.2、如果按键已经按下了,那么他就没意义了,我们只想知道按下的按键。

mov key,r0
bl KeyWasDown
teq r0,#0
bne keyLoopContinue$

2.3、如果一个按键有个超过 104 的扫描码,它将会超出我们的表,所以它是无关的按键。

cmp key,#104
bge keyLoopContinue$

2.4、我们需要知道修饰键来推断字符。

mov r0,kbd
bl KeyboardGetModifiers

2.5、当将字符更改为其 shift 变体时,我们要同时检测左 shift 键和右 shift 键。记住,tst 指令计算的是逻辑和,然后将其与 0 进行比较,所以当且仅当移位位都为 0 时,它才等于 0。

tst r0,#0b00100010
ldreq r0,=KeysNormal
ldrne r0,=KeysShift

2.6、现在我们可以从查找表加载按键了。

ldrb r0,[r0,key]

2.7、如果查找码包含一个 0,我们必须继续。为了继续,我们要增加索引,并检查是否到 6 次了。

teq r0,#0
bne keyboardGetCharReturn$
keyLoopContinue$:
add r5,#1
cmp r5,#6
blt keyLoop$

3、在这里我们返回我们的按键,如果我们到达 keyLoopBreak$ ,然后我们就知道这里没有按键被握住,所以返回 0。

keyLoopBreak$:
mov r0,#0
keyboardGetCharReturn$:
pop {r4,r5,r6,pc}
.unreq kbd
.unreq key

8、记事本操作系统

现在我们有了 KeyboardGetChar 方法,可以创建一个操作系统,只打印出用户对着屏幕所写的内容。为了简单起见,我们将忽略所有非常规的键。在 main.s,删除 bl SetGraphicsAddress 之后的所有代码。调用 UsbInitialise,将 r4r5 设置为 0,然后循环执行以下命令:

  1. 调用 KeyboardUpdate
  2. 调用 KeyboardGetChar
  3. 如果返回 0,跳转到步骤 1
  4. 复制 r4r5r1r2 ,然后调用 DrawCharacter
  5. r0 加到 r4
  6. 如果 r4 是 1024,将 r1 加到 r5,然后设置 r4 为 0。
  7. 如果 r5 是 768,设置 r5 为0
  8. 跳转到步骤 1

现在编译,然后在树莓派上测试。你几乎可以立即开始在屏幕上输入文本。如果没有工作,请参阅我们的故障排除页面。

当它工作时,祝贺你,你已经实现了与计算机的接口。现在你应该开始意识到,你几乎已经拥有了一个原始的操作系统。现在,你可以与计算机交互、发出命令,并在屏幕上接收反馈。在下一篇教程输入02中,我们将研究如何生成一个全文本终端,用户在其中输入命令,然后计算机执行这些命令。


via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/input01.html

作者:Alex Chadwick 选题:lujun9972 译者:ezio 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在我们的树莓派使用入门的第八篇文章中,我们将学习如何使用树莓派观看 Netflix 上的影片和用它来听音乐。

到目前为止,本系列文章已经学习了很多话题 — 如何 挑选购买设置、和 更新 你的树莓派,以及 儿童成人 如何使用它来做的不同的事情(包括学习 Linux)。今天我们换一个话题,将学习一些娱乐方面的内容!我们将学习如何使用树莓派来做一些娱乐方面的事情,明天我们继续这个话题,将用它来玩游戏。

观看电视和电影

你可以使用你的树莓派和 开源媒体中心 (OSMC) 去 观看 Netflix!OSMC 是一个基于 Kodi 项目的系统,你可以使用它来播放来自本地网络、附加存储以及互联网上的多媒体。它因为良好的功能特性而在媒体播放应用界中拥有非常好的口碑。

NOOBS(我们在本系列的 第三篇文章 中介绍过它)可以让你在你的树莓派中很容易地 安装 OSMC。在 NOOBS 中也提供了另外一个基于 Kodi 项目的媒体播放系统,它的名字叫 LibreELEC

听音乐

你还可以让你的树莓派借助 Pi Music Box 项目通过网络来播放来自附加存储或像 Spotify 服务上的流媒体音乐。以前我 写过关于这个主题的文章,但是你可以在 Pi Music Box 网站 上找到最新的指导,包括如何使用和 DIY 项目。


via: https://opensource.com/article/19/3/raspberry-pi-entertainment

作者:Anderson Silva 选题:lujun9972 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在我们的树莓派入门指南的第七篇学习如何给树莓派打补丁。

像平板电脑、手机和笔记本电脑一样,你需要更新树莓派。最新的增强功能不仅可以使你的派运行顺畅,还可以让它更安全,特别是在如果你连接到网络的情况下。我们的树莓派入门指南中的第七篇会分享两条关于让派良好运行的建议。

更新 Raspbian

更新 Raspbian 有两步

  1. 在终端中输入:sudo apt-get update

该命令的 sudo 让你以管理员(也就是 root)运行 apt-get update。请注意,apt-get update 不会在系统上安装任何新东西,而是将更新需要更新的包和依赖项列表。

  1. 接着输入:sudo apt-get dist-upgrade

摘自文档:“一般来说,定期执行此操作将使你的安装保持最新,因为它将等同于 raspberrypi.org/downloads 中发布的最新镜像。”

小心 rpi-update

Raspbian 带有另一个名为 rpi-update 的更新工具。此程序可用于将派升级到最新固件,不管该固件是不是有损坏或问题。你可能会发现一些如何使用它的信息,但是建议你永远不要使用这个程序,除非你有充分的理由这样做。

一句话:保持系统更新!


via: https://opensource.com/article/19/3/how-raspberry-pi-update

作者:Anderson Silva 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

通过树莓派学习编程,让你在就业市场上更值钱。

在本系列的上一篇文章中,我分享了 教孩子们使用树莓派编程 的一些方式。理论上,这些资源并不局限于只适用于孩子们,成人也是可以使用的。但是学习就业市场上急需的编程语言,可以让你得到更好的机会。

这里是你可以使用树莓派学习的三种编程语言。

Python

Python 已经成为开源世界里 最流行的编程语言。它的解释器已经打包进每个流行的 Linux 发行版中。如果你在树莓派中安装的是 Raspbian,你就会看到一个名为 Thonny 的应用,它是为新手准备的 Python 集成开发环境。简单来说,一个集成开发环境就是能够提供让你的代码运行起来所需要的任何东西的一个应用程序,一般来说,包括调试器、文档、自动编译,和仿真程序。这是一个在树莓派上使用 Thonny 和 Python 入门的非常好的小教程

Java

虽然 Java 已经不像以前那样引人注目了,但它仍然在世界各地的大学和企业中占据着重要的地位。因此,即便是一些人对我建议新手学习 Java 持反对意见,但我仍然强烈推荐大家去学习 Java;之所以这么做,原因之一是,它仍然很流行,原因之二是,它有大量的便于你学习的图书、课程和其它的可用信息。在树莓派上学习它,你可以从使用 Java 集成开发环境 BlueJ 开始。

JavaScript

“我的黄金时代…" JavaScript 的本质是一个允许用户去组织和自动化浏览器中的用户事件以及修改 HTML 元素的客户端语言。目前,JavaScript 已经不仅限于浏览器中,它在其它类型的客户端(移动应用)中也是可以使用的,甚至也用在服务器端编程。Node.js 是一个流行的运行时环境,它允许开发者在客户端-浏览器范式之外写程序。想学习在树莓派上运行 Node.js 的更多知识,请查看 W3Schools 教程

其它编程语言

如果这里没有列出你想学习的编程语言,别失望。你可以使用你的树莓派去编译或解释任何你选择的语言,包括 C、C++、PHP 和 Ruby,这种可能性还是很大的。

微软的 Visual Studio Code 也可以运行在 树莓派 上。它是来自微软的开源代码编辑器,它支持多种标记和编程语言。


via: https://opensource.com/article/19/3/programming-languages-raspberry-pi

作者:Anderson Silva 选题:lujun9972 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

这是我们的《树莓派入门指南》系列的第五篇文章,它探索了帮助孩子们学习编程的一些资源。

无数的学校、图书馆和家庭已经证明,树莓派是让孩子们接触编程的最好方式。在本系列的前四篇文章中,你已经学习了如何去购买安装、和配置一个树莓派。在第五篇文章中,我们将分享一些帮助孩子们使用树莓派编程的入门级资源。

Scratch

Scratch 是让孩子们了解编程基本概念(比如变量、布尔逻辑、循环等等)的一个很好的方式。你在 Raspbian 中就可以找到它,并且在互联网上你可以找到非常多的有关 Scratch 的文章和教程,包括在 Opensource.com 上的 今天的 Scratch 是不是像“上世纪八十年代教孩子学 LOGO 编程”?

Code.org

Code.org 是另一个非常好的教孩子学编程的在线资源。这个组织的使命是让更多的人通过课程、教程和流行的一小时学编程来接触编程。许多学校(包括我五年级的儿子就读的学校)都使用它,让更多的孩子学习编程和计算机科学的概念。

阅读

读书是学习编程的另一个很好的方式。学习如何编程并不需要你会说英语,当然,如果你会英语的话,学习起来将更容易,因为大多数的编程语言都是使用英文关键字去描述命令的。如果你的英语很好,能够轻松地阅读接下来的这个树莓派系列文章,那么你就完全有能力去阅读有关编程的书籍、论坛和其它的出版物。我推荐一本由 Jason Biggs 写的书: 儿童学 Python:非常有趣的 Python 编程入门

Raspberry Jam

另一个让你的孩子进入编程世界的好方法是在聚会中让他与其他人互动。树莓派基金会赞助了一个称为 Raspberry Jams 的活动,让世界各地的孩子和成人共同参与在树莓派上学习。如果你所在的地区没有 Raspberry Jam,基金会有一个指南和其它资源帮你启动一个 Raspberry Jam。

游戏

最后一个(是本文的最后一个,当然还有其它的方式),Minecraft 有一个树莓派版本。 我的世界 Minecraft 已经从一个多玩家的、类似于”数字乐高“这样的游戏,成长为一个任何人都能使用 Python 和其它编程语言去构建我自己的虚拟世界。更多内容查看 Minecraft Pi 入门Minecraft 一小时入门教程

你还有教孩子用树莓派学编程的珍藏资源吗?请在下面的评论区共享出来吧。


via: https://opensource.com/article/19/3/teach-kids-program-raspberry-pi

作者:Anderson Silva 选题:lujun9972 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出