Propeller Manual - Parallax Home

443
Propeller Manual Version 1.0

Transcript of Propeller Manual - Parallax Home

Page 1: Propeller Manual - Parallax Home

Propeller Manual Version 1.0

Page 2: Propeller Manual - Parallax Home

WARRANTY Parallax Inc. warrants its products against defects in materials and workmanship for a period of 90 days from receipt of product. If you discover a defect, Parallax Inc. will, at its option, repair or replace the merchandise, or refund the purchase price. Before returning the product to Parallax, call for a Return Merchandise Authorization (RMA) number. Write the RMA number on the outside of the box used to return the merchandise to Parallax. Please enclose the following along with the returned merchandise: your name, telephone number, shipping address, and a description of the problem. Parallax will return your product or its replacement using the same shipping method used to ship the product to Parallax.

14-DAY MONEY BACK GUARANTEE If, within 14 days of having received your product, you find that it does not suit your needs, you may return it for a full refund. Parallax Inc. will refund the purchase price of the product, excluding shipping/handling costs. This guarantee is void if the product has been altered or damaged. See the Warranty section above for instructions on returning a product to Parallax. COPYRIGHTS AND TRADEMARKS This documentation is copyright © 2006 by Parallax Inc. By downloading or obtaining a printed copy of this documentation or software you agree that it is to be used exclusively with Parallax products. Any other uses are not permitted and may represent a violation of Parallax copyrights, legally punishable according to Federal copyright or intellectual property laws. Any duplication of this documentation for commercial uses is expressly prohibited by Parallax Inc. Duplication for educational use is permitted, subject to the following Conditions of Duplication: Parallax Inc. grants the user a conditional right to download, duplicate, and distribute this text without Parallax's permission. This right is based on the following conditions: the text, or any portion thereof, may not be duplicated for commercial use; it may be duplicated only for educational purposes when used solely in conjunction with Parallax products, and the user may recover from the student only the cost of duplication. This text is available in printed format from Parallax Inc. Because we print the text in volume, the consumer price is often less than typical retail duplication charges. Parallax, Propeller Spin, and the Parallax and Propeller Hat logos are trademarks of Parallax Inc. BASIC Stamp, Stamps in Class, Boe-Bot, SumoBot, Toddler, and SX-Key are registered trademarks of Parallax, Inc. If you decide to use any trademarks of Parallax Inc. on your web page or in printed material, you must state that (trademark) is a (registered) trademark of Parallax Inc.” upon the first appearance of the trademark name in each printed document or web page. Other brand and product names herein are trademarks or registered trademarks of their respective holders.

ISBN 1-928982-38-7

Page 3: Propeller Manual - Parallax Home

DISCLAIMER OF LIABILITY Parallax Inc. is not responsible for special, incidental, or consequential damages resulting from any breach of warranty, or under any legal theory, including lost profits, downtime, goodwill, damage to or replacement of equipment or property, or any costs of recovering, reprogramming, or reproducing any data stored in or used with Parallax products. Parallax Inc. is also not responsible for any personal damage, including that to life and health, resulting from use of any of our products. You take full responsibility for your Propeller microcontroller application, no matter how life-threatening it may be.

网络讨论组列表

我们为对 Parallax 产品感兴趣的用户提供了一个基于web的论坛。可以通过访问 www.parallax.com 网站的链接 Support → Discussion Forums 菜单来访问。下面的这些论坛是我们的网站正在运作的:

• Propeller chip – 用于使用 Propeller 芯片的客户讨论和交流问题。 • BASIC Stamp – 可以由工程师,爱好者和学生共享 BASIC Stamp 项目和提出相关问题并寻求答案。 • Stamps in Class® – 为教育者和学生提供关于如何在教室中使用 Stamp 的讨论区。 • Parallax Educators – 专为教育者和为 Stamps 教育有贡献的人而设置的论坛。Parallax 可以从中获得关于

我们的课程的反馈,为教育者提供开发指导和教师指导。 • Robotics – 为 Parallax 机器人而设计,该论坛目的是为机器人爱好者提供对话和交流。其主题包括汇编

语言,源代码,扩展和手动更新等。在这里可以讨论 Boe-Bot®, Toddler®, SumoBot®, HexCrawler 和 QuadCrawler 机器人。

• SX Microcontrollers and SX-Key –讨论使用 Parallax 汇编语言 SX – Key® 工具和第三方 BASIC 以及 C 编

译器对 SX 微控制器进行编程。 • Javelin Stamp –讨论使用 Javelin Stamp 的应用和设计, Javelin Stamp 是 Parallax 公司的一项产品,它可以

用 Sun Microsystem 公司的 Java® 语言来编程。

勘误

虽然作了很大努力,以保证文字的准确性,但仍可能存在偏差。如果您发现了错误,请给 [email protected] 发送电子邮件

让我们知道。我们不断努力改进我们所有的教材和文献,并经常修改文本. 在我们的网站 www.parallax.com.上有勘误表

列出了已知错误和文本的更正。请查看个别产品网页的勘误文件进行免费下载。

支持的硬件,固件和软件

本手册适用于下列硬件,软件和固件版本:

硬件 软件 固件 P8X32A-D40 P8X32A-Q44 P8X32A-M44

Propeller Tool v1.0 P8X32A v1.0

CREDITS

作者: Jeff Martin. 排版 & 编辑, Stephanie Lindsay. 封面设计: Jen Jacobs; 技术图表: Rich Allred; 感谢 Parallax Inc.公司的每一个人。

Page 4: Propeller Manual - Parallax Home
Page 5: Propeller Manual - Parallax Home

目录

Propeller Manual v1.0 · Page 5

序言 ......................................................................................................................................... 13 CHAPTER 1 : 介绍 PROPELLER 芯片 ................................................................................... 15

概念 ..................................................................................................................................... 15 封装类型.............................................................................................................................. 16 引脚描述.............................................................................................................................. 17 规格 ..................................................................................................................................... 18 硬件连接.............................................................................................................................. 19 启动程序.............................................................................................................................. 20 运行时(RUN-TIME)程序 ................................................................................................... 20 关机程序.............................................................................................................................. 21 方块图 ................................................................................................................................. 22 共享资源.............................................................................................................................. 24 系统时钟.............................................................................................................................. 24 COGS (处理器) ..................................................................................................................... 24 HUB ..................................................................................................................................... 26 I/O 引脚 ............................................................................................................................... 27 系统计数器 .......................................................................................................................... 29 CLK 寄存器 ......................................................................................................................... 29 锁(LOCKS ) ...................................................................................................................... 31 主内存 ................................................................................................................................. 32 主 RAM ............................................................................................................................... 32 主 ROM ............................................................................................................................... 33 字符定义.............................................................................................................................. 33 对数和反对数表................................................................................................................... 35 正弦值表.............................................................................................................................. 36 BOOTLOADER和 SPIN解释器 ............................................................................................... 36

CHAPTER 2 : 使用 PROPELLER 工具 ................................................................................... 37 概念 ..................................................................................................................................... 37 屏幕组织.............................................................................................................................. 39 菜单项 ................................................................................................................................. 47

File 菜单.......................................................................................................................... 47 Edit 菜单 ......................................................................................................................... 48 Run 菜单 ......................................................................................................................... 49 Help 菜单 ........................................................................................................................ 50

FIND/REPLACE对话框 .......................................................................................................... 51 对象视图.............................................................................................................................. 54

Page 6: Propeller Manual - Parallax Home

目录

Page 6 · Propeller Manual v1.0

对象信息 ..............................................................................................................................57 字符表..................................................................................................................................60 视图模式,书签和行号 ........................................................................................................63

视图模式..........................................................................................................................63 书签 .................................................................................................................................65 行号 .................................................................................................................................66

编辑模式 ..............................................................................................................................67 插入和覆盖模式 ...............................................................................................................67 对齐模式..........................................................................................................................68

块选择和选择移动................................................................................................................70 增加缩进和减少缩进 ............................................................................................................71

单行 .................................................................................................................................72 多行 .................................................................................................................................73

块-组指示器 .........................................................................................................................75 快捷键..................................................................................................................................77

分类列表..........................................................................................................................77 按键分类..........................................................................................................................82

CHAPTER 3 : PROPELLER 编程指导 ....................................................................................87 概念 .....................................................................................................................................87 PROPELLER语言(SPIN和 PROPELLER汇编) .....................................................................88 PROPELLER对象 ...................................................................................................................88

快速回顾: 介绍 ................................................................................................................93 练习 1: OUTPUT.SPIN –我们的第一个对象.............................................................................93

下载到 RAM vs. EEPROM.............................................................................................94 快速回顾: 练习 1..............................................................................................................97

COGS (处理器) .....................................................................................................................98 练习 2: OUTPUT.SPIN -常量 ...................................................................................................99 块标识器 ............................................................................................................................100 练习 3: OUTPUT.SPIN -注释 .................................................................................................101

快速回顾:练习 2 & 3....................................................................................................104 练习 4: OUTPUT.SPIN –参数,调用,和有限循环................................................................105 练习 5: OUTPUT.SPIN –并行处理 .........................................................................................107

快速回顾:练习 4 & 5....................................................................................................110 练习 6: OUTPUT.SPIN & BLINKER1.SPIN –使用对象 ..............................................................111 对象视图 ............................................................................................................................113 顶部对象文件 .....................................................................................................................114 哪些对象被编译了?............................................................................................................116

Page 7: Propeller Manual - Parallax Home

目录

Propeller Manual v1.0 · Page 7

快速回顾: 练习 6 ........................................................................................................... 117 对象 VS. COGS ................................................................................................................... 118 练习 7: OUTPUT.SPIN – 更多增强........................................................................................ 118

快速回顾: 练习 7 ........................................................................................................... 124 练习 8: BLINKER2.SPIN – 多个对象,多个 COG ................................................................ 125 对象信息窗口 .................................................................................................................... 129 对象的生命周期................................................................................................................. 131

快速回顾: 练习 8 ........................................................................................................... 131 练习 9: 时钟设定................................................................................................................ 133 练习 10: 时钟相关的时序................................................................................................... 135

快速回顾: 练习 9 & 10 .................................................................................................. 139 练习 11: 库对象 ................................................................................................................. 140

工作文件夹和库文件夹 ................................................................................................. 144 练习 12: 整数和实数 .......................................................................................................... 146

伪实数 ........................................................................................................................... 146 浮点数 ........................................................................................................................... 147 上下文敏感的编译信息 ................................................................................................. 150 快速回顾: 练习 11 & 12 ................................................................................................ 151

CHAPTER 4 : SPIN 语言参考 ............................................................................................... 153 PROPELLER 对象的结构 ..................................................................................................... 154 PROPELLER SPIN 语言列表 ................................................................................................. 156

块标识符 ....................................................................................................................... 156 配置 .............................................................................................................................. 156 Cog 控制 ....................................................................................................................... 157 程序控制 ....................................................................................................................... 157 流程控制 ....................................................................................................................... 157 内存 .............................................................................................................................. 158 命令 .............................................................................................................................. 159 寄存器 ........................................................................................................................... 159 常量 .............................................................................................................................. 160 变量 .............................................................................................................................. 160 一元运算符.................................................................................................................... 160 二元运算符.................................................................................................................... 161 语法符号 ....................................................................................................................... 162

SPIN 语言元素.................................................................................................................... 163 符号命名规则 ................................................................................................................ 163 数值的表示.................................................................................................................... 163

Page 8: Propeller Manual - Parallax Home

目录

Page 8 · Propeller Manual v1.0

语法定义........................................................................................................................164 ABORT..................................................................................................................................165 BYTE ...................................................................................................................................169 BYTEFILL ............................................................................................................................174 BYTEMOVE ............................................................................................................................175 CASE ...................................................................................................................................176 CHIPVER ..............................................................................................................................179 CLKFREQ ..............................................................................................................................180 _CLKFREQ ............................................................................................................................182 CLKMODE ..............................................................................................................................184 _CLKMODE ............................................................................................................................185 CLKSET................................................................................................................................188 CNT .....................................................................................................................................189 COGID..................................................................................................................................191 COGINIT ..............................................................................................................................192 COGNEW................................................................................................................................194 COGSTOP ..............................................................................................................................198 CON .....................................................................................................................................199 CONSTANT ............................................................................................................................205 常量 (预定义) .....................................................................................................................207 CTRA, CTRB .........................................................................................................................209 DAT .....................................................................................................................................213 DIRA, DIRB .........................................................................................................................217 FILE ...................................................................................................................................220 FLOAT..................................................................................................................................221 _FREE..................................................................................................................................223 FRQA, FRQB .........................................................................................................................224 IF .......................................................................................................................................225 IFNOT..................................................................................................................................231 INA, INB ............................................................................................................................232 LOCKCLR ..............................................................................................................................234 LOCKNEW ..............................................................................................................................236 LOCKRET ..............................................................................................................................239 LOCKSET ..............................................................................................................................240 LONG ...................................................................................................................................242 LONGFILL ............................................................................................................................246 LONGMOVE ............................................................................................................................247 LOOKDOWN, LOOKDOWNZ.........................................................................................................248 LOOKUP, LOOKUPZ................................................................................................................250 NEXT ...................................................................................................................................252 OBJ .....................................................................................................................................253 运算符................................................................................................................................255

Page 9: Propeller Manual - Parallax Home

目录

Propeller Manual v1.0 · Page 9

OUTA, OUTB ........................................................................................................................ 286 PAR..................................................................................................................................... 289 PHSA, PHSB ........................................................................................................................ 291 PRI..................................................................................................................................... 292 PUB..................................................................................................................................... 293 QUIT ................................................................................................................................... 297 REBOOT ............................................................................................................................... 298 REPEAT ............................................................................................................................... 299 RESULT ............................................................................................................................... 305 RETURN ............................................................................................................................... 307 ROUND ................................................................................................................................. 309 SPR..................................................................................................................................... 311 _STACK ............................................................................................................................... 313 STRCOMP ............................................................................................................................. 314 STRING ............................................................................................................................... 316 STRSIZE ............................................................................................................................. 317 符号 ................................................................................................................................... 318 TRUNC ................................................................................................................................. 320 VAR..................................................................................................................................... 321 VCFG ................................................................................................................................... 324 VSCL ................................................................................................................................... 327 WAITCNT ............................................................................................................................. 329 WAITPEQ ............................................................................................................................. 333 WAITPNE ............................................................................................................................. 335 WAITVID ............................................................................................................................. 336 WORD ................................................................................................................................... 338 WORDFILL............................................................................................................................ 342 WORDMOVE............................................................................................................................ 343 _XINFREQ............................................................................................................................ 344

CHAPTER 5 : 汇编语言参考 ................................................................................................. 347 PROPELLER汇编结构 ......................................................................................................... 347 PROPELLER 汇编语言分类列表 .......................................................................................... 349

命令 .............................................................................................................................. 349 配置 .............................................................................................................................. 349 Cog 控制 ....................................................................................................................... 349 程序控制 ....................................................................................................................... 349 条件 .............................................................................................................................. 349 流程控制 ....................................................................................................................... 351 效果 .............................................................................................................................. 351 主内存访问.................................................................................................................... 351

Page 10: Propeller Manual - Parallax Home

目录

Page 10 · Propeller Manual v1.0

普通运算........................................................................................................................351 寄存器 ...........................................................................................................................354 常量 ...............................................................................................................................354 一元运算符 ....................................................................................................................354 二元运算符 ....................................................................................................................356

汇编语言元素 .....................................................................................................................357 语法定义........................................................................................................................357 Propeller 汇编指令表.....................................................................................................358

ABS .....................................................................................................................................362 ABSNEG................................................................................................................................363 ADD .....................................................................................................................................363 ADDABS................................................................................................................................364 ADDS ...................................................................................................................................365 ADDSX..................................................................................................................................365 ADDX ...................................................................................................................................366 AND .....................................................................................................................................367 ANDN ...................................................................................................................................367 CALL ...................................................................................................................................368 CLKSET................................................................................................................................369 CMP .....................................................................................................................................370 CMPS ...................................................................................................................................370 CMPSUB................................................................................................................................371 CMPSX..................................................................................................................................372 CMPX ...................................................................................................................................372 COGID..................................................................................................................................373 COGINIT ..............................................................................................................................374 COGSTOP ..............................................................................................................................375 条件 ( IF_X )........................................................................................................................376 DJNZ ...................................................................................................................................378 效果 ...................................................................................................................................379 FIT .....................................................................................................................................380 HUBOP..................................................................................................................................381 JMP .....................................................................................................................................382 JMPRET................................................................................................................................382 LOCKCLR ..............................................................................................................................383 LOCKNEW ..............................................................................................................................384 LOCKRET ..............................................................................................................................384 LOCKSET ..............................................................................................................................385 MAX .....................................................................................................................................386 MAXS ...................................................................................................................................386 MIN .....................................................................................................................................387

Page 11: Propeller Manual - Parallax Home

目录

Propeller Manual v1.0 · Page 11

MINS ................................................................................................................................... 388 MOV..................................................................................................................................... 388 MOVD ................................................................................................................................... 389 MOVI ................................................................................................................................... 390 MOVS ................................................................................................................................... 390 MUXC ................................................................................................................................... 391 MUXNC ................................................................................................................................. 392 MUXNZ ................................................................................................................................. 392 MUXZ ................................................................................................................................... 393 NEG..................................................................................................................................... 394 NEGC ................................................................................................................................... 394 NEGNC ................................................................................................................................. 395 NEGNZ ................................................................................................................................. 396 NEGZ ................................................................................................................................... 397 NOP..................................................................................................................................... 397 运算符 ............................................................................................................................... 398 OR ...................................................................................................................................... 400 ORG..................................................................................................................................... 400 RCL..................................................................................................................................... 401 RCR..................................................................................................................................... 402 RDBYTE ............................................................................................................................... 402 RDLONG ............................................................................................................................... 403 RDWORD ............................................................................................................................... 404 寄存器 ............................................................................................................................... 405 RES..................................................................................................................................... 406 RET..................................................................................................................................... 407 REV..................................................................................................................................... 407 ROL..................................................................................................................................... 408 ROR..................................................................................................................................... 408 SAR..................................................................................................................................... 409 SHL..................................................................................................................................... 410 SHR..................................................................................................................................... 410 SUB..................................................................................................................................... 411 SUBABS ............................................................................................................................... 412 SUBS ................................................................................................................................... 412 SUBSX ................................................................................................................................. 413 SUBX ................................................................................................................................... 414 SUMC ................................................................................................................................... 414 SUMNC ................................................................................................................................. 415 SUMNZ ................................................................................................................................. 416 SUMZ ................................................................................................................................... 416 TEST ................................................................................................................................... 417

Page 12: Propeller Manual - Parallax Home

目录

Page 12 · Propeller Manual v1.0

TJNZ ...................................................................................................................................418 TJZ .....................................................................................................................................418 WAITCNT ..............................................................................................................................419 WAITPEQ ..............................................................................................................................420 WAITPNE ..............................................................................................................................421 WAITVID ..............................................................................................................................422 WRBYTE................................................................................................................................422 WRLONG................................................................................................................................423 WRWORD................................................................................................................................424 XOR .....................................................................................................................................425

附录 A: 保留字列表 ................................................................................................................426 附录 B: 访问数学函数表 .........................................................................................................427 索引........................................................................................................................................431

Page 13: Propeller Manual - Parallax Home

Preface

Propeller Manual v1.0 · Page 13

序言 感谢您购买 Propeller 芯片。您将会很快拥有自己的程序了!

Propeller 芯片是功能强大的多处理器微控制器,是 Chip Gracey 和整个

Parallax 工程团队 8年来不懈的努力的成果。

本书将是 Propeller 芯片及其编程语言-Spin™和汇编-的完整参考指南。

尽管我们已经尽了 大的努力,但是仍然有这本手册不能回答的问题。请访问

我们的 Propeller 芯片论坛-( 在 www.parallax.com 网页上 Support->

Discussion Forums)-这里是专为 Propeller 用户提供的,您可以贴出您的问题

或检查之前的讨论,可能会解决您的问题。

Page 14: Propeller Manual - Parallax Home

Preface

Page 14 · Propeller Manual v1.0

Page 15: Propeller Manual - Parallax Home

1: Propeller 芯片简介

Propeller Manual v1.0 · Page 15

Chapter 1: 介绍 Propeller 芯片 本章描述了 Propeller 芯片的硬件。为了能有效地理解和使用 Propeller,理解其硬

件体系是很重要的。本章描述了一些硬件细节,比如封装类型,封装尺寸,引脚描述

和功能等。

概念 Propeller 芯片被设计成能为嵌入式系统提供快速处理,同时又具有较低的电

流消耗和较小的封装。除了高运算速度,Propeller 通过其八个处理器(cog)提供

了灵活性和功能。 Cog 可以同时独立或协同任务,同时又具有相对简单的体系

易学易用。

使用 Propeller 可以使开发员从平时复杂的嵌入式系统编程中解放出来。比如: 内存映射是平面的(Flat)。不需要带有分页结构的代码,数据或变量。在开发过程中将

节省大量时间。 异步事件处理比使用中断更容易。Propeller 不需要中断,只要指派一些 cog 执行独

立,高带宽任务同时保持其他 cog 空闲。结果是可以有更多的易于管理的响应程序 Propeller 汇编语言的特色是每条单独指令的有条件执行和可选结果写入。这使得代码

中关键的多决策块能一直被计时;即使处理器资源紧张,开发员不得不填充或压缩时

钟循环的时候也是如此。

Page 16: Propeller Manual - Parallax Home

Propeller 芯片简介

Page 16 · Propeller Manual v1.0

封装类型 Propeller 芯片可用的封装类型如下: P8X32A-Q44

44-pin LQFP

P8X32A-D40 40-pin DIP

P8X32A-M44 44-pin QFN

Page 17: Propeller Manual - Parallax Home

1: Propeller 芯片简介

Propeller Manual v1.0 · Page 17

引脚描述 表 1-1: 引脚描述

引脚名 方向 描述

P0 – P31 I/O

通用 I/O 端口 A(Port A),在 3.3V VDC 环境下可以吸收或输出 30mA 电流。

同一时刻一组 I/O 的电流之和不能超过 100mA, 逻辑门限为½VDD。3.3V 时

为 1.65V。 下述几个引脚在上电或复位时具有特殊功能,此后又可以作为通用 I/O: P28 – I2C SCL 连接到可选的外部 EEPROM P29 – I2C SDA 连接到可选的外部 EEPROM P30 – Serial Tx 发送端 P31 – Serial Rx 接收端

VDD --- 3.3V 电压(2.7-3.3VDC)

VSS --- 电源地

BOEn I

掉电使能(低有效)。必须连接到 VDD 或 VSS。 如果 BOEn 引脚为低,

RESn 将成为弱输出(通过 5KΩ上拉到 VDD),可用于监控,但是该引脚

仍然可以被拉低来复位。如果 BOEn 为高,RESn 为带施密特触发的 CMOS输入。

RESn I/O 复位(低有效)。该引脚被拉低后,Propeller 所有 COG 被禁用,I/O 引脚

浮空,在 RESn 由低到高跳变后 50ms,Propeller 重新启动。

XI I 晶振输入。可以连接到外部晶振(XO 引脚不连接),或连接到晶振的一脚

(XO 连接到晶振或共振器的另一脚),这取决于 CLK 寄存器的设置。不需

要外部电阻或电容器。

XO O 晶振输出。为外部晶振提供反馈,或者不连接,这取决于 CLK 寄存器的设

置。不需要外部电阻或电容器。

Propeller(P8X32A)有 32 个 I/O 引脚(端口 A (Port A),引脚 P0 到 P32)。其中的四个引脚

P28—P31,在上电或复位时有特殊功能。上电或复位时,P30 和 P31 会与主机通信进行编程,P28 和

P29 则是外部 32KB EEPROM(24LC256)的接口。

Page 18: Propeller Manual - Parallax Home

Propeller 芯片简介

Page 18 · Propeller Manual v1.0

规格 表 1-2: 规格

型号 P8X32A

电源需求 3.3V 直流

外部时钟速度 80MHz(4MHz 到 8MHz 带有锁相环)

系统时钟速度 80MHz

内部 RC 振荡器 12MHz 或 20MHz(近似值,可能是 8MHz—20MHz 或 13KHz—33KHz)

主 RAM/ROM 64K Bytes;32KB RAM + 32 KB ROM COG RAM 每个 512×32 Bit

RAM/ROM 机制 长字节(32 位),字节(16 位),或字(8 位)寻址

I/O 引脚 32 个 CMOS 信号,½VDD 输入门限

每个 I/O 吸收或输出的电流 30mA

每组(8 个)引脚吸收或输出的电流 100mA

电流消耗 3.3V 直流,70 每 MIPS 500uA

Page 19: Propeller Manual - Parallax Home

1: Propeller 芯片简介

Propeller Manual v1.0 · Page 19

硬件连接 图 1-1 展示的原理图展示的是一个为 Propeller 提供了和主机通信以及访问

EEPROM 能力的例子。例子中,主机访问是通过 Propeller Clip 设备实现的(USB 到

TTL 串行转换)。

图 1-1: 示例连接图,该连接允许对 Propeller 芯片编程,使用外部 32K 字节的 EEPROM,以

及外部晶振。

Page 20: Propeller Manual - Parallax Home

Propeller 芯片简介

Page 20 · Propeller Manual v1.0

启动程序 上电后(100ms),RESn 由低拉高,或者软件复位:

1. Propeller 芯片以低速模式(≈20KHz)启动内部时钟,延时 50ms 后(复位延

时),将内部时钟切换到快速模式(≈12MHz),同时在第一个 COG (Cog 0)载入并运行内建的 Boot Loader 程序。

2. Boot Loader 将执行下述一项或多项任务,顺序为:

a. 检测 P30,P32 引脚上同主机的通信,比如 PC。如果检测到通信,Boot Loader 将与主机建立会话,尝试将程序下载到主内存(Main RAM)或

外部 32KB EEPROM。

b. 如果没有检测到主机通信,Boot Loader 将在 P28 和 P29 引脚上检测外

部 32KB EEPROM(24LC256)。如果检测到了 EEPROM,就将其整个

32KB 的数据映像载入 Propeller 芯片的主内存(Main RAM)。

c. 如果没有检测到 EEPROM,Boot Loader 停止,Cog 0 停止运行,

Propeller 芯片进入关机模式,所有的 I/O 引脚设置为输入。

3. 如果第二步中 a) 或 b)成功的将程序装入主内存(Main RAM),并且主机也没

有发出休眠命令,那么 Cog 0 将重新装载内建的 Spin 语言解释器(Spin Interpreter),然后执行用户代码。

运行时(Run-Time)程序 Propeller 程序是一个用户程序,被编译为二进制形式并下载到 Propeller 芯片的

RAM 或外部 EEPROM 中。程序中包含了以 Spin 语言(高级语言)或 Propeller 汇编语

言(低级语言)编写的代码。以 Spin 语言编写的代码在 cog 上运行时会被 Spin 解释器

解释执行,而以 Propeller 汇编语言编写的程序则会直接在 cog 上执行。每一个

Propeller 程序都至少是由一些 Spin 代码,实际上有时是全部,组成的。或者是由 Spin代码和汇编语言代码组合而成。Propeller 芯片的 Spin 解释器是在启动程序的第三步开

始的,然后运行用户程序。 一旦启动程序完成,Cog 0 上开始运行程序,那么所有的进一步的活动就将由用户

程序定义。用户程序将控制诸如内部时钟速率,I/O 引脚用法,寄存器配置,以及何时

和有多少个 cog 运行。参见第三章:Propeller 编程教程。

Page 21: Propeller Manual - Parallax Home

1: Propeller 芯片简介

Propeller Manual v1.0 · Page 21

关机程序 当 Propeller 进入关机模式,内部时钟停止,这将导致所有的 cog 挂起(halt),所

有 I/O 引脚设置为输入(高阻抗)。关机模式是由下列三个事件之一触发的: 1) VDD 低于掉电门限(≈2.7VDC),掉电电路启动。 2) RESn 引脚被拉低 3) 程序要求重新启动(见 REBOOT 命令,292 页) 当电压上升到掉电门限以上或 RESn 引脚拉高后,关机模式被中断。

Page 22: Propeller Manual - Parallax Home

Propeller 芯片简介

Page 22 · Propeller Manual v1.0

方块图 图 1-2: Propeller 芯片方块图

Page 23: Propeller Manual - Parallax Home

1: Propeller 芯片简介

Propeller Manual v1.0 · Page 23

Propeller 芯片中 Cog 和 Hub 的交互是很重要的。Hub 控制了 cog 可以使用的互斥

(独占)资源,如主内存(Main RAM/ROM),寄存器等。Hub 以轮转的方式在一个

时刻给一个 cog 独占的资源,这种方法以严格的时序进行,而不管有多少个 cog 在运

行。

Page 24: Propeller Manual - Parallax Home

Propeller 芯片简介

Page 24 · Propeller Manual v1.0

共享资源 Propeller 中有两种类型的共享资源:1) 通用资源 和 2)互斥(独占)资源。 通用资

源可以在任何时刻被不限数目的 cog 访问。彼此互斥(独占)资源也可以被不限数目

的 cog 访问,但是在一个时刻只能有一个 cog 访问。通用资源是 I/O 引脚和系统计数

器。其他的共享资源是彼此互斥的,对它们的访问是由 Hub 控制的。见 24 页上 Hub小节。

系统时钟 系统时钟(在图 1-2 中为“时钟 CLOCK”)几乎是 Propeller 芯片中每个部件的中

心时钟源。系统时钟的信号可能来自于三个信号源:1) 内部 RC 震荡器,2) 时钟锁相

环(CLOCK PLL)或 3) 晶振(内部电路由外部晶振提供信号)。信号源由 CLK 寄存

器的设置指定,它在编译或运行时是可选择的。不直接使用系统时钟的部件是 Hub 和

总线(Bus);它们使用的时钟是由系统时钟二分频得到的。

Cogs (处理器) Propeller 包含了 8 个处理器,编号 0~7。每个 Cog 都包含了相同的部件(见图 1-

2):一个处理器块,长度为 512 的本地 2KB RAM(512×32 bits),两个带锁相环

的 I/O 助手(Assistant),一个视频发生器,I/O 输出寄存器,I/O 方向寄存器,以及其

它没有包含在图内的寄存器。见表 1-3 中关于 cog 内寄存器的完整列表。每个 cog 都彼

此相同,可以独立地工作。 所有的 8 个 cog 都由统一个时钟源—系统时钟—来驱动,所以它们有同样的时钟参

考,所有活动的 cog 可以同时执行指令。参见上述系统时钟。它们也可以访问相同的

共享资源,比如 I/O 引脚,主内存(Main RAM/ROM),以及系统时钟。参见上述共

享资源。 Cog 可以在运行时被启动和停止,也可被编程同时执行任务,以独立或协同方式访

问主内存(Main RAM)。除了它们原有的功能,Propeller 程序开发员有完全的控制权

来控制何时和如何启用每个 cog,多个 cog 之间没有编译器驱动或操作系统驱动的分布

任务。这种方法增强了程序员严格控制时序,功耗,以及对嵌入式程序响应的能力。 每个 cog 都有各自的 RAM,称为“Cog RAM”,其包含了 512 个 32 位的寄存器

。Cog RAM 除了 后 16 个寄存器,都是通用的,16 个寄存器是特殊功能寄存器,在

表 1-3 中对其进行了描述。Cog RAM 用于执行代码,数据,变量, 后 16 个寄存器作

为 cog 与系统计数器,I/O 引脚和本地 Cog 周边的接口。

Page 25: Propeller Manual - Parallax Home

1: Propeller 芯片简介

Propeller Manual v1.0 · Page 25

当 cog 启动时,地址(Location)0($000)到 495($1EF),被从主 RAM/RAM中依次载入,特殊寄存器 496($1F0)到 511($1FF)被清零。载入后,cog 从 RAM地址 0 开始执行指令,直到程序停止或重新启动。

表 1-3: Cog RAM 特殊用途寄存器

Cog RAM 分布图 地址 名称 类型 描述

$1F0 PAR 只读1 启动参数

$1F1 CNT 只读1 系统计数器

$1F2 INA 只读1 P31 - P0 的输入状态

$1F3 INB 只读1 P63 – P322 的输入状态

$1F4 OUTA 读/写 P31 - P0 的输入状态

$1F5 OUTB 读/写 P63 – P322 的输出状态

$1F6 DIRA 读/写 P31 - P0 的方向状态

$1F7 DIRB 读/写 P63 – P322 的方向状态

$1F8 CTRA 读/写 计数器 A 控制

$1F9 CTRB 读/写 计数器 B 控制

$1FA FRQA 读/写 计数器 A 频率

$1FB FRQB 读/写 计数器 B 频率

$1FC PHSA 读/写 计数器 A 相位

$1FD PHSB 读/写 计数器 B 相位

$1FE VCFG 读/写 视频配置

$1FF VSCL 读/写 视频比例(Video Scale) 注 1: 只有作为源变量时可访问 (i.e. MOV DEST, SOURCE). 注 2: 保留

Page 26: Propeller Manual - Parallax Home

Propeller 芯片简介

Page 26 · Propeller Manual v1.0

每个特殊寄存器可以通过如下方式访问:

1) 物理寄存器地址,

2) 预定义的名称,或

3) 一个寄存器数组,索引值从 0 到 15。

下面是一个 Propeller 汇编语言的例子:

MOV $1F4, #$FF '将 OUTA 7:0 置高

MOV OUTA, #$FF '同上 下面是 Spin 语言的例子:

SPR[$4] := $FF '将 OUTA 7:0 置高

OUTA := $FF '同上

Hub 为了保持系统的完整性,必须保证在一个时间内互斥(独占)的资源只有一个 cog

访问。Hub 通过控制独占资源保证了这种完整性,通过轮转的方式(从 cog0 到

cog7),Hub 赋予每个 cog 访问独占资源的权限。Hub 和被 Hub 控制的总线,以系统

时钟一般的速率运行。就是说每 16 个系统时钟周期,Hub 会把独占资源交给一个

cog。Hub 指令(指能访问独占资源的汇编指令)需要 7 个时钟周期执行,在这之前首

先需要同步到 Hub 访问窗口(Hub Access Window)。这里需要 15 个时钟周期(16 减

1,如果我们忽略它的话)同步到 Hub 访问窗口,加上 7 个时钟周期执行指令,所以

Hub 指令需要 7 到 22 个周期才能完成。 图 1-3 和图 1-4 的例子中 Cog 0 有一条 Hub 指令正在执行。图 1-3 是 好的情况;

Hub 指令在 Hub 访问窗口的开始已经准备好执行。Hub 指令执行了 7 个周期,在下一

个 Hub 访问窗口到来前留下 9 个周期用于其他指令。

Page 27: Propeller Manual - Parallax Home

1: Propeller 芯片简介

Propeller Manual v1.0 · Page 27

图 1-3: Cog-Hub 互动 – 好情况

图 1-4 中是 坏的情况;Hub 指令在 cog0 的访问窗口开始后就准备好执行;但是

它刚刚错过。Cog 会等待下一个 Hub 访问窗口(15 个周期后)然后 Hub 指令执行(7个周期)。再一次的,在 Hub 指令后,下一个 Hub 访问窗口到来前,会有 9 个额外的

周期。为了达到高效率,可以在要频繁地访问独占资源的汇编程序中插入非 Hub 指

令,减少等待下一个 Hub 访问窗口消耗的时钟周期。因为大多数 Propeller 汇编指令需

要 4 个时钟周期,所以在两条连续的 Hub 指令之间可以执行两条指令。

图 1-4: Cog-Hub 互动 – 坏情况

请记住,由于 Hub 的机制,一个实际的 Cog 的 Hub 指令不会和其他 Cog 的指令冲

突。例如,在系统时钟周期 2,Cog1 可以启动一条 Hub 指令,在这些例子中,可能会

使彼此的执行相互重叠而不会造成损害或带来问题。同时,其他的 cog 可以继续执行

非 Hub 指令,或者等待其他的单独 Hub 访问窗口,彼此互不影响。

I/O 引脚 Propeller 有 32 个 I/O 引脚,其中 28 个是完全用于通用目的的。4 个引脚(28-31)

在启动时有特殊用途,启动后可用于通用 ;参见 18 页中关于启动程序的描述。启动

之后,任何 I/O 引脚可被任意一个 cog 在任何时间使用,因为此时 I/O 引脚是共用资源

Page 28: Propeller Manual - Parallax Home

Propeller 芯片简介

Page 28 · Propeller Manual v1.0

(Common Resources)。这需要开发员确保在运行时不会有两个 cog 将同一个 I/O 引

脚用于不同目的。 每个 cog 都有其独有的 32 位 I/O 方向寄存器和 32 位输出寄存器。每个 cog 的方向

寄存器的状态会与前一次方向寄存器的值做或运算(OR’d)。注意每个 cog 的输出状

态由内部 I/O 的或运算后的状态组成,按旧式所有 AND’d 带有方向寄存器的状态。 结果是每个 I/O 引脚的方向和输出状态是整个 cog 集合的“线或(wired-OR)”。Cog 之

间没有电气连接,所以他们可以同时访问 I/O 引脚!

I/O 引脚线配置的结果可以被简述如下:

A. 一个引脚(状态)是输入,当且仅当没有活动的 cog 设置它为输出。

B. 一个引脚输出为低,当且仅当所有活动的 cog 将该引脚设置为输出且设置输

出为低。.

C. 一个引脚输出为高,当任意一个活动的 cog 设置它为输出,且输出为高。

表 1-4 展示了一些全部 cog 对一个实际 I/O 引脚的影响的组合,以 P12 为例子。为

简单起见,例子中假定每个 cog 的 I/O 硬件的第 12 位,除了 I/O 输出寄存器,都被清

零。. 表 1-4: I/O 共享的例子

Cog 的 I/O 方向寄存

器的第 12 位 Cog 的 I/O 输出寄存器

的第 12 位

Cog ID 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7

I/O 引脚 P12 的

状态 所遵循的规

例子 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 输入 A

例子 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 输出低 B

例子 3 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 输出高 C

例子 4 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 输出低 B

例子 5 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 输出高 C

例子 6 1 1 1 1 1 1 1 1 0 1 0 1 0 0 0 0 输出高 C

例子 7 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 0 输出高 C

例子 8 1 1 1 0 1 1 1 1 0 0 0 1 0 0 0 0 输出低 B 注:对于 I/O 方向寄存器,一个“1”会将相应的 I/O 引脚设置为输出,而“0” 会将其设置为输入方

向。

Page 29: Propeller Manual - Parallax Home

1: Propeller 芯片简介

Propeller Manual v1.0 · Page 29

任何关闭的 cog 会将其方向寄存其和输出状态清零,这样可以有效地消除对其他

cog 正在控制的 I/O 引脚的影响。

每个 cog 同样也有 32 位输入寄存器。输入寄存器是模拟出来的寄存器(Pseudo-Register);每当它被读取的时候,那么 I/O 引脚的实际状态会被读取,而不论其输入

或输出方向。

系统计数器 系统计数器是全局、只读、32 位的计数器,每经过一个系统时钟周期会自加一。

Cog 可以读取系统计数器(通过 CNT 寄存器,184 页)执行时序计算以及通过

WAITCNT 命令(322 页)来创建有效的延迟函数。系统计数器是共用资源。每个 cog都可以同时读取它的值。因为系统计数器是用于差分计时的,所以它不会在启动后立

即清零。如果一个 cog 需要从一个特定的时刻开始计时,只需要读取并保存初始值,

然后将其与计数器稍后的值作比较即可。

CLK 寄存器 CLK 寄存器是系统配置控制,它决定了系统时钟的信号源和特性。更精确

地说,CLK 寄存器配置 RC 振荡器,时钟锁相环(Clock PLL),晶振,和时钟

选择电路。(见 20 页图 1-2 Propeller 芯片方块图)图中在编译时由

_CLKMODE 的声明来配置,在运行时通过 CLKSET 命令可写。当 CLK 寄存器

被写入时,会有≈75µs 的全局时间延时,这是由于时钟源转换造成的。

当该寄存器改变时,写入值的备份应该存入时钟模式值位置(Clock Mode value location,主 RAM 中 BYTE[4])主时钟频率应该写入时钟频率值位置(Clock Frquency value location)(在主 RAM 中为 LONG[4]),这样参考了这些数据的对象才会有当前

的信息用于计时计算。(见 179 页 CLKMODE 和 175 页 CLKREQ)如果可能,推荐使

用 CLKSET 命令(183 页),因为它会自动更新所有上述相关的信息。

表 1-5: CLK 寄存器结构

Bit 7 6 5 4 3 2 1 0

名称 RESET PLLENA OSCENA OSCM1 OSCM0 CLKSEL2 CLKSEL1 CLKSEL0

Page 30: Propeller Manual - Parallax Home

Propeller 芯片简介

Page 30 · Propeller Manual v1.0

表 1-6: RESET (Bit 7)

Bit 效果

0 除非要复位芯片,否则保持“0”。

1 同硬件复位一样,重新启动芯片。Spin 命令 REBOOT 会向 RESET 位,写入“1”。

表 1-7: PLLENA (Bit 6)

位 效果

0 禁用 PLL 电路。_CLKMODE 声明的 RCFAST 和 RCSLOW 设定以这种方式配置

PLLEA。

1

启用晶振电路。_CLKMODE 声明的每个 PLLxx 设定以这种方式在运行时配置

PLLENA。时钟锁相环(Clock PLL)内部会将 XIN 引脚上的频率乘以 16。OSCENA 必须被设置为‘1’,将 XIN 的信号传递到时钟锁相环。时钟锁相环的内部频率必须保持

在 64 MHz 到 128 MHz 之间,换算到 XIN 频率就是 4 MHz 到 8 MHz。在通过

CLKSELx 位设置输出之前,允许时钟锁相环有 100 µs 的时间来稳定输出。晶体震荡器

和时钟锁相环电路启动并稳定后,就可以通过设置 CLKSELx 位来在时钟源之间切换。

表 1-8: OSCENA (Bit 5)

位 效果

0 禁用晶振电路。_CLKMODE 声明的 RCFAST 和 RCSLOW 设定以这种方式配置

OSCENA。

1

启用晶振电路,时钟信号就可以从 XIN 输入,或者 XIN 和 XOUT 可以一起作为反馈振荡

器。_CLKMODE 声明的 XINPUT 和 XTALx 设定以这种方式配置 OSCENA。 OSCMx 位选择晶振电路的操作模式。请注意晶振和共振器不需要外部电阻或电容。在通过

CLKSELx 位切换到晶振或时钟 PLL 输出前,允许晶振或共振器有 10ms 的时间来稳定

输出。当启用晶振电路时,时钟 PLL 也需要同时被起用,这样它们才能共享稳定的周

期。

Page 31: Propeller Manual - Parallax Home

1: Propeller 芯片简介

Propeller Manual v1.0 · Page 31

表 1-9: OSCMx (Bits 4:3) OSCMx

1 0 _CLKMODE

设置 XOUT 阻抗

XIN/XOUT 容值 频率范围

0 0 XINPUT 无穷大 6 pF (pad only) DC to 128 MHz 输入

0 1 XTAL1 2000 Ω 36 pF 4 到 16 MHz 晶振/共振器

1 0 XTAL2 1000 Ω 26 pF 8 到 32 MHz 晶振/共振器

1 1 XTAL3 500 Ω 16 pF 20 到 60 MHz 晶振/共振器

表 1-10: CLKSELx (Bits 2:0)

CLKSELx

2 1 0

_CLKMODE 设定

主时钟 源 注释

0 0 0 RCFAST ~12 MHz 内部 无外部器件 范围从 8 MHz 到 20 MHz。

0 0 1 RCSLOW ~20 kHz 内部 极低的功耗。 范围从 13 kHz 到 33 kHz。

0 1 0 XINPUT XIN OSC OSCENA 必须为 '1'.

0 1 1 XTALx and PLL1x XIN x 1 OSC+PLL OSCENA 和 PLLENA 必须为 '1'.

1 0 0 XTALx and PLL2x XIN x 2 OSC+PLL OSCENA 和 PLLENA 必须为 '1'.

1 0 1 XTALx and PLL4x XIN x 4 OSC+PLL OSCENA 和 PLLENA 必须为 '1'.

1 1 0 XTALx and PLL8x XIN x 8 OSC+PLL OSCENA 和 PLLENA 必须为 '1'.

1 1 1 XTALx and PLL16x XIN x 16 OSC+PLL OSCENA 和 PLLENA 必须为 '1'.

锁(Locks ) 有八个锁位(Lock Bit)(也称为信号位)可用于在多个 cog 间灵活地独占(互

斥)式地访问用户定义的资源。如果内存块被两个或者更多个 cog 使用,同时该内存

块由多于一个长字(四字节)组成,那么这些 cog 中的每一个将执行多次读写来取回

(Retrieve)或更新改内存块。这将可能导致在该内存块上读写冲突,也就是一个 cog在另一个 cog 读取数据时写入,导致误读或误写。

Page 32: Propeller Manual - Parallax Home

Propeller 芯片简介

Page 32 · Propeller Manual v1.0

锁是全局位,通过 Hub 指令:LOCKNEW, LOCKRET, LOCKSET, 和 LOCKCLR 来

访问。因为锁是通过 Hub 来完成的,所以一个时刻只会有一个 cog 能影响它们。Hub会维护一份清单,标明了哪些锁位正在被使用以及其当前的状态,cog 可以在需要时

检出(取出),检入(退回,Return),设置和清除锁位。见 LOCKNEW,230 页;

LOCKRET,233 页;LOCKSET,234 页;LOCKCLR,228 页 更多的信息。

主内存 主内存是一个 64K 字节大小(16K 长字)的块(Block),所有的 cog 都可以通过

Hub 以独占资源的形式访问。它包含了 32KB 的 RAM 和 32KB 的 ROM,32KB 的主

RAM 是通用的,不论 Propeller 程序是从主机下载或是从外部 32KB EEPROM 中上传

的,都会写入 32KB 的主 RAM。32KB 的主 ROM 包含了对 Propeller 芯片而言,所有

重要的代码和数据资源:字符定义,对数,反对数和正弦值表,BootLoader 和 Spin 解

释器。主内存的组织如图 1-5.

图 1-5: 主内存影射

主 RAM 主内存的前半部分是 RAM。这段空间用于用户程序,数据,变量和堆栈;也就是

您的 Propeller 应用程序。

当一个程序载入芯片时,无论从主机或外部 EEPROM,整个内存空间都会被写

入。前 16 个位置,$0000 – $000F,保存了 Boot Loader 和解释器的初始数据。您程序

Page 33: Propeller Manual - Parallax Home

1: Propeller 芯片简介

Propeller Manual v1.0 · Page 33

的可执行代码会从$0010 开始,并延续一定长度。可执行代码后的一段区域,直到

$7FFF,用于变量和堆栈空间。

有两个值会存储在初始化区域,它们可能对您的程序有用: $0000 存储的一个长字

型值包含了主时钟频率的初始化值,单位是赫兹,其后的一个字节($0004)包含了要

写入 CLK 寄存器的初始值。这两个值可以使用其物理地址 (LONG[$0] 和 BYTE[$4]) 读写,也可以用预定义名字被读取(CLKFREQ 和 CLKMODE)。 如果您没有使用 CLOCKSET 命令

来修改 CLK 寄存器,您就需要去更新这两个位置,以使引用他们的对象能有正确的信

息。

主 ROM 主内存的后一半是 ROM。这块空间用于字符定义,数学函数,和 BootLoader 以及

Spin 解释器。

字符定义 ROM 的前半部分专用于 256 个字符组成的字符集的定义。每个字符定义为 16 像素

宽 32 像素高。这些字符定义可以用于视频显示,图形 LCD 显示,打印等。字符集是

基于北美/西欧布局(基本拉丁语和拉丁语-1 增补),并插入了特殊的符号。这些特殊

符号是互联的波形和原理图内建块(Schematic Building-block),电子领域内通用的希

腊符号,以及一些箭头和其它符号。

Page 34: Propeller Manual - Parallax Home

Propeller 芯片简介

Page 34 · Propeller Manual v1.0

图 1-6: Propeller 字体符号

图 1-6 中的字符定义是从 0 到 255,以从左到右,从上到下的方式排列的。在

ROM 中,它们排列成相邻的奇偶字符对,共 32 对。 第一个字符对位于$8000-$807F字节处。第二对字符占据了$8080-$80FF 字节,以此类推,直到 后一对位于$BF80-$BFFF。Propeller 工具包括了一个互动字符表(帮助->显示字符表…),它的 ROM 位

图视图(ROM Bitmap view)可以显示每个字符的位置。

字符对的像素列与列之间被融合在一起,意思是每个字符的 16 个像素和下一个字

符的像素是间隔排列的,偶数字符占用了 0, 2, 4, ...30 位,奇数字符占用了 1, 3, 5, ...31位。 左侧的像素在 低的位中, 右侧的像素在较高的位中,如图 1-7。这样每个字

符对中的每行像素就形成了一个长字型(4 字节)值。32 个这样的长字型值,就形成

了从字符顶部到底部的完整的融合对(merged-pair)定义。使用这样的定义方式是为

了使 cog 的视频硬件可以直接处理融合的长字型值,通过颜色选择来显示奇数或偶数

字符。 还有优点就是允许运行时字符对(四色字符,参见下一段)用于画出斜边按

钮,线条和焦点指示器(focus indicator)。

Page 35: Propeller Manual - Parallax Home

1: Propeller 芯片简介

Propeller Manual v1.0 · Page 35

图 1-7: Propeller 字符插入

有些字符编码有内在的意义,比如 9 是制表符(Tab),10 是换行(Line Feed),

以及 13 是回车(Carriage Return)。这些字符编码包含了动作,不能用静态字符来定

义。因此,这些字符定义被用作特殊的四色字符。这些四色字符可用于画出运行时 3-D 图形的边缘,以 16 x 16 像素的方式实现,与正常的 16 x 32 像素单元(cell)不同。 它们占用了偶数-奇数字符对 0-1,8-9,10-11,和 12-13。图 1-8 所示为一个带有 3D斜面边缘的按钮,它是由上面介绍的字符组成的。

图 1-8: 3D 斜面边缘的

按钮

Propeller 工具包括,并使用 Parallax True Type® 字体,它遵循嵌入硬件的 Propeller

字体的设计。使用这样的字体,以及 Propeller 工具,您可以在源代码中嵌入原理图,

时序图和其他图表。

对数和反对数表 对数和反对数表在转换数值的数字形式和幂指数形式时很有用。

当数值表示为幂指数形式时,简单的数学运算会变得复杂。比如“加”和“减”变成了

“乘”和“除”。“左移”变成了“平方”,“右移”变成了“平方根”。“除 3”会变成“立方根”。当幂指数形式转换回数字形式,结果就会显而易见了。

见 420 页上附录 B:访问数学函数表 更多的信息。

Page 36: Propeller Manual - Parallax Home

Propeller 芯片简介

Page 36 · Propeller Manual v1.0

正弦值表 正弦值表提供了 2049 个从 0°到 90°的无符号 16 位正弦采样值(分辨率

0.0439°)。其它象限的正弦值(>90°到<360°)可以通过对第一象限的正弦值作简单的

变换得到。正弦值表可以用于和角度相关的计算。

见 420 页上附录 B:访问数学函数表 更多的信息。

BootLoader 和 Spin 解释器 Propeller 芯片中主 ROM 的 后一段包含了 Boot Loader 和 Spin 解释器程序。 BootLoader 负责初始化上电/复位之后的 Propeller。当一个启动程序开始,

BootLoader 会被载入 Cog 0 的 RAM 中,Cog 从位置 0 开始执行代码。BootLoader 程序

首先检查主机和 EEPROM 的通信引脚以进行代码/数据的下载/上传,处理相应的信息

,然后在 Cog0 的 RAM 中启动 Spin 解释器程序(覆盖掉 Bootloader),或者使

Propeller 进入关机模式。见 18 页中启动程序一节。

Spin 解释器程序从主 RAM 中取得并执行 Propeller 应用。应程序要求,将启动额外

的 cog 来执行更多的 Spin 代码或 Propeller 汇编程序。见 18 页 运行时程序。

Page 37: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 37

Chapter 2: 使用 Propeller 工具 本章描述了 Propeller 工具软件的特性,从概念和结构开始,然后是软件的屏幕组

织和目的,菜单功能的细节,高级特性和快捷键。.

概念 Parallax 的工程人员在过去的 20 年内使用过很多开发工具。很多时候我们发现我们

想的事情比如:

• 如果特性“x”更易于被找到/调用会不会好一些?

• 我的项目文件在哪里和怎么会有这么多?

• 我仍然能够几年后正确地安装/编译/维护他们吗?

• 有没有便宜一点的方案?

这些经历驱使我们加强了为我们的产品创建简单,便宜的开发工具的决心。

Propeller 工具(Propeller Tool)在设计时,这些想法就一直伴随着我们,那就是提

供有用的功能,同时保持简单,有连续性的开发环境,促进快速而简单地开发

Propeller 芯片固件对象。

Propeller 工具软件包含了一个简单的可执行文件,一些在线帮助文件和 Propeller 库文件,都和安装文件一起存储在一个文件夹里,通常是 C:\Program Files\Parallax Inc\Propeller。Propeller 工具的可执行文件“Propeller.exe”可以被拷贝到计算机中的任

何文件夹;它不依赖于任何特殊系统文件。

每个库文件(带有“.spin”扩展名的文件)是独立对象(Self-contained),内建了

源代码和文档,可以用于你自己的 Propeller 项目。这些库文件都是 ANSI 或 Unicode编码的文本文件,可以在任何支持该编码的文本编辑器里编辑;Windows®2000(及以

上版本)里的记事本(Notepad)同时支持 ANSI 和 Unicode 编码的文本文件。

您是否注意到我们提到对象的文档是内建在对象文件中的?我们鼓励在对象的源代

码右侧书写用户文档。这就是说在代码升级时需要维护较少的文档。为了进一步增强

过程,我们创建了:

Page 38: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 38 · Propeller Manual v1.0

• 两种源代码注释,1) 代码注释(注释代码块); 2) 文档注释(也在代码中,但

是应该从文档阅读的观点)。

• 为了便于阅读,Propeller 工具中的“文档视图(documentation view)”从代码

中提取了对象文档。

• 特殊字体,Parallax 字体,包含了特殊符号,比如原理图,时序图,和在对象

文档中的表格。

Parallax 字体是内建在 Propeller 工具可执行文件中的 True Type®字体。它和内建于

Propeller 芯片 ROM 中的字体相同。通过使用字体中的特殊符号,对象文档能包含有用

的图表供工程需要,比如:

330ω sig1 P0 sig2 220ω AB C D P1 00 1 n/a 0.1µF 50kω pot 01 2 5

图 2-1: 使用 Parallax 字体建立的图形

运行过一次 Propeller 工具后,这些字体就可以用于其它程序,这样你也可以在其

他文本编辑其中看到这些图表,比如记事本,或者在你的 email 软件中(支持 Unicode编码)。

为项目创建的每个对象都将以库文件的格式存储(带有.spin 扩展名)在你选定的工作

目录中。

这都是为了促进共享和从其他对象中学习,而不论是由我们或是其他 Propeller 产

品的用户创建的。

Page 39: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 39

关于文件,对象,对象文档,库文件和源代码的信息,见第三章:Propeller 编程指

导。

屏幕组织 Propeller 工具软件的主窗口分为四个部分,被称为“窗格(pane)”,每一个都有

特殊的功能。

图 2-2: Propeller 工具软件的主窗口包含了四个部分,或“窗格”

Page 40: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 40 · Propeller Manual v1.0

窗格 1,2 和 3 是集成浏览器(Integrated Explorer)的一部分。集成浏览器在编辑

窗格的左边,提供了关于目前工作项目所在的磁盘,文件夹和文件的视图。集成浏览

器被一个垂直的分割条从编辑窗格中分割出来,分割条可以被鼠标调整大小。集成浏

览器可以被隐藏(左键单击并拖动分割条),通过选择 File->Hide Explorer,或者按快

捷键 Ctrl+E。菜单和快捷方式选项的执行会使集成浏览器在两种状态下切换:1) 可见

(设置为 后一次已知大小),2) 不可见(完全折叠到 Propeller 工具左侧)。

图 2-3: 集成浏览器及其部件可以通过拖动分隔栏来调整大小

Page 41: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 41

窗格 1: 对象视图窗格 窗格 1 是对象视图窗格。Propeller 的芯片语言,Spin,是基于对象的,一个

Propeller 项目可以由多个对象组成。对象视图显示了你 近成功编译的项目的等级关

系,可以为你项目的结构提供有价值的反馈信息。通过对象视图,你可以决定哪些对

象被使用了,它们与其他对象的配合,它们在磁盘上的物理位置(工作文件夹,库文

件夹或仅仅是编辑器),冗余的优化结果(如果有)和任何潜在的对象冲突问题等。

见第 52 页中“对象视图”中更多的信息。

窗格 2: 近使用的文件夹区域和文件夹列表 窗格 2 包含了两个部件:1) 近使用的文件夹区域,2)文件夹列表。这两个部件一

起为您提供了计算机上可用的磁盘驱动器的导航访问(Navigational Access)。文件夹

列表显示了每个磁盘驱动器上文件夹的等级关系,可以和 Windows 资源管理器左侧的

窗格一样进行操作。

近使用文件夹区域(文件夹列表上方)以下拉菜单的方式提供了一些文件夹的列

表,这些文件夹是您 近从中载入过文件的。从 近使用的文件夹列表中选择文件

夹,会使文件夹列表快速定位到相应的文件夹。此外,如果您在文件夹列表中选择了

一个已经在 近使用的文件夹列表中存在的文件夹,那么 近使用的文件夹列表会自

动更新显示。

近使用的文件夹列表中的第一项是“Propeller Library”和“Propeller Library Demos”。这两项是自动包含在内的,它们指向存放了 Propeller 库文件和库文件演示

程序的文件夹。上述文件都是包含在 Propeller 工具安装文件内的。

如果您选择了一个不在 近使用的文件夹列表中的文件夹, 近使用的文件夹区域

将被清空。 近使用的文件夹区域左侧的按钮会激活 近使用的文件夹和文件夹列表

的两种不同显示:1)显示每个驱动器和文件夹 2)只显示 近使用的驱动器和文件夹。

设置为只显示 近使用的文件夹是比较传统的方式,可以在实际的驱动器或者网路中

大量不想关得文件夹中快速定位到 Propeller 项目文件夹.

窗格 3: 文件列表和过滤器 窗格 3 包含了两个部件:1)文件列表 2)过滤器区域。文件列表显示了在文件夹列表

中选定的文件夹中满足过滤器条件设定的文件。文件列表的使用方式和 Windows 资源

管理器的右侧窗格相似。

Page 42: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 42 · Propeller Manual v1.0

过滤器区域(在文件列表下方)提供了基于文件扩展名(称为过滤器(Filters))

下拉菜单方式的列表显示。通常过滤器会被设置为只显示 Spin 文件(带有“.spin”扩

展名的文件),但是也可以设置为显示文本文件或全部文件。如果您定位到一个文件

夹后看不到您希望看到的文件,请先确认文件过滤器的设置是否正确。

在文件列表中的文件可以被编辑器打开,有三种方式:1)双击该文件,2)选中该文

件,将其拖入编辑器窗格中(窗格四),或者 3)右键单击该文件,从上下文菜单中选

择“打开(Open)”。

窗格 4: 编辑器窗格 窗格四是编辑器窗格。它提供了对您已经打开的 Spin 源代码的视图,您可以在在

这里对代码浏览,编辑或进行其他的操作。在编辑器窗格内,每个您打开的文件(源

代码对象)都会作为单独的编辑栏出现在文件后。当前活动的编辑栏被高亮显示。您

可以一次打开多个文件,仅仅取决于内存大小的限制。

单击一个编辑栏会打开编辑页面。您可以在已打开的文件间切换,方法是:1)按Alt+CrsrLeft 或者 Alt+CrsrRight, 2)按 Ctrl+Tab 或者 Ctrl+Shift+Tab。如果鼠标指针在编

辑栏上停留较长时间,将会显示一条提示信息,信息中有文件的完整路径和文件名。

编辑页面内的源代码会自动将关键字高亮,以助于区分块类型,元素类型,注释和可

执行代码等。

图 2-4: 将鼠标在编辑栏上停留可以显示当前文件的完整的路径和文件名

Page 43: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 43

每个编辑页可以以四种方式之一来显示源代码:

1) 全部代码

2) 浓缩代码

3) 摘要

4) 文档.

显示代码的模式可以被改变,每个编辑栏都可以被单独改变,方法是:

1) se 鼠标选择相应的按钮,

2) 按下 Alt+Up 或 Alt+Down,

3) 按下 Alt+<letter>, where <letter>是希望的显示模式的下划线热键,或

4) 按下 Alt 同时滑动鼠标滚轮

请注意如果对象不能被完全编译,将不能进入文档视图模式。参见 61 页上

关于视图模式,书签,和行号等更多信息。 一个项目可能会由多个对象组成,如果不能同时看到您正在编辑的对象和您

将要接口的对象,项目开发可能会变得很棘手。 编辑器窗格允许您将编辑栏拖放到不同的位置。举例而言,如果打开多个对

象,您可以使用鼠标左键选中并拖动编辑栏向下移动到编辑器窗格的下半部

分,在那里释放按键。这时会在您拖放的区域出现一个新的编辑窗格区域。如

果您愿意,您可以继续拖放窗格到这个新区域。这些步骤见图 2-5。

Page 44: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 44 · Propeller Manual v1.0

Figure 2-5: 查看和排列多个对象

步骤 1: 同步显示多个对象源代码,左键单击一个编辑栏,将它拖放到编辑窗格内较低的位置。

步骤 2: 释放按键。编辑栏会在新位置显示其内容。

步骤 3: 如果有其他编辑栏要显示,重复步骤 1 和 2,可以通过拖动水平分隔条调整大小。

Page 45: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 45

两个区域之间的垂直尺寸可以通过拖动水平分隔条来调整。当然,在您正在全部代

码方式下(唯一可编辑的视图)开发对象时,您可以以您认为方便的方式(全部代

码,压缩,汇总,或文档)来查看你正在接口的对象。

编辑窗格甚至允许将其内部的编辑栏完全被拖离 Propeller 工具。拖动完成后,一

个新的编辑栏会出现在一个新的窗口中,这个窗口可以独立于 Propeller 工具应用程序

窗口。这种方式在计算机有多个监视器的时候很有用,可以将编辑栏拖放到第二个监

视器的桌面上。 图 2-6: 排列对象

步骤 1: 在桌面空间允许的情况下,您可以将编辑栏拖动离开 propeller 工具程序;左键单击编辑栏,将其拖动离开Propeller 工具。

Step 2: 释放左键。该编辑栏会形成自身独立于 Propeller 工具的新窗口。可以将更多的编辑栏拖放成独立的窗口。.

Propeller Tool 的底部是状态栏,它被分为 6 格,每一个都显示了在各个开发阶段有

用的信息。

Page 46: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 46 · Propeller Manual v1.0

第一格显示了在当前活动的编辑栏中脱字符的行列位置。

图 2-7: 状态栏

第二格显示了对当前编辑栏的修改状态: 1) 空白,意思是没有修改, 2) 修改

(Modify),或 3) 只读(read-only)。

第三格显示了当前的编辑模式:1) 插入(Insert,默认状态),2) 对齐(Align),

或 3) 覆盖(Overwrite)。 编辑模式可以通过按下 Insert 键来改变。 不同编辑模式的更

多信息参见 65 页开始的编辑模式一节。

第四格显示的是当前编辑栏的编译状态:1) 空白,意思是未编译,或 2) 已编译

(compiled)。它表示该源代码自从上一次编译后是否有改变。如果该代码自从上一

次编译后未被修改,就会显示“Compiled”。

第五格显示了当前在编辑栏内的源代码的上下文敏感的信息,如果代码自上一次编

译后没有改变,将编辑页的脱字符移动到 CON 或 DAT 块符号或 PUB/PRI 块内的位置可以

看到该区域的相关信息。

第六格显示的是 近操作的临时信息。这里会显示自上一次成功编译以后的错误信

息,直到另一条消息将其覆盖。这里也会显示成功编译信息,字体大小改变和其他状

态信息。

整个状态栏显示的提示描述了菜单项目的功能,它和将鼠标悬停在菜单项上时出现

的提示是一样的。

Page 47: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 47

菜单项

File 菜单 New 创建一个新的,空白的编辑栏。不会影响到已有的编辑

栏。

Open… 使用打开(Open)文件对话框建立一个新的编辑栏。

Open From… 使用打开文件对话框,从 近访问的文件夹中打开一个

文件,建立一个新的对话框。

Save 将当前的编辑栏的内容保存到磁盘中,保存时使用现有

的文件名(如果有文件名)。

Save As… 将当前的编辑栏的内容保存到磁盘中,保存时使用 Save As 对话框。

Save To… 将当前的编辑栏的内容保存到磁盘中的 近访问的文件

夹中,保存时使用 Save As 对话框。

Save All 将所有的未保存的编辑栏的内容保存到磁盘中,保存时

使用已有的文件名(如果有文件名)。

Close 关闭当前编辑栏(如果文件未保存会提示保存)。

Close All 关闭全部的编辑栏(如果有文件未保存,会提示保

存)。

Select Top Object File… 为当前的项目设置顶部对象文件。该设定适用于所有的

“编译顶部…(Compile Top)”命令,直到有新的设定

做出改变。

Archive

→ Project… 将所有的在对象视图中的对象和数据文件打包存储在一

个 zip 文件中。同时加入一个“readme”文件,该文件

中包含了压缩包和结构的信息。压缩文件的文件名会是

顶部文件的名称加上“Archive”和日期/时间,然后存贮

在顶部对象的工作目录中。

Page 48: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 48 · Propeller Manual v1.0

→ Project + Propeller Tool... 和上面的选项执行相同的任务,但是会向压缩包内添加

整个 Propeller 工具的可执行文件。

Hide/Show Explorer 隐藏或显示集成浏览器面板(应用程序的左侧)。

Print Preview… 打印预览。

Print… 打印当前编辑栏的内容。

<recent files> 在 Print… 和 Exit 项目中间的内容的菜单区域显示了

近访问的文件, 大数目为 10 个。可以从中选择这些项

目打开。将鼠标指向 近访问的文件菜单可以在状态栏

(Status bar)看到完整的路径和文件名。

Exit 关闭 Propeller 工具。

Edit 菜单 Undo 撤销作用于当前编辑页的上一次操作。在页面被关闭

前,每个编辑页面都有其独自的撤销历史缓冲区。允许

多次撤销操作,只受内存大小限制。

Redo 恢复作用于当前编辑页的上一次操作。在页面被关闭

前,每个编辑页面都有其独自的恢复历史缓冲区。允许

多次恢复操作,只受内存大小限制。

Cut 从当前的编辑页删除选中的文本,将其复制到 Windows 剪贴板中。

Copy 将当前的编辑页中选中的文本复制到 Windows 剪贴板

中。

Paste 将 Windows 剪贴板中的内容复制到当前编辑页的脱字符

位置。

Select All 全选当前编辑页中的所有文本。

Find / Replace… 打开 Find/Replace(查找/替换)对话框;参见 49 页上关

于 Find/Replace 对话框的更多信息。

Find Next 查找上一次输入 Find/Replace 对话框的内容所在的位

置。

Page 49: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 49

Replace 在 Find/Replace 对话框中,用在 Replace 域中的内容替换

当前选择内容。

Go To Bookmark 跳转到书签 1, 2, 3… (只有在书签被显示时才可见)。

Text Bigger 增加全部页面中字体的字号。

Text Smaller 减少全部页面中字体的字号。

Preferences… 打开 Preferences 窗口。 用户可以自定义 Propeller 工具的

设定。

Run 菜单 Compile Current

→ View Info… 编译当前编辑栏的源代码,如果编译成功,则显示对象

信息。对象信息会显示一些细节,包括对象结构,代码

长度,变量空间,自由空间和冗余优化等。

→ Update Status 编译当前编辑栏中的代码,如果编译成功,就更新项目

中 状态条中的对象状态信息。

→ Load RAM 编译当前编辑栏中的代码,如果编译成功,将应用程序

下载到 Propeller 芯片的 RAM 中,并运行。

→ Load EEPROM 编译当前编辑栏中的代码,如果编译成功,将应用程序

下载到 Propeller 芯片的 EEPROM(和 RAM)中,并运

行。

Compile Top

→ View Info… 和 Compile Current → View Info 一样,除了编译会从被

指定为顶部对象文件的文件开始。

→ Update Status 和 Compile Current → Update Status 一样,除了编译会从

被指定为顶部对象文件的文件开始。

→ Load RAM 和 Compile Current → Load RAM + Run 一样,除了编译

会从被指定为顶部对象文件的文件开始。

→ Load EEPROM 和 Compile Current → Load EEPROM + Run 一样,除了

编译会从被指定为顶部对象文件的文件开始。

Page 50: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 50 · Propeller Manual v1.0

Identify Hardware… 为 Propeller 扫描可用的端口,如果发现可用的端口,就

显示连接的端口和硬件版本号。

Help 菜单 Propeller Tool… 显示 Propeller 工具的在线帮助。

Spin Language… 显示 Spin 语言的在线帮助。

Assembly Language… 显示 Propeller 汇编语言的在线帮助。

Example Projects… 显示包含有 Propeller 例子项目的在线帮助。

View Character Chart… 显示互动 Parallax 字符表。该表以三种可能视图显示

Parallax 字体符号集:标准顺序,ROM 位图和符号顺

序。标准顺序是标准 ANSI 顺序,ROM 位图展示的是这

些字符数据在 Propeller 芯片 ROM 中的组织方式。符号

顺序以分类顺序列出所有的字符(字母,数字,标点,

原理图符号等)。参见 58 页,字符表。

View Parallax Website… 用计算机默认的网络浏览器打开 Parallax 的网站。

E-mail Parallax Support… 打开计算机的默认 Email 软件向 Parallax 支援小组发送

消息。

About… 显示关于(About)窗口,提供 Propeller 工具的详细信

息。

Page 51: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 51

Find/Replace 对话框 Find/Replace 对话框用于在当前编辑页中查找和/或替换文本。

图 2-8: Find/Replace 对话框

Find 选项: Find: 域中输入要查找的字符串。如果在当前的编辑页中选择了一个字或词组,然

后打开 Find/Replace 对话框,那个字或词组会自动被输入盗 Find:域中。Find:域会

保留过去 10 次不同的输入内容。要选择上一个条目,单击 Find:域的向下箭头,从列

表中选择就可以了。

Replace: Replace: 域中输入替换后的字符串。Replace:域会保留过去 10 次不同的输入内

容。要选择上一个条目,单击 Find:域的向下箭头,从列表中选择就可以了。

Match Match 组控制的是 Find:域的内容如何匹配编辑页内的文本。Match 选项是:1) 全

字匹配,2) 大小写,和 3) 使用通配符。

Page 52: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 52 · Propeller Manual v1.0

Whole Words 如果想要完全匹配 Find:域中的内容,而不是一个单词中的某些字符或较长的单

词中的字符,则应选择该选项。

Case 如果你想要 Find:域中的内容完全匹配大小写,就因该选中 Case checkbox;这也

称作大小写敏感搜索。

With Wildcards 如果想要在 Find:域中使用正则表达式通配符搜索,则需要选中该选项。

Origin, Scope and Direction 组合起来表明了搜索的开始位置,范围,和方向。

Origin Origin 组控制了搜索的起点;从文件顶部或从光标处开始。选择 Top,会从文件顶

部开始搜索(或者如果选择区域已经在 Scope 组中设定,则选择区域的顶部开

始。)。选择 Cursor 会从文件当前光标(脱字符)所在的位置开始。注意:如果

Direction(方向)组被设置为 Backward,则需要将 “Top” 选项设置为 “Bottom”。

Scope Scope 组控制了搜索的范围:整个文件或只是当前的选择。这是在文件中有限的范

围内执行搜索,或查找替换的方便的方法。Scope 组默认是被设置为 Entire File (整个

文件)而且不可用,除非在打开 Find/Replace 对话框之前已经选定了一个区域。如果

在打开 Find/Replace 对话框之前已经选择了至少一行以上的内容,则 Scope 组会自动

选择成 Selection。

Direction Direction 组控制了搜索的方向;Forward(前向,向文件底部)或 Backward (后

向,向文件顶部)。如果设置为 Backward,Origin 组的第一项会从“Top” 改为

“Bottom”,意思是搜索的起点是从文件或选区的底部。

Find 按钮 Find 按钮启动了搜索过程,该搜索是基于 Find/Replace 对话框中所有选项进行的。

如果在编辑页面内找到了和关键字匹配的内容,该内容会被选择并移动到可显示的位

置, Find 按钮会变为 Find Next 按钮。点击 Find Next 按钮会使下一项匹配的结果选择

Page 53: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 53

并被显示。也可以使用 F3 键执行 Find Next(查找下一项)动作而不需要打开

Find/Replace 对话框。

Replace 按钮 Replace 按钮只有在 Replace:域中有文本,以及至少发现一个匹配的文本时才可以

使用,(通过 Find 按钮或 F3)。单击 Replace,或不打开 Find/Replace 对话框的情况

下按 F4,会使当前匹配的字符串被在 Replace: 域中的内容替换。替换后,如果需要再

次替换,则可以先按 Find Next 按钮,或 F3 键,然后再选择替换。按下 Control (Ctrl) 键,会将 Replace 按钮变为“Replace/Find”,单击该按钮或按 Ctrl+F4(不论是否打开

Find/Replace 对话框),会使当前匹配的字符串被替换,然后立即执行 Find Next 动作。

Replace All 按钮 Replace All 按钮只有在 Replace:域中有文本,以及至少发现有一个匹配的文本的

情况下才可以使用。单击 Replace All 会使在文件中匹配的字符串被在 Replace 域中的

内容替换,关闭对话框时,会给出结果对话框指出找到的内容和替换内容的数字。

Close 按钮 Close 按钮会关闭 Find/Replace 对话框。

Page 54: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 54 · Propeller Manual v1.0

对象视图 对象视图会显示 近成功编译的对象的层次结构。在 Propeller 工具中有两种对象

视图:1) 在 Propeller 工具主窗口的集成浏览器的顶部的对象视图(参见 39 页窗格

1: )和 2) 在对象信息表单上层的对象信息视图(参见 55 页对象信息 这两种对象视图

的功能都一样。

对象视图提供了 近一次成功编译的对象的结构,以及被编译的项目中每个对象信

息的视觉反馈。

图 2-9: 例子对象视图显示了 ABC Product 编译后的结构

在上面的图 2-9 中,对象视图指出 ABC Product 应用程序的结构。在该例子中,

ABC Product 对象是“顶部对象文件”(参见 87 页对象和应用程序),它使用了

Numbers,Rotary Encoder 和 Controller 对象。此外,Controller 对象使用了 TV 对象。

对象名称显示出实际的文件名(不带扩展名)。只有在该对象是数据文件时才会在

显示时包含扩展名(参见 215 页 FILE)并且以斜体字显示。

每个对象名称左边的图标表明了对象所在的文件夹。下面的例子列出的四种可能的

情况:

(黄色): 对象在工作文件夹中。

(蓝色) : 对象在库文件夹中。

(条纹): 对象在工作文件夹中,但另外有同名对象被使用。

(中空): 对象不在任何文件夹中,因为文件还没有保存。

Page 55: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 55

工作文件夹 工作文件夹(黄色)是顶部对象文件所在的文件夹。每个项目都会有一个,只有一

个,工作文件夹。

库文件夹 库文件夹(蓝色)是 Propeller 工具的库对象所在的文件夹,这些库对象是随

Propeller 工具软件安装时一起被安装的。库文件夹是 Propeller 工具可执行的起点,在

库文件中的所有对象(有.spin 扩展名)都会被视为是库文件。

条纹文件夹 有条纹图标的对象指出工作文件夹中的对象和库文件夹中的对象都引用了同名子对

象,该子对象存储在工作文件夹或库文件夹中。该同名对象可能是 1) 同一个对象的副

本,2) 同一个对象的两个版本,或 3) 两个完全不同的对象,只是偶然同名。不考虑这

种情形,仍然推荐尽快解决这个潜在的问题,因为它迟早会产生问题,比如不能使用

Archive 特性。

中空文件夹 有中空图标的对象表明该对象是在编辑器中创建的,但是没有被保存到任何硬盘文

件夹中。这种情况下,就像上面提到过的,不会立刻产生问题,但是如果不解决,迟

早会带来麻烦。

将鼠标指向并选定对象可以提供额外的信息。在对象视图中单击一个对象会在编辑

窗口打开该对象。左键单击会以完整代码视图方式打开,右键单击会以文档试图方式

打开。双击会以全部代码方式打开包括子对象在内的所有代码。如果对象已经打开,

则将相应的编辑窗口激活,并切换到合适的视图;左键单击或双击是完整代码视图,

或右键单击是文档视图。

Page 56: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 56 · Propeller Manual v1.0

在对象视图中将鼠标悬停在一个对象上会显示该对象得更多的提示信息。图 2-10a 显示了 ABC Product 对象的提示。该提示表明 1) ABC Product 对象是该项目的顶部对

象文件,2) 它被存储在工作文件夹中,3) 它的路径和文件名是:C:\Source\ABC Product.spin。从这条信息我们可以推断出该项目的工作文件夹是:

C:\Source

a.

b.

图 2-10: 将鼠标悬停在对象上可以看到更多的提示信息

图 2-10b 显示了 Numbers 对象的提示信息:1) 它是一个对象文件(就是说它是一

个子对象,而不是顶部对象),2) 它存储在库文件夹中,以及 3) 它的路径和文件名

是: C:\Program Files\Parallax Inc\Propeller\Numbers.spin。从这条信息我们也可以推断

出该项目的库文件夹是:

C:\Program Files\Parallax Inc\Propeller.

对象视图的提示信息常常能提供有用的信息,例如冲突的报警,和优化结果等。

Page 57: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 57

对象信息 对象信息表单显示了使用 Compile Current/Top → View Info… 功能成功地编译后的

项目的详细信息。顶部是信息对象视图,类似于集成浏览器的对象试图(参见 52 页,

Error! Reference source not found.)。信息对象试图下方是两个面板,其中有汇总信

息.

图 2-11: 对象信息表单 该例子对象信息显示了 ABC Product 项目编译后的详细信息。

Page 58: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 58 · Propeller Manual v1.0

对象信息视图 对象信息视图类似于对象视图(参见 52 页,Error! Reference source not

found.),但有几点不同:

• 在对象信息视图中单击一个对象可以更新对象信息显示该对象的相关信息。

• 在对象信息视图中双击一个对象会在编辑窗中打开改对象。

• 在对象信息视图中,数据文件是不可选择的。

RAM 使用面板 RAM 使用面板显示的是在对象信息视图中已选择的对象所使用的 RAM 空间的统

计信息。水平进度条中所示为有颜色标示的整个 RAM 的摘要视图,它的下方是数具

的细节。例如,图 2-11 所示 ABC 对象占用了 524 个长字(2096 字节)的程序空间,

12 个长字(48 字节)的变量空间,剩余超过 7k 长字(超过 30k 字节)的自由空间。

时钟面板 时钟面板,在 RAM 使用面板下方,显示了当前在对象信息视图中选中的对象的时

钟/振荡器设定。例如,图 2-11 显示了对象 ABC Product 配置了 RCFAST,时钟为 12 MHz,无 XIN 频率。

十六进制视图 Show/Hide Hex 按钮可以显示或隐藏对象的十六进制细节视图。例如下一页的图

2-12。十六进制试图显示了实际的编译后的对象数据,这些数据是被写入 Propeller 芯

片的 RAM/EEPROM 中的内容。

Page 59: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 59

图 2-12: 例子对象信息表单,显示对象 ABC Product 编译后的十六进制视图

在十六进制显示窗口下的按钮允许将当前显示的数据下载并保存。

前两个按钮,Load RAM 和 Load EEPROM,和在 Compile Current/Top 菜单下的项

目执行相同的功能。要明白这里指的是将当前的对象(在 Info Object View 中被选中的

对象)下载。换句话说,可以从项目中选择子对象单独下载。除非该对象是被设计成

完全单独运行的。

后的三个按钮,Open File,Save Binary File,和 Save EEPROM File,都可以打开

一个文件或保存一个文件。Open File 按钮将前一个保存过的二进制或 EEPROM 文件

打开。“save”按钮将当前对象的十六进制数据保存到磁盘上的文件中。Save Binary File 只能保存该对象实际在使用的部分;只有程序数据,但不包括变量或堆栈/自由空

间。Save EEPROM File 能将整个 EEPROM 的映像,包括变量和堆栈/自由空间。如果

是为了生产需要在 EEPROM 烧录器烧录另外的 EEPROM,应该选择 Save EEPROM File。

Page 60: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 60 · Propeller Manual v1.0

字符表 字符表窗口可以通过菜单 Help → View Character Chart… 来访问。它显示了

Parallax 字体的全部符号,Parallax 字体是 Propeller 工具软件和内建在 Propeller 芯片

ROM 中的字体符号。在字符表中有三种视图:1) 标准顺序(Standard Order), 2) ROM 位图(ROM Bitmap),和 3) 符号顺序(Symbolic Order)。

在每种视图下,都可以通过鼠标,鼠标左键,光标按键和回车(Enter)键来将一

个字符高亮并选中。如果是鼠标单击(或按回车键),高亮的字符会输入到当前编辑

页面中脱字符所在的位置。当一个字符被高亮时,窗口顶部的标题栏和信息栏会自动

更新显示该字符的名称,和地址信息。滚动鼠标滚轮可以将该窗口显示的字符字体放

大或缩小。

标准顺序 标准顺序,如图 2-13,显示的字符是以 ANSI 标准集的顺序。ANSI 是现代计算机

普遍使用的编码标准。

图 2-13: Parallax 字体符号表,标准顺序

Page 61: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 61

这个例子中竖直方向的电阻被选中(靠近符号表的右下角)。窗口底部的信息显示

的是字体大小,单位是点(point),以及在符号表中字符的位置,位置信息分别以十

进制,16 进制和 Unicode 编码的方式显示。注意,Unicode 值是在 True Type®字体文件

中的符号地址。True Type®是 Propeller 工具软件所使用的字体。十进制和十六进制值

是在字符集以及 Propeller 芯片中字符的逻辑位置,该位置对应于 ANSI 字符集中字符

的位置。

ROM 位图 ROM 位图,如图 2-14,显示的是字符在 Propeller 芯片的 ROM 中是如何被表示

的。该视图使用四种颜色,白色,亮灰,暗灰,和黑色,来表示每个字体字符的位模

式。在 Propeller 芯片 ROM 中的每个字符在定义时都有两个颜色位(four colors per row in each character cell)。每个相邻字符对的行在内存中都是重叠的,这是为了能建立运

行时字符,将其用于绘制带有热键的 3D 按钮和焦点指示器;参见 32 页字符定义。在

窗口底部的信息显示了字体的大小,单位是点,和被选中的字符的像素数据在

Propeller 芯片 ROM 中所占的范围。

图 2-14: Parallax 字体字符表,ROM 位图

Page 62: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 62 · Propeller Manual v1.0

符号顺序 符号顺序,图 2-15,是字符的分类排列。使用 Parallax 字体符号绘制时序图,线

条,箭头和原理图时可以快速找到需要的特殊的字符。

图 2-15: Parallax 字体符号表,符号顺序

Page 63: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 63

视图模式,书签和行号 在开发对象,或和其他用户讨论对象的时候,要快速跳转到希望的代码区域时可能

会遇上不便,可能是由于文件过大或过长的代码段和注释段使得目标区域不容易被找

到。Propeller 工具内建了一些特性有助于解决这类问题,包括不同的视图模式,书签

以及行号。

视图模式 每个编辑栏都可以以以下四种视图模式显示源代码:1) 完整代码,2) 压缩,3) 汇

总,和 4) 文档。

• 完整代码视图模式显示了对象中的每行代码,是唯一支持编辑的模式。

• 压缩视图模式会隐藏只有注释的代码行,连续的注释行不会显示,只显示可编

译的代码行。

• 摘要视图模式只显示块头部的行(CON, VAR, OBJ, PUB, PRI, 和 DAT);是查看对象

结构的方便的方法。

• 文档视图模式会显示对象的文档,该文档是由编译器从源代码的注释中提取的

(更多信息参见 100 页练习 3: Output.spin -注释)。

通过快速地切换到另外一种视图模式,就可以查找到希望的程序或区域。例如,图

2-16a 演示了在编辑页中打开的 Graphics 对象。如果在源代码中找不到“plot”程序

段,可以切换到摘要视图模式(图 2-16b),在“plot”程序段的首行单击鼠标设置光

标位置,然后切换回完整代码模式(图 2-16c)。注意看有光标的代码行,代码会从光

标所处的位置向上,向下展开。

视图模式可以通过很多方法改变;参见 75 上的快捷键列表。例如,在不是完整代

码视图 的情况下,按 Escape 键会回到完整代码视图 o 在压缩或摘要视图模式下,在一

行代码上双击也会切换回完整代码视图,从被双击的代码行向上,向下展开。同样

的,视图模式栏也可以作为视图模式的开关,单击 Summary 项会在摘要模式和其他模

式之间切换。

Page 64: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 64 · Propeller Manual v1.0

图 2-16: 视图模式的例子

a.

b.

c.

无法在对象中找到程序 ?

步骤 1: 选择摘要模式

步骤 2: 单击程序行

步骤 3: 选择全部代码模式;代码会在光标所在行周围重新展开,

-或-

双击步骤 2 中希望的程序行

Page 65: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 65

书签 可以在编辑页中多行代码上设置书签,利用书签就可以快速跳转到希望的位置。图

2-17 显示的是在 Graphics 对象的编辑栏中设置的两个书签。要启用书签,按

Ctrl+Shift+B 使书签槽可见;书签槽是编辑页左侧的空白区域。在希望设置书签的代码

行左侧的书签槽位置单击鼠标。 后,在页面内的任意位置按 Ctrl+#,这里# 是要跳转

的书签号;光标会立刻跳转到该位置。每个编辑栏 多可以设置 9 个书签。书签不会

保存在源代码中;由 Propeller 工具打开过的 近 10 个文件的书签信息会 Propeller 工具记录,再次打开这些文件的时候这些书签会恢复。

图 2-17: 启用了书签的编辑页,其中设置了两个书签。 单击 Bookmark Gutter (编辑页左侧的空白区域 ) 设置或清除书签。按 Ctrl+#,# 是希望的书签号,可以立刻跳转到已有的书签。.

Page 66: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 66 · Propeller Manual v1.0

行号 如果通过行号来记住一个代码区域也许会更容易。可以在任何时间启用或禁用行

号。行号会显示在行号槽内,行号槽与书签槽相邻(参见图 2-18),可以通过按

Ctrl+Shift+N 显示或不显示。一旦创建了行号,Propeller 工具会为其编号;行号只是可

见的内容,不会存储在源代码中。虽然行号和书签共享空间,但这两者是彼此独立

的,可以被分别启用或禁用。如果需要,行号可以被打印。

图 2-18: 带有书签和行号的编辑页的例子

Page 67: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 67

编辑模式 编辑器窗格提供了三种编辑模式:1) 插入 (默认),2) 对齐 (只可用于“.spin”对象),

和 3) 覆盖。可以通过按插入键在三种模式之间切换。当前的编辑模式可以由脱字符的

形状和状态栏的第四格显示出来。

图 2-19: 编辑模式

插入编辑模式

脱字符是闪烁的,垂直的条状,状态栏会显示 “Insert.”

对齐编辑模式

脱字符是闪烁的下划线,状态栏会显示“Align.”

覆盖编辑模式

脱字符是闪烁的,实体块,状态栏会显示“Overwrite.”

插入和覆盖模式 插入和覆盖模式类似于其他的文本编辑器。只有这两种编辑模式可以编辑非

Propeller 的“.spin”对象的文件,如 “.txt” 文件。

Page 68: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 68 · Propeller Manual v1.0

对齐模式 对齐(Align)模式是为维护源代码而设计的插入模式(Insert Mode)的特殊版。

要了解对齐模式,我们首先需要了解一般的编程技巧。在编写源代码时,有两种常用

方法:代码缩进和代码注释右对齐。通常会使用两种以上的编辑工具对源代码编辑和

浏览。一直以来,程序员们都使用 Tab 键和空格键来对代码进行缩进和对齐,这两种

方法都会带来问题。Tab 字符会在对齐上产生问题,因为有些编辑器工具使用不同类

型的表格设定,而且彼此不兼容。Tab 和空格字符会带来对齐的问题,因为如果以后

再修改代码时,会使右端的注释脱离原来的位置。下面是一个例子;图 2-20 是我们原

有的代码。

图 2-20: 常见对齐问题– 原有代码

如果原有代码使用 Tab 字符来对齐注释,那么在将“Delay”修改为“BtnDelay”

时会使 注释右移,这是因为修改的内容超越了表格边界。

图 2-21: 常见对齐问题– Tab 对齐

如果原有代码使用 Tab 字符对齐注释,将“Delay” 改为 “BtnDelay” 会使第二行注释被推挤出原有位置。

Page 69: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 69

如果原有代码使用空格来对齐注释,那么将“Delay”修改为“BtnDelay”会使注释

右移 3 个字符。

图 2-22: 常见对齐问题 – 空格对齐

如果原有代码使用空格来对齐注释,使用了标准插入编辑模式,那么将 “Delay” 改为 “BtnDelay” 会使第二和第五行代码被推后 3 个空格。

对 Spin 代码而言,Propeller 工具为此问题提供的方案是首先不使用 tab 字符(按下

Tab 键后会空出一定数量的空格位),第二是提供了对齐编辑模式。在对齐模式中,

插入的字符会影响到相邻的字符,但是由多个空格分隔的字符不会受到影响。这样做

的结果是注释和其他由至少一个空格分隔的内容可以维持原有的对齐状态,如图 2-23所示。 图 2-23: 对齐编辑模式的效果

使用对齐编辑模式,将“Delay”改为“BtnDelay” 会使注释保留在原来的对齐位置。不需要手动重新对齐。

Page 70: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 70 · Propeller Manual v1.0

因为对齐模式尽可能地维持了原有的对齐,可以减少程序员为此(手动重新对齐)

付出的时间。此外因为使用空格代替 tab 字符,代码在所有的编辑器中看起来都不会

有不同。

对齐模式并不是对所有的情况都有效。我们推荐,在大多数代码录入工作中使用插

入模式,当对齐是所要关心的问题时,在维护代码时使用对齐模式。插入(Insert)键

会在三种模式间切换: Insert → Align → Overwrite,然后回到 Insert。快捷键

Ctrl+Insert 可以在 Insert 和 Align 模式间切换。做一些对齐模式和插入模式的小练习会

让你在编程时更有效率。

要注意非 Spin 代码(无.spin 扩展名)不允许使用对齐模式。这是因为对非 Spin 代

码,Propeller 工具被设计成保留任何已有的 Tab 字符,如果在编辑过程中有 Tab 键按

下,则会插入一个 tab 字符,这样做是为了保证该文件原有的缩进形式。因为该文件

可能是用 Tab 键分隔的 Spin 程序数据代码或其他希望使用 tab 字符的文件。

块选择和选择移动 除了用鼠标选择普通文本,Propeller 工具也允许块选择(文本的长方形区域)。要

进行块选择,首先按下 Alt 键,按下鼠标左键并拖动,选择文本区。选择完成后,可

以进行剪切和复制操作。图 2-24 演示了块选择和文本块移动。

Page 71: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 71

图 2-24: 块选择和选择移动

原有代码。

我们想把注释 “LCD Screen Addr’’ 移动到 PrintMode 程序的右侧。

首先按下并保持 Alt 键,然后用鼠标左键拖动出选择区域。

后,单击并拖动选择区域(丛选择区域内任意位置),放在希望的位置。

增加缩进和减少缩进 为了使程序便于阅读,通常会使在循环或条件表达式中的可执行代码缩进。这种做

法称为“缩进(增加缩进)”。与之相反的动作称之为“减少缩进”。Spin 语言需要

这种格式来表示那些行是属于循环或条件块的。Propeller 工具包括了下面的特性,使

在维护代码或创建代码时更容易完成。

Page 72: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 72 · Propeller Manual v1.0

单行 对 Spin 代码,Propeller 工具使用设定的 tab 位置(tab 所占的空格),可以通过菜

单 Edit → Preferences 来修改此设置。每个 Spin 块 (CON, VAR, OBJ, PUB, PRI, 和 DAT) 都有

其固定的 Tab 设定。

按 Tab 键将光标移动到下一个 tab 位置(右侧),按 Shift + Tab 可以将光标移动到

上一个 tab 位置(左侧)。此外,按 Backspace 键会将光标移动到上一个 tab 位置。下

面会有更多的讨论。

PUB 和 PRI 块的默认 Tab 设定包括了每行的第一个字符和上一行开始字符之间有两

个字符的位置,这样就可以支持通用的代码缩进。示例见图 2-25,图中所示一个名为

FSqr 的公共方法,它包含了不同级别的缩进行,每行(比上一级)缩进两个字符。.

图 2-25: PUB 和 PRI 块的固定 Tab 的默认设定

通过使用 Tab 键,可以按下面的顺序快速输入代码:

• 输入: “PUB FSqr” <Enter>

• 输入: <Tab> “repeat 31” <Enter>

• 输入: <Tab> “result |= root” <Enter>, etc.

注意回车键会将光标自动对齐到本行所处的缩进级别;也就是说要进行下一级别的

缩进,只要按一次 Tab 键就可以了。

如果在按 Tab 时,在光标的右侧有字符,它们也会被移动,例如图 2-26。

图 2-26: 增加缩进

Page 73: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 73

如果脱字符刚好在某行第一个字符的左侧,那么按 Shift + Tab 和 Backspace 键都可

以将脱字符和文本移动到上一个 tab 位置;也就是我们所说的缩进。但如果脱字符不

是在第一个字符的左侧,那么 Backspace 会和普通的擦除键一样(删除前一个字

符),Shift + Tab 只会将脱字符移动到前一个 tab 位置。

图 2-27: 减少缩进

多行 除了作用于单行,多行代码也可以通过增加缩进和减少缩进,来移动到合适的 tab

位置。请看图 2-28。

图 2-28: 示例代码块。我们想

要前四行循环 31 次。

假设我们想要把该例子的前四行放进循环 “repeat 31” 中;让它们执行 31 次。可以

通过下面的步骤快速达到此目的: 1) 在已有的代码上方输入“repeat 31”,2) 用鼠标选

择这四行,3) 按 Tab 键缩进。这些步骤如图 2-29 所示。

图 2-29: 增加代码块缩进

Page 74: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 74 · Propeller Manual v1.0

步骤 1:在块的上方插入指令:

repeat 31。 步骤 2: 用鼠标选择要缩进的 四行代码。

步骤 3: 按 Tab 键将选择的代

码行缩进。

注意,我们在第二步中选择的四行代码现在已经缩进到下一个 tab 位置了

(“repeat”后两个空格),选择区域变成了四行代码的第一列。选择区域改变说明了

我们执行的是多行缩进。再按 Tab 键会进一步缩进,按 Shift + Tab 会减少缩进。

任何连续的代码组都可以以这种方式增加缩进或减少缩进。选择时不必包含整行,

但要包括至少一个字符才能工作。这种类型的选择被称为“流(stream)选择。

第二种类型的选择,一个“块”选择(参见 70 页块),也可以用于增加缩进和减

少缩进。例如图 2-30 中所示,每行代码的右侧都有注释。

图 2-30: 带有注释的代码块

Page 75: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 75

如果我们块选择时只选择了注释的前几个字符(Alt + 鼠标左键并拖动,图 2-31),则可以按 Tab 键将这些注释缩进到下一个 tab 位置。按 Shift + Tab 会减少缩

进,直到任何一行注释与其左侧的字符相遇, 例如图 2-32。 图 2-31: 使用块选择来减少注释的缩进

步骤 1: 按块的形式选择注释 (Alt + 鼠标左键 并拖动 )。

步骤 2: 按 Tab 键减少注释的缩进。

块-组指示器 有时很难只通过缩进级别看出一组代码的逻辑关系。Propeller 工具可以选择显示循

环或条件表达式内的逻辑块组,如图 2-32。可以按 Ctrl + I,开启或关闭这一特性。

Page 76: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 76 · Propeller Manual v1.0

图 2-32: 块-组指示器

只有在条件块或循环块内的可编译代码才能启用缩进指示器。同样的,这只是显示

代码是如何被组织,执行的。它不会实际影响到源代码。真正影响到代码的只有缩进

的级别。

Page 77: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 77

快捷键

分类列表 表 2-1 中,键盘快捷键依相关功能分组。表 2-2 中,从 80 页开始,键盘快捷键依按键分类.

表 2-1: 快捷键 – 分类列表

工具快捷键

功能 按键

新建 Ctrl + N

打开 Ctrl + O

关闭 Alt + Q -或- Ctrl + W

保存 Ctrl + S

保存全部 l Ctrl + Alt + S

打印 Ctrl + P

显示/隐藏书签 Ctrl + Shift + B

在当前行显示书签 Ctrl + B

显示块组指示器 Ctrl + I

显示/隐藏浏览器 Ctrl + E

显示/隐藏行号 Ctrl + Shift + N

增大字体 Ctrl + Up -或- Ctrl + Mouse Wheel Up

减小字体 Ctrl + Down -或- Ctrl + Mouse Wheel Down

选择完整代码视图模式 Alt + S

选择压缩视图模式 Alt + C

选择摘要视图模式 Alt + U

选择文档视图模式 Alt + D

选择 下一项视图 (向全部代码视图方向) Alt + Up

选择 下一项视图 (向文档视图方向) Alt + Down -或- Alt + Mouse Wheel Down

在活动的编辑上设置焦点 Esc

Page 78: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 78 · Propeller Manual v1.0

表 2-1: 快捷键 – 分类列表 (续)

编译器 快捷键

功能 按键

选择顶部文件 Ctrl + T

识别硬件 F7

编译当前文件和视图信息 F8

编译当前文件和更新状态 F9

编译当前文件并写入 RAM 运行 F10

编译当前文件并写入 EEPROM 运行 F11

编译顶部文件并显示信息 Ctrl + F8

编译顶部文件并更新状态 Ctrl + F9

编译顶部文件,载入 RAM 并运行 Ctrl + F10

编译顶部文件,载入 EEPROM 并运行 Ctrl + F11

导航快捷键

选择下一个编辑栏 Alt + Right -或- Ctrl + Tab

选择上一个编辑栏 Alt + Left -或- Ctrl + Shift + Tab

上卷页面 Page Up

下卷页面 Page Down

左卷页面 Shift + Mouse Wheel Up

右卷页面 Shift + Mouse Wheel Down

跳到下一个单词的开始 Ctrl + Right

跳到上一个单词的开始 Ctrl + Left

跳到行首 Home

跳到行尾 End

跳到页首 Ctrl + Page Up

跳到页尾 Ctrl + Page Down

跳到文件的开始 Ctrl + Home

跳到文件的结尾 Ctrl + End

Page 79: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 79

表 2-1: 快捷键 – 分类列表 (续)

导航快捷键 (续)

功能 按键

选择一个单词 Double-Click

选择一行 Triple-Click

选择光标到下一个单词前的内容 Ctrl + Shift + Right

选择光标到前一个单词开始的内容 Ctrl + Shift + Left

选择光标到本行开始的内容 Shift + Home

选择光标到本行结束的内容 Shift + End

选择光标到本页开始的内容 Ctrl + Shift + Page Up

选择光标到本页结束的内容 Ctrl + Shift + Page Down

选择本页和上一页光标所处位置之间的内容 Shift + Page Up

选择本页和下一页光标所处位置之间的内容 Shift + Page Down

选择从文件开始到光标处之间的内容 Ctrl + Shift + Home

选择从光标处到文件结尾之间的内容 Ctrl + Shift + End

编辑快捷键

撤销 Ctrl + Z

恢复 Ctrl + Shift + Z

选择全部 Ctrl + A

拷贝到剪贴板 Ctrl + C

剪切到剪贴板 Ctrl + X

从剪贴板粘贴 Ctrl + V

查找/替换 Ctrl + F

查找下一个 F3

替换 F4

替换后查找下一个 Ctrl + F4

改变编辑模式到对齐, 插入或覆盖 Insert

在对齐和插入编辑模式间切换 Ctrl + Insert

在下一个表格位置前插入空格 Tab

删除到前一个表格位置间的空格 Shift + Tab

Page 80: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 80 · Propeller Manual v1.0

表 2-1: 快捷键 – 分类列表 (续) 编辑快捷键 (续)

功能 按键 删除当前行 Ctrl + Y 删除从当前光标位置到行尾的内容 Ctrl + Shift + Y 重命名文件夹/文件 (在文件夹列表或文件列表中) F2

符号快捷键

插入 Negative One Superior 符号 ( ) Ctrl + Alt + 1

插入 One Superior 符号 ( ¹ ) Ctrl + Shift + 1

插入 Two Superior 符号 ( ² ) Ctrl + Shift + 2

插入 Three Superior 符号 ( ³ ) Ctrl + Shift + 3

插入 Bullet 符号 ( • ) Ctrl + Shift + .

插入 Rectangle Bullet 符号 ( ‣ ) Ctrl + Alt + .

插入 Left Bullet 符号 ( ) Ctrl + Shift + Alt + <

插入 Right Bullet 符号 ( ) Ctrl + Shift + Alt + >

插入 Left Arrow Bullet 符号 ( ← ) Ctrl + Shift + Alt + Left

插入 Right Arrow Bullet 符号 ( → ) Ctrl + Shift + Alt + Right

插入 Up Arrow Bullet 符号 ( ↑ ) Ctrl + Shift + Alt + Up

插入 Right Arrow Bullet 符号 ( → ) Ctrl + Shift + Alt + Right

插入 Euro 符号 ( € ) Ctrl + Shift + $

插入 Yen 符号 ( ¥ ) Ctrl + Alt + $

插入 Sterling 符号 ( £ ) Ctrl + Shift + Alt + $

插入 Left Arrow 符号 ( ) Ctrl + Alt + Left

插入 Right Arrow 符号 ( ) Ctrl + Alt + Right

插入 Up Arrow 符号 ( ) Ctrl + Alt + Up

插入 Down Arrow 符号 ( ) Ctrl + Alt + Down

插入 Degree 符号 ( ° ) Ctrl + Shift + %

插入 Plus/Minus 符号 ( ± ) Ctrl + Shift + -

Page 81: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 81

表 2-1: 快捷键 – 分类列表 (续) 符号快捷键 (续)

功能 按键

插入 Multiply 符号 ( × ) Ctrl + Shift + *

插入 Divide 符号 ( ÷ ) Ctrl + Shift + /

插入 Radical (根号)符号 ( √ ) Ctrl + Shift + R

插入 Infinity(无穷) 符号 ( ∞ ) Ctrl + Shift + I

插入 Delta 符号 ( ∆ ) Ctrl + Shift + D

插入 Mu 符号 ( µ ) Ctrl + Shift + M

插入 Omega 符号 ( Ω ) Ctrl + Shift + O

插入 Pi 符号 ( π ) Ctrl + Shift + P

插入 Sigma 符号 ( Σ ) Ctrl + Shift + S

Page 82: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 82 · Propeller Manual v1.0

按键分类

表 2-2: 快捷键依按键分类 单键或鼠标

按键 功能

F2 重命名文件夹/文件 (在文件夹列表或文件列表中)

F3 查找下一个

F4 替换

F7 识别硬件

F8 编译当前文件和视图信息

F9 编译当前文件并更新状态信息

F10 编译当前文件并写入 RAM 运行

F11 编译当前文件并写入 EEPROM 运行

End 跳到行尾

Esc 选择完整代码视图模式或在活动的编辑上设置焦点

Home 跳到行首

Insert 改变编辑模式到对齐, 插入或覆盖

Page Down 下卷页面

Page Up 上卷页面

Tab 在下一个表格位置前插入空格

双击 选择一个单词

三击 选择一行

Ctrl + …

Ctrl + A 选则全部

Ctrl + B 在当前行打开书签

Ctrl + C 复制到剪贴板

Ctrl + E 显示/隐藏浏览器

Ctrl + F 查找/替换

Ctrl + I 显示块组指示器

Page 83: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 83

表 2-2: 快捷键依按键分类 (续) Ctrl + … (续)

按键 功能

Ctrl + N 新建

Ctrl + O 打开

Ctrl + S 保存

Ctrl + P 打印

Ctrl + T 选择顶部文件

Ctrl + V 从剪贴板粘贴

Ctrl + W 关闭

Ctrl + X 剪切到剪贴板

Ctrl + Y 删除当前行

Ctrl + Z 撤销

Ctrl + F4 替换后查找下一个

Ctrl + F8 编译顶部文件并显示信息

Ctrl + F9 编译顶部文件并更新状态

Ctrl + F10 编译顶部文件,载入 RAM 并运行

Ctrl + F11 编译顶部文件,载入 EEPROM 并运行

Ctrl + F4 替换后查找下一个

Ctrl + Down 减小字体

Ctrl + End 跳到文件末尾

Ctrl + Home 跳到文件开始

Ctrl + Insert 在对齐和插入编辑模式间切换

Ctrl + Left 跳到上一个单词的开始

Ctrl + Page Down 跳到本页末尾

Ctrl + Mouse Wheel Down 减小字体

Ctrl + Mouse Wheel Up 增大字体

Ctrl + Up 增大字体

Page 84: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 84 · Propeller Manual v1.0

表 2-2: 快捷键依按键分类 (续) Alt + …

Alt + C 选择压缩视图模式

Alt + D 选择文档视图模式

Alt + S 选择完整代码视图模式

Alt + Q 关闭

Alt + U 选择摘要视图模式

Alt + Down 选择下一个视图模式(向文档视图方向)

Alt + Left 选择上一个编辑栏

Alt + Mouse Wheel Down 选择下一个视图模式(向文档视图方向)

Alt + Mouse Wheel Up 选择下一个视图模式(向全部代码视图方向)

Alt + Right 选择下一个编辑栏

Alt + Up 选择下一个视图模式(向全部代码视图方向)

Shift + …

Shift + End 选择光标到本行结束的内容

Shift + Home 选择光标到本行开始的内容

Shift + Page Down 选择本页和下一页光标所处位置之间的内容

Shift + Page Up 选择本页和上一页光标所处位置之间的内容

Shift + Tab 删除到前一个表格位置间的空格

Shift + Mouse Wheel Down 滑块右移

Shift + Mouse Wheel Up 滑块左移

Ctrl + Alt + …

Ctrl + Alt + . 插入 Rectangle Bullet 符号 ( ‣ )

Ctrl + Alt + $ 插入 Yen 符号( ¥ )

Ctrl + Alt + 1 插入 Negative One Superior 符号( )

Ctrl + Alt + S 全部保存

Ctrl + Alt + Down 插入 Down Arrow 符号( )

Ctrl + Alt + Left 插入 Left Arrow 符号( )

Ctrl + Alt + Right 插入 Right Arrow 符号( )

Ctrl + Alt + Up 插入 Up Arrow 符号( )

Page 85: Propeller Manual - Parallax Home

2: 使用 Propeller 工具软件

Propeller Manual v1.0 · Page 85

表 2-2: 快捷键依按键分类 (续)

Ctrl + Shift + … 按键 功能

Ctrl + Shift + $ 插入 Euro 符号( € )

Ctrl + Shift + % 插入 Degree 符号( ° )

Ctrl + Shift + * 插入 Multiply 符号( × )

Ctrl + Shift + - 插入 Plus/Minus 符号( ± )

Ctrl + Shift + . 插入 Bullet 符号( • )

Ctrl + Shift + / 插入 Divide 符号( ÷ )

Ctrl + Shift + = 插入 Approximate 符号( ≈ )

Ctrl + Shift + 1 插入 One Superior 符号( ¹ )

Ctrl + Shift + 2 插入 Two Superior 符号( ² )

Ctrl + Shift + 3 插入 Three Superior 符号( ³ )

Ctrl + Shift + B 显示/隐藏书签

Ctrl + Shift + D 插入 Delta 符号( δ )

Ctrl + Shift + I 插入 Infinity 符号( ∞ )

Ctrl + Shift + M 插入 Mu 符号( µ )

Ctrl + Shift + N 显示/隐藏行号

Ctrl + Shift + O 插入 Omega 符号( ω )

Ctrl + Shift + P 插入 Pi 符号( π )

Ctrl + Shift + R 插入 Radical 符号( √ )

Ctrl + Shift + S 插入 Sigma 符号( σ )

Ctrl + Shift + Y 删除从光标所在位置到本行结尾的内容

Ctrl + Shift + Z 恢复

Ctrl + Shift + End 选择从光标处到文件结尾之间的内容

Ctrl + Shift + Home 选择从文件开始到光标处之间的内容

Ctrl + Shift + Left 选择光标到前一个单词开始的内容

Ctrl + Shift + Page Down 选择本页和下一页光标所处位置之间的内容

Ctrl + Shift + Page Up 选择本页和上一页光标所处位置之间的内容

Ctrl + Shift + Right 选择光标到下一个单词前的内容

Page 86: Propeller Manual - Parallax Home

使用 Propeller 工具软件

Page 86 · Propeller Manual v1.0

Ctrl + Shift + … (续)

按键 功能

Ctrl + Shift + Tab 选择前一个编辑栏

表 2-2: 快捷键依按键分类 (续)

Ctrl + Shift + Alt… 按键 功能

Ctrl + Shift + Alt + $ 插入 Sterling 符号( £ )

Ctrl + Shift + Alt + < 插入 Left Bullet 符号( )

Ctrl + Shift + Alt + > 插入 Right Bullet 符号( )

Ctrl + Shift + Alt + Down 插入 Down Arrow Bullet 符号 ( ↓ )

Ctrl + Shift + Alt + Left 插入 Left Arrow Bullet 符号 ( ← )

Ctrl + Shift + Alt + Right 插入 Right Arrow Bullet 符号 ( → )

Ctrl + Shift + Alt + Up 插入 Up Arrow Bullet 符号 ( ↑ )

Page 87: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 87

Chapter 3: Propeller 编程指导 本章假定您熟悉其他编程语言的一般编程概念,包括面向对象语言。我们会讨论一

些基本概念,但是仍然推荐开始之前有些知识和编程经验。

除了上述条件之外,下列材料应该在已经完成第一章和第二章之后阅读。如果您还

没有通读完第一章和第二章的大部分,请您在继续本章的内容之前将其完成。本讲将

会涉及一些第一章和第二章中的主题,但不会详述。

下述 Propeller 编程指导逐步描述了 Propeller 芯片编程概念,并带有快速回顾。阅

读本章的 佳方法是通读,不要有略过的部分,同时使用您的电脑和 Propeller 芯片试

验每一个例子。前面的练习会很基础,稍后的练习将会覆盖更多的高级材料。

概念 Propeller 产品(硬件,固件和软件)设计时带有许多众所周知的和全新的概念。

后,我们设计了硬件,固件,软件和两种编程语言与其配合(Spin 和 Propeller 汇编),为用户提供 直接和有效的控制 Propeller 设备的方案。

为了完全明白和使用这些工具和语言,在您接触它们时 好能有开放的观念。换句

话说,请注意不要让陈旧的编程概念和方法阻止您体验到 Propeller 芯片和编程语言的

优越性。我们相信有些陈旧的概念不属于实时处理环境,因为它们趋向于将使用者引

向混乱。

Page 88: Propeller Manual - Parallax Home

Propeller编程指导

Page 88 · Propeller Manual v1.0

Propeller 语言(Spin 和 Propeller 汇编) Propeller 芯片以两种特定的语言编程:1) Spin,一种高级的基于对象的语言;2)

Propeller 汇编,一种低级的,高度优化的汇编语言。在 Propeller 汇编中,有很多基于

硬件的命令在 Spin 语言中有等效的语句。这使得学习两种语言和使用 Propeller 芯片变

得容易。

Spin 语言由 Propeller 工具软件编译成为令牌,在运行时由 Propeller 芯片内间的

Spin 解释器解释执行。这些和其他语言的相似性使得 Spin 易学,而且适合于很多应

用。有了 Spin,您可以简单地执行高级/低频宽的任务,以及创建代码去处理一些典型

的高频宽的特性比如在 19200 波特率下处理异步串行通信。

Propeller 汇编语言被 Propeller 工具汇编为纯机器码,在运行时以纯态运行。汇编语

言程序员喜欢 Propeller 汇编的特性和可以以非常少的代码完成高频宽任务。

Propeller 对象(见下)可以完全由 Spin 编写或者使用 Spin 和 Propeller 汇编的组合

。有可能用 Propeller 汇编完全编写对象而在 后两行用 Spin 代码来启动 终的程序。

Propeller 对象 Propeller 芯片的 Spin 语言是基于对象的,是每一个 Propeller 应用程序的基础。

什么是对象? 对象是以这样的方式书写的程序:1) 创建一个自包含的实体, 2) 执行特殊的任

务,3)可以有很多应用程序重用。

比如,Propeller 工具软件中的键盘对象和鼠标对象。键盘对象是一个将 Propeller 芯片和普通 PC 风格键盘接口的程序。与此相似,鼠标对象接口到标准电脑鼠标。这两

个对象都是自包含的程序,有仔细设计的接口允许其他对象,开发员容易地使用。

利用已有的对象,可以更快地建立更复杂的应用程序。例如,一个应用程序可以同

时包含键盘和鼠标对象,只要添加几行代码,就可以实现一个标准的用户接口。因为

对象是自包含的,提供了简明的软件接口,应用程序开发员不需要了解对象内部工作

的机制就可以使用它达到目标。同样的,汽车的驾驶员不必要了解引擎的工作原理,

但是只要驾驶员能明白接口(点火钥匙,油门踏板,制动器等),他或她就可以驱车

加速或减速。

一位程序员所创建的有良好书写风格的对象可以很容易地被其他程序员重用。

Page 89: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 89

对象和应用程序 一个 Propeller 对象包含了 Spin 代码和可选的 Propeller 汇编代码;参见图 3-1。从

现在起我们将简称 Propeller 对象为“对象”。

Propeller Object

Spin Code

Propeller Assembly Code

图 3-1: Propeller 对象

对象以文件的形式存储在计算机内,文件扩展名为“.spin”,因此,您可以把每个

Spin 文件想成是一个对象。

图 3-2: 对象文件包含 Spin,和 Propeller 汇编语言,以“.spin”文件的形式存储在计算机

Page 90: Propeller Manual - Parallax Home

Propeller编程指导

Page 90 · Propeller Manual v1.0

的硬盘上。

每个对象都可以是构建整个应用程序的“砖块”。一个对象可以选择利用一个或多

个对象来构建更复杂的应用程序。这一过程一般称为“引用”或“包含”另一个对

象。当一个对象引用另外对象的时候,就形成了体系(Hierarchy),该对象就成为顶

部对象, 例如 Error! Reference source not found.中, 顶端的对象是“顶部对象文

件”,它是 Propeller 应用程序编译的起点。

图 3-3: 对象等级 被编译时,Graphics Demo 对象是“顶部对象”,它引用了其他三个对象。

在上面的图中,Graphics Demo 象引用了另外三个对象:TV,Graphics 和 Mouse。

如果 Graphics Demo 对象被编译,它会被设置为顶部对象文件(Top Object File),另

外的三个对象会被载入,并一起编译, 终形成 Propeller 应用程序,或者简称为应用

程序。

应用程序由一个或多个对象组成。它是特殊编译的二进制流,包含了 Propeller 芯

片可以执行代码和数据。

下载完成后,应用程序会存储在 Propeller 芯片主 RAM 中,或可选的存储在外部

EEPROM 中。在运行时,应用程序会由一个或多个处理器,称为 cog,来执行。

Page 91: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 91

图 3-4: 下载 包含了一个或多个对

象的应用程序被下载

到 Propeller 芯片

RAM 中,或可选地

下载到外部

EEPROM 中。

下载连接 为了从 PC 中下载 Propeller 应用,您首先需要正确连接 Propeller 芯片。

• 如果您有一块 Propeller 演示板(Rev C 或 D),那么它已经包括了 Propeller 芯片和所有必要的电路。将它接上电源,用 USB 电缆与 PC 连接,打开电源。就

像 Propeller 演示板文档中提示的一样,您也可能需要安装 USB 驱动程序。

• 如果您没有 Propeller 演示板,那我们假定您有 Propeller 芯片,并且您在使用电

线连接的电路方面有一定经验。参考 14 页上封装类型(Propeller 的引脚排列)

和 17 页上的硬件连接作为例子电路,其中有编程和电源的连接线路。如果您

Page 92: Propeller Manual - Parallax Home

Propeller编程指导

Page 92 · Propeller Manual v1.0

正在使用 Propeller 插入设备(Plug device),您可能也需要安装 USB 驱动程

序。本章剩下的内容将依赖于和演示板相似的电路,除了上述提及的电源和编

程连接,还包括了在您的电路中以下部件和连接。您可以参考演示板电路原理

图,可从 Parallax 网站下载。

图 3-5: Propeller 教程示例原理图

如果您已经制作好了上述连接,您现在就可以通过 Propeller 软件验证和识别芯片

了。启动 Propeller 工具软件(版本 1.0),按 F7 键(或从菜单选择运行 识别硬

件)。如果 Propeller 芯片已经上电并正确连接到 PC,您应该可以看到如图 3-6 的“信

息”对话框。

图 3-6: 信息对话框 端口 (COM5) 在你的电脑上可能不同。

Page 93: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 93

快速回顾: 介绍 • 可以由两种用户设计的语言编程:Spin 和 Propeller 汇编。

o Spin 是高级,基于对象的语言,它在运行时被解释。 o 汇编是低级的,优化的汇编语言,在运行时被立即执行。

• 对象是一段程序,特性是: o 自包含的(Self-Contained). o 执行特殊任务. o 可以被重用.

• 良好书写的对象可以被另一位开发员和应用程序重用。 • 一个 Propeller 对象:

o 包含两行或更多行 Spin 代码和 Propeller 汇编代码。 o 存储在以“.spin”为扩展名的计算机文件中。 o 可能使用一个或多个其他对象来构建一个复杂的应用程序。

• Propeller 应用程序: o 包含一个或多个对象。 o 是一种编译过的二进制流,包含可执行代码和数据. o 由 Propeller 芯片运行,由应用程序控制的在一个或多个 cog 中执行。.

• 一个编译过的应用程序的顶部对象称为“顶部对象文件(Top Object File)”。

练习 1: Output.spin –我们的第一个对象 下面是一个简单的对象,用 Spin 写成,它反复地把一个 I/O 引脚拉高或拉低。启

动 Propeller 工具软件,并将下面的程序输入编辑器。我们将立刻解释它是如何工作

的。确保“PUB”所在的行是从第一列开始的(编辑窗的 左边沿),同时请注意每

行的缩进;这对芯片正确地运行很重要。

PUB Toggle dira[16]~~ repeat !outa[16] waitcnt(3_000_000 + cnt)

缩进很重要,而大小写则不是。Propeller 代码不是大小写敏感的。但是本书中的所

有保留字都是大写粗体,除了在代码片断和摘录中,以帮助您熟悉他们。

Page 94: Propeller Manual - Parallax Home

Propeller编程指导

Page 94 · Propeller Manual v1.0

在检查过您的输入无误后,按 F10 键(或选择 Run Compile Current Load RAM + Run )编译并下载我们的例子程序。如果您的输入语法正确,Propeller 芯片正确地上

电并连接到 PC,您应该看到一个“Propeller Communication”对话框出现在屏幕上,

如图 3-7,现在 Propeller 芯片的 16 引脚应该开始闪烁,大约每秒两次。我们刚才完成

的步骤就是在 89 页图 3-4:下载 顶部所示的。

图 3-7: Propeller 通信

对话框

由于太快,我们看不到真正发生了什么,这是因为我们输入的程序太小了。当您按

下 F10,它使 Propeller 工具把刚才输入的源代码编译成 Propeller 应用程序。然后

Propeller 工具搜索一个已经连接到 PC 的 Propeller 芯片,并把应用下载到 Propeller 芯片的 RAM 中。 后,Propeller 开始从 RAM 运行应用程序,使 I/O 引脚上的 LED 闪

烁。

下载到 RAM vs. EEPROM 在我们解释代码前,我们来仔细看看下载过程。因为我们的代码只下载到 RAM

中,电源周期(Power Cycling)或复位会导致 RAM 的内容丢失和程序永久终止。试

着按一下复位(reset)键,LED 将熄灭不会再亮。

如果我们不想永久终止程序该怎么办?我们应该把程序下载到 EEPROM 中而不是

只下载到 RAM。我们再下载一次,但这次要按 F11 键(或选择菜单 Run Compile Current Load EEPROM + Run)来编译并将例子程序下载到 EEPROM 中。这就是在

89 页图 3-4 中 下部的图所示的过程。就像您在途中看到的一样,实际是先下载到

RAM 中,Propeller 然后对外部 EEPROM 编程,然后从 RAM 中运行程序,使接在 I16引脚上的 LED 闪烁。

您可能注意到“Propeller Communication”对话框在屏幕上的时间变长了;

EEPROM 需要比 RAM 更长的时间来编程。

现在试着按下复位按钮。当您释放按钮的时候,您会注意到一个大约 1.5 秒的延

迟,然后 LED 开始闪烁。这就是我们想要的,一段固化在 Propeller 芯片中的应用.

Page 95: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 95

从复位后,Propeller 执行 18 页上描述的启动程序。启动程序中需要从外部

EEPROM 启动,花 1.5s 的时间将 32K 字节的内容从 EEPROM 中复制到 RAM 中,然

后开始运行程序。

因为 RAM 很快,在开发阶段只下载到 RAM 中是很方便的。下载到 RAM 和

EEPROM 中可以保持程序,但是 好只有在需要的时候才这么做,因为这要花额外的

下载时间。

警告:如果您已经将程序下载到了 EEPROM 中,而此后您修订了程序,并将其下

载到 RAM 中,手动复位后,Propeller 芯片会从您旧的程序开始启动。这问题在这里看

起来一目了然,但是如果您不注意,程序运行的结果就可能使您困惑。如果在复位后

工作不正常,请先检查 EEPROM 中的程序。

练习 1: Output.spin 的解释 现在我们来解释源代码:

PUB Toggle dira[16]~~ repeat !outa[16] waitcnt(3_000_000 + cnt)

第一行,PUB Toggle,声明了我们正在创建一个“公共的(public)”方法,叫做

“Toggle”,方法是面向对象中表示程序(procedure)或例程(routine)的术语。我

们选择“toggle(中文意为‘触发’)”这个名字是因为它描述了我们的方法要做什么

和我们知道它是一个唯一的符号(Unique symbol);唯一符号的定义规则见 159 页。

我们会在后面更多地提到术语 PUB, “public(公共的)”,但是请注意每一个对象必

须至少包含一个公共(PUB)方法。

剩下的代码是 Toggle 方法的一部分。我们在每行的开始缩进两格,使代码看起来

更清晰;缩进不是必须的,但是它却是一个良好的习惯能保持代码清晰。

Toggle 方法的第一行(我们例子中的第二行),dira[16]~~,设置了第 16 引脚上的

I/O 方向为输出。符号 DIRA 是 I/O 引脚 P0~P31 的方向寄存器;将该位清零或置位能

改变相应 I/O 引脚的方向为输入或输出。[16]表明我们想访问的是方向寄存器的第 16位;也就是对应 I/O 第 16 引脚的寄存器位。 后,~~是 Post-Set 操作符可以设置方向

寄存器的第 16 位为高(1);这将使 I/O 第 16 引脚的方向变为输出。Post-Set 操作符

是 dira[16]:=1 的缩写。

Page 96: Propeller Manual - Parallax Home

Propeller编程指导

Page 96 · Propeller Manual v1.0

下一行,repeat,创建了一个包含了两行代码的循环。这个 REPEAT 循环是无限循

环,触发 P16,等待¼秒,触发 P16,等待¼秒等。

下一行,!outa[16],将 I/O 第 16 引脚的状态在高(VDD)和低(VSS)之间转换。

OUTA 符号是 P0 到 P31 引脚的输出状态寄存器。!outa[16]中的[16]表明我们想访问输

出寄存器的第 16 位;也就是对应 I/O 第 16 引脚的寄存器位。语句开始的“!”是位

非(Bitwise Not)操作符;它将指定位的状态反转(例子中是 I/O 第 16 引脚)

后一行,waitcnt(3_000_000 + cnt) ,会产生三百万个时钟周期的延迟。

WAITCNT 意思是“等待系统计数器”。符号 cnt 是系统计数器寄存器;cnt 返回系统

计数器的当前值,所以这行的意思是“等待系统计数器三百个脉冲加上当前值”。在

例子程序中,我们没有制定任何时钟设定,所以默认将返回内部快速时钟(大约

12MHz),这意味着三百万个时钟周期大约¼秒。

记得我们说过要注意每行的缩进吗?这里就需要缩进:Spin 语言使用缩进的级别

来标明哪些行是属于条件语句或循环语句(IF, CASE, REPEAT 等)。例子中,repeat之后的语句向右缩进了至少一个空格,所以这两行就被看作是 repeat 循环的一部分。

如果您对识别这些结构化分组有困难,Propeller 工具可以通过组块指示器特性来使得

他们看起来更清晰。用 Ctrl+I 可以打开或者关闭该特性。图 3-8 中是打开该指示器后

的例子程序。

图 3-8: 块-组指示器 Ctrl+I 可以将该特性打开或关闭。

如果您还没有保存这个例子对象,您可以按 Ctrl+S(或选择菜单 File Save from the menu)。您可以在任意选定的文件夹保存它,但是请确保它的文件名是“

Output.spin”,因为下面的一些练习将依赖它。

Page 97: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 97

快速回顾: 练习 1 • 应用被下载到 Propeller RAM 中或同时下载到 EEPROM 和 RAM 中.

o 在 Propeller 芯片上电或复位时在 RAM 中的程序不会被保存。 o 在 EEPROM 中的程序在启动时被载入 RAM,用时大约 1½秒。 o 将当前的对象下载到:

RAM: 按 F10 或选择 Run Compile Current Load RAM + Run.

RAM + EEPROM: 按 F11 或选择 Run Compile Current Load EEPROM + Run.

• Spin 语言: o 方法意思是“程序”或“例程”。 o 符号 PUB 声明了一个名为 Symbol 的公共方法。每个对象都必须至少包

含一个公共(PUB)方法。见 287 页上 PUB 的描述和 159 页符号规

则。 o DIRA 是 I/O 引脚 0~31 的方向寄存器。每一位都对应于相应的 I/O 引脚

的方向,输入(0)或输出(1),见 212 页上 DIRA 和 DIRB 的描述。 o OUTA 是 I/O 引脚 0~31 的输出状态寄存器。每一位都对应相应的 I/O 引

脚的状态,低(0)和高(1),见 280 页 OUTA 和 OUTB 的描述。 o 寄存器可以使用下标,例如[16],来访问寄存器内独立的位,见 212 页

DIRA,DIRB 或 280 页 OUTA,OUTB。 o 寄存器/变量后的~~符号将寄存器/变量置高,见符号扩展 15 或 263 页中

操作符小节中 Post-Set “~~”。 o 在一个值/寄存器/变量前加前 “!”会使当前的状态反向。见 272 页上

操作符一节中“位非 !”的描述。 o REPEAT 建立了一个循环结构。见 293 页 REPEAT。 o WAITCNT 建立一个延时,见 322 页 WAITCNT。 o 在行首缩进:

表明他们属于一个程序结构;需要在条件和循环命令后有命令

(就像 REPEAT)。(块指示器后的缩进是可选的,比如

PUB)。 Ctrl+I 可以将块组结构指示器打开或关闭。

Page 98: Propeller Manual - Parallax Home

Propeller编程指导

Page 98 · Propeller Manual v1.0

Cogs (处理器) Propeller 有 8 个相同的处理器,称为 cog。每个 cog 可以由程序控制独立运行或停

止。每个 cog 都可以被编程来按需要运行独立的任务或与其他 cog 协同运行任务。

但是我们没有指定用哪一个 cog 来执行我们的 Output.spin 例子,所以,这是怎么

工作的?作为复习,您可以阅读 18 页第一章的启动程序,运行时程序的相关内容,但

是我们在这里会稍微讨论一下。

在我们的例子中,Propeller 芯片会启动第一个处理器(Cog 0),并将内建的 Boot Loader 程序载入运行。 Boot Loader 程序是从 Propeller 的 ROM 中复制到 Cog 0 的内部

RAM 中的。Cog 0 随后运行该 Boot Loader 程序,Boot Loader 程序会将用户程序代码

从 EEPROM 中复制到 Propeller 芯片的 32K 的 RAM 空间中(与 Cog 的内部内存空间

不同)。然后 Boot Loader 程序使 Cog 0 装载内建的 Spin 语言解释器(这一装载过程会

覆盖 Boot Loader 程序);Cog 0 中的 Boot Loader 程序会在其自身被 Spin 解释器覆盖

时停止运行。

Main RAM

Cog

0R

AM

Cog

1R

AM

Cog

2R

AM

Cog

7R

AM

Application

...

ROMInterpreter

图 3-9: 运行 Output.spin 请注意是 Spin 解释器,而不是 Spin 应用程序,被载入 cog 的RAM 中。Spin 应用程序驻留在主 RAM 中,并被 Spin 语言解释器所解释执行。

现在,Cog 0 正在运行 Spin 语言解释器,它会从主内存取得程序的代码并解释执

行。这一过程在图 3-9 中表示出来。因为我们的程序全部是由 Spin 代码写成,所以会

一直驻留在内存中,等待运行 Spin 语言解释器的 cog(在这里是 Cog 0)读取,解

释,并有效地执行它。启动过程或程序执行过程中没有其它的 cog 会运行;其他的七

Page 99: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 99

个 cog 仍然保持休眠状态,基本上不消耗电力。稍后,我们会修改我们的程序来启动

其他的 cog。

练习 2: Output.spin -常量 我们来使我们的程序加强一点。假设我们想在改变 I/O 引脚和延时长度时更容易一

些。就目前我们的程序中,我们必须找到然后更改两处引脚标号和一处延时的值。我

们可以用单独定义的方法来使得查找和编辑变得容易些。请看下面的代码并编辑您的

代码与其一致(我们突出了每一处新添加或有修改的部分)。

CON Pin = 16 Delay = 3_000_000 PUB Toggle dira[Pin]~~ repeat !outa[Pin] waitcnt(Delay + cnt)

代码顶部的新的 CON 块定义了对象的全局常量(见 194 页 CON)。在 CON 块

里,我们创建了两个符号,Pin 和 Delay,并把常量值 16 和 3000000 赋给他们。现在我

们可以在代码中任意使用 Pin 和 Delay 来代表常数值 16 和 3000000 了。注意到在代码

中我们使用了下划线(_)来分隔数字 3000000 中的千位了吗?代码常量中不允许出现

逗号,但是下划线可以;这使得大数字读起来更方便。

在 Toggle 方法中,我们用符号 Pin 取代了 16 的出现,用符号 Delay 取代了

3000000。编译时,Propeller 工具会使用常量值取代相应位置上的符号。这使得在以后

改变引脚标号或延时的时候很容易,只要改变代码顶部的定义就可以了。

试着把 Delay 的值从 3000000 改为 5000000,并再下载一次;LED 会以每秒 12 次

的速度闪烁(每秒 24 个触发)。您也可以把 Pin 常数从 16 改为 17,并再一次下载,

就可以看到不同的 LED 闪烁。提示:您也可以尝试从 18 到 23 引脚,但是在 Propeller演示板上,他们被成对连接了电阻,用于 VGA 驱动电路,所以,两个 LED 会同时闪

烁。

Page 100: Propeller Manual - Parallax Home

Propeller编程指导

Page 100 · Propeller Manual v1.0

块标识器 您可能已经注意到了在编辑时,CON 和 PUB 代码块的背景颜色彼此不同,这是

Propeller 工具来区别不同代码块的方法。

Spin 代码被组织成不同目的的代码块。CON 和 PUB 是块标识符,分别指明了常量

块和公共方法块的开始。每个块标识器必须开始于文本的第一列(编辑窗格的左边

沿)。Spin 语言中有六种类型的块标识符:CON,VAR,OBJ,PUB,PRI,和

DAT。下面是这些块标识符及其应用的列表:

CON 全局常量块。定义的符号常量可用于对象内的任何使用数值的地方(有些

情况下对象外部也可用)。

VAR 全局变量块。定义的符号变量用于对象内任何使用变量的地方。

OBJ 对象参考块。定义了对一个已存在对象的符号参考,用于访问被参考的对

象,以及其方法和常量。

PUB 公共方法块。公共方法是一段程序,可用于对象内部和外部。公共程序提

供了对象的接口;外部方法与对象间的互动。每个对象都必须至少有一个

PUB 声明。

PRI 私有方法块。私有方法是一段程序,只可以被对象内部使用。因为它们对

外部是不可见的,私有方法提供了对对象内关键元素的概括级别的保护,

并有助于保持对象的完整性。

DAT 数据块。定义了数据表,内存缓冲区,以及 Propeller 汇编代码。数据区的

数据可以被指派符号名,并且可以被 Spin 代码和汇编代码访问。

每种类型的块可以多次出现,以希望的顺序排列,但是每个对象里必须至少有一个

PUB 块。尽管每种块的数量和顺序都是很灵活的,但通常 CON,VAR,OBJ 和 DAT 块只

出现一次,PUB 和 PRI 块可以多次出现,一般程序中建议为上面列出的顺序。

开始的 PUB 块在第一个对象里(顶部对象文件,编译的起始文件)会自动成为

Propeller 应用的起始点;应用启动时它会首先执行。不会有其他公共的或私有的方法

自动执行,确切地说是只有当应用的流程指向该方法时,该方法才会执行。 Propeller 工具会自动将不同的块标注不同的颜色,即使是两个连续出现的同一类型的

块,这样做是为了能更容易地区分不同块的类型,开始和结尾。这样做不会影响到代

码本身,因为这只是为屏幕显示的指示器,使用缩进来解决编辑源代码时遇到的问

题;那就是当代码变得越来越大,除非您在不同的函数方法间有区分器,否则很难在

Page 101: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 101

快速拖动滑条时找到您要找的方法。背景颜色编码作为一种自动区分器,可以防止您

在手动键入文字区分器上浪费时间。

练习 3: Output.spin -注释 我们的输出对象现在更完善了,但是还应该变得更具有可读性。为什么不添加一些

注释,使阅读者能更容易理解代码呢?下一个例子的功能和以前的一样,但是有了一

些注释(适于使用者阅读的,非可执行的文本)在现有代码的右侧。

这些注释能帮助人们理解代码的作用。Propeller 工具支持四种类型的注释(如例子

中所示): '… - 单行代码注释(撇号)

''… - 单行文档注释(两个撇号,不是引号)

… - 多行代码注释(大括号)

… - 多行文档注释(双大括号)

Page 102: Propeller Manual - Parallax Home

Propeller编程指导

Page 102 · Propeller Manual v1.0

Output.spin 以延迟时钟周期触发引脚 CON Pin = 16 要触发的 I/O 引脚

Delay = 3_000_000 时钟周期 Delay内的开/关延迟 PUB Toggle ''反复触发引脚

触发指定的 I/O 引脚,等待 Delay 个系统时钟周期再次触发 dira[Pin]~~ '将 I/O 引脚设置为输出方向

repeat '重复执行下面的内容

!outa[Pin] ' 触发 I/O 引脚

waitcnt(Delay + cnt) ' 等待 Delay 个周期

单行注释从第一个撇号(')开始,直到本行结束。可执行代码可以位于单行注释

的左边而不是右边,因为这样会使该代码“被注释掉”。“'Set I/O pin…”和“'Repeat following…”是单行注释的例子。

多行注释开始于一个左大括号( ),由一个右大括号 ( )结束。不像单行注

释,可执行代码可以位于多行注释的左边或右边。多行注释在实际中可以是整行或多

行。“On/Off Delay…”和“Toggle I/O pin given…”都是多行注释的例子。 如果一行代码开始于一个撇号(’)或一个左大括号( ),那么它就是一段“代码”

注释。这段注释是为代码开发员回顾代码时阅读的。 如果一段注释开始于两个撇号('’)或两个左大括号( ),内部没有空格,那么

它就是一段“文档”注释。这是一种特殊的注释,除了在代码编辑时可以看到,它也

可以被 Propeller 工具提取,形成一个易于阅读,不含可执行代码的文档。 如在第二章 61 页视图模式中所讨论的,Propeller 工具的编辑器有文档视图模式。当所

有的代码输入后,如果选择了文档视图模式,代码会被编译,文档注释被单独与一些

统计信息显示在一起。下面是例子:

Page 103: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 103

Output.spin Toggles Pin with Delay clock cycles of high/low time. Object "Output" Interface: PUB Toggle Program: 8 Longs Variable: 0 Longs PUB Toggle Toggle Pin forever

如果您将它与我们的代码做比较,您会看出所有的文本都直接来自我们的文档注

释。“Object ‘’Output’’ Interface”一段是由 Propeller 工具自动创建的;它列出了所有

公共方法(本例中只有 PUB Toggle),显示出程序的大小是 8 个长字(32 字节),没

有使用变量。在这之后再一次列出了全部的公共方法,每个方法上有上横线,以及属

于该方法的文档注释。这段显示的是公共方法 Toggle 和我们 新的文档注释,“

Toggle Pin Forever”,表明了 Toggle 方法做了什么。

Page 104: Propeller Manual - Parallax Home

Propeller编程指导

Page 104 · Propeller Manual v1.0

快速回顾:练习 2 & 3 • Propeller 有八个完全相同的处理器,称为 Cogs。

o 在同一时间,可以由程序指定任意数量的 cog 运行或挂起。 o 每个 cog 可以运行独立的或协同任务。 o 启动时,Cog 0 运行 Spin 语言解释器以执行基于主内存的 Spin 应用。

• Spin 语言: o 基于不同的用途而组织成块(Blocks)。

CON - 定义全局常量,见 194 页

VAR - 定义全局变量,见 315 页 OBJ - 定义对象参考,见 247 页 PUB - 定义公共方法,见 287 页 PRI - 定义私有方法,见 286 页 DAT - 定义数据,缓冲区,和汇编代码,见 208 页

o 块-组指示器(改为标识)必须位于一行的第一列。 o 每个块类型可以多次出现,可以被以任何顺序布置。 o Propeller 应用中第一个对象的第一个 PUB 块将成为 Propeller 应用的起

始点。 o 常量中的下划线“_”代表逻辑分组,就像十进制数中的以一千分位一

样。 o 注释的类型:

代码注释;只在源代码中可见。帮助开发员认识代码的功能。

'… – 单行:从撇号开始直到本行结束。 … – 多行;一对大括号中的内容。

文档注释:在源代码和文档视图中可见。用于对象文档。可以

包括原理图,时序图和其他特殊符号。

''… – 单行;从双撇号开始直到本行结束。 … – 多行;一对双大括号中的内容。

Page 105: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 105

练习 4: Output.spin –参数,调用,和有限循环 我们从练习 3 得到的对象很有趣,但是还不够灵活;毕竟,Toggle 方法只能工作与

特定的引脚和延时。让我们把 Toggle 方法变得更灵活,同时让它出发特定的,有限的

次数。阅读下面的代码并保证您的代码和它保持一致。我们已经划掉了一些需要删除

的部分,并将每一处新的改动标示出来。

Output.spin 以延迟时钟周期触发引脚

触发两个引脚,一个接一个 CON Pin = 16 要触发的 I/O 引脚

Delay = 3_000_000 在时钟周期内 On/Off Delay PUB Main Toggle(16, 3_000_000, 10) '触发 P16 10 次,每次 1/4 s

Toggle(17, 2_000_000, 20) '触发 P17 20 次,每次 1/6 s PUB Toggle(Pin, Delay, Count) ''反复触发引脚

触发指定的 I/O 引脚,等待 Delay 个系统时钟周期再次触发.

触发引脚 Count 次,,每次触发有 Delay 个时钟周期的间隔. dira[Pin]~~ '将 I/O 引脚设置为输出方向

repeat Count '重复 Count 次

!outa[Pin] ' 触发 I/O 引脚

waitcnt(Delay + cnt) ' 等待 Delay 个周期

编译并下载新程序观察结果。第 16 引脚上的 LED 会闪烁 5 次(10 个触发),¼ 持续和间隔后该 LED 会熄灭,第 17 引脚上的 LED 会闪烁 10 次(20 个触发),有 1/6th持续和间隔。

Page 106: Propeller Manual - Parallax Home

Propeller编程指导

Page 106 · Propeller Manual v1.0

在这个例子里,我们删去了常量(CON)块,添加了名为 Main 的新方法,对

Toggle 方法作了一些小修改。Toggle 方法仍然执行实际的引脚触发工作,但是 Main 方

法会告诉它何时以及如何去做。

Toggle 方法 首先我们来仔细看看 Toggle 方法。在它的声明里,我们在它的名字后面添加了

(Pin,Delay,Count)。这样就为我们的 Toggle 方法创建了一个“参数列表”,包含

了三个参数,Pin,Delay,和 Count。参数列表是一个或多个符号,在方法调用时,这

些符号必须被填上值;每个参数符号对方法来说是长整型的(4-byte)变量;它们在方

法内部是可以访问,但是在方法外部则不可访问。参数变量可以在方法内部被修改,

但是这些修改不会影响到方法的外部。 现在,我们的 Toggle 方法可以被另一个方法调用,并给符号 Pin,Delay,和 Count

指定特定的值;只要我们调整操作参数,调用方法就变得更灵活。 Toggle 内部,除了 REPEAT 命令没有改变任何东西,REPEAT 被替换成了 repeat

Count。请记住,在我们前一个例子中,REPEAT 循环是无限循环;它不会停止。如果

你在 REPEAT 后面添加一个表达式,那么它就变成了有限循环,循环迭代的次数由表

达式给定。在这个例子中,我们的 REPEAT 循环将会执行 Count 次,然后会停止,在

循环结束后的代码将被执行。 Main 方法

现在来看 Main 方法。Main 的第一行,Toggle(16,3_000_000,10),是一个方

法调用;它会使 Toggle 方法执行时以 16 为 Pin 的参数,3000000 为 Delay 的参数,10为 Count 的参数。下一行看起来很相似,Toggle(17,2_000_000,20),但它在调用

Toggle 时使用了不同的参数:Pin 的参数是 17,Delay 参数是 2000000,Count 的参数

是 20。 注意到我们把 Main 方法放在 Toggle 之上了么?记得在 Propeller 应用启动时第一个对

象中的第一个公共方法会自动执行吗?在这个例子中我们只用了一个对象,所以下载

完应用后 Main 方法会自动执行。 当 Main 的第一行,Toggle(16,3_000_000,10),执行时,Toggle 方法就被调用并

执行其功能:使第 16 引脚上 LED 闪烁 5 次,间隔为¼秒。此后因为在循环后没有代码

需要执行,它会返回调用者,Main,然后执行下一行:Toggle(17,2_000_000,20)。该行执行时,Toggle 方法被调用,它会将第 17 引脚上的 LED 闪烁 10 次,间隔

1/6s。 后,Toggle 方法再次返回 Main,但是 Main 已没有需要执行的代码,所以

Page 107: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 107

Main 推出,程序终止;cog 停止,Propeller 进入低耗电模式直到下一次复位或电源上

电。

在看代码的时候请不要迷惑。两个方法,Main 和 Toggle,在显示时排列在一起,

但是他们是作为不同的程序对待的,范围从 PUB 块的声明开始到本块的结束或源代码

结束。换句话说,Propeller 知道 Toggle 方法不是 Main 方法可执行代码的一部分。 同时请注意我们的例子中只使用了一个 cog,整个应用串行地执行:首先闪

烁 P16,停止,闪烁 P17,然后停止。下一个练习中我们将使用多个 cog。

练习 5: Output.spin –并行处理 练习 1-4 中,我们在应用中只使用了一个 cog;它只触发 P16,然后停止,接着触

发 P17,随后终止。这样的流程叫做“串行处理(Serial Processing)”。

假定我们想并行地做一些事;同时触发 P16 和 P17,每个都以不同的速率和周期运

行。这样的任务当然可以通过串行处理和巧妙的编程实现,但是通过激活两个 cog,采用并行处理的方式会更容易。请看下面的代码并修改您的代码。我们添加了一个变

量块(VAR)并对 Main 方法作了一些小改动。

Output.spin Toggle two pins, one after another simultaneously. VAR long Stack[9] '新 cog 的堆栈空间 PUB Main cognew(Toggle(16, 3_000_000, 10), @Stack) '触发 P16 10次… Toggle(17, 2_000_000, 20) '触发 P17 20次… PUB Toggle(Pin, Delay, Count) 触发引脚 Count次,,每次触发有 Delay 个时钟周期的间隔. dira[Pin]~~ '将 I/O 引脚设置为输出

repeat Count '重复 Count 次迭代

Page 108: Propeller Manual - Parallax Home

Propeller编程指导

Page 108 · Propeller Manual v1.0

!outa[Pin] ' 触发 I/O引脚

waitcnt(Delay + cnt) ' 等待 Delay 个周期的延迟

VAR 块 在 VAR 块中,我们定义了一个长型数组(An array of Longs), Stack,有九个元

素。它由 Main 方法使用。

Main 方法 我们修改了 Main 方法的第一行,原来调用了 Toggle 的代码现在被包含在

COGNEW 命令里。COGNEW 命令会启动一个新的 cog 来执行 Spin 或汇编代码。这个

例子中,我们输入了 Toggle(16,3_000_000,10)作为第一个参数,@Stack 作为第

二个参数。这意味着 COGNEW 启动了一个新的 COG 来运行 Toggle 方法,使用从

Stack 的地址开始的内存空间作为运行时堆栈空间。符号@是符号取址操作符(Symbol Address operator);它返回其后的变量的实际地址。

要运行 Spin 代码,新的 cog 需要一些运行时空间,叫做“堆栈空间”,这里存储

了临时数据,比如返回地址,返回值,中间表达式值等。我们选择保留 9 个长字型的

空间(36 字节),并将它的地址作为第二个参数(@Stack)传递给 COGNEW。那么

需要多大空间的堆栈呢?这依赖于要执行的 Spin 代码,我们会在稍后讨论这个问题。

现在我们保留的 9 个长字空间对 Toggle 方法来说已经足够了。 编译并下载 Output.spin。您应该可以看到 P16 和 P17 上的 LED 在以不同的速率同

时闪烁,分别为 5 次和 10 次。这时因为现在我们有两个 cog 在同时运行;一个触发

P16 同时另一个触发 P17.

下面来解释它是如何工作的:Cog 0 开始执行我们的应用 Main 方法。Main 的第一

行使用 COGNEW 命令激活了一个新的 Cog(cog 1)来运行参数为(16,3000000,10)的 Toggle 方法。当 Cog 1 启动时,Cog 0 继续执行 Main 方法的第二行,直接调用

参数为(17,3000000,20)的 Toggle 方法。 后,Cog 0 在 P17 上执行 Toggle,Cog 1 在 P16 上执行 Toggle,两者同步进行。当其各自的任务结束后,由于已没有要执行

的代码,处理器会停止。Cog 1 在执行完 Toggle 后停止。Cog 0 在执行完 Toggle,返回

Main 后停止。在这里 Cog 1 会比 Cog 0 早一些停止。

Page 109: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 109

图 3-10 阐明了上述过程。Propeller 将 Spin 解释器载入 Cog 0 执行应用(图中 左

边的箭头)。然后应用请求激活一个新的 COG,通过命令 COGNEW,这会使

Propeller 将 Spin 解释器载入下一个可用的 Cog,Cog1,以执行一小段应用中的代码,

也就是 Toggle 方法(图中 右端的两个箭头)。每个 cog 会彼此完全独立地执行代

码,真正的并行处理。请注意直到应用结束,两个 cog 都在执行同样的 Spin 代码,

Toggle 方法,但是每个 cog 都有各自的工作空间和不同的 Pin,Delay 和 Count 值。

Main RAM

Cog

0R

AM

Cog

1R

AM

Cog

2R

AM

Cog

7R

AM

Application

...

Spin Code

ROMInterpreter

图 3-10: 两个 cog 运行

Output 应用程序和

Toggle 方法。 请注意 Spin 解释器会被载入到每个 Cog 的RAM 中。Spin 应用程序,Output,驻留在主RAM 中,被 Cog 0 解释,它启动 Cog 1 来运行 Toggle 方法。

Page 110: Propeller Manual - Parallax Home

Propeller编程指导

Page 110 · Propeller Manual v1.0

快速回顾:练习 4 & 5 • Spin 语言:

o 方法: 要在同一个对象内调用方法,可以直接写出方法的名称,参见

287 页的 PUB 。 方法可以自动退出,当要执行的代码结束后返回到调用者。 当应用程序的第一个方法退出后,应用程序和运行该程序的 cog

也会停止。 .

o 参数列表: 方法以下列形式声明参数:方法 (param1, param2, etc.) , 参

见 287 页 PUB 。 参数是长字型的本地变量,只能在方法内部被访问。

• 它们可以在方法内部被修改,但是任何相应的调用者使

用的变量会不受影响地返回。 o REPEAT 命令:

无穷循环:repeat 有限循环:repeat expression,这里 expression 指出了希望的循

环迭代次数,参见 293 页 REPEAT。 o 数组:

数组以以下的形式定义 symbol [count],symbol 是数组的符号名

称,count 是数组元素,参见 315 页 VAR。 o COGNEW 命令:

激活另一个 cog(处理器)来运行 Spin 或 Propeller 汇编代码,参见

189 页 COGNEW。 允许实并行处理。 需要指出为 Spin 代码运行时要保留的堆栈空间的地址。

o 符号取址操作符(@)返回其后变量的地址。参见 278 页符号取值操作

符‘@’。

Page 111: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 111

练习 6: Output.spin & Blinker1.spin –使用对象 现在我们来探索对象的力量。之前所有的练习都只创建了一个对象;Output.spin 对

象是整个应用程序。这是新对象开发初期典型的做法。假定在此背后的动机是创建一

个对象,使其他程序员能使用它来触发一个或多个 I/O 引脚。是的,为这种用途创建

一个对象也许很愚蠢,但是无论如何,我们可以从中找些乐趣!

现在是时候为我们的 Output 对象创建和其他对象的接口了。按照如下形式编辑我

们的代码:

Example Object: Output.spin

Output.spin 触发两个引脚,一个接一个. VAR long Stack[9] '新 cog的堆栈空间 PUB Main cognew(Toggle(16, 3_000_000, 10), @Stack) '触发 P16 10次… Toggle(17, 2_000_000, 20) '触发 P17 20次… PUB Start(Pin, Delay, Count) 启动新的 cog,在新 cog 上启动触发程序. cognew(Toggle(Pin, Delay, Count), @Stack) PUB Toggle(Pin, Delay, Count) 触发引脚 Count次,,每次触发有 Delay 个时钟周期的间隔. dira[Pin]~~ '将 I/O 引脚设置为输出

repeat Count '重复 Count 次迭代

!outa[Pin] ' 触发 I/O 引脚

waitcnt(Delay + cnt) ' 等待 Delay 个周期延迟

确认将此对象保存时文件名为 “Output.spin”,我们下一个对象仍然会使用它。

Page 112: Propeller Manual - Parallax Home

Propeller编程指导

Page 112 · Propeller Manual v1.0

Start 方法 在这里,我们将 Main 方法替换成了 Start。 Start 方法激活了另一个 cog 来独立运

行 Toggle 方法,同时向它传递参数 Pin, Delay, 和 Count 。

一个对象的接口由它的公共方法组成 (PUB) ,所以我们的 Output 对象现在有两个借

口元件, Start 方法和 Toggle 方法。

现在我们的 Output 对象可以被另一个对象使用,来以任意速率,任意次数来触发

任意引脚。现在可以选择串行方式来处理,通过调用 Output 的 Toggle 方法,或者和其

他任务并行处理,通过调用 Output 的 Start 方法。

我们来创建另一个使用 Output 的对象。要创建新对象,从菜单中选择 File → New,一个新的 Tab 会出现。在新的编辑页面中,输入下列代码。要特别注意粗体的

部分,我们会在稍后讨论它们。

Example Object: Blinker1.spin

Blinker1.spin OBJ LED : "Output" PUB Main 以不同的速率触发引脚,同步处理 LED.Start(16, 3_000_000, 10) LED.Toggle(17, 2_000_000, 20)

将这个新对象保存为 “Blinker1.spin” ,和 Output.spin 保存在同一个文件夹内。现在

保持 Blinker1 的编辑窗格为活动的,按 F10 编译并下载。这时,LED 应该和练习 5 中

的 LED 一样闪烁,但是我们的代码中使用了不同的技术;Blinker1 使用了我们的

Output 对象,简单的调用 Output 的 Start 和 Toggle 方法。

这里解释一下是如何工作的。在 Blinker1 中,我们有一个对象块(OBJ)和一个公

共方法(PUB)。对象块的 LED : "Output" 行声明了我们将使用一个名为 Output 的对

象,并在 Blinker1 对象中用 LED来引用此对象。

对象-方法引用 在公共方法 Main 中,我们有两个方法调用。我们在练习 4 中已经学到通过引用名

称来调用另一个方法。如果两个方法在同一个对象中,这时可行的,但是现在我们要

Page 113: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 113

调用的是在另一个对象中的方法。要做到这一点,我们可以使用 object . 方法 的形式来

调用,其中 object 是在 OBJ 块中的符号名(在此是 LED),方法 是该对象的方法。这

就是对象方法引用。Blinker1 以 LED 来引用 Output 对象,所以,LED.Start 会调用 Output 的 Start 方法,LED.Toggle 会调用 Output 的 Toggle 方法。

在 Blinker1 被编译时,由于它引用到了 Output,这两个对象会被编译成一个应用

程序。图 3-11 将这点展示出来。该结果也会出现在我们将马上学习的对象视图中

(Object View)。

图 3-11: Blinker1 结构和 Blinker1 应用程序

对象视图 在编译 Blinker1 时,对象视图面板,会更新以显示出该应用程序的结构。如果您打

开了集成浏览器面板,那么对象视图会出现在 Propeller 工具的左上方 (参见 39 页面板

1) 图 3-12 展示出了它应该出现的样子:

Page 114: Propeller Manual - Parallax Home

Propeller编程指导

Page 114 · Propeller Manual v1.0

图 3-12: Blinker1 对象

视图

在每次编译成功后,对象视图会自动更新以展示出该应用程序的逻辑结构。图 3-12 中所示是以对象视图的方式表达图 3-11 中的逻辑结构。有时在排除故障很或验证合

适的编辑时有必要检查对象视图。

您整个应用程序会显示在对象视图中,或至少是在上一次成功编译后它的样子。您

也可以使用它浏览应用程序。例如,在对象视图中用鼠标指向每个对象会给出每个对

象的提示信息。左键单击每一个对象会将其打开或将活动的 edit tab 切换到该对象。右

键单击和左键单击一样,但是会打开文档视图,而不是全代码视图。

顶部对象文件 在对象视图顶部的对象是该设计的“顶部对象文件”。在这个例子里就是从

Blinker1 开始。当我们用 F10 或 F11 快捷键,或者其相应的菜单项进行编译时,

Propeller 工具从当前活动的编辑栏开始进行编译。活动的 Edit Tab 是高亮的 edit tab,与其它不同;参考 42 页上的编辑器面板和图 2-4。

如果意外的单击了 Output 对象的 tab,然后按 F10 或 F11 开始了编译,那么编译将

从该对象开始。这会使应用程序和对象视图只显示一个对象,Output。这是因为我们

使用的编译功能是“编译当前”选项;意思是从当前活动的对象或 edit tab 开始编译。

有其他的编译功能可以帮助我们,选择 Run 菜单察看选项。您应该可以看到“编

译当前(Compile Current) ”和“编译顶部(Compile Top)”竖向菜单(图 3-13)。

Page 115: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 115

图 3-13: 编译当前菜单

(上)和编译顶部菜单

(下)

每个菜单,编译当前和编译顶部,都有同样的子选项,但是它们编译的起始点不

同。编译当前从活动的 Edit tab 开始,编译顶部从设计的顶部对象文件开始。

您可以告诉 Propeller 工具应该将哪一个对象作为指定的顶部对象文件。可以通过

下面的任一方法:

1) 右键单击希望的对象 edit tab ,选择“顶部对象文件 Top Object File”或

2) 从文件列表(在集成浏览器)中右键单击希望的对象,选择“顶部对象文件

Top Object File”或

3) 选择菜单 File → Select Top Object File… 选项,然后从浏览窗口中选择希望的

文件,或

4) 按 Ctrl+T 然后从浏览窗口中选择希望的文件。

在下面的图示中,我们使用了方法#1 将 Blinker1 选为顶部对象文件 Top Object File。 注意,此后 Blinker1 的 tab 的字体变粗了;见 图 3-14b。 Propeller 工具会将顶部

对象文件的字体加粗。

现在,如果我们使用编译顶部的某个选项,比如 Ctrl+F10 或 Ctrl+F11 的时候,不

论哪个 Tab 被激活,Propeller 工具将会从顶部对象文件开始编译。例如,在图 图 3-14b 中, Output 对象是活动的 edit tab。但是如果我们按 Ctrl+F10,应用程序将从

Blinker1 对象开始编译。如果我们按的是 F10,Output 对象将会被编译。

编译当前选项的每一个快捷键,如 F8, F9, F10, 等,都有在编译顶部选项中有

对应的变体,如 Ctrl+F8, Ctrl+F9, Ctrl+10, 等。

Page 116: Propeller Manual - Parallax Home

Propeller编程指导

Page 116 · Propeller Manual v1.0

图 3-14: 将 Blinker1 设置为顶部对象文件

a.

设置顶部对象文件的方法之一是右键单击希望的编辑栏,然后选择 Top Object File。

b.

顶部对象文件的名称会被加粗显示。

哪些对象被编译了? 如果想知道上一次成功编译的对象文件有哪些,可以用鼠标浏览对象视图中应用程

序的结构。

记录哪个文件被指定为顶部对象文件和所选择的编译选项失衡重要的;当前 vs. 顶部。一次只能有一个文件可以被指定为顶部对象文件,Propeller 工具会记住该文件,

即使在会话间也是如此。

同样的,要记住一个对象不需要在 Propeller 工具中被打开就可以被编译。如果一

个编译对象引用了其他对象,则不论那个对象不论打开与否都会被编译。例如,按下

Ctrl+F10 会从 新的被指定的顶部对象文件开始编译,而不论它是否属于你当前正在

开发的应用程序。

Page 117: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 117

快速回顾: 练习 6 • Spin 语言:

o 方法: 要在另一个对象中调用方法,使用 object . 方法 的形式,object

是对象的符号名称,(given to it in the OBJ block),方法 是该对象

内的方法的名称。参见 247 页 OBJ 。 公共(PUB)方法是对象接口;其他对象可以调用对象的公共方

法。参见 287 页 PUB。 • 对象视图

o 阐明了 近成功编译的应用程序的结构。参见 52 页对象视图(Error! Reference source not found.)。

o 将鼠标指向被显示的对象,会给出该对象提示信息。 o 左键单击一个被显示的对象会将其打开或使其成为活动 edit tab。 o 右键单击一个被显示的对象会将其打开或为其打开文档视图。

• 编译当前(Compile Current) – (F8 到 F11) – 从当前的对象开始编译(活动 edit tab)。

• 编译顶部(Compile Top) – (Ctrl+F8 到 Ctrl+F11) – 从顶部对象文件开始编译。 • 顶部对象文件:

o 在 Edit Tab 和文件列表中的名称变成粗体。 o 可以通过如下方法之一指定 (以及通过编译顶部操作进行编译): 1) 右键单击对象的 Edit-Tab,选择“顶部对象文件(Top Object File)”

或 2) 在文件列表中右键单击一个对象,然后选择“顶部对象文件”或 3) 从菜单选择 File → Select Top Object File… 然后从浏览器中选择对象文

件。 4) 按下 Ctrl+T 然后从浏览器中选择对象。

• 对象不需要被打开就可以编译;它们可以是其它对象编译的结果或是编译顶部

操作的结果。

Page 118: Propeller Manual - Parallax Home

Propeller编程指导

Page 118 · Propeller Manual v1.0

对象 vs. Cogs 明白对象和 cogs 之间没有直接的关系是很重要的。记住,练习 5 只使用了一个对

象,但是使用了两个 cog;练习 6 使用了两个对象和两个 cog。但是如果这些练习要串

行地处理所有的事务,那么就只能使用一个 cog。何时和使用几个 cog 完全由应用和编

写应用程序的开发人员来决定。

练习 7: Output.spin – 更多增强 现在我们来为我们的 Output 对象添加一些重大的功能增强。目前, Toggle 方法可

以被串行调用来触发引脚,或者调用 Start 方法以独立进程的方式载入 Toggle 方法,

以并行方式运行。但是我们还没有提供一种方法在一旦程序开始运行后,来停止程

序,或者一种方法来检测程序是否在运行。同样的,除了我们已有的能触发有限次触

发的方法,如果能提供一种方法能实现无限次触发就更好了。

我们来添加一个 Stop 方法来停止活动的进程以及一个 Active 方法来测试一个并行

的进程是否在运行。此外,我们将按如上所述增强我们的 Toggle 方法。

对于这样的对象,通常约定使用“Start”这样的方法名称来表明激活一个新的

cog,使用“Stop”方法来撤销由对象激活的 cog。通过这种方法,在以摘要或文档视

图检查对象时,其他的开发人员可以更快地明白如何使用你的对象;当他们看到 Start 和 Stop ,他们可以推断出是激活/释放另一个 cog。对于不会激活其他 cog,但是仍然

需要某种初始化的对象而言,推荐使用“Init”作为名称。

这段代码在被载入时有些巧妙的小改变;准备好,我们将花大量的篇幅来解释,但

与您所获得知识相比是值得的。

这是代码;请修改您的代码与之保持一致:

Page 119: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 119

Output.spin VAR long Stack[9] '新 cog的堆栈空间

byte Cog '在使用中 cog 的 Hold ID PUB Start(Pin, Delay, Count): Success 在新的 cog上运行新的 blinking 程序; 如果成功,返回 TRUE Stop Success := (Cog := cognew(Toggle(Pin, Delay, Count), @Stack) + 1) PUB Stop 停止触发程序, if any. if Cog cogstop(Cog~ - 1) PUB Active: YesNo 如果程序是活动的返回 TRUE,否则返回 FALSE YesNo := Cog > 0 PUB Toggle(Pin, Delay, Count) 触发 Pin,Count次,间隔 Delay 个时钟周期 If Count = 0, toggle Pin forever. dira[Pin]~~ '将 I/O 引脚设置为输出… repeat Count '重复 Count次

repeat '重复执行下面的内容

!outa[Pin] ' 触发 I/O 引脚

waitcnt(Delay + cnt) ' 等待 Delay 个周期 while Count := --Count #> -1 'While not 0 (make min -1) Cog~ '清除 Cog ID 变量

Page 120: Propeller Manual - Parallax Home

Propeller编程指导

Page 120 · Propeller Manual v1.0

VAR 块 在 VAR 块中,我们添加了一个字节型变量 Cog。它将用于记录由 Start 启动的 cog

的 ID。Stack 和 Cog 变量是对象的全局变量;它们可以用在 Output 对象的任何 PUB 或 PRI 块中。如果它们被一个方法修改过,其它的方法在重新引用它们时将使用新的值。

Start 方法 对于 Start 方法, 我们已经决定了要记录是否成功。因为在 Propeller 芯片中对 cog

数量的限制,所以 Start 方法不可能在每次调用时激活一个新的 cog。因此,我们让它

返回一个布尔值(TRUE 或 FALSE)作为它输出的指示;声明中的“: Success”表明它将

返回 Success 这个值,PUB 和 PRI 方法不管是否被指定要返回值,总会返回一个长字型

值(4 个字节)。当一个方法被指定返回一个有意义的值时候,就将该返回值声明出

来,如同我们在这里做的一样。我们的 Success 符号变成了方法的内建 RESULT 变量的

别名,所以我们可以给 Success 或 RESULT 赋值,使得方法结束时能返回适当的值。

Start 方法现在做了两件事:首先,它停止所有存在的进程,然后启动一个新的进

程。它首先调用 Stop 方法,这样做是为了防止 Start 已经被多次调用,而在对象外部

没有调用 Stop 方法。如果不这样做,一个新的 cog 启动后会覆盖另一个 cog 的工作空

间变量,例如 Stack。

下一行和我们以前的程序相似,但是因为它是一个复合表达式,所以看起来有些复

杂。我们会从内到外仔细分析它。该行 COGNEW 的部分就是以前的样子:

cognew(Toggle(Pin, Delay, Count), @Stack)。它会激活另一个 cog 来运行 Toggle 方法。可能你不知道的是 COGNEW 命令总会返回它所启动的 cog 的 ID;从 0 到 7,或当没

有可以启动的 cog 的时候返回-1。在先前的 Output 的版本中,我们忽略了这个返回

值。但这次,我们将 COGNEW 的返回值用在表达式中,将该结果赋值给一个变量: Cog := cognew(Toggle(Pin, Delay, Count), @Stack) + 1. 该表达式的意思是执行

COGNEW,将它的返回值加 1,然后将结果赋给一个名为 Cog 的变量。‘:=’是赋值运算

符;与其它语言中的等于号‘=’类似。

我们使用变量 Cog 来记录我们启动的 cog 的 ID,所以如果有必要我们可以在稍后

将它停止。我们马上会解释为什么要加 1。

我们还没有完成这一行,在 Cog := … 这部分的左侧是 Success := 赋值语句。所以

在新的 cog 的 ID 返回后会加 1,然后存储到 Cog 中,也存储在 Success 变量中。那么

Success 是如何成为我们的 Start 方法的布尔返回值呢?布尔结果 FALSE 实际上是数值

0,TRUE 是-1,但是布尔比较运算中会将 0 作为 FALSE,任何非零值(≠0)作为 TRUE。

Page 121: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 121

这就是为什么我们会在 COGNEW 的返回值上加 1 的原因;范围-1 到 7 会变为 0 到 8,0(FALSE)意味着 没有 cog 启动,1 到 8(TRUE)意味着有 cog 启动了。.

所以,在该单行代码中我们启动了一个新的 cog,向该 cog 传递了对 Toggle 程序和

堆栈空间的引用,将新激活的 cog 的 ID 加 1 后存储在变量 Cog 中,将该结果作为

Start 的返回值,也就是变量 Success 的值!该行演示了 Spin 语言的 强大的特性之

一:使用可中间赋值的复合表达式

写在 Cog :=… 语句外的括号不是必须的,我们在这里加上括号的原因是帮助区分

两个不同的变量赋值;Cog 先被赋值,然后它的值被赋值给 Success。为了能有助于学

习复杂的表达式,Propeller 工具会零时将光标所在处匹配的括号加粗。将光标处于该

行不同的位置可以看到效果,如下图所示,星号表明了当前光标的位置,箭头所示为

加粗体的括号,阴影部分是该匹配括号中的内容。

图 3-15: 匹配的括号变为粗体 匹配的括号会零时以粗体显示,使用该特性可以检查复杂的表达式是否正确

Stop 方法 我们的 Stop 方法用来停止由 Start方法启动的 cog。语句 if Cog 是条件结构,意思

是“如果 Cog 变量为 TRUE,则执行下面的缩进代码行”。记住,如果没有 cog 启动, Cog 会被设置为 0,如果有 cog 启动了,那么 Cog 的值会被设置为 1 到 8 中间的某个

值。因为 0 的意思是 FALSE,非零值代表 TRUE,所以只有启动了新的 cog 时,IF 语句才

会为真。

COGSTOP 语句在 IF 之后缩进,所以只有当 IF 语句为真时,它才能执行。COGSTOP 命令通过 Cog~ - 1 将得到 ID,并将该 ID 值的 cog 停止。这是 Spin 语言中另一个有用的

Page 122: Propeller Manual - Parallax Home

Propeller编程指导

Page 122 · Propeller Manual v1.0

表达式。记住的前面的练习中的 Post-Set 运算符~~吗?这里,一个~ 符号紧跟在变量后

就是 Post-Clear 运算符;它将变量的值置零。这些运算符之所以被称为是“post”运算

符(后运算符)是因为它们在变量的值提交给表达式后才动作。所以,Cog~ - 1 首先

取得 Cog 的值,将它减 1,把计算结果提交给 COGSTOP 命令,然后将 Cog 清零。实际上

cogstop(Cog~ - 1) 语句会停止 ID 为 Cog-1 的 cog,然后将变量 Cog 清零,这样,以后

再引用到 Cog 时,就会得知没有其它 cog 在运行。

Active 方法 Active 方法很简单,它根据 Cog的值来设置返回值 YesNo,如果 Cog 的值大于 0,则

设置为 TRUE,否则为 FALSE。符号 > 是大于运算符(Is Greater Than)。注意,我们也

可以只设置 YesNo 等于 Cog,因为 0 被视为 FALSE,非零值被视为 TRUE;这样就可以利

用返回的 cog 的 ID 来判断 TRUE还是 FALSE。

Toggle 方法 我们已经对 Toggle 方法做了一些细小而重大的改动。首先,我们来看 后一行,

Cog~,记住如果 Start 被调用,它会在另一个 cog 运行 Toggle 方法并在变量 Cog中存储

cog 的 ID。当 Toggle 终止,它所运行的 cog 也会终止,但是 Cog 变量会保留下来,让

Active 和 Start 方法认为该 cog 仍然是活动的。所以我们把 Cog~ 安排在 Toggle 方法的

后,来将 Cog 变量清零(0)以保持代码的完整性。

记得我们说过我们想改变 Toggle 方法,使其能像处理有限循环一样处理无限循环

么?我们的下一项改变以巧妙的方式达到了目的。Count 参数是要触发引脚的次数。这

就是说将 Count 设置为 0 没有意义,谁会想要将一个引脚触发 0 次呢?所以,我们会

将 0 作为例外情况,意思是“无限次触发该引脚”。

我们将循环形式从 repeat Count 改为 repeat..while。 ‘while’在循环的结尾处,

repeat 下第三行。这是 REPEAT 循环结构的另一种形式,称为“有条件一到多次循

环”。它会至少执行一次表达块内的程序,然后当“while”条件为真时会再次迭代。

在这个例子中,当 Count := --Count #> -1 为 TRUE (ie: 非 0 值)时会一直重复。 该条件是另一个复合表达式。Count 之前的双负号‘--’是前减运算符(Pre-Decrement operator); 它在 Count 值被使用前会将 Count 的值减一。 #> 是 Limit Minimum 运算

符;它会返回它两侧的值中较大的一个。所以该表达式在被计算时,Count 被减 1,该

值被限制为-1 或更大, 终结果被赋值给 Count。 我们接下来会解释这么做的巧妙之

处。

Page 123: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 123

如果 Toggle 被调用时 Count 的值为 2,这个循环会按照我们希望的那样执行两次。

第一次迭代后,语句 while Count := --Count #> -1 会将 Count 减一,使 Count 等于

1,然后会将其限制到-1 或更大的值(1)并将该值存储在 Count 中。由于这个结果 1是非零值(TRUE),所以循环会再次运行。在第二次迭代后,WHILE 语句会将 Count 减

一,使其等于 0,并将其限制到-1 或更大的值(0),因为 0 是 FALSE,WHILE 条件会终

止循环。

对一般的 Count 值而言,程序可以正常工作,但是如果 Toggle 被调用时 Count 等

于 0 怎么办?在第一次迭代后,语句 while Count := --Count #> -1 会将 Count 减一,

使其等于-1,然后限制到-1 或更大的值(还是-1),并将结果存储到 Count 中。因为这

个结果-1 是非零值(TRUE),循环会再次执行。第二次迭代后, WHILE 会将 Count 减

一,使其等于-2,然后将其限制到-1 或更大的值(改为-1),并存储到 Count 中。因为

结果-1 是非零值(TRUE),循环会再次执行。

所以,如果 Count 的起始值为 0,循环会无穷次迭代!如果 Count s 的起始值大于

0,它才会按照指定的次数迭代!

Page 124: Propeller Manual - Parallax Home

Propeller编程指导

Page 124 · Propeller Manual v1.0

快速回顾: 练习 7 • 对象:

o 和 cog 没有直接联系。 o 如果对象影响到其它 cog,应该调用接口方法“Start”和“Stop”。 o 如果对象本身需要初始化,应该调用方法“Init”。

• Spin 语言: o 变量块中定义的变量对对象而言是全局的,所以如果变量被一个方法修

改后对其它方法是可见的。参见 315 页 VAR。 布尔:(参见 220 页,常量(常量 (预定义)),249 页运算符) FALSE = 0 TRUE = -1; 对布尔表达式而言,任何非零值(≠0) 都是 True。

o 组合表达式可以包含中间赋值,参见 253 页。 o 运算符:

“Pre”/“Post” 运算符在变量的值用于表达式之前或之后执行任

务。 赋值‘:=’类似于其它语言中的等于‘=’,参见 255 页,变量

赋值 ‘:=’。 Post-Clear ‘~’ 将在它之前的变量清零(0),参见 267 页 Sign-

Extend 7 或 Post-Clear ‘~’。 Pre-Decrement ‘--’ 会使它的运算对象变量减少(减 1)将结果

返回给表达式。参见 262 页 减量, 前减(pre-) 或 后减(post- ‘- -’。

Is Greater Than ‘>’ ,如果其左侧的值大于其右侧的值,返回

True。 参见 281 页布尔大于 ‘>’, ‘>=’。 Limit Minimum ‘#>’ 返回其两侧的数值中较大的一个。参见 265

页 Limit Minimum ‘#>’, ‘#>=’。 o 方法:(参见 287 页 PUB)

不论是否指定返回值,总会返回一个长字型值。 包含内建的本地变量,RESULT,保存了返回值。 返回值通过方法的名称和参数之后的分号(:)以及描述性的

返回值名称来声明。 o COGNEW 返回启动的 cog 的 ID(0 到 7);如果没有则为-1,参见 189 页

COGNEW。 o COGSTOP 通过 ID 撤销一个 cog。参见 193 页 COGSTOP。

Page 125: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 125

o IF 是一个条件结构,如果条件满足,则执行紧随它的缩进的代码块。

参见 220 页 IF。 o REPEAT 的条件,一次到多次形式:REPEAT WHILE Condition 执行至少一

次,若 Condition 为真,则继续执行。参见 293 页 REPEAT。 • Propeller 工具会将光标周围相匹配的圆括号加粗。

练习 8: Blinker2.spin – 多个对象,多个 cog 现在我们来建立一个新的对象,它可以利用增强后的 Output 来使用多个 cog 进行

并行处理。这里是源代码:

例子对象: Blinker2.spin

Blinker2.spin CON MAXLEDS = 6 '要使用的 LED 对象的个数 OBJ LED[6] : "Output" PUB Main 同时以不同的速率触发引脚 dira[16..23]~~ '将引脚设置为输出

LED[NextObject].Start(16, 3_000_000, 0) '使 LED闪烁 LED[NextObject].Start(17, 2_000_000, 0) LED[NextObject].Start(18, 600_000, 300) LED[NextObject].Start(19, 6_000_000, 40) LED[NextObject].Start(20, 350_000, 300) LED[NextObject].Start(21, 1_250_000, 250) LED[NextObject].Start(22, 750_000, 200) '<-延迟

LED[NextObject].Start(23, 400_000, 160) '<-延迟

LED[0].Start(20, 12_000_000, 0) 'object 0重启动

repeat '无限循环

Page 126: Propeller Manual - Parallax Home

Propeller编程指导

Page 126 · Propeller Manual v1.0

PUB NextObject : Index 扫描 LED 对象,返回下一个可用的 LED对象的索引值。

扫描一直持续到发现新的可用的对象为止。 repeat repeat Index from 0 to MAXLEDS-1 if not LED[Index].Active quit while Index == MAXLEDS

编译并下载 Blinker2。您应该可以看到 6 个 LED 开始以不同的,独立的速率和周

期闪烁。请仔细看,大约 8 秒后,P20 会停止闪烁,而 P22 开始闪烁。几秒钟后,P18会停止 P23 会开始闪烁,但是是以不同的速率进行。 终,除了 P17 和 P20,所有的

闪烁都会停止。您能说出为什么会这样么?我们接下来会解释。

OBJ 块 在对象块中,我们定义了一个 Output 对象的数组,称为 LED,有六个元素。这就是

为什么我们能有 6 个同时运行的程序的原因,它们彼此是相互独立的。

Main 方法 Main 的第一行,dira[16..23]~~,将第 16 到第 23 I/O 引脚设置为输出。I/O 寄存

器,DIRA, OUTA,和 INA,可以使用这种形式来作用于多个连续的引脚。我们将整个组

的 I/O 引脚设置为输出是为了防止出现令人困惑的结果,因为在 Propeller Demo Board上在 I/O 对中 18 到 23 引脚之间的电阻连接造成了这样的结果。如果一个 cog 是唯一个

将某引脚设置为输出的,在关闭 cog 时,该引脚会变成输入,这会使连接在这个引脚

和它旁边引脚间的电阻影响到 LED。(假设引脚 A,B 被不同的 cog 设置为输出,当

引脚 A 恢复为输入时,电流会通过引脚 A 流经 A,B 间的电阻,从引脚 B 的 LED 流

出,LED 发光)。我们将保持该应用程序的 cog 为活动的,这样结果对我们来说就很

清晰了。

下一行,LED[…,调用了 Output 对象的 Start 方法来启动一个新的 cog 并以不同的

速率触发不同的 I/O 引脚。 LED[NextObject].Start…,调用了 NextObject 方法来取得数

组的索引值。我们稍后解释 NextObject 方法的更多细节,在这里,它会返回下一个可

用的 Output 对象的索引值(例如第一个空闲的对象),然后暂停,直到另外一个对象

可用。

Page 127: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 127

我们只为 LED 数组定了六个 Output 对象,所以这六个对象会调用 Start 然后快速

地执行,每个对象的访问 LED 索引号是从 0 到 5,再激活六个 cog。前两个带有参数

Count,其值等于 0,所以它们会无限次触发;后四个会在执行完指定的触发次数后停

止。

第七行,LED[NextObject].Start(22, 750_000, 200) 会首先调用 NextObject 来取得

下一个可用的对象的索引值,但是因为全部的六个对象都在触发引脚,NextObject 会一直等待,而且不会返回到 Main,直到发现一个可用的对象。结果,索引号为 4 的对

象(I/O 引脚 20)会先完成任务并关闭。所以 NextObject 方法会返回 4,允许该对象的

Start 方法执行,这会重新启动另外一个 cog 触发 I/O 引脚 22。第八行是同样的过程,

LED[NextObject].Start(23, 400_000, 160);所有的对象都处于忙状态,所以 NextObject 会将进一步的操作延后,直到发现可用的对象,索引号为 2 的对象就是这样。

八行代码全部执行完后,第九行会开始执行:LED[0].Start(20, 12_000_000, 0)。

该语句不象之前的语句调用了 NextObject,它使用的索引号是固定值 0。意思是索引号

为 0 的 LED 对象在忙于将 I/O 引脚 Pin 16 无限触发,当它的 Start 方法被再次调用的

时候,会使执行触发动作的 Cog 立刻停止,然后重新启动执行触发第 20 引脚。

后一行,repeat,是用于保持应用程序的 cog 始终为活动状态。它建立了一个无

限循环,该循环体没有属于它的缩进行,所以不会做任何事。(加入该行的原因是)

如果应用程序的 cog 停止,被设置为输出的 I/O 引脚会恢复为输入状态,这会产生一

些奇怪的现象。这些现象是由于连接在有些电阻对之间的电阻造成的。如果你使用的

不是 Propeller 演示板,那么 Main方法就不需要第一行和 后一行语句。

NextObject 方法 代码中我们有 6 个 LED 对象,它们全部可以并行运行。NextObject 方法在于能指

出哪个对象是可用的,如果没有发现,它会阻止程序进一步运行,直到发现一个可用

的对象。要做到这一点,就需要扫描所有的六个 LED 对象来寻找第一个没有运行在并

行状态下的对象,并返回该对象的 LED 索引值。如果所有的对象现在都在运行,它会

一直扫描,直到有一个对象可用。 NextObject 使用的是我们 Output 对象中的 Active 方法来达到该目的。

程序中有两个嵌套 REPEAT 循环。外层循环,repeat..while Index == MAXLEDS 会迭

代的次数由 Index 次,Index 等于 MAXLEDS,在这里是 6。我们已经再上一个练习中学习

过这种类型的 REPEAT 是如何工作的。

Page 128: Propeller Manual - Parallax Home

Propeller编程指导

Page 128 · Propeller Manual v1.0

内层 REPEAT 循环,repeat Index from 0 to MAXLEDS-1,是我们要学的新东西。它称

作“计数循环”,会重复执行属于它的缩进块语句,但是每次迭代他都会将变量 Index 设置为一个新的值。第一次迭代时 Index 被设置为 0,第二次是 1 等等,直到 后一次

迭代时 Index 等于 MAXLEDS-1,或 5。这是一种根据已经执行过的迭代的次数来调整循

环内的操作的很好的方法。

下一行,if not LED[Index].Active,是一个条件语句,如果被标示为 Index 的 LED对象是“不活动”的,那么就执行属于该语句的缩进代码块。因为内层循环会在执行

时改变 Index 的值(从 0 到 5),该语句会按顺序调用每个 LED 对象的地 Active 方法。

如果条件为真(索引值为 Index 的 LED 对象是不活动的),会执行下一行,quit。

QUIT 命令是专用于 REPEAT 的命令;它会将它所在的 REPEAT 循环立刻中止。当执行到

此时,程序退出外层 REPEAT 循环,执行“while”条件。

如果所有的 LED 对象是都活动的,内层循环会计数,Index 从 0 到 5,然后在退出

时 Index 会变成 6(MAXLEDS),这会使外层循环再次开始迭代整个过程。如果发现了

一个不活动的 LED 对象,Index 的值会小于 MAXLEDS,外层循环会终止,NextObject 会返

回可用的对象的 Index。该值将被 Main 方法用于选择要启动的 LED 对象。

幕后真相 在对象块中,我们创建了一个有六个元素的数组。应用程序使用的每个对象都要保

持其独立性,其关键数据要和其他对象相分离。所以,如果我们需要 6 个 Output 对

象,我们就要在对象块中声明它们。

编译完 Blinker2 后,Object View 显示了 Output 对象在我们的应用程序出现了六

次;“[6]”出现在 Output 对象图像的右侧。这是对象视图显示我们的应用程序的结构

的方法。如图 3-16。

Page 129: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 129

图 3-16: Blinker2 应用程序 这里有六个 Output 对象的实例。所以应用程序实际上一份可执行代码的拷贝,但是有六个全局变量空间的副本。

这是否意味着我们的应用程序会增大六倍?幸运的是,答案是 否。Propeller 工具

会优化这类程序的代码,一个对象的每一次出现都只是源代码的副本,但是会创建该

对象全局变量的多个副本。这是因为代码本身是被看作静态的(不变的),每个对象

都一样。但是代码的全局变量(在代码的 VAR 块中定义)不是静态的;为了能独立工

作,彼此互不影响实例,每个对象都需要独立的变量空间。

对象信息窗口 我们可以使用 Propeller 工具的对象信息窗口来看到这一特性。首先,修改 Blinker2

的对象块,只使用一个 Output 对象的实例;LED[1] : "Output"。现在不要运行代码,

我们只是实验。

现在,按下 F8 键(或者选择 Run → Compile Current → View Info…)将应用程序

编译并显示对象信息窗口。如图 3-17 所示对象信息窗口的外观:

Page 130: Propeller Manual - Parallax Home

Propeller编程指导

Page 130 · Propeller Manual v1.0

图 3-17: Blinker2 应用程序的对

象信息窗口(Object Info Window)

窗口的顶部是对象视图信息;类似于对象视图。窗口的中间部分是应用程序的

RAM 使用状况。请注意,“Program(程序,编译过的源代码)”自身会占用 68 个长

字型 RAM 空间,“Variable(变量,全局变量)”会占用 10 个长字型的空间。

现在,关闭该窗口,将对象块改为以前的样子,指定六个 Output 的实例; LED[6] : "Output"。编译并在此查看信息(F8 或 Run → Compile Current → View Info…)。注

意这次 Program 占用了 73 个长字型的 RAM 空间,Variable 占用 60 个长字型空间。 Program 空间只增加了 5 个长字型空间,但是 Variable 空间占用却多了 50 个长字型空

Page 131: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 131

间。这里,额外的 Program 空间是 5 个新增对象的开销,而 Variable 空间却是之前的 6倍大小。我们的 Blinker2 对象没有定义任何全局变量孔家,但是 Output 定义了 9 个长

字型的空间用于 Stack,和一个 Cog 要使用的字节,总共是 10 个长字型空间,因为对

象的变量空间总是长字型对齐的。

在对象信息窗口中,也可以点击 Output 对象来查看对象的每个实例占用的空间。

可以看到 Output 的程序大小是 21 长字型空间和 variable 是 10 个长字型空间。

对象的生命周期 当对象被编译时,会建立一份可执行代码的二进制映像。这份二进制映像是实际下

载到 Propeller 中,也就是我们所说的“应用程序”或“Propeller 应用程序”的东西。

应用程序所使用的每个对象的被编译的代码,和每个对象实例的变量空间一起,被集

成在该二进制映像中。

在运行时,应用程序可以在任何时间使用任何对象,有些对象可能会很常用而另一

些较少被使用,但它们都会占用固定量的内存用于存储变量和代码。

对于习惯了使用计算机进行对象程序设计的程序员,这是很重要的概念。在

Propeller 中,一个对象的生命周期是固定的;不论该对象是否处于活动状态,它总会

在应用程序的二进制映像中占用一定量的空间。在桌面/膝上计算机中,对象需要的是

动态内存,因为它们在运行时会被按需要“创建”和“销毁”。在 Propeller 上,对象

在编译时会被“创建”,而永远不会被在运行时被“创建”或“销毁”,因为这样做

会产生内存碎片,在实时嵌入系统中产生不可预测的行为。

这就是说对象的每一个实例,会,或者会,需要在编译时在 OBJ 块中声明,就像在

练习 9 中我们的 Output 对象数组一样。

快速回顾: 练习 8 • 应用程序:

o 每个实例使用唯一的符号,或数组元素。 o 使用一份对象代码,一份或多份全局变量的副本。

• 对象: o 对象数组可以在对象块中建立,就像变量块中的变量数组一样。 o 一个对象的生命周期是静态的,不论活动与否,都占用指定的,固定量

的内存空间。这样做排出了在运行时产生内存碎片的可能性,确保在实

时系统中所有的行为都是可预测的。

Page 132: Propeller Manual - Parallax Home

Propeller编程指导

Page 132 · Propeller Manual v1.0

• Spin 语言: o REPEAT 命令:(参见 299 页 REPEAT)

有限,计数循环:REPEAT Variable FROM Start TO Finish,Variable 是用作计数器的变量,Start 和 Finish 指出了范围。

QUIT 命令用于 REPEAT 循环内部,可以立刻终止循环,参见 291页 QUIT。

o I/O 寄存器 (DIRx, OUTx, and INx) 可以使用 reg[a..b] 的形式作用于多个连

续的引脚; reg 是寄存器(DIRx, OUTx, or INx),a 和 b 是 I/O 引脚数,

参见 212 页 DIRA, DIRB,280 页 OUTA, OUTB,和 225 页 INA, INB。 • I/O 引脚当且仅当有 cog 将其设置为输出时才为输出。参见 212 页 DIRA, DIRB。 • Compile & View Info: F8 键 (或选择 Run → Compile Current → View Info…), 参

见 55 页对象信息。

Page 133: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 133

练习 9: 时钟设定 Propeller 芯片的内部时钟有两个速度,低速 (≈ 20 KHz) 和快速 (≈ 12 MHz)。因为

在之前的程序中我们都没有指定任何时钟设定,所以所有的练习都使用的是 Propeller芯片的默认的,内部 RC 时钟快速模式。

要为应用程序指定时钟设定,顶部对象文件必须在 CON 块中设定一个或多个常量。

这些常量是: _CLKMODE,_CLKFREQ 和 _XINFREQ。

我们先来看_CLKMODE。请参考 180 页上时钟模式设定常量一节中表 4-3,那里列出

了_CLKMODE 可以被设定的预定义符号值。 例如,我们继续修改 Blinker2 对象,按下面

的程序修改 CON 块的内容,将时钟模式设置为内部低速时钟(这里只列出 CON 块)。

Blinker2.spin CON _CLKMODE = RCSLOW '设置为内部低速时钟

MAXLEDS = 6 '要使用的 LED 对象的数量 <剩下的代码不改变>

编译并下载 Blingker2。Propeller 完成下载/启动过程后,它会自动切换到 RCSLOW 时钟模式并执行应用程序。因为应用程序现在的运行时钟比之前的慢几百倍,所以应用

程序运行会慢的多, 快也要超过 20 秒才能触发引脚 P20,然后再关闭引脚。

可以将_CLKMODE = RCSLOW 替换为 _CLKMODE = RCFAST ,使应用程序运行在内部快速

时钟模式下(默认)。

如果要使用外部时钟,就有很多_CLKMODE 可用的选项。我们假定使用的是 5MHz 的外部晶振(就像 Propeller 演示板上的一样)。

Page 134: Propeller Manual - Parallax Home

Propeller编程指导

Page 134 · Propeller Manual v1.0

按下面的内容修改你的代码:

Blinker2.spin CON _CLKMODE = RCSLOW '设置为内部低速时钟

_CLKMODE = XTAL1 '设置为外部低速晶振

_XINFREQ = 5_000_000 'XIN 引脚上的频率为 5MHz

MAXLEDS = 6 '要使用的 LED对象的个数 <剩下的代码不改变>

这里我们将_CLKMODE 设置为 XTAL1,这项设置将始终模式设置为外部低速晶振,同

时将 Propeller 内部晶振增益电路配置为 4MHz 到 16MHz 晶振。除了晶振(连接到 XI和 XO 引脚),在这项时钟配置中不再需要外部电路了。

当使用外部晶振或外部时钟时,除了_CLKMODE,_XINFREQ 或 _CLKFREQ 也必须被指

定。_XINFREQ 指定了输入 XI 引脚的频率值(晶振输入引脚)。_CLKFREQ 指定了系统时

钟频率。这两个值是由 PLL 设定联系在一起的,我们会在稍后讨论 PLL 设定。

在这个例子中,我们指定了_XINFREQ 的值为 5 百万,也就是从 XI 引脚输入的频率

是 5MHz,因为我们将 5MHz 的晶振连接到 XI 和 XO。 一旦指定了该值,_CLKFREQ 的值会自动被计算,并由 Propeller 工具设置。

也可以指定_CLKFREQ 的值为 5 MHz (代替 _XINFREQ),那么正确的_XINFREQ 值也会被

自动计算。但是通常指定_XINFREQ 的值,因为_CLKFREQ 会被 PLL 的设定直接影响。我

们的例子中,_XINFREQ 和 _CLKFREQ,有同样的值,但是后面的例子中会展示它们的不

同。

如果将 Blinker2 编译并下载运行,现在应该可以看到 LED 触发的速度比在练习 8中的速度满了一半。我们的设定中使用的是外部 5MHz 晶振,而不是内部 12MHz 震荡

器。

为什么会有人想要用比内部时钟慢的外部晶振呢?有两个原因:1) 精确;因为芯

片和芯片之间的差异,电压会变化,所以内部时钟不够精确, 2) 锁相环只能和外部时

钟源一起使用。

试试下面的例子:

Page 135: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 135

Blinker2.spin CON _CLKMODE = XTAL1 + PLL4X '设置为外部低速晶振, 4x PLL

_XINFREQ = 5_000_000 'XIN引脚上的频率为 5 MHz

MAXLEDS = 6 '要使用的 LED对象 <剩下的代码不改变>

这里,我们_CLKMODE 设置作了小小的改变,添加了+ PLL4X。它将时钟模式配置为

使用内部锁相环(PLL)to wind up the XIN frequency by four times, resulting in a System Clock frequency of 5 MHz * 4 = 20 MHz.

试着将此配置的 Blinker2 编译并下载。你应该看到 LED 会比以前闪烁的快得多。

NOTE: 因为我们在这里指定了_XINFREQ,所以_CLKFREQ 会被自动计算为 20 MHz。如果我们指定的是_CLKFREQ 等于 5 MHz,_XINFREQ 会被计算为 1.25 MHz,该值不能匹

配我们的外部晶振频率。也就是为什么通常都指定 XIN 频率(_XINFREQ)而不是指定

时钟频率(_CLKFREQ)的原因。

时钟 PLL 电路被启用时,总是将频率提升 16 倍,但是也可以选择 1x,2x,…16x 来指定 终的系统时钟频率,方法是使用 PLL1X,PLL2X,PLL4X,PLL8X 和 PLL16X。

试试将 _CLKMODE 从 XTAL1 + PLL4x 改为 XTAL1 + PLL16x,并再次下载。这次会将系统时

钟配置为 5 MHz * 16 = 80 MHz! 大多数的 LED 会快速闪烁,速度之快就像它们一直亮

着一样。

练习 10: 时钟相关的时序 上一个练习可能已经让你注意到一些事情:我们的 Output 对象会受到时钟频率的

影响。它依赖于指定的,硬件编码的时钟,而子对象则不是,因为子对象不能预测使

用它的应用程序的时钟设定是怎样的。此外,Propeller 应用程序在运行时可以多次改

变系统时钟频率设定。

如果我们想要使 Output 对象以固定的频率触发引脚,而与时钟无关。就是说必须

能够动态响应系统时钟频率。下面是修改后的代码;请修改您的代码时确保与之相

同。

Page 136: Propeller Manual - Parallax Home

Propeller编程指导

Page 136 · Propeller Manual v1.0

例子对象: Output.spin

Output.spin VAR long Stack[9] '新 cog的堆栈空间

byte Cog '保存在使用的 cog的 ID PUB Start(Pin, DelayMS, Count): Success 在新的 cog上启动新的闪烁程序;如果成功返回 True Stop Success := (Cog := cognew(Toggle(Pin, DelayMS, Count), @Stack) + 1) PUB Stop 停止触发程序 if Cog cogstop(Cog~ - 1) PUB Active: YesNo 如果程序是活动的,返回 TRUE,否则返回 FALSE YesNo := Cog > 0 PUB Toggle(Pin, DelayMS, Count) 触发引脚, Count 次,间隔 DelayMS milliseconds 时钟周期

如果 Count = 0, 则无限次触发. dira[Pin]~~ '将 I/O 引脚设置为输出… repeat '重复执行下面的内容

!outa[Pin] ' 触发 I/O引脚

waitcnt(clkfreq / 1000 * DelayMS + cnt) ' 等待 DelayMS…

Page 137: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 137

while Count := --Count #> -1 '当不等于 0时(make min… Cog~ '清除 Cog ID变量

我们通过将参数 Delay改为 DelayMS,修改了 Start 和 Toggle 方法,DelayMS的意思

是“以毫秒为单位延迟”。然后我们修改了 waitcnt… 表达,它取消了以前程序中

等待固定个数的时钟周期,而代之以计算在 DelayMS 个毫秒的时间内有多少个时钟周

期。CLKFREQ 命令会以赫兹为单位返回当前系统时钟频率。它的值在编译时由 Propeller工具设定,或者在运行时由 CLKSET 命令设置(183 页)。每秒钟有 1000 毫秒,CLKFREQ 是每秒时钟周期的个数,所以 clkfreq / 1000 * DelayMS 就是 DelayMS 个毫秒的时间内

时钟周期的个数。

这样,无论应用程序的启动频率是多少,或者应用程序在运行时修改频率,Output对象都会重新计算循环内正确的延迟。

现在,当然,我们需要修改我们的 Blinker2 对象来调整 DelayMS 参数。请按照

136 页的内容输入代码。请注意,我们输入的_CLKMODE 和 _XINFREQ 设定和之前练习中

的一样。

Page 138: Propeller Manual - Parallax Home

Propeller编程指导

Page 138 · Propeller Manual v1.0

例子对象: Blinker2.spin

Blinker2.spin CON _CLKMODE = XTAL1 + PLL4X '设置为外部低速晶振, 4x PLL

_XINFREQ = 5_000_000 'XIN 引脚上的频率为 5 MHz

MAXLEDS = 6 '要使用的 LED对象个数 OBJ LED[6] : "Output" PUB Main 同时以不同的速率触发引脚 dira[16..23]~~ '将引脚设置为输出 LED[NextObject].Start(16, 250, 0) 'Blink LEDs LED[NextObject].Start(17, 500, 0) LED[NextObject].Start(18, 50, 300) LED[NextObject].Start(19, 500, 40) LED[NextObject].Start(20, 29, 300) LED[NextObject].Start(21, 104, 250) LED[NextObject].Start(22, 63, 200) '<-延迟

LED[NextObject].Start(23, 33, 160) '<-延迟

LED[0].Start(20, 1000, 0) '重新启动对象 0

repeat '无限循环 PUB NextObject : Index 扫描 LED对象,返回下一个可用的 LED对象的索引值。

扫描持续到发现可用的 LED对象为止 repeat repeat Index from 0 to MAXLEDS-1 if not LED[Index].Active quit

Page 139: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 139

while Index == MAXLEDS

在 Main 方法中,我们调整了对 Start 调用的第二个参数,将“delay in clock cycles(以时钟周期延迟)”改成了“delay in milliseconds(以毫秒延迟)”。编译并下载

Blinker2 对象。注意,现在每个 LED 的闪烁速度和我们使用内部快速时钟时一样了。

试着增加时钟速度,修改_CLKMODE,将 XTAL1 + PLL4X 改为 XTAL1 + PLL16X。你应该看

不到任何闪烁速率的变化,即时我们将时钟频率增大了四倍!

要记住内部时钟的精确在你的 Propeller 芯片中可能很重要,就象上面的例子一

样,特别是在使用 RCSLOW 模式时尤其如此。

虽然有两种方法使用 WAITCNT 命令,但是我们只演示了一种。更多关于时序的提

示,参见 322 页 WAITCNT 命令。

快速回顾: 练习 9 & 10 • 时钟:

o 内部时钟有两个速度,低速 (≈ 20 KHz) 和快速 (≈ 12 MHz)。 o 要指定应用程序的时钟设定,顶部对象文件必须设定一个或多个特殊常

量:_CLKMODE, _CLKFREQ 和 _XINFREQ。 o 当使用外部晶振时,除了设定 _CLKMODE 同时必须设定_XINFREQ 或

_CLKFREQ 。 o _CLKMODE 指定了时钟模式:内部/外部,振荡器增益,PLL 设定等。参

见 180 页_CLKMODE。 o _XINFREQ 指定了输入 XI 引脚的频率(晶振输入)。参见 337 页

_XINFREQ。 o _CLKFREQ 指定了系统时钟频率。参见 177 页_CLKFREQ。 o 当时钟精确性不太重要时,使用内部时钟。如果需要使用精确的时钟,

可以使用锁相环或外部时钟。 o

• 时序: o 子对象不会依赖指定的,硬件编码的时钟,因为应用程序可能会改变时

钟频率。 o 使用 CLKFREQ 命令取得当前系统时钟频率,单位是 Hertz(赫兹)。参

见 175 页 CLKFREQ。

Page 140: Propeller Manual - Parallax Home

Propeller编程指导

Page 140 · Propeller Manual v1.0

练习 11: 库对象 Propeller 工具带有一个对象库,这些对象是由 Parallax 的工程师创建的。它们可以

执行一些有用的功能,如串行通信,浮点数学运算,数字-字符串和字符串-数字的转

换,以及 TV 显示发生,使用标准 PC 的键盘,鼠标和监视器等。

Propeller 的对象库其实是一个包含了 Propeller 对象文件的文件夹,它会在 Propeller工具安装时自动创建。您可以从 近使用的文件夹列表中选择“Propeller Library”来

打开 Propeller 库文件夹;参见图 3-18。选择 Propeller 库后,文件列表会显示所有的对

象。

图 3-18: 浏览 Propeller 库 从集成浏览器的 近使用文件夹列表中选择“Propeller Library”可以快速浏览库文件夹。

现在我们来使用其中一些对象。建立一个新文件,输入下面的代码。高亮的内容对

接下来要讨论的内容是很重要的。

Page 141: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 141

例子对象: Display.spin

Display.spin CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 OBJ Num : "Numbers" TV : "TV_Terminal" PUB Main | Temp Num.Init '初始化 Numbers

TV.Start(12) '启动 TV 终端 Temp := 900 * 45 + 401 '计算表达式

TV.Str(string("900 * 45 + 401 = ")) '然后显示结果

TV.Str(Num.ToStr(Temp, Num#DDEC)) '结果分别以十进制 TV.Out(13) TV.Str(string("In hexadecimal it's = ")) '和十六进制显示 TV.Str(Num.ToStr(Temp, Num#IHEX)) TV.Out(13) TV.Out(13) TV.Str(string("Counting by fives:")) 'Now count by fives TV.Out(13) repeat Temp from 5 to 30 step 5 TV.Str(Num.ToStr(Temp, Num#DEC)) if Temp < 30 TV.Out(",")

将该对象在您所选择的文件夹中保存为“Display.spin” ;在这个例子中我们选择文

件夹:“C:\Source\”。

本例中,我们使用了两个 Propeller 库对象,Numbers 和 TV_Terminal,将数字转换

为字符串并显示在 TV 上。将该例子编译并下载到 Propeller 演示板上,将演示板和 TV

Page 142: Propeller Manual - Parallax Home

Propeller编程指导

Page 142 · Propeller Manual v1.0

(NTSC)显示器连接,选择合成输出 (RCA jack) 模式,TV 显示器上应该显示下面的

文本:

Page 143: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 143

900 * 45 + 401 = 40,901 In hexadecimal it's = $9FC5 Counting by fives: 5, 10, 15, 20, 25, 30

看看我们做了什么!只要几行自己的代码加上现有的库对象和 3 个电阻(在

Propeller 演示板上),我们就将数字值转换为文本字符串,并产生了 TV 兼容的信

号,在标准的 TV 上显示了该字符串,实际上当您在阅读本文的时候,Cog 正在忙于

保持 NTSC 信号稳定在每秒 60 帧,也就是 TV 可以锁定的频率。

TV_Terminal 对象提供了调试用的显示能力。因为 Propeller 有多个处理器,而且可

以快速运行,使用一台能实时显示的设备,例如 TV(CRT 或 LCD)就可以用于调

试。 我们推荐使用该技术和普通调试方法来缩短开发时间。

现在我们来看看代码中的重要部分。第一项新内容是出现在 Main 的声明中的

| Temp。不要被它所欺骗,它看起来像是返回值变量声明,但其实不是。管道符“|”的意思是接下来我们将声明本地变量。所以| Temp 为 Main 方法声明了一个长字型的本

地变量 Temp。

接下来是两条很重要的语句,Num.Init 和 TV.Start(12)。 这两条语句分别初始化了

Numbers 对象和启动了 TV_Terminal 对象(在第 12,13 和 14 引脚上)。这里的每一

个对象在使用前都需要一定的初始化过程。Numbers 需要调用它的 Init 方法来初始化

内部寄存器。TV_Terminal 需要调用它的 Start 方法来配置合适的引脚并启动另外两个

cog 来产生视频信号。通常,对象会在它的文档中指出这些需求,一般情况下如果在

使用前需要初始化,那么对象都会包含一个 Init 或 Start 方法(来完成初始化)。

下一行执行了一些计算,并将本地变量,Temp,赋值。我们会在稍后使用这个值。

下面的三行语句建立了要显示的第一行内容:9 * 45 + 401 = 40,901。 TV.Str 方法输出了一个以 0 结尾的字符串,这个字符串将被显示在显示器上。它的参数, string("900 * 45 + 401 = ") 对我们来说是全新的内容。STRING 是一条用于创建以零结

尾的字符串(多个字节的字符和一个零字节组成,有时也称作 z-string)的指令,它会

返回字符串的地址。大多数处理字符串的函数和方法在工作时,都需要字符串的起始

地址和一个等于 0 的字节作为字符串的终止符。TV.Str 方法的参数就需要该字符串的

地址。所以 TV.Str(string("900 * 45 + 401 = ")) 会让字符串“900 * 45 + 401 = ”显

示在 TV 上。

Page 144: Propeller Manual - Parallax Home

Propeller编程指导

Page 144 · Propeller Manual v1.0

下一条语句, TV.Str(Num.ToStr(Temp, Num#DDEC)) 会在屏幕上显示“40,901”。

Num.ToStr 方法将存储在 Temp 中的数字值转换为一个字符串,转换时使用了被划分的

十进制数格式(以逗号划分)并返回该字符串的地址。Temp 保存了我们之前的表达式

的长字型结果:40901。Num#DDEC 也是新内容。 井号 # 用于对象常量引用;也就是引用

其它对象定义的常量。在这里, Num#DDEC 引用了在 Numbers 对象中声明的“格式常量

(Format Constant)”:DDEC。DDEC 在 Numbers 中定义,用于划分十进制数值,并向

ToStr 方法标示应该使用将数值格式化为使用千位定界符(这个例子中是逗号)分隔的

格式。所以,ToStr 创建了一个等于“40901”的 z-string,并返回它的地址。TV.Str 随后将该字符串送到显示器输出。更多信息请阅读关于 Numbers 对象中的文档。

TV.Out(13) 输出信号字节,13,给显示器。13 是 ASCII 编码中的回车码(Carriage Return,不可显示),它会使 TV_Terminal 对象移动到下一行。为下一行要输出的内

容做准备。

工作文件夹和库文件夹 在 Display 对象被编译时,对象视图会显示对象的结构。途中显示出我们的 Display

对象使用了 Numbers 和 TV_Terminal 对象,TV_Termianl 对象使用了 TV 和 Graphics 对象。

图 3-19: Display 应用程序的对

象视图 黄色文件夹指出了对象所在的“工作”文件夹。蓝色文件夹指出了对象的“库”文件夹。

每个对象前的文件夹图标都有不同的颜色,这些颜色标示出了对象的独立文件夹。

有黄色文件夹的对象是在“工作”文件夹中,而标示有蓝色文件夹的对象是在“库”

文件夹中。从中我们可以看到 Propeller 工具发现了 Number,TV_Termianl,TV 和

Graphics 四个对象都在库文件夹中。

记得我们曾将 Display 对象存储在文件夹 C:\Source 中么?在一个应用程序编译

时,存储顶部对象文件的文件夹会成为工作文件夹。如果有引用到其他对象的文件,

Page 145: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 145

Propeller 工具会首先查找工作文件夹。如果被引用的文件夹不在工作文件夹中,接下

来会查找库文件夹。如果在库文件夹中的对象引用到另一个对象,会在库文件夹中寻

找该对象。如果在上述两个文件夹中都没有找到所引用的对象,会产生一个错误。

由于这一特性,可以说每个应用程序都是由来自两个文件夹的文件组成;工作文件

夹和/或库对象文件夹。在建立您自己的应用程序的时候请记住这一点。

您可以在对象视图中将鼠标指向每个对象,Propeller 工具会提示每个对象所在文件

夹,工作文件夹,以及库文件夹。下图中,我们可以看到 Display 在文件夹 C:\Source (工作文件夹)中,Numbers 在文件夹 C:\Program Files\Parallax Inc\Propeller Tool (库文件

夹)中。

图 3-20: Display 应用程序的对

象视图提示 可以在提示消息中看到工作和库文件夹路径

Page 146: Propeller Manual - Parallax Home

Propeller编程指导

Page 146 · Propeller Manual v1.0

练习 12: 整数和实数 Propeller 是 32 位设备,可以处理在常量和运行时数学表达式中将整数作为有符号

整数处理 (-2,147,483,648 到 2,147,483,647)。对实数(有整数和小数部分),编译器支

持常量浮点格式(单精度,兼容 IEEE-754),以及有支持运行时浮点数学运算的库对

象。

伪实数 要处理实数,有很多可用的技术。其中之一是将将表达式中的实数调整为整数,按

整数的方式计算。我们称之为 pseudo-real numbers(伪实数)。

Propeller 内建了 32 位整数,这为计算提供了很大的空间。例如,我们有一个执行

有两位小数的乘除运算的等式,如下:

A = B * C / D

在我们的例子中, A = 7.6 * 38.75 / 12.5 计算结果是 23.56。

要在运行时计算这一结果,我们可以将等式中的值调整 2 位(小数点移动两位),

将它们变为整数,然后进行数学计算,将计算结果的 右边两位作为小数部分处理。

只要将每个值乘 100 就可以了。下面是代数证明:

A = (B* 100) * (C * 100) / (D * 100)

A = (7.6 * 100) * (38.75 * 100) / (12.5 * 100)

A = 760 * 3875 / 1250

A = 2356

因为我们把原有的值乘了 100,所以 终的结果应该是 2356 / 100 = 23.56,但是大

多数情况下,我们可以将其保留为整数,只要知道该数值的 右侧两位应该是小数部

分就可以了。

上面的解决方法在原有数值不超过有符号整数范围: -2,147,483,648 到 2,147,483,647 都有效。

接下来的例子中同时使用了伪实数(pseudo-real number) 和浮点数技术。

Page 147: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 147

浮点数 很多时候,包含了实数的表达式可以不使用浮点值和方法,例如伪实数技术,来处理。

因为这种技术执行速度更快,占用较少的内存,所以在真正应用浮点数之前,推荐你

要认真思考是否真的需要支持浮点数。如果有足够的时间和内存能,支持浮点数因该

是 好的选择。

Propeller 工具直接支持浮点常量。Propeller 芯片可以使用一些对象来提供对浮点运

行时表达式的支持;也就是说在运行时,Spin 语言解释器只能直接支持整型表达式。

下面的例子中,RealNumber.Spin,演示了使用将被转换为伪实数(Pseudo-real number)的整型常量(iB, iC, 和 iD)和 浮点常量(B, C, 和 D)

下一个例子对象,RealNumbers.spin,演示了使用已经预先转换为伪实数的整型常

量(iB, iC, 和 iD) ,以及浮点常量(B, C, 和 D),它们以 Native 形式被 FloatMath 和FloatString 库对象使用,以及在编译时转换为伪实数的浮点常量。

Page 148: Propeller Manual - Parallax Home

Propeller编程指导

Page 148 · Propeller Manual v1.0

例子对象: RealNumbers.spin

RealNumbers.spin CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 iB = 760 '整型常量 iC = 3875 iD = 1250 B = 7.6 '浮点常量 C = 38.75 D = 12.5 K = 100.0 '实数到伪实数的计算倍数 OBJ Term : "TV_Terminal" F : "FloatMath" FS : "FloatString" PUB Math Term.Start(12) 整型常量(real numbers * 100)做快速整型数学计算 Term.Str(string("Pseudo-Real Number Result:")) Term.Dec(iB*iC/iD) 浮点常量使用 FloatMath和 FloatString 对象 Term.Out(13) Term.Str(string("Floating-Point Number Result:")) Term.Str(FS.FloatToString(F.FDiv(F.FMul(B, C), D))) 浮点常量被转换为伪实数进行快速计算 Term.Out(13) Term.Str(string("Another Pseudo-Real Number Result:")) Term.Dec(trunc(B*K)*trunc(C*K)/trunc(D*K))

Page 149: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 149

编译并下载 RealNumbers.spin。它会在 TV 上显示下面的内容:

Pseudo-Real Number Result:2356 Floating-Point Number Result:23.56 Another Pseudo-Real Number Result:2356

Pseudo-real 结果代表了数值 23.56,但是为了和整数兼容,小数点右移了 2 位。使

用一些额外的代码,我们就可以显示 23.56。

常量 iB, iC, 和 iD 是我们以前使用的标准整型常量,但在我们的例子中,它们的值

是伪实数形式表达的。

常量 B, C, D, 和 K, 是浮点常量(实数)。编译器会自动识别它们,并将其存储为 32位单精度浮点格式。它们可以被直接用于其他编译时浮点表达式,但是在运行时,它

们只能被用在处理浮点值的方法中,比如在 FloatMath 和 FloatString 对象中的方法。

语句 Term.Dec(iB*iC/iD) 使用了预转换(pre-translated)伪实数常量,就像上面提

到的伪实数技术。该计算比浮点计算快 1.6 倍,并且占用较少的代码空间。

语句 Term.Str(FS.FloatToString(F.FDiv(F.FMul(B, C), D))) 调用了 FloatMath 的

FMul 方法来对浮点值 B 和 C做乘运算,然后调用 FloatMath 的 FDiv 方法将前面的计算

结果除以浮点值 D,之后使用 FloatString 的 FloatToString 方法将结果转换成字符串,

后显示在 TV 上。

语句 Term.Dec(trunc(B*K)*trunc(C*K)/trunc(D*K)) 在 TRUNC 内部使用了编译时表达

式,将浮点常量 B, C, 和 D 的小数点移动两位,将值截为整数。计算的结果等于第一个

伪实数 等式 Term.Dec(iB*iC/iD) 的值,但好处是能将值表示为浮点形式。

指令 TRUNC 在编译时将全解析的浮点数截去小数位形成整数形式。在这里必须这样

做,是因为在运行时表达式中不能直接使用浮点常量。

Page 150: Propeller Manual - Parallax Home

Propeller编程指导

Page 150 · Propeller Manual v1.0

上下文敏感的编译信息 一个对象编译后,Propeller 工具会在状态栏(第五格)显示上下文敏感,也就是离

光标 近的源代码项目,的编译信息,这对了解和验证对象中声明中的常量值非常有

帮助。例如,按 F9 编译该例子(或选择 Run → Compile Current → Update Status menu 菜单选项),然后将光标移动到 CON 块的常量 iB 位置处。状态栏会临时性的加亮所显

示的信息,它看齐来应该是下面的样子:

图 3-21: 带有编译信息的状态栏 编译完成后,状态栏的第五格会显示离光标近的源代码的信息。

它告诉我们常量 iB 在 CON 块内被定义为十进制值 760,或十六进制值$2F8。

将光标移动到常量 B 上。现在编译信息应该变成了“CON B = 7.6 ($40F3_3333) Floating Point”,意思是这是一个浮点形式的实数,等于十进制值 7.6(十六进制值

$40F3-3333)。这表明浮点数为了和整数形式保持兼容,会被编码为 32 位。

除了在 CON 和 DAT 块中声明的符号,编译信息也会显示光标所在的 PUB/PRI/DAT 块的

字节大小。在我们的例子中,Math 方法是 196 字节长。这在我们优化代码长度时是很

有用的特性;修改代码,按 F9 编译,检查代码长度,再修改等等。

Page 151: Propeller Manual - Parallax Home

3: Propeller 编程指导

Propeller Manual v1.0 · Page 151

快速回顾: 练习 11 & 12 • Propeller 库:

o 是一个由 Propeller 工具安装程序自动创建的文件夹。 o 包含 Parallax 提供的一些有用的 Propeller 对象。 o 在 近使用文件夹中的“Propeller Library” 项,可以提供快速访问。

• Spin 语言: o 方法声明中的管道符(pipe symbol ‘|’)为方法声明了一个本地变量列

表;参见 289 页参数和本地变量。 o STRING 指令创建了一个以零结尾的字符串,并返回其地址;参见 310

页 STRING。 o # 形成一个对对象常量的引用,用于访问在其它对象中定义的常量;

参见 199 页 常量作用域。 o TRUNC 指令将浮点常量的小数部分截去,形成整数;参见 314 页

TRUNC。 • 工作和库文件夹:

o 对象视图的文件夹图标指出了对象的位置。 黄色文件夹的对象是“工作文件夹”。 蓝色文件夹是“库文件夹”。

o 每个应用程序都是由来自两文件夹中的文件组成的;工作文件夹 和/或 库文件夹。

• 整数和实数:(参见 194 页 CON,或 249 页运算符) o 在常量和运行时表达式中直接支持整数。 o 在常量中以浮点形式直接支持实数,但是在运行时以间接方式通过特殊

的库对象提供支持。 o 在许多情况下,包含了实数的表达式可以不使用浮点值而被解算。

• 状态条显示了 靠近光标的源代码的编译信息。包括 CON/DAT 块符号的大小/地址,以及 PUB/PRI/DAT 块的大小。

Where to go from here... 您现在已经有能力自己探索 Propeller 芯片和开发您自己的第一个应用程序了。使

用本手册的剩下部分作为 Spin 语言和 Propeller 汇编语言的参考,探索每一个能引起您

兴趣的库对象,加入 Propeller 论来保持和其它 Propeller 芯片使用者相互学习和共享。

Page 152: Propeller Manual - Parallax Home

Propeller编程指导

Page 152 · Propeller Manual v1.0

Page 153: Propeller Manual - Parallax Home

4: Spin语言参考

Propeller Manual v1.0 · Page 153

Chapter 4: Spin 语言参考 本章描述了 Propeller 芯片 Spin 语言的所有元素及其 佳使用的参考。作为 Spin 语

言的一般指导,请先阅读第三章:Propeller 编程指导,然后再返回到本章参考更多的

细节。.

Spin 语言参考被分成三节:

1) Propeller 对象的结构。 Propeller 对象包含了 Spin 代码,可选的汇编代码和数

据。一个对象的 Spin 代码提供了其结构,由特殊用途的块组成。该节列出了这

些可能被用到的块和元素。每个被列出的元素都有一页包含更多信息的参考

页。

2) Propeller Spin 语言列表。 所有的元素,包括运算符和语法符号,都按相关功

能分组。这种方法可以使使用者快速认识语言的分支和哪些特性可以被用于特

殊用途。每个列出的元素都有一页包含更多信息的参考页。有些元素被标记了

“a”的上标,这表明这些元素也可以用在 Propeller 汇编语言中,但是语法可

能会发生变化。这些标记过的元素也包含在第五章:汇编语言参考中。

3) Spin 语言元素。 大多数元素都有其子结构,为了方便查找,都按字母顺序排

列。没有子结构的元素,比如运算符,符号和一些常量等,都以相关子节的形

式分组,但是仍然可通过 Spin 语言列表方便的查找。

Page 154: Propeller Manual - Parallax Home

Spin语言参考

Page 154 · Propeller Manual v1.0

Propeller 对象的结构 每个 Propeller 对象都有其内在结构,该结构由 6 种不同目的的块组成:CON, VAR,

OBJ, PUB, PRI, 和 DAT。这些块列出如下(以他们在对象中出现的顺序) ,以及其可用的元

素集。

欲了解对象结构和用法的更详细信息,请参考 85 页 Chapter 3: Propeller 编程指

导。

CON: 常量块,定义了全局常量 ( 199 页). _CLKFREQ p 182 NEGX p 207 PLL16X p 185 XINPUT p 185 _CLKMODE p 185 Operators* p 255 POSX p 207 XTAL1 p 185 _FREE p 223 PI p 207 RCFAST p 185 XTAL2 p 185 _STACK p 313 PLL1X p 185 RCSLOW p 185 XTAL3 p 185 _XINFREQ p 344 PLL2X p 185 ROUND p 309 FALSE p 207 PLL4X p 185 TRUE p 207 FLOAT p 221 PLL8X p 185 TRUNC p 320

*仅限于非赋值运算符 VAR: 变量块,定义了全局变量 ( 321 页). BYTE p 169 LONG p 242 ROUND p 309 TRUNC p 320 FLOAT p 221 Operators* p 255 WORD p 338

*仅限于非赋值运算符 OBJ: 对象块,定义了参考对象 ( 253 页). FLOAT p 221 Operators* p 255 ROUND p 309 TRUNC p 320

*仅限于非赋值运算符

Page 155: Propeller Manual - Parallax Home

4: Spin语言参考

Propeller Manual v1.0 · Page 155

PUB/PRI: 公共和私有方法块,定义了 Spin 程序 ( 293/292 页). ABORT p 165 FLOAT p 221 Operators p 255 ROUND p 309 BYTE p 169 FRQA p 224 OUTA p 286 SPR p 311 BYTEFILL p 174 FRQB p 224 OUTB p 286 STRCOMP p 314 BYTEMOVE p 175 IF p 225 PAR p 289 STRING p 316 CASE p 176 IFNOT p 231 PHSA p 291 STRSIZE p 317 CHIPVER p 179 INA p 231 PHSB p 291 TRUE p 207 CLKFREQ p 180 INB p 231 PI p 207 TRUNC p 320 CLKMODE p 184 LOCKCLR p 234 PLL1X p 185 VCFG p 324 CLKSET p 188 LOCKNEW p 236 PLL2X p 185 VSCL p 327 CNT p 189 LOCKRET p 239 PLL4X p 185 WAITCNT p 329 COGID p 191 LOCKSET p 240 PLL8X p 185 WAITPEQ p 333 COGINIT p 192 LONG p 242 PLL16X p 185 WAITPNE p 335 COGNEW p 194 LONGFILL p 246 POSX p 207 WAITVID p 336 COGSTOP p 198 LONGMOVE p 247 QUIT p 297 WORD p 338 CONSTANT p 205 LOOKDOWN p 248 RCFAST p 185 WORDFILL p 342 CTRA p 209 LOOKDOWNZ p 248 RCSLOW p 185 WORDMOVE p 343 CTRB p 209 LOOKUP p 250 REBOOT p 298 XINPUT p 185 DIRA p 217 LOOKUPZ p 250 REPEAT p 299 XTAL1 p 185 DIRB p 217 NEGX p 207 RESULT p 305 XTAL2 p 185 FALSE p 207 NEXT p 252 RETURN p 307 XTAL3 p 185

DAT: 数据块,定义了数据和 Propeller 汇编代码 ( 213 页).

Assembly p 347 FRQB p 224 PI p 207 TRUNC p 320 BYTE p 169 INA p 231 PLL1X p 185 VCFG p 324 CNT p 189 INB p 231 PLL2X p 185 VSCL p 327 CTRA p 209 LONG p 242 PLL4X p 185 WORD p 338 CTRB p 209 NEGX p 207 PLL8X p 185 XINPUT p 185 DIRA p 217 Operators* p 255 PLL16X p 185 XTAL1 p 185 DIRB p 217 OUTA p 286 POSX p 207 XTAL2 p 185 FALSE p 207 OUTB p 286 RCFAST p 185 XTAL3 p 185 FILE p 220 PAR p 289 RCSLOW p 185 FLOAT p 221 PHSA p 291 ROUND p 309 FRQA p 224 PHSB p 291 TRUE p 207 * 仅限于非赋值运算符

Page 156: Propeller Manual - Parallax Home

Spin语言参考

Page 156 · Propeller Manual v1.0

Propeller Spin 语言列表 标记有“a”上标的元素也可用于 Propeller 汇编语言。

块标识符 CON 声明常量块; p 199. VAR 声明变量块; p 321. OBJ 声明对象参考块; p 253. PUB 声明公共方法块; p 293. PRI 声明私有方法块; p 292. DAT 声明数据块; p 213.

配置 CHIPVER Propeller 芯片版本号; p 179. CLKMODE 当前时钟模式设置; p 184. _CLKMODE 应用定义的时钟模式(只读); p 185. CLKFREQ 当前时钟频率; p 180. _CLKFREQ 应用定义的时钟频率(只读); p 182. CLKSETa 设置时钟模式和时钟频率; p 188. _XINFREQ 应用定义的外部时钟频率(只读); p 344. _STACK 应用定义的保留堆栈空间 (只读); p 313. _FREE 应用定义的自由堆栈空间(只读); p 223. RCFAST _CLKMODE 常量: 内部快速振荡器; p 185. RCSLOW _CLKMODE 常量: 内部低速振荡器; p 185. XINPUT _CLKMODE 常量: 外部时钟/振荡器(XI 引脚); p 185. XTAL1 _CLKMODE 常量: 外部低速晶振; p 185. XTAL2 _CLKMODE 常量: 外部中速晶振; p 185. XTAL3 _CLKMODE 常量: 外部快速晶振; p 185. PLL1X _CLKMODE 常量: 1 倍外部频率; p 185.

Page 157: Propeller Manual - Parallax Home

4: Spin语言参考

Propeller Manual v1.0 · Page 157

PLL2X _CLKMODE 常量: 2 倍外部频率; p 185. PLL4X _CLKMODE 常量: 4 倍外部频率; p 185. PLL8X _CLKMODE 常量: 8 倍外部频率; p 185. PLL16X _CLKMODE 常量: 16 倍外部频率; p 185.

Cog 控制 COGIDa 当前 cog 的 ID (0-7); p 191. COGNEW 启动下一个可用的 cog; p 194. COGINITa 通过 ID 来启动,或复位一个 cog; p 192. COGSTOPa 通过 ID 停止一个 cog; p 198. REBOOT 复位 Propeller 芯片; p 298.

程序控制 LOCKNEWa 检出(取出)一个新的锁; p 236. LOCKRETa 释放一个锁; p 239. LOCKCLRa 通过 ID 清除一个锁; p 234. LOCKSETa 通过 ID 设置一个锁; p 240. WAITCNTa 等待系统计数器达到一个值; p 329. WAITPEQa 等待引脚等于一个值; p 333. WAITPNEa 等待引脚不等于一个值; p 335. WAITVIDa 等待视频同步并发送下一个颜色/像素组; p 336.

流程控制 IF 有条件地执行一个或多个代码块; p 225.

IFNOT 有条件地执行一个或多个代码块; p 231.

...ELSEIF

...ELSEIFNOT

...ELSE

...ELSEIF

...ELSEIFNOT

...ELSE

Page 158: Propeller Manual - Parallax Home

Spin语言参考

Page 158 · Propeller Manual v1.0

CASE 计算表达式并执行满足条件的代码块; p 176.

REPEAT 反复执行代码块,执行方式可以是无穷循环,或者使用带有可选的

循环计数,步长,继续执行或退出条件的有限循环; p 299.

NEXT 跳过剩下的 REPEAT 块,跳至下一个循环迭代; p 252. QUIT 从 REPEAT 循环退出; p 297. RETURN 正常退出 PUB/PRI ,可选返回值; p 307. ABORT 中断 PUB/PRI ,可选返回值; p 165.

内存 BYTE 声明一个字节大小的符号或主内存的可访问字节; p 169. WORD 声明一个字大小的符号或主内存可访问字; p 338. LONG 声明一个长字大小的符号或主内存可访问字; p 242. BYTEFILL 将指定值写入将主内存的字节; p 174. WORDFILL 将指定值写入将主内存的字; p 342. LONGFILL 将指定值写入将主内存的长字; p 246. BYTEMOVE 将字节从主内存的一个区域复制到另一个区域; p 175. WORDMOVE 将字从主内存的一个区域复制到另一个区域; p 343. LONGMOVE 将长字从主内存的一个区域复制到另一个区域; p 247. LOOKUP 按照索引值(1…N)取得在列表中相应的值; p 250. LOOKUPZ 按照索引值(1…N−1)取得在列表中相应的值; p 250. LOOKDOWN 在一个列表中查找匹配值,取得其索引值(1…N); p 248. LOOKDOWNZ 在一个列表中查找匹配值,取得其基于零的索引值(0..N−1); p 248. STRSIZE 取得一个字符串的字节大小; p 317. STRCOMP 比较两个字节型字符; p 314.

...OTHER

...FROM

...TO

...STEP

...UNTIL

...WHILE

Page 159: Propeller Manual - Parallax Home

4: Spin语言参考

Propeller Manual v1.0 · Page 159

命令 STRING 声明内联字符串表达式; 在编译时解析; p 316. CONSTANT 声明内联常量表达式; 在编译时解析; p 205. FLOAT 声明浮点表达式;在编译时解析; p 221. ROUND 将编译时浮点表达式变为整型表达式; p 309. TRUNC 编译时将浮点表达式缩减为十进制; p 320. FILE 从外部文件输入数据; p 220.

寄存器 DIRAa 32-位端口 A 的方向寄存器; p 217. DIRBa 32-位端口 B 的方向寄存器(保留); p 217. INAa 32-位端口 A 的输入寄存器(只读); p 231. INBa 32-位端口 B 的输入寄存器(只读) (保留); p 232. OUTAa 32-位端口 A 的输出寄存器; p 286. OUTBa 32-位端口 B 的输出寄存器(保留); p 288. CNTa 32-位系统计数器寄存器 (只读); p 189. CTRAa 计数器 A 控制寄存器; p 209. CTRBa 计数器 B 控制寄存器; p 209. FRQAa 计数器 A 频率寄存器; p 224. FRQBa 计数器 B 频率寄存器; p 224. PHSAa 计数器 A 锁相环(PLL)寄存器; p 291. PHSBa 计数器 B 锁相环(PLL)寄存器; p 291. VCFGa 视频配置寄存器; p 324. VSCLa Video Scale Register; p 327. PARa Cog 启动参数寄存器 (只读); p 289. SPR 特殊用途寄存器阵列; 间接 cog 寄存器访问; p 311.

Page 160: Propeller Manual - Parallax Home

Spin语言参考

Page 160 · Propeller Manual v1.0

常量 TRUEa 逻辑真: -1 ($FFFFFFFF); p 207. FALSEa 逻辑假: 0 ($00000000) ; p 207. POSXa 大正整数: 2,147,483,647 ($7FFFFFFF); p 207. NEGXa 小负整数: -2,147,483,648 ($80000000); p 207. PIa PI 的浮点值: ~3.141593 ($40490FDB); p 207.

变量 RESULT PUB/PRI 方法的默认结果变量; p 305.

一元运算符 + 正的 (+X); 加法的一元形式; p 261. - 负的 (-X); 减法的一元形式; p 262. - - 前减 (--X) 或后减 (X--) ,并赋值; p 262. + + 前加(++X) 或后加 (X++),并赋值; p 263. ^^ 平方根; p 266. || 绝对值; p 267. ~ Sign-extend from bit 7 (~X) or post-clear to 0 (X~); p 267. ~~ Sign-extend from bit 15 (~~X) or post-set to -1(X~~); p 268. ? 随机数正向 (?X) 或逆向 (X?); p 269. |< 将一个值(modulus of 32; 0-31)解码为单高位长字值; p 270. >| 将长字编码为高位优先的值(0 - 32); p 271. ! 位操作: NOT; p 277. NOT 布尔: NOT (将非 0 变为-1); p 279. @ 符号地址; p 283. @@ 对象地址加符号地址; p 284.

Page 161: Propeller Manual - Parallax Home

4: Spin语言参考

Propeller Manual v1.0 · Page 161

二元运算符 注意: 右侧的运算符是赋值运算符。

= --和-- = 常量赋值 (CON 块); p 259. := --和-- := 变量赋值 (PUB/PRI 块); p 260. + --或-- += 加; p 261. - --或-- -= 减; p 261. * --或-- *= 乘,返回低 32 位 (有符号); p 264. ** --或-- **= 乘,返回高 32 位 (有符号); p 264. / --或-- /= 除 (有符号); p 265. // --或-- //= 模数 (有符号); p 265. #> --或-- #>= Limit minimum (有符号); p 265. <# --或-- <#= Limit maximum (有符号); p 266. ~> --或-- ~>= 算数右移; p 268. << --或-- <<= 位运算: 左移; p 271. >> --或-- >>= 位运算: 右移; p 272. <- --或-- <-= 位运算: 左转; p 272. -> --或-- ->= 位运算: 右转; p 273. >< --或-- ><= 位运算: 反转; p 274. & --或-- &= 位运算: AND; p 274. | --或-- |= 位运算: OR; p 275. ^ --或-- ^= 位运算: XOR; p 276. AND --或-- AND= 布尔运算: AND (promotes non-0 to -1); p 277. OR --或-- OR= 布尔运算: OR (promotes non-0 to -1); p 278. = = --或-- = = = 布尔运算: 等于; p 279. <> --或-- <>= 布尔运算: 不等于; p 280. < --或-- <= 布尔运算: 小于 (有符号); p 281. > --或-- >= 布尔运算: 大于 (有符号); p 281. =< --或-- =<= 布尔运算: 等于或小于 (有符号); p 282.

Page 162: Propeller Manual - Parallax Home

Spin语言参考

Page 162 · Propeller Manual v1.0

=> --或-- =>= 布尔运算: 等于或大于 (有符号); p 283.

语法符号 % 二进制数字标识符, 例如 %1010; p 318. %% 四进制数字标识符, 例如 %%2130; p 318. $ 十六进制数字标识符, 例如$1AF; p 318. " 字符串标识符,例如 "Hello"; p 318. _ 在常量中为分位符,或在符号中为下划线; p 318. # 对象常量引用: obj#constant; p 318. . 对象方法引用: obj.method(param) 或十进制小数点; p 318. .. 范围指示, 例如 0..7; p 318. : 返回分隔符: PUB method : sym, 或对象赋值; p 318. | 本地变量分隔符: PUB method | temp, str; p 319. \ 中止陷阱, 例如 \method(parameters); p 319. , 列表分隔符, 例如 method(param1, param2, param3); p 319. ( ) 参数列表指定符, 例如 method(parameters); p 319. [ ] 数组索引标识符, 例如 INA[2]; p 319. 内联/多行 代码注释标识符; p 319. 内联/多行 文档注释标识符; p 319. ' 代码注释标识符; p 319. ' ' 文档注释标识符; p 319.

Page 163: Propeller Manual - Parallax Home

4: Spin语言参考

Propeller Manual v1.0 · Page 163

Spin 语言元素 本章接下来的部分将按字母顺序,描述 Spin 语言的元素。为了简明,一些元素的

解释会出现在另一些元素的解释中;可以从上面的列表中使用页面引用来查找到这些

讨论。有些元素既可以用于 Spin 语言,也可以用于 Propeller 汇编语言。这些元素在相

应的章节都有详细的描述,相对应的 Propeller 汇编语言元素可以在 Chapter 5: 汇编语

言参考中找到(347 页)。

符号命名规则 符号是大小写敏感的,不论是由编译器创建的(保留字)或是由开发员创建的(用

户定义)字母与数字构成的名称都是如此。它们代表了数值(常量或变量)使源代码

更易懂和易于维护。符号命名规则如下:

1) 由字母 (a – z) 或下划线开始 ‘_’。 2) 只能包含字母,数字,和下划线 (a – z, 0 – 9, _ ); 不允许有空格。 3) 多不超过 32 个字符。 4) 对象内命名不能重复;不能是保留字 (p. 426) 或已由用户定义的符号。

数值的表示 数值可以以二进制,四进制,十进制,十六进制或字符方式输入。数字也可以用下

划线‘_’作为分位符表示。下面是这些格式的例子。

表 4-1: 数值表示 基数 类型 例子

2 二进制 %1010 –或– %11110000_10101100 4 四进制 %%2130_3311 –或– %%3311_2301_1012

10 十进制(整型) 1024 –或– 2_147_483_647 –或– -25 10 十进制(浮点) 1e6 –或– 1.000_005 –或– -0.70712 16 十六进制 $1AF –或– $FFAF_126D_8755 n/a 字符 "A"

分隔符可以代替逗号(十进制数),或形成逻辑组,例如半个字节,字节,字等等。

Page 164: Propeller Manual - Parallax Home

Spin语言参考

Page 164 · Propeller Manual v1.0

语法定义 除了细节描述,下面的定义中也包含了所提到的元素中可选的术语定义。语法定义

中使用特殊符号来标明这些元素特性何时以及如何被使用。

BOLDCAPS 粗体大写的内容应该准确地输入。

Bold Italics 粗斜体的内容应该用用户文本,符号,运算符或表达

式来替换。

. .. : , # P 句号,双句号,分号,逗号,英镑符号,管道符,

反斜杠,方括号和圆括号应该准确地输入。

⟨ ⟩ 尖括号内的内容是可选项。如果需要的话可以输入,

但是不要输入尖括号。

(( )) 双圆括号内的内容是互斥的,由 Dash-bar 分隔。也就

是说每次只能输入 Dash-bar 分隔的两项内容之一。程

序编写时不要输入双括号或 dash-bar。

… 重复符号表示之前的内容,或组,可以被多次重复。

如果希望,则重复上一个内容。程序编写时不要输入

重复符号。

新行/缩进符号表明接下来的内容应该出现在下一行,

有至少一个空格进行缩进。

缩进符号表明接下来的内容应该有至少一个空格进行

缩进。

Single line 分离的变量语法结构选项。

Double line 区分指令和该指令的返回值。

因为元素被限制到特定的 Spin 块,所有的语法定义都应该由该 Spin 块的类型标示

开始。 例如,下面的语法表明了 BYTEFILL 命令和它的参数必须出现在一个 PUB 或 PRI 块中,但可能是该块中诸多命令中的一个。 ((PUB PRI)) BYTEFILL (StartAddress, Value, Count )

| \ [ ] ( )

Page 165: Propeller Manual - Parallax Home

4: Spin语言参考– ABORT

Propeller Manual v1.0 · Page 165

ABORT 从 PUB/PRI 方法中退出,使用带有可选返回值 Value 的终止状态。 ((PUB PRI)) ABORT ⟨Value⟩ 返回: 提供当前的 RESULT 值或 Value 值。

• Value 是一个可选的返回值表达式,从 PUB 或 PRI 方法中终止退出。 解释

ABORT 是终止 PUB 或 PRI 方法执行的两条命令中的一个 (ABORT 和 RETURN)。

ABORT 导致从 PUB 或 PRI 方法中终止退出,意思是它多次调用堆栈直到所调用的堆

栈为空或到达了一个终止陷阱(Abort Trap, “\”),并向程序中传递一个值。

ABORT 在这种情况下很有用,那就是需要终止一个方法以及向调用者标明一个异常

或提升状态。举例而言,一个应用程序可能包含了复杂的事件链条,这些事件的任何

一个都可能导致不同分支的 终动作发生。可能写一段小型的,特殊的方法以嵌套方

式调用,用于处理链条中的子事件。当这些简单方法之一决定了一系列动作时,他可

以发出一个终止嵌套调用链,阻止中间方法继续执行。

当 ABORT 出现时没有带可选的 Value,它会返回 PUB/PRI 内建 RESULT 变量的当前

值。如果 Value 域有值,则返回指定的 Value 值。

关于调用堆栈 当方法被另一个方法调用时,必须有一种机制存储调用结束后返回的位置。这种机

制称为“堆栈(Stack)”,但是在这里我们使用术语“调用堆栈(Call Stack)”。它

在 RAM 中存储返回地址,返回值,参数和中间结果。随着越来越多方法的调用,调

用堆栈会变得越来越长(大)。随着越来越多调用返回(通过 RETURN 或到达方法的结

尾),调用返回会变短(小)。这些过程相应地称为入栈(Pushing)和出栈

(Poping)。

RETURN 命令将 近被压入堆栈的数据弹出给调用者。而 ABORT 命令则重复地弹出

堆栈中的数据,直到到达了一个终止陷阱(Abort Trap)(见下); 返回到更高级的调用

者,可能是一个调用,也可能是多个调用,取决于嵌套调用链。在退出方法和推出陷

Page 166: Propeller Manual - Parallax Home

ABORT – Spin 语言参考

Page 166 · Propeller Manual v1.0

阱之间的返回点都被忽略,终止。ABORT 以这种方式允许跳出较深和复杂的调用逻

辑,在较高的级别处理一系列问题。

使用 ABORT 任何方法都可以选择使用 ABORT 命令。 这取决于高级能否检测到一个终止状态并作

出相应的处理。高级代码可以直接调用终止方法(Aborting method)或通过其他方

法。要使用 ABORT 命令,可以按如下方式调用:

if <bad condition> abort '如果检测到坏条件,则终止 —或—

if <bad condition> abort <value> '如果检测到坏条件,则终止并返回一个值

...这里 <bad condition> 是一个条件,表明在该条件下方法应该终止,同时 <value> 是依靠终止返回的值。

Abort Trap ( ﹨ ) 要捕获一个 ABORT, 对方法的调用或潜在会终止的方法链必须前置一个终止陷阱符

号(Abort Trap symbol, 一个反斜杠 “﹨”)。例如,如果调用 MayAbort 的方法可能终

止,或调用其他可能终止的方法,那么一个正在调用的方法就可以将其捕获:

if ﹨MayAbort '带有 about trap的调用 MayAbort

abort <value> '处理终止

MayAbort 实际使用的退出类型, ABORT 或 RETURN,不会自动被陷阱调用所知晓;它

可能刚好是 RETURN 命令的目标地址。因此,代码必须被写成能被检测是使用哪种退出

类型的方式。一些可行的方法是:1) 将代码设计成只有高级方法才能捕获终止,其它

中间级代码处理正常的事物,而且不允许返回(RETURN)到更高级代码(意思是只有

终止的返回值才能被高级代码处理,普通的返回会被中间级代码拦截),或 2) 终止的

方法可以返回一个异常值,或 3) 在实际终止前,在终止方法中将全局标志位置位。

Page 167: Propeller Manual - Parallax Home

4: Spin语言参考– ABORT

Propeller Manual v1.0 · Page 167

使用 Abort 的例子 下面的例子是一段不太智能的机器人程序,这个机器人利用四个传感器(Left,

Right, Front 和 Back)感知周围环境,并远离障碍物。假定 CheckSensors, Beep, 和 MotorStuck 是已经定义的方法。

CON #0, None, Left, Right, Front, Back '方向枚举值 PUB Main | Direction Direction := None repeat case CheckSensors '检查传感器

Left : Direction := Right '有物体在左边? 那就走右边

Right : Direction := Left '有物体在右边? 那就走左边

Front : Direction := Back '有物体在前面? 那就后退

Back : Direction := Front '有物体在后面? 那就前进

other : Direction := None '否则,留在原地

if not \Move(Direction) '移动机器人 Beep 'We're stuck? Beep PUB Move(Direction) result := TRUE '假定是成功的 if Direction == None return '如果没有向任何方向移动则返回 repeat 1000 DriveMotors(Direction) '驱动电机 1000次 PUB DriveMotors(Direction) <code to drive motors> if MotorStuck abort FALSE '如果电机堵转,abort <more code>

上面的例子演示了三个不同逻辑级别的方法,Main (“高级”),Move (“中

级”),和 DriveMotors (“低级”)。高级方法, Main,是应用程序的决定者;决定

了如何去响应例如传感器活动和电动机移动这样的事件。中级的方法, Move, 负责将

Page 168: Propeller Manual - Parallax Home

ABORT – Spin 语言参考

Page 168 · Propeller Manual v1.0

Robot 移动一个距离。低级方法, DriveMotors,处理驱动电动机的细节并确保(驱

动)是成功的。

在一个这样的应用程序中,关键的事件可能会发生在低级代码中,这些事件需要高

级代码来处理。 ABORT 命令有助于向高级代码传递消息时,不需要经过复杂的中间级

代码之间的消息传递过程。在这个例子中,我们只有一个中级方法,但是在高级和低

级代码间可以有多次嵌套的中级方法。

Main 方法取得传感器的输入,并通过 CASE 语句来决定将要移动到哪个方向。然后

以特别的方式调用 Move,也就是将中止陷阱(Abort Trap)符号 \ 放在它前面。Move 方法将其 RESULT 的值设置为 TRUE,然后再一个优先循环内调用 DriveMotors。如果成功, Move 返回 TRUE。 DriveMotors 方法负责继续移动电动机达到希望的方向,但是如果它

检测到电动机堵转,不能继续移动,那它就中止,返回一个 FALSE。否则它会继续运

转。

如果一切正常,DriveMotors 方法正常返回,Move 方法继续正常执行,并 终返回

TRUE,并且 Main 方法也会正常运行。如果,DriveMotors 发现了一个问题,它会终止

(ABORT),这会使 Propeller 弹出调用堆栈内的内容,越过 Move 方法到达 Main 方法,

在这里发现了终止陷阱。Move 方法察觉不到此过程,并且已经终止。Main 方法检查

Move 调用的返回值(which is now the FALSE value that was actually returned by the aborted DriveMotors method deep down the call stack)并决定执行 Beep 作为检测到失败的提

示。

如果我们没有将终止陷阱符号 ( \ )放在对 Move的调用之前,那么当 DriveMotors 终止的时候,调用堆栈会一直弹出(pop),直到堆栈为空,那么应用程序本身也会立刻

结束。

Page 169: Propeller Manual - Parallax Home

4: Spin语言参考– BYTE

Propeller Manual v1.0 · Page 169

BYTE 声明字节型符号,字节对齐的数据,或从主内存中读/写一个字节。 VAR

BYTE Symbol ⟨[Count]⟩ DAT BYTE Data ((PUB PRI)) BYTE [BaseAddress] ⟨[Offset]⟩ ((PUB PRI)) Symbol.BYTE ⟨[Offset]⟩

• Symbol 是希望的变量名(语法 1),或已存在的变量名(语法 4)。 • Count 是可选的表达式,指出了 Symbol 的字节型元素的个数,存储在数组中,

数组下标从 0 到 Count-1。 • Data 是常量表达式或逗号分隔的常量表达式列表。允许括号内的字符串;它们

会作为逗号分隔的字符列表来对待。 • BaseAddress 是表达式,描述了要读写的主内存的地址。如果忽略 Offset,

BaseAddress 就是实际要操作的地址。如果指定了 Offse,实际操作的地址是 BaseAddress + Offset。

• Offset 是可选的表达式,指出了从 BaseAddress 偏移的地址,或一个从符号的 0字节开始的偏移。.

解释

BYTE 是三条多用途指令(BYTE, WORD, 和 LONG)之一,可用于声明或内存操作。BYTE 可以被用于:

1) 声明字节型 (8-位) 符号或在 VAR 块中声明一个多字节数组符号,或 2) 在 DAT 块中声明字节对齐的,和字节型的数据,或 3) 按基址和可选的偏移读写一个字节的内存,或 4) 在字型或长字型变量中访问一个字节。

Page 170: Propeller Manual - Parallax Home

BYTE – Spin语言参考

Page 170 · Propeller Manual v1.0

字节变量声明 (语法 1) 在 VAR 块中,BYTE 的语法 1 用于声明全局的符号变量,这些变量是字节型或字节数

组。

例如:

VAR byte Temp 'Temp 是一个字节

byte Str[25] 'Str 是一个字节数组

上面的例子声明了两个变量(符号),Temp 和 Str。Temp 是字节型变量。在 Temp 声明下面的声明使用了可选的 Count 域,这样建立了一个有 25 个字节元素的数组,名

为 Str。 Temp 和 Str 可以从同一项目中的和 VAR 一起声明的任何 PUB 或 PRI 方法中访

问,它们对于对象而言是全局性的。下面是一个例子。

PUB SomeMethod Temp := 250 '将 Temp 设置为 250

Str[0] := "A" '将 Str的第一个元素设置为 "A"

Str[1] := "B" '将 Str的第二个元素设置为 "B"

Str[24] := "C" '将 Str的 后一个元素设置为 "C"

要了解更多这种方法的 BYTE 用法,请参考 315 页,VAR 一节中的变量声明 (语法 1),记住在变量声明中, BYTE 用于 Size 域。

字节数据声明 (语法 2) 在 DAT 块中,BYTE 的语法 2 用于声明字节对齐的,和/或主内存中会被编译为常量

的字节数据。DAT 块允许在该类型的声明前有可选的符号,这些符号可以在之后的程序

中用于引用这些声明的数据 (参见 DAT, 213 页)。例如:

DAT MyData byte 64, $AA, 55 '字节对齐和字节数据

MyString byte "Hello",0 '一个字节字符串(字符串)

上面的例子声明了 2 个数据符号,MyData 和 MyString。每个数据符号都指向了主

内存中字节对齐的和字节型数据的起点。 MyData 的值,在主内存中,分别是 64, $AA 和 55。 MyString的值,在主内存中,分别是 “H”, “e”, “l”, “l”, “o”, 和 0。该数据被编

译进对象,作为应用程序可执行代码的一部分,可以使用 syntax 3, of BYTE 的语法 3

Page 171: Propeller Manual - Parallax Home

4: Spin语言参考– BYTE

Propeller Manual v1.0 · Page 171

(见下)访问。要了解更多这种方法的 BYTE 用法,请参考 208 页, DAT 一节中的声明

数据 (语法 1),记住在声明变量时, BYTE 用于 Size 域。

读/写主内存的字节 (语法 3) 在 PUB 和 PRI 块中,BYTE 的语法 3 用于读写主内存的字节值。下面的两个例子中,

我们会假设我们的对象包含 DAT 块,和上面的例子一样。我们会演示两种访问数据的

方法。

首先,试着使用在数据块中提供的标签来直接访问数据。

PUB GetData | Index, Temp Temp := MyData '将 MyData的第一个字节写入 Temp

<do something with Temp> '用 Temp执行任务 Index := 0 repeat Temp := MyString[Index++] '将字符读入 Temp

<do something with Temp> '用字符执行任务

while Temp > 0 '循环,直到发现终点 GetData 方法的第一行代码 Temp := MyData 读取 MyData 列表中的第一个值(字节值

64)并将其存储在 Temp中。接下来,在 REPEAT 循环中,Temp := MyString[Index++] 读取了位于 MyString + Index 的字节值。因为 Index 之前已经被设置为 0,MyString 的第

一个字节会被读取,也就是“H”。同一行中的 Index 使用了后增量运算符(++),所以

下一次循环会读取下一个字节,也就是位于 MyString + 1 的值(“e”),再下一次是位于 MyString + 2 的值(“l”)等。

和上面的例子类似,我们可以使用 BYTE 声明来达到此目标。请参考下面的例子。

Page 172: Propeller Manual - Parallax Home

BYTE – Spin语言参考

Page 172 · Propeller Manual v1.0

PUB GetData | Index, Temp Temp := BYTE[@MyData] '将 MyData的第一个字节读入 Temp <do something with Temp> 'Perform task with Temp Index := 0 repeat Temp := BYTE[@MyString][Index++] '将字符读入 Temp

<do something with Temp> '用字符执行任务

while Temp > 0 '循环,直到发现结尾

这个例子和前一个一样,除了我们使用的是 BYTE 声明来读取了主内存的一个字

节,地址是 MyData 和 MyString + Index。

使用相似的语法,就可以向主内存的字节写入数据,就如同它们是 RAM 位置一

样。例如:

BYTE[@MyString][0] := "M" '将 MyString的第一个字符设置为 M

该行将字符 M 写入 MyString的第一个字节,这使字符串变为 “Mello”,0。

Page 173: Propeller Manual - Parallax Home

4: Spin语言参考– BYTE

Propeller Manual v1.0 · Page 173

访问长字型变量中的字节 (语法 4) 在 PUB 和 PRI 块中,BYTE 的语法 4 用于读写字型或长字型变量中的字节。例如:

VAR word WordVar long LongVar PUB Main WordVar.byte := 0 '将 WordVar 的第一个字节设置为 0

WordVar.byte[0] := 0 '和上面相同

WordVar.byte[1] := 100 '将 WordVar to的第二个字节设置为 100

LongVar.byte := 25 '将 LongVar 的第一个字节设置为 25

LongVar.byte[0] := 25 '和上面相同

LongVar.byte[1] := 50 '将 LongVar 的第二个字节设置为 50

LongVar.byte[2] := 75 '将 LongVar 的第三个字节设置为 75

LongVar.byte[3] := 100 '将 LongVar 的第四个字节设置为 100

这个例子分别访问了 WordVar 和 LongVar 中的字节数据。每一行的注释都表明了代

码的用处。在 Main 方法的结尾, WordVar 会等于 l 25,600 , LongVar 等于

1,682,649,625。

Page 174: Propeller Manual - Parallax Home

BYTEFILL – Spin语言参考

Page 174 · Propeller Manual v1.0

BYTEFILL 将内存中某些字节的用某个值填充。 ((PUB PRI)) BYTEFILL (StartAddress, Value, Count )

• StartAddress 是表达式,指出了将要用 Value 填充的内存位置的第一个地址。 • Value 是表达式,指出了将要填入的内容。 • Count 是表达式,指出了由 StartAddress 开始,要填充的字节个数。

解释

BYTEFILL 是三条用指定值填充内存块的命令 (BYTEFILL, WORDFILL, 和 LONGFILL) 之一。 BYTEFILL 用 Value 的值填充的,由 StartAddress 开始的,内存中 Count 个字节。

使用 BYTEFILL BYTEFILL 是将以字节为单位的内存块清零的有效方法。例如:

VAR byte Buff[100] PUB Main bytefill(@Buff, 0, 100) 'Clear Buff to 0 上面 Main 方法的第一行将 100 个字节的数组 Buff 清零。BYTEFILL 在这里要比一个复杂

的 REPEAT 循环快得多。

Page 175: Propeller Manual - Parallax Home

4: Spin语言参考– BYTEMOVE

Propeller Manual v1.0 · Page 175

BYTEMOVE 将主内存中中一个区域的字节复制到另一个区域。 ((PUB PRI)) BYTEMOVE (DestAddress, SrcAddress, Count )

• DestAddress 是表达式,指出了主内存中要复制的第一个字节的位置。 • SrcAddress 是表达式,指出了复制的第一个字节将要写入的位置。 • Count 是表达式,指出了要复制的字节的数量。

解释

BYTEMOVE 是三条用于移动主内存中块数据的命令(BYTEMOVE, WORDMOVE, 和 LONGMOVE)之一。 BYTEMOVE 将复制主内存中从地址 SrcAddress 开始的 Count 个字节到地址 DestAddress 中。

使用 BYTEMOVE BYTEMOVE 是复制以字节为单位的内存数据时有效的方法。例如:

VAR byte Buff1[100] byte Buff2[100] PUB Main bytemove(@Buff2, @Buff1, 100) '从 Buff1 复制到 Buff2

Main 方法的第一行,复制了 100 字节的 Buff1 数组到 Buff2 数组。 BYTEMOVE 命令在

这个任务中比一个复杂的 REPEAT 循环更有效。

Page 176: Propeller Manual - Parallax Home

CASE – Spin语言参考

Page 176 · Propeller Manual v1.0

CASE 将表达式和已设定的匹配表达式相比较,如果找到匹配的项则执行相应的代码。 ((PUB PRI)) CASE CaseExpression MatchExpression : Statement(s) ⟨ MatchExpression : Statement(s) ⟩ ⟨ OTHER : Statement(s) ⟩

• CaseExpression 是要比较的表达式。 • MatchExpression 是正则表达式或逗号分隔的值或范围表达式,它会和

CaseExpression 作比较。每个 MatchExpression 之后都必须有一个分号(:)。 • Statement(s) 是一行或多行代码块,当 CaseExpression 和相关的 MatchExpression.

匹配时就会执行。Statement(s) 的第一个语句可以写在 MatchExpression 的冒号

的右边,或写在 MatchExpression 下方带有缩进的行中。 解释

CASE 是三条条件命令(IF, IFNOT, 和 CASE)之一,可以用来有条件地执行代码块。

如果需要将表达式的值(CaseExpression)和多个不同的值相比较,那么推荐使用

CASE,而不要用 IF..ELSEIF..ELSE。

CASE 将 CaseExpression 按顺序和每个 MatchExpression 的值作比较,如果发现了匹

配值,则执行相关的 Statement(s)。如果没有找到匹配值,则执行可选的 OTHER 命令的

相关的 Statement(s)。

必不可少的缩进 重要: 缩进是必不可少的。Spin 语言依赖于紧跟条件命令后代码的缩进(一个或多

个空格)来确定它们是否属于该命令。要使 Propeller Tool 指示出这些逻辑分组的代码

块,可以按 Ctrl + I 来打开块组指示器。再次按 Ctrl + I 将关闭这一特性。参见 69 页上

的增加缩进和减少缩进, 以及 74 上的块-组指示器。

Page 177: Propeller Manual - Parallax Home

4: Spin语言参考– CASE

Propeller Manual v1.0 · Page 177

使用 CASE 当需要依表达式的不同计算结果执行不同的动作时,就可以使用 CASE。下面的例子

假定 A, X 和 Y 是已经定义过的变量。

case X+Y '测试 X+Y

10, 15: !outa[0] 'X+Y = 10 或 15? 触发 P0

A*2 : !outa[1] 'X+Y = A*2? 触发 P1

30..40: !outa[2] 'X+Y 的范围是 30 到 40? 触发 P2

X += 5 'X 加 5

因为 MatchExpression 行是从 CASE 行缩进的,所以他们是属于 CASE 结构的,并基

于 CaseExpression 和计算结果相比较的结果来执行。下一行 X += 5,没有缩进,所以

不论 CASE 的结果是什么,它都会执行。

这个例子将 X + Y 的值和 10 或 15,A*2 和范围从 30 到 40,作比较。如果 X + Y 等于 10 或 15,P0 会被触发。如果 X + Y 等于 A*2,P1 会被触发。如果 X + Y 的值在 30到 40 的范围内,P2 被触发。如果没有找到匹配的值,会执行 X += 5。

使用 OTHER CASE 的可选项 OTHER,类似于 IF 结构中的可选项 ELSE。例如:

case X+Y '测试 X+Y

10, 15: !outa[0] 'X+Y = 10 或 15? 触发 P0

25 : !outa[1] 'X+Y = 25? 触发 P1

20..30: !outa[2] 'X+Y 在 20 到 30的范围内? 触发 P2

OTHER : !outa[3] '否则,触发 P3

X += 5 'X 加 5

这个例子类似于上一个,除了第三个 MatchStatement 检查的范围是 20 到 30,以及

有一个 OTHER 部分。如果 X + Y 不等于 10, 15, 25, 或不在 20 到 30 的范围内,那么

OTHER 之后的 Statement(s)代码块会被执行。然后会执行 X += 5。

这里有一个很重要的概念,如果 X + Y 等于 10 或 15,P0 会被触发,或如果 X + Y 是 25,P1 会被触发,如果 X + Y 是在 20 到 30 的范围内,P2 会被触发。这是因为 MatchExpressions 会被按列出的顺序依次检查,只有第一个被满足的表达式的代码会

Page 178: Propeller Manual - Parallax Home

CASE – Spin语言参考

Page 178 · Propeller Manual v1.0

被执行,之后不会再测试其他的表达式。意思是如果我们重新排列 MatchExpression 行25 和 20…30,范围表达式(20..30)会首先被测试。我们如果这样做:

case X+Y '测试 X+Y

10, 15: !outa[0] 'X+Y = 10 或 15? 触发 P0

20..30: !outa[2] 'X+Y 在范围 20 到 30内? 触发 P2

25 : !outa[1] 'X+Y = 25? 触发 P1 <-- 永远不会执行

上面的例子就包含了一个错误,那就是 X + Y 可能等于 25,但是其匹配的语句永

远不会执行,因为之前的表达式会先被测试,因为 20…30 为真,它的语句块会执行。

之后不会再检查别的表达式。

Statement(s)的变体 上面的例子在 Statement(s) 中只用了一行代码,实际上每个 Statement(s) 块都可以支

持多行代码。此外,Statement(s) 块也可以写在 MatchExpression 下方,并缩进。下面

的例子所示为这两种变体。

case A '测试 A

4 : !outa[0] 'A = 4? 触发 P0

Z+1 : !outa[1] 'A = Z+1? 触发 P1

!outa[2] '同时触发 P2

10..15: !outa[3] 'A 在范围 10 到 15内? 触发 P3 case A '测试 A 4: 'A = 4? !outa[0] '触发 P0 Z+1: 'A = Z+1? !outa[1] '触发 P1

!outa[2] '同时触发 P2

10..15: 'A 在范围 10 到 15内?

!outa[3] '触发 P3

Page 179: Propeller Manual - Parallax Home

4: Spin语言参考– CHIPVER

Propeller Manual v1.0 · Page 179

CHIPVER 取得 Propeller 芯片的版本号。 ((PUB PRI)) CHIPVER

返回: Propeller 芯片的版本号。

解释

CHIPVER 命令读取并返回 Propeller 芯片的版本号。例如:

V := chipver

这个例子将 V 设置为 Propeller 芯片的版本号,在这个例子中,等于 1。以后的

Propeller 应用程序可以使用该命令检测 Propeller 芯片的版本和类型,并据此按需要调

整操作。

Page 180: Propeller Manual - Parallax Home

CLKFREQ – Spin语言参考

Page 180 · Propeller Manual v1.0

CLKFREQ 当前系统时钟的频率;正在运行的 cog 的频率。 ((PUB PRI)) CLKFREQ

返回:当前系统时钟频率,单位是 Hz。 解释

CLKFREQ 返回的值是实际系统时钟的频率,(震荡器类型,增益,和 PLL 设定)和

外部 XI 引脚的频率(如果存在)。对象可以使用 CLKFREQ t 来为时间敏感的运算决定

合适的时间延迟。例如:

waitcnt(clkfreq / 10 + cnt) '等待 .1 秒 (100 ms)

该语句将 CLKFREQ 10 分频,将结果加 CNT (当前系统计数器的值)然后等待

(WAITCNT)系统计数器达到某个值。因为 CLKFREQ 是每秒的周期数,除以 10 后得到每

0.1 秒(或 100ms)内的周期数。所以不论处理表达式的时间如何,该语句都会暂停

cog 程序的执行 100ms。下面的表格展示的是系统时钟嘀嗒和时间计算的例子。

表 4-2: 系统时钟嘀嗒 vs. 时间计算 表达式 结果

clkfreq / 10 时钟嘀嗒 每 0.1 秒 (100 ms)

clkfreq / 100 时钟嘀嗒 每 0.01 seconds (10 ms) clkfreq / 1_000 时钟嘀嗒 每 0.001 seconds (1 ms) clkfreq / 10_000 时钟嘀嗒 每 0.0001 seconds (100 µs) clkfreq / 100_000 时钟嘀嗒 每 0.00001 seconds (10 µs) clkfreq / 9600 时钟嘀嗒 每 serial bit period at 9,600 baud (~ 104 µs) clkfreq / 19200 时钟嘀嗒 每 serial bit period at 19,200 baud (~ 52 µs)

CLKFREQ 返回的值会在应用程序改变时钟模式时改变,改变时钟的方式可以是手动

或通过 CLKSET 命令。对时间敏感的对象应该在策略点(设定的位置和方式)检查

CLKFREQ 以便能自动调整成新的设定。

Page 181: Propeller Manual - Parallax Home

4: Spin语言参考– CLKFREQ

Propeller Manual v1.0 · Page 181

CLKFREQ vs. _CLKFREQ CLKFREQ 和_CLKFREQ.相关,但是并不相同。CLKFREQ 命令会返回当前系统时钟的频

率,而_CLKFREQ 是一个应用程序定义的常量,该常量包含了应用程序启动时的系统时

钟频率值。换句话说,CLKFREQ 是当前系统时钟频率,而_CLKFREQ 是原有的时钟频

率;它们的值可能相同,也可以不同。

Page 182: Propeller Manual - Parallax Home

_CLKFREQ – Spin语言参考

Page 182 · Propeller Manual v1.0

_CLKFREQ 预定义常量,用于指定系统时钟频率。 CON _CLKFREQ = Expression

• Expression 是整型表达式,决定了应用程序启动时的系统时钟频率。 解释

_CLKFREQ 指定了启动时系统时钟频率。它是预定义的常量符号,它的值是由应用程

序的顶部对象文件决定的。_CLKFREQ 是由应用程序直接设定的,或是_CLKMODE 和 _XINFREQ 设定的间接结果。

应用程序的顶部对象文件(应用程序编译的起点),可以在 CON 块中为 _CLKFREQ 设定一个值。它定义了应用程序的系统时钟频率的初始值,这个值也是应用程序在启

动后开始执行时立即切换到的系统时钟的频率值。

应用程序可以在 CON 块中指定_CLKFREQ 或 _XINFREQ;它们是互斥的,未被指定的那

个值会自动被计算,并作为另一个值所指定的结果。

下面的例子假定它们是被包含在顶部对象文件中的。任何在自对象中的_CLKFREQ 设定会被编译器忽略。

例如:

CON _CLKMODE = XTAL1 + PLL8X _CLKFREQ = 32_000_000

上面 CON 块的第一行声明将时钟模式设置为外部低速晶振,时钟 PLL 乘 8。第二行

声明将系统时钟频率设置为 32MHz,意思是外部晶振的频率必须是 4MHz,因为 4 MHz * 8 = 32 MHz。_XINFREQ 的值会因这些声明被设置为 4 MHz。

CON _CLKMODE = XTAL2 _CLKFREQ = 10_000_000

Page 183: Propeller Manual - Parallax Home

4: Spin语言参考– _CLKFREQ

Propeller Manual v1.0 · Page 183

这两个声明将时钟模式设置为外部中速晶振,没有时钟 PLL 倍频,系统时钟频率

为 10 MHz。_XINFREQ 的值会因这些声明自动被设置为 10 MHz。

_CLKFREQ vs CLKFREQ _CLKFREQ 和 CLKFREQ 相关,但两者并不相同。_CLKFREQ 包含了应用程序启动时的系

统时钟频率,而 CLKFREQ 命令则返回当前系统时钟频率。换句话说,_CLKFREQ 是原有的

系统时钟频率而 CLKFREQ 是当前系统时钟频率;它们的值可能偶然相同,当然也可能

不同。

Page 184: Propeller Manual - Parallax Home

CLKMODE – Spin语言参考

Page 184 · Propeller Manual v1.0

CLKMODE 当前时钟模式设定。 ((PUB PRI)) CLKMODE

返回: 当前的时钟模式。 解释

时钟模式设定是字节型值,由应用程序在编译时指定(CLK 寄存器)。可用的设

定的解释请参见 29 页 CLK 寄存器。例如:

Mode := clkmode

该语句可用于将变量 Mode 设置为当前的时钟模式设定。很多应用程序包含了一个

静态时钟模式设定;但是也有很多应用程序会在运行时改变时钟模式设定,以此调整

时钟速度,进入低功耗模式等等。所有有些对象需要关注动态时钟模式以便调整合适

的时序和功能。

CLKMODE vs _CLKMODE CLKMODE 和_CLKMODE.相关,但两者并不相同。CLKMODE 命令返回当前时钟的模式

( 以 in the form of the CLK 寄存器的位的形式)而 _CLKMODE 是应用程序定义的常量,

它指出了应用程序启动时要求的时钟模式(in the form of clock setting constants that are OR’d together)。这两者都描述了同样的逻辑时钟模式,但它们的值并不相等。

Page 185: Propeller Manual - Parallax Home

4: Spin语言参考– _CLKMODE

Propeller Manual v1.0 · Page 185

_CLKMODE 预定义常量,用于指定应用程序级别的时钟模式设定。 CON _CLKMODE = Expression

• Expression 是整型表达式,由表 4-3 中的一个或两个时钟模式设定常量组成。这

将是应用程序启动的时钟模式。 解释

_CLKMODE 用于指定系统时钟,它是一个预定义常量符号,它的值由应用程序的顶部

文件指定。时钟模式设定是一个字节值,由编译时的 RCxxxx, XINPUT, XTALx 和 PLLxx 常量组合而成。表 4-3 阐明了时钟模式设定常量。注意并不是每种组合都有效;表 4-4 所

示为所有的有效组合。

表 4-3: 时钟模式设定常量 时钟模式设

定常量 1 XO 阻抗 2 XI/XO 电容 2 描述

RCFAST 无穷大 n/a 内部快速震荡器 (~12 MHz). 范围可以从 8 MHz 到 20 MHz. (默认) RCSLOW 无穷大 n/a 内部慢速震荡器 (~20 KHz). 范围可以从 13 KHz 到 33 KHz XINPUT 无穷大 6 pF (pad only) 外部时钟震荡器 (DC - 80 MHz); 从 XI 引脚输入, 忽略 XO引脚 XTAL1 2 kΩ 36 pF 外部低速晶振 (4 MHz - 16 MHz) XTAL2 1 kΩ 26 pF 外部中速晶振 (8 MHz - 32 MHz) XTAL3 500 Ω 16 pF 外部高速晶振 (20 MHz - 80 MHz) PLL1X n/a n/a 外部频率倍频 PLL2X n/a n/a 外部频率 2倍频 PLL4X n/a n/a 外部频率 4倍频 PLL8X n/a n/a 外部频率 8倍频 PLL16X n/a n/a 外部频率 16倍频

1. 所有常量也可以用于 Propeller 汇编语言 2. 所有必须的电容/电阻都包括在 Propeller 芯片中

Page 186: Propeller Manual - Parallax Home

_CLKMODE – Spin语言参考

Page 186 · Propeller Manual v1.0

表 4-4: 有效的时钟模式表达式和 CLK 寄存器值

有效的表达式 CLK 寄存器值 有效的表达式 CLK 寄存器值

RCFAST 0_0_0_00_000

RCSLOW 0_0_0_00_001

XINPUT 0_0_0_00_010

XTAL1 + PLL1X 0_1_1_01_011 XTAL1 + PLL2X 0_1_1_01_100 XTAL1 + PLL4X 0_1_1_01_101 XTAL1 + PLL8X 0_1_1_01_110 XTAL1 + PLL16X 0_1_1_01_111

XTAL1 0_0_1_01_010 XTAL2 0_0_1_10_010 XTAL3 0_0_1_11_010

XTAL2 + PLL1X 0_1_1_10_011 XTAL2 + PLL2X 0_1_1_10_100 XTAL2 + PLL4X 0_1_1_10_101 XTAL2 + PLL8X 0_1_1_10_110 XTAL2 + PLL16X 0_1_1_10_111

XINPUT + PLL1X 0_1_1_00_011 XINPUT + PLL2X 0_1_1_00_100 XINPUT + PLL4X 0_1_1_00_101 XINPUT + PLL8X 0_1_1_00_110 XINPUT + PLL16X 0_1_1_00_111

XTAL3 + PLL1X 0_1_1_11_011 XTAL3 + PLL2X 0_1_1_11_100 XTAL3 + PLL4X 0_1_1_11_101 XTAL3 + PLL8X 0_1_1_11_110 XTAL3 + PLL16X 0_1_1_11_111

应用程序的顶部对象文件(编译的起点)可以在 CON 块中指定_CLKMODE 的值。这定

义了应用程序的初始时钟模式,应用程序启动完成开始执行时会切换到该模式。下面

的例子假定都包含了顶部对象文件。任何在自对象中设定的_CLKMODE 都会被编译器忽

略。例如:

CON _CLKMODE = RCFAST

这将时钟模式设置为内部,快速 RC 时钟/震荡器电路。系统时钟会运行在 12MHz的频率上。RCFAST 设定是默认的设置,所以如果没有定义_CLKMODE,它将是实际使用的

设定。要注意时钟锁相环不可以和内部 RC 时钟/震荡器一起使用:

CON _CLKMODE = XTAL1 + PLL8X

这里将时钟模式设定为外部低速晶振(XTAL1),启用了时钟锁相环电路并将系统

时钟设定为使用 8x tap(因为设定为 PLL8X)。例如,如果将外部 4 MHz 晶振连接到

XI 和 XO,那么它的信号将被乘以 16(时钟锁相环总是乘以 16),但是会使用 8x,所以系统时钟将会是 4 MHz * 8 = 32 MHz。

CON

Page 187: Propeller Manual - Parallax Home

4: Spin语言参考– _CLKMODE

Propeller Manual v1.0 · Page 187

_CLKMODE = XINPUT + PLL2X

这里将时钟模式设定为外部时钟-震荡器,连接到 XI 引脚,启用了时钟锁相环电

路,将系统时钟设置为使用 2x。如果使用的是 8MHz 的外部时钟-震荡器(晶振),那

么系统时钟将会运行在 16 MHz;也就是 8 MHz * 2。

注意,时钟锁相环不需要倍频设定,如果不使用倍频设定,可以禁运时钟锁相环。

例如:

CON _CLKMODE = XTAL1

这里将时钟模式设定为外部低速晶振,但是不使用时钟锁相环电路;系统时钟等于

外部晶振频率。

_CLKFREQ 和 _XINFREQ 设定 简单起见,上面的例子只列出了 _CLKMODE 设定,但是对象需要 _CLKFREQ 或

_XINFREQ 来决定它实际的系统时钟频率。下面的例子,使用外部晶振(_XINFREQ),

频率为 4 MHz。

CON _CLKMODE = XTAL1 + PLL8X '低速晶振 x 8

_XINFREQ = 4_000_000 '4 MHz的外部晶振

这个例子和第二个例子类似,但是 _XINFREQ 设定指出外部晶振的频率是 4MHz。Propeller 芯片使用它和 _CLKMODE 设定一起决定系统时钟频率(CLKFREQ 返回的内

容),便于对象可以正确地调整其时序。参见 344 页_XINFREQ。

_CLKMODE vs CLKMODE _CLKMODE 和 CLKMODE相关,但两者并不相同 s, CLKMODE。_CLKMODE 是用户应用程序定

义的常量,包含了启动时要求的时钟模式(in the form of clock setting constants that are OR’d together)而 CLKMODE 命令返回的是当前时钟模式( in the form of the CLK register’s bit pattern)。这两者都描述了同样的逻辑时钟模式,但它们的值并不相等。

Page 188: Propeller Manual - Parallax Home

CLKSET – Spin语言参考

Page 188 · Propeller Manual v1.0

CLKSET 在运行时设定时钟模式和系统时钟频率。 ((PUB PRI)) CLKSET (Mode, Frequency)

• Mode 是一个整型表达式,它将被写入 CLK 寄存器改变时钟模式。 • Frequency 是整型表达式,指定了系统时钟频率。

解释

Propeller 芯片 强大的特性之一就是可以在运行时改变时钟的行为。例如,一个应

用程序可以选择在低速时钟(较低的电力消耗)和快速时钟(高带宽运算)之间切。

CLKSET 用于在运行时改变时钟模式和运行的频率。它等同于编译模式下应用程序定义

的_CLKMODE 和_CLKFREQ 常量。例如:

clkset(%01101100, 4_000_000) '设置为 XTAL1 + PLL2x

这里将时钟模式设定为低速外部晶振,时钟锁相环 2 倍频,也就是系统时钟频率

(CLKFREQ) 为 4 MHz。执行了该命令后,CLKMODE 和 CLKFREQ 命令会报告对象的更新设

定。

从内部时钟切换到外部晶振时,需要执行下面的 3 个步骤:

1) 首先,按需要设定 PLLENA,OSCENA,OSCM1 和 OSCM2 位,

2) 等待晶振稳定,时间为 10ms,

3) 设置 CLKSELx 位,将系统时钟切换到新的时钟源。

Propeller 芯片大约需要 75 µs 来执行时钟源转换的动作。

Page 189: Propeller Manual - Parallax Home

4: Spin语言参考– CNT

Propeller Manual v1.0 · Page 189

CNT 系统计数器寄存器。 ((PUB PRI)) CNT

返回: 当前 32 位系统计数器的值。 解释

CNT 寄存器包含了全局 32 位系统计数器的当前值。系统计数器作为所有的 cog 的中

央时钟参考;在每个系统时钟周期,它都会增加它的 32 位值。

在上电/重启动过程中,系统计数器会从一个任意值开始正向计数,每个系统时钟

周期增加一次。因为系统计数器是只读资源,每个 cog 都可以同步读取系统计数器的

值,并将返回值用于同步事件,计算周期和测量时间。

使用 CNT 读取 CNT 可以取得当前的系统计数器的值。这个值本身没有什么意义,但是在连续

读取时获得的差则是很重要的。大多数情况下,CNT 寄存器用于延迟一段指定的周期后

执行或者同步到时间窗口的起点。下一个例子用了 WAITCNT 指令来达到此目的:

waitcnt(3_000_000 + cnt) '等待 3百万个时钟周期

上面的代码是“固定延迟”的例子。它将 cog 的执行延迟了 3 百万个系统时钟(如

果系统运行在内部快速振荡器模式下,大约 ¼ 秒)。

下一个例子则是“同步延迟”。

PUB Toggle | TimeBase, OneMS dira[0]~~ '将 P0 设置为输出

OneMS := clkfreq / 1000 '计算每 1 毫秒的周期数

TimeBase := cnt '取得当前的计数值

repeat '无限循环

waitcnt(TimeBase += OneMS) ' 等待下一个毫秒开始

!outa[0] ' 触发 P0

Page 190: Propeller Manual - Parallax Home

CNT – Spin语言参考

Page 190 · Propeller Manual v1.0

这里,I/O pin 0 被设置为输出。之后本地变量 OneMS 被设置为系统时钟频率的当前

值除 1000;也就是每毫秒系统计数器的周期值。接下来,本地变量 TimeBase 被设置为

当前系统计数器的值。 后的两行程序无限循环执行;等待下一个毫秒开始,然后触

发 P0。

更多的信息参见 329 页 WAITCNT 一节中的固定延迟和 330 页同步延迟。

Page 191: Propeller Manual - Parallax Home

4: Spin语言参考– COGID

Propeller Manual v1.0 · Page 191

COGID 当前 cog 的 ID 号码 (0-7). ((PUB PRI)) COGID

返回: 当前 cog 的 ID (0-7). 解释

COGID 返回的值是执行该命令的 cog 的 ID。通常,运行代码的 cog 是哪个并没什么

关系,但是对一些对象来说,可能需要保持对 cog 的记录,这时就很重要了。例如:

PUB StopMyself '停止正在运行本代码的 cog cogstop(cogid)

该示例中的方法,StopMyself ,有一行简单的调用了 COGSTOP,以 COGID 为参数。

因为 COGID 返回当前运行代码的 Cog 的 ID,该程序会使该 cog 自己停止运行。

Page 192: Propeller Manual - Parallax Home

COGINIT – Spin语言参考

Page 192 · Propeller Manual v1.0

COGINIT 通过 ID 启动或重启动一个 cog 以运行 Spin 代码或 Propeller 汇编代码。 ((PUB PRI)) COGINIT (CogID, SpinMethod ⟨(ParameterList)⟩, StackPointer ) ((PUB PRI)) COGINIT (CogID, AsmAddress, Parameter )

• CogID 是要启动或重启动的 cog 的 ID (0 – 7)。如果 CogID 的值大于 7,会使下

一个可用的 cog 被启动(如果可用)。 • SpinMethod 是 cog 启动后要运行的 PUB 或 PRI Spin 方法。可以选择在括号内写上

该方法的参数。 • ParameterList 是 SpinMethod 方法可选的,逗号分隔的一个或多个参数的列表。

如果 SpinMethod 需要参数,则该项目不可忽略。 • StackPointer 是指向内存的指针,比如一个长字型数组,为要启动的 cog 保留的

堆栈空间。该 cog 使用这个空间存储临时数据,这些临时数据来自方法调用和

表达式计算。如果指定的空间不足,应用程序可能会不能正常运行。 • AsmAddress DAT 块中一段 Propeller 汇编程序的地址。 • Parameter 可选的,用于向新 cog 传递一个值。该值存储在新 cog 的只读的 Cog

启动参数寄存器(PAR)中。Parameter 可以被用于向 cog 传递一个 14 位的值,

或由 Propller 汇编程序使用的内存块地址。 COGINIT命令需要 Parameter 作为参

数,但是如果你的程序中不需要,请将它设置为无关值,比如零(0)。 解释

COGINIT 工作时类似于 COGNEW,但是有两点不同:1) 它可以在指定的 cog(由

CogID 指定)上运行程序。2) 它没有返回值。因为 COGINIT 作用于由 CogID 指定的

Cog,所以它可以被用于一步停止或激活 Cog。包括了当前的 cog;换句话说一个 cog可以使用 COGINIT 命令来停止自身的运行或重新启动运行另外一段代码。

Spin 代码 (语法 1) 要在指定的 cog 上运行 Spin 方法, COGINIT 命令需要 cog ID,方法的名称,方法的

参数,和一个指向某个堆栈空间的指针作为参数。例如:

coginit(1, Square(@X), @SqStack) '在 Cog 1上启动 Square

Page 193: Propeller Manual - Parallax Home

4: Spin语言参考– COGINIT

Propeller Manual v1.0 · Page 193

这个例子在 cog 1 中启动了 Square 方法,将 X传递给 Square,并将 SqStack 的地址

作为 COGINIT的堆栈指针。更多信息参见 194 页 COGNEW。

Propeller 汇编代码 (语法 2) 要在指定的 cog 上运行 Propeller 汇编代码,COGINIT 命令需要 cog ID,汇编程序的

地址,和一个可选的,汇编程序使用的值,作为参数。例如:

coginit(2, @Update, Pos)

这个例子在 Cog 2 上运行 Propeller 汇编程序 Update,并将 Pos 的值写入 Cog 2 的 PAR 参数。更多信息参见 194 页 COGNEW。

Page 194: Propeller Manual - Parallax Home

COGNEW – Spin语言参考

Page 194 · Propeller Manual v1.0

COGNEW 启动下一个可用的 cog 来运行 Spin 代码或 Propeller 汇编语言程序。 ((PUB PRI)) COGNEW (SpinMethod ⟨(ParameterList)⟩, StackPointer ) ((PUB PRI)) COGNEW (AsmAddress, Parameter ) 返回: 如果启动成功,则返回 cog 的 ID(0-7),否则返回-1。

• SpinMethod 是新启用的 cog 要运行的 PUB 或 PRI Spin 方法。可以有写在括号中的

可选参数列表。 • ParameterList 是可选的,逗号分隔的 SpinMethod 的参数列表。如果 SpinMethod

需要参数,则该项不可省略。 • StackPointer 是指向内存的指针,例如一个长字数组,该内存是为新 cog 而保留

的堆栈空间。新的 cog 使用该空间存储临时数据,这些临时数据来自方法调用

和表达式计算。如果没有分配足够的空间,应用程序可能不能正常运行。 • AsmAddress Propeller 汇编程序的地址,该汇编程序来自一个 DAT 块。 • Parameter 可选的,用于向新 cog 传递一个值。该值存储在新 cog 的只读的 Cog

启动参数寄存器(PAR)中。Parameter 可以被用于向 cog 传递一个 14 位的值,

或由 Propller 汇编程序使用的内存块地址。 COGINIT命令需要 Parameter 作为参

数,但是如果你的程序中不需要,请将它设置为无关值,比如零(0)。 解释

COGNEW 启动一个新的 cog 并在新的 cog 上运行一个 Spin 方法或者一段 Propeller 汇编程序。如果启动成功 COGNEW 会返回新启动的 cog 的 ID。如果没有可用的 cog,则

COGNEW 返回-1。

Page 195: Propeller Manual - Parallax Home

4: Spin语言参考– COGNEW

Propeller Manual v1.0 · Page 195

Spin 代码 (语法 1) 要在另一个 cog 上运行 Spin 方法, COGNEW 命令需要方法的名称,该方法的参数,和一

个指向堆栈空间的指针作为参数。例如:

VAR long SqStack[6] 'Stack space for Square cog PUB Main | X X := 2 'Initialize X cognew(Square(@X), @SqStack) 'Launch square cog <check X here> 'Loop here and check X PUB Square(XAddr) 'Square the value at XAddr repeat 'Repeat the following endlessly long[XAddr] *= long[XAddr] ' Square value, store back waitcnt(2_000_000 + cnt) ' Wait 2 million cycles

上面的例子演示了两个方法,Main 和 Square。Main 启动了另一个 cog 来运行

Square 方法,而 Main 方法可以监视变量 X 的结果。Square 方法由另一个 cog 运行,取

得 XAddr的值,将其平方后将结果存储回 XAddr中,之后等待 2 百万个周期再次执行。

接下来会有更多解释,X 的起始值为 2,第二个 cog 运行 Square方法,使 X 的值变为 4, 16, 256, 65536 终为 0(溢出了 32 位),其它的 cog 都可以检查 X 的值并据此执行另

外一些动作。

Main 方法声明了一个本地变量,X,在第一行被设置为 2。然后 Main 用 COGNEW 命令

启动一个新的 cog 来运行 Square 方法。COGNEW 的第一个参数 Square(@X),是要运行的

Spin 方法和它的参数;这个例子中我们向它传递了变量 X 的地址。COGNEW 的第二个参

数@SqStack,是为新的 cog 保留的堆栈空间。当一个 cog 运行 Spin 代码时,它需要一

些堆栈空间来存储临时数据,例如调用堆栈,参数,和表达式中间值等。这个例子中

只需要 6 个长字的堆栈空间来工作。(更多信息参见 Propeller 库对象“堆栈长度

(Stack Length)”)。

在 COGNEW 命令执行后,有两个 cog 在运行;第一个仍然在运行 Main 方法,第二个

启动后运行 Square 方法。尽管它们运行的代码都来自同一个 Spin 对象,但是它们是彼

Page 196: Propeller Manual - Parallax Home

COGNEW – Spin语言参考

Page 196 · Propeller Manual v1.0

此独立运行的。语句“<check X here>”可以被用户代码替代,这些代码以某些方式处

理 X 的值。

Propeller 汇编代码 (语法 2) 要在另一个 cog 上运行 Propeller 汇编代码,COGNEW 命令需要该汇编程序的地址和一

个可选的用于该程序的值。例如:

VAR byte Cog '用于存储新启动的 cog的 ID PUB Start(Pos) : Pass '启动新的 cog来运行 Update,参数为 Pos,

'如果成功,返回 TRUE Pass := (Cog := cognew(@Update, Pos) + 1) > 0 PUB Stop '停止之前启动的 cog if Cog cogstop(Cog~ - 1)

上面的例子演示了在一个已定义的理想对象中的两个方法,Start 和 Stop。设计对

象时要求启动另一个 cog 运行汇编程序 Update(未列出),并向它传递参数 Pos。之后

我们可能要停止该 cog。

Start方法用到了一个参数,Pos,并返回 TRUE 或 FALSE 来表明新的 cog 是否启动成

功。首先,它调用 COGNEW,“cognew(@Update, Pos)”,将 Update 程序的地址作为第一

个参数,Pos 作为第二个参数。此外,它将 COGNEW 的返回值,新启用的 cog 的 ID 否则

返回-1,加 1 后存储在变量 Cog 中;“Cog := cognew(@Update, Pos) + 1”。 后,如

果 Cog 大于 0,它会将返回值 Pass 设置为 TRUE;否则为 FALSE。如果新的 cog 启动成

功,它会载入名为 Update,的汇编程序并运行它。同时,对象的 Cog 变量(在原有的

cog 中)的范围是 1 到 8,表示新的 cog 的 ID 是 0 到 7。如果没有可用的 cog,Cog 将等于 0。

Page 197: Propeller Manual - Parallax Home

4: Spin语言参考– COGNEW

Propeller Manual v1.0 · Page 197

之后,如果 Stop 方法被调用,它会首先检查条件 “if Cog”。该条件只有当 Cog 为非零值时才为真。如果为真(也就是说 Start 程序成功的启用一个新的 cog)那么就会

执行下一行“cogstop(Cog~ - 1)”,并传递将要停止的 cog 的 ID,“Cog~ - 1”。表达

式 Cog~ - 1 返回的是 COGSTOP 的参数:Cog – 1。然后将变量 Cog 清零(0)。因为在停止

cog 后, Cog 被清零,所以以后任何对 Stop 方法的偶然调用都不会将不是该对象启动

的 cog 停止。

这个例子可以有些改进,那就是在 Start 方法中先调用 Stop 方法,这是为了防止

对象在同一行两次调用 Start 方法。例如:

PUB Start(Pos) : Pass '启动新的 cog来运行 Update,参数为 Pos,

'如果成功,返回 TRUE Stop Pass := (Cog := cognew(@Update, Pos) + 1) > 0

应该注意到 Parameter 域是用于传递一个长字地址,所以只有 14 位(bit2 到 bit5)会被传递到 cog 的 PAR 寄存器。

Page 198: Propeller Manual - Parallax Home

COGSTOP – Spin语言参考

Page 198 · Propeller Manual v1.0

COGSTOP 通过 ID 停止 cog。 ((PUB PRI)) COGSTOP (CogID )

• CogID 是要停止的 cog 的 ID (0 – 7)。 解释

COGSTOP 将 ID 为 CogID a 的 cog 停止运行,使其进入休眠状态。在休眠状态下,该

cog 不再接收系统时钟脉冲,所以可以降低电力消耗。

要停止一个 cog,使用 COGSTOP 命令和要停止的 cog 的 ID。例如:

VAR byte Cog '用于存储新启用的 cog的 ID PUB Start(Pos) : Pass '启动新的 cog来运行 Update,参数为 Pos,

'如果成功,返回 TRUE Pass := (Cog := cognew(@Update, Pos) + 1) > 0 PUB Stop '停止之前启动的 cog if Cog cogstop(Cog~ - 1)

这个例子在 Stop 方法中使用了 COGSTOP 来停止之前由 Start 方法启用的 cog。该例

子的更多信息参见 194 页的 COGNEW。

Page 199: Propeller Manual - Parallax Home

4: Spin语言参考– CON

Propeller Manual v1.0 · Page 199

CON 声明一个常量块。 CON Symbol = Expression ⟨(( , )) Symbol = Expression⟩… CON #Expression (( , )) Symbol ⟨[Offset]⟩ ⟨(( , )) Symbol⟩⟨[Offset]⟩… CON Symbol ⟨[Offset]⟩ ⟨(( , )) Symbol ⟨[Offset]⟩ ⟩…

• Symbol 是希望的常量名称。 • Expression 可以是任何有效的整型,或浮点常量算数表达式。表达式中可以包含

其它任何已定义的常量符号。 • Offset 是可选的表达式,用于调整枚举中 Symbol 的相对于上一个的值。如果没

有指定 Offset,则默认使用 1。使用 Offset,来调整枚举值,而不是使用 Symbol 的值加 1。

解释

常量块是源代码的一节,它声明了全局常量符号和全局 Propeller 配置设定。它是

六条特殊声明(CON, VAR, OBJ, PUB, PRI, 和 DAT)之一,它们提供了 Spin 语言的内在结

构。

数值型常量不能在运行时被更改。它们可以按照单值(1, $F, 65000, %1010, %%2310, “A”)或表达式,称为常量表达式(25 + 16 / 2, 1000 * 5), 终会被解析成

一个数值。

常量块是一段专用的代码区域,在这里将常量赋值给符号(有用的名称),这些符

号可以用在程序中需要常量的地方。这使得代码更具有可读性和易于维护。这些常量

在对象内是全局的,所有在该对象内声明的方法都可以使用它们。接下来描述不同的

定义常量的方法。

普通常量声明 (语法 1) 常量声明 常用的形式是由 CON 开始,之后是一个或多个声明。CON 必须从本行第

一列开始( 左边的列),之后的声明至少要比该行缩进一个空格。表达式可以包含

Page 200: Propeller Manual - Parallax Home

CON – Spin语言参考

Page 200 · Propeller Manual v1.0

数字,运算符,括号组合以及字符等。参见 255 页,运算符中所列出更多表达式的例

子。

例如:

CON Delay = 500 Baud = 9600 AChar = "A" —或—

CON Delay = 500, Baud = 9600, AChar = "A"

这两个例子都创建了名为 Delay ,等于 500 的符号,名为 Baud,等于 9600 的符号 和等于字符“A”的符号 AChar。以 Delay 的声明为例,我们也可以使用算术表达式进

行声明。例如:

Delay = 250 * 2

和之前结果一样,上面的语句会使 Delay 等于 500,但是使用表达式而不是一个代

数值可以让代码更易懂。

CON 块也可以用于指定全局设定,例如系统时钟设定。下面的例子演示了如何将时

钟模式设置为低速晶振,时钟锁相环设置为 8x,并指定从 XIN 引脚输入的频率值是

4MHz。

CON _CLKMODE = XTAL1 + PLL8X _XINFREQ = 4_000_000

这些设定的细节描述参见 185 页_CLKMODE,和 344 页_XINFREQ。

浮点值也可以被定义为常量。浮点数是实数(有小数部分),它们以 32 位的方式

存储,与整型常量不同。要指定浮点常量,必须明确定义一个值是浮点值;即表达式

必须是浮点型货全部由浮点值组成(没有整型值)。

浮点值必须被写成:

1) 十进制数值后跟随十进制小数点,至少有一位十进制小数,或

Page 201: Propeller Manual - Parallax Home

4: Spin语言参考– CON

Propeller Manual v1.0 · Page 201

2) 十进制数值后有一个“e”(意思是指数),以及一个整型指数值,或 3) 方法 1,2 的组合。 下面的例子是有效的常量:

0.5 浮点值

1.0 浮点值

3.14 浮点值

1e16 浮点值

51.025e5 浮点值

3 + 4 整型表达式

3.0 + 4.0 浮点表达式

3.0 + 4 无效表达式,编译出错

3.0 + FLOAT(4) 浮点表达式

下面的例子声明了一个整型常量和两个浮点型常量。

CON Num1 = 20 Num2 = 127.38 Num3 = 32.05 * 18.1 - Num2 / float(Num1)

上面的代码分别将 Num1, Num2 和 Num3 设置为 20, 127.38 和 573.736。 注意 后一个

表达式中,必须将 Num1 写在 FLOAT 声明的括号中,这样编译器就可以将其作为浮点值

进行运算。

Propeller 编译器将浮点产量作为单精度实数进行计算,如 IEEE-754 标准所描述的

那样。单精度实数以 32 位存储,它有 1 位符号位,8 位指数,和 23 位尾数数(小数部

分),这样可以有大约 7.2 有效的十进制位。

对于运行时浮点运算,Propeller 提供了能兼容于单精度数运算的 FloatMath 和 FloatString 对象。

更多信息参见 221 页 FLOAT,309 页 ROUND,320 页 TRUNC,以及 FloatMath 和 FloatString 对象。

Page 202: Propeller Manual - Parallax Home

CON – Spin语言参考

Page 202 · Propeller Manual v1.0

枚举 (语法 2 和 3) 常量块也可以声明枚举常量符号。枚举是逻辑上组合在一起的符号,它们的整型值

依次增加。例如,一个对象可能需要多种操作模式。这些操作模式可以被标示为数

字,例如 0, 1, 2 和 3。这些数字的数值本身没什么意义,它们只是区别不同的操作模

式。因为数字本身不具有描述意义,所以很难记住模式 3 的功能是什么,但是如果能

有一个描述性的名字,那么就很容易记住该模式的意思了。参考下面的例子:

CON '声明操作模式 RunTest = 0 RunVerbose = 1 RunBrief = 2 RunFull = 3

上面的例子能够满足我们的要求;现在我们的对象的用户可以用“RunFull”代替

“3”来指定希望的操作模式。这里的问题是,以这种方法定的逻辑组可能会有漏洞和

代码维护上的问题,因为如果有任何的值被改变(无论是有意或无意),而没有修改

剩下的值,可能会导致程序崩溃。同样的,试想假如有 20 个操作模式,那么这将是一

个很长的常量列表,也会带来更多的代码维护上的问题。

枚举通过自动为符号赋值来解决这些问题,赋值的方式是自动为每个值赋予递增的

值。我们以枚举方式来重写上述代码如下:

CON '声明操作模式 #0, RunTest, RunVerbose, RunBrief, RunFull

这里,#0,告诉编译器从 0 开始计数,它会将下一个符号设置为那个值。之后任何

没有以赋值方式指定值的符号会被赋值为前面的值加一。结果是 RunTest 等于 0,RunVerbose 等于 1,RunBrief 等于 2,RunFull 等于 3。大多数情况下,这些数值本身没

什么意义,只要它们彼此不同就可以了。这样定义的枚举值可以确保彼此之间的值是

不同的,以及数值在组中的连续性。

Page 203: Propeller Manual - Parallax Home

4: Spin语言参考– CON

Propeller Manual v1.0 · Page 203

使用上面的例子,可以编写一个方法来使用它们(假定 Mode 是要调用的符号集):

case Mode RunTest : <test code here> RunVerbose : <verbose code here> RunBrief : <brief code here> RunFull : <full code here> —或—

if Mode > RunVerbose <brief and run mode code here>

注意,这些程序并不会依赖这些模式的本身的数值,对程序而言真正重要的是这些

符号在枚举列表中的位置。以该方法编写的代码可以降低由以后对程序的改动而带来

的潜在的风险。

枚举并不一定需要由逗号分隔的内容组成,下面的例子也达到了和上面的例子同样

的功能,但是在每行的右侧为注释留下了空间。

CON '声明操作模式 #0 RunTest 'Run in test mode RunVerbose 'Run in verbose mode RunBrief 'Run with brief prompts RunFull 'Run in full production mode

这个例子和上面的例子作了同样的事情,但是现在我们有足够的空间来添加每行代

码的注释,同时又不影响符号自动增量的特性。此后如果需要添加第五种模式只要将

其添加到列表中就可以了。如果需要指定列表的起始值,只要把#0 改为需要的值就可

以了,如#1,#20等等。

也可以在列表的中间修改枚举值。

CON '声明操作模式 #1, RunTest, RunVerbose, #5, RunBrief, RunFull

这里,RunTest,RunVerbose,RunBrief,和 RunFull 分别是 1,2,5 和 6。这一特性

用起来会比较方便,但是要养成良好的编程习惯,应该少用。

Page 204: Propeller Manual - Parallax Home

CON – Spin语言参考

Page 204 · Propeller Manual v1.0

要达到这个例子中的效果,推荐的方法是使用可选的 Offset,上面的例子可以改写

为:

CON '声明操作模式 #1, RunTest, RunVerbose[3], RunBrief, RunFull

就像之前所描述的一样,RunTest 和 RunVerbose 被分别设置为 1 和 2。在

RunVerbose 之后的[3]使当前的枚举值由 2 增加到 3,所达到的效果和之前是一样的,

也就是 RunBrief和 RunFull被分别设置为 5 和 6。该技术的优点在于,尽管枚举内的值

都是相关的,改变枚举值的起始值就可以将其全部改变。例如,将#1 改为#4 会使

RunTest和 RunVerbose被分别设置为 4和 5,RunBrief和 RunFull被分别设置为 8 和 9。相

反,在原来的例子中,如果将#1 改为#4,会使 RunVerbose 和 RunBrief 都变成 5,这会

导致依靠这些符号运作的代码出现误动作。

语法 3 是枚举声明的变体。它不会指定任何起始值。

以该方式定义的第一个符号的值是等于 0(新的 CON 块)或等于下一个枚举值(同

一个 CON 块)。这里的“下一个”是指此前有定义过枚举中的下一个值。

常量作用域 在常量块中定义的符号常量在其所定义的对象内是全局的。就是说在对象内部可以

直接访问这些常量,但是常量的名字不会和父对象或子对象中的符号名相冲突。

符号常量可由父对象使用常量引用语法间接访问。例如

OBJ Num : "Numbers" PUB SomeRoutine Format := Num#DEC '将 Format设置为 Number的 Decimal常量

这里,一个对象“Numbers”被声明为符号 Num。之后,一个方法使用 Num#DEC 引用

到了 numbers 的 DEC 常量。Num 是对象引用,# 表明我们要访问对象的常量,DEC 是我

们所需要的对象内的常量。该特性允许对象定义的常量可供父对象和自身使用,这样

父对象访问这些常量时就不会受自己创建的符号干扰。.

Page 205: Propeller Manual - Parallax Home

4: Spin语言参考– CONSTANT

Propeller Manual v1.0 · Page 205

CONSTANT 声明内联的常量表达式,在编译时解析。 ((PUB PRI)) CONSTANT (ConstantExpression ) 返回: 常量表达式的解析值。

• ConstantExpression 是希望的常量表达式。 解释

CON 块可以被用于建立以表达式形式描述的常量,这些常量可以在之后的代码中被

引用,但是很少会因临时需要而使用将常量表达式。CONSTANT 用于在编译时将方法的

内联表达式完全解析。如果不使用 CONSTANT 指令,一个方法的内联表达式会在运行时

解析,即使该表达式是总一个常量值时也是如此。

使用 CONSTANT CONSTANT 指令可以建立一次性使用的常量表达式,以节省代码空间和加速程序运

行。请参考下面两个例子:

示例 1, 使用标准运行时表达式:

CON X = 500 Y = 2500 PUB Blink !outa[0] waitcnt(X+200 + cnt) '标准运行时表达式 !outa[0] waitcnt((X+Y)/2 + cnt) '标准运行时表达式

示例 2, 与上例相同,但是在常量和运行时表达式外使用 CONSTANT 指令:

Page 206: Propeller Manual - Parallax Home

CONSTANT – Spin语言参考

Page 206 · Propeller Manual v1.0

CON X = 500 Y = 2500 PUB Blink !outa[0] waitcnt(constant(X+200) + cnt) 'exp w/compile & run-time parts !outa[0] waitcnt(constant((X+Y)/2) + cnt)'exp w/compile & run-time parts

上述两个例子做了两件同样的事:它们的 Blink 方法触发 P0, 等待 X+200 个周期,

再次触发 P0 并在返回前等待(X+Y)/ 2 个周期。CON 块中的 X 和 Y 符号可能会用在对

象中的多处,而每个例子中 Blink 方法的 WAITCNT 表达式只会用到一次。因此,在 CON 块中定义额外的常量,如 X+200 和 (X+Y)/2,没什么意义。把表达式放在运行时代码中

并没有错,就像例子1那样,但是整个表达式会在运行时被计算,这会占用额外的时

间和代码空间。

CONSTANT 指令适用于这种情况,因为它会将表达式完全解析为单值,静态的值,节

省了代码空间并提高了执行速度。在例子 1 中,Blink m 方法消耗了 33 字节的代码空

间,而例子 2 的 Blink 方法,使用了 CONSTANT 指令,只需要 23 个字节的空间。注意表

达式中 “+ cnt” 的部分不是包含在 CONSTANT 指令的括号中的;这是因为 cnt 是一个变

量(系统计数器变量,参见 189 页 CNT),所以它不能在编译时解析。

如果在代码中多处需要同一个常量值, 好将其在 CON 块中定义,这样就可以在代

码中使用该常量的符号来简化工作。

Page 207: Propeller Manual - Parallax Home

4: Spin语言参考– (常量 (预定义))Constants (pre-defined)

Propeller Manual v1.0 · Page 207

常量 (预定义)

下列常量已由编译器预定义:

TRUE 逻辑真: -1 ($FFFFFFFF)

FALSE 逻辑假: 0 ($00000000)

POSX 大正整数: 2,147,483,647 ($7FFFFFFF)

NEGX 大负整数: -2,147,483,648 ($80000000)

PI 圆周率(PI)的浮点值: ≈ 3.141593 ($40490FDB)

RCFAST 内部快速振荡器: $00000001 (%00000000001)

RCSLOW 内部低速振荡器: $00000002 (%00000000010)

XINPUT 外部时钟/振荡器: $00000004 (%00000000100)

XTAL1 外部低速晶振: $00000008 (%00000001000)

XTAL2 外部中速晶振: $00000010 (%00000010000)

XTAL3 外部快速晶振: $00000020 (%00000100000)

PLL1X 1 倍外部时钟频率: $00000040 (%00001000000)

PLL2X 2 倍外部时钟频率: $00000080 (%00010000000)

PLL4X 4 倍外部时钟频率: $00000100 (%00100000000)

PLL8X 8 倍外部时钟频率: $00000200 (%01000000000)

PLL16X 16 倍外部时钟频率: $00000400 (%10000000000)

(上述常量也可用于 Propeller 汇编语言)

TRUE 和 FALSE TRUE 和 FALSE 通常用于布尔比较:

if (X = TRUE) or (Y = FALSE)

Page 208: Propeller Manual - Parallax Home

(常量 (预定义))Constants (pre-defined) – Spin语言参考

Page 208 · Propeller Manual v1.0

<code to execute if total condition is true>

POSX 和 NEGX POSX 和 NEGX 通常用于比较或作为特殊事件的标志:

if Z > NEGX <code to execute if Z hasn't reached smallest negative>

—或—

PUB FindListItem(Item) : Index Index := NEGX 'Default to "not found" response <code to find Item in list> if <item found> Index := <items index>

PI PI 可用于浮点计算,也可作为浮点常量或在使用 FloatMath 和 FloatString 对象的浮

点变量。

RCFAST through PLL16X RCFAST through PLL16X 是时钟模式设定常量。这些内容会在 180 页开始的_CLKMODE

一节中进一步解释。

Page 209: Propeller Manual - Parallax Home

4: Spin语言参考– CTRA, CTRB

Propeller Manual v1.0 · Page 209

CTRA, CTRB 计数器 A 和计数器 B 控制寄存器。 ((PUB PRI)) CTRA ((PUB PRI)) CTRB

返回: 如果作为源变量时,计数器 A 或计数器 B 控制寄存器的当前值。 解释

CTRA 和 CTRB 是六个影响 Cog 计数器模块行为的寄存器中的两个(CTRA, CTRB, FRQA, FRQB, PHSA, 和 PHSB) 。每个 cog 有两个相同的计数器模块(A 和 B),可以执行重复的

任务。 CTRA 和 CTRB r 寄存器包含了计数器 A 和计数器 B 模块相应的配置信息。

下面的讨论中使用了 CTRx, FRQx and PHSx 来表示每个寄存器对应的 A 和 B 对。

两个计数器单元中的任一个可以控制或监控两个 I/O 引脚,以及在每个时钟周期执

行有条件的,FRQx 寄存器中数值的 32 位累加,计算的结果会写入 PHSx 寄存器。每个

计数器单元都有独立的锁相环(PLLx),可以用于同步 64 MHz 到 128 MHz 的频率。

通过调整配置和有些时候来自 Cog 的适当的维护,计数器模块可用于:

• 频率合成

• 频率测量

• 脉冲计数

• 脉冲测量

• 多引脚状态测量

• 脉冲宽度调制 (PWM)

• 占空比测量

• 数/模转换 (DAC)

• 模/数转换 (ADC)

• 更多…

对上述一些操作,cog 可以通过 CTRA 和 CTRB 来设置计数器的配置,使其可以执行

完全独立的任务。而对另一些,cog 可以通过使用 WAITCNT 来使一个循环内的计数器读

写操作能时间对位;创建更复杂的状态机效果。因为计数器的刷新周期可以很短

(80MHz 时 12.5ns),使得动态信号的发生和测量都成为可能。

控制寄存器域 CTRA 和 CTRB 寄存器都包含了下表中所列出的四个域。

Page 210: Propeller Manual - Parallax Home

CTRA, CTRB – Spin语言参考

Page 210 · Propeller Manual v1.0

表 4-5: CTRA 和 CTRB R 寄存器

31 30..26 25..23 22..15 14..9 8..6 5..0 - CTRMODE PLLDIV - BPIN - APIN

APIN

CTRA 的 APIN 域选择了该计数器的主 I/O 引脚。如果不使用可以被忽略。%0xxxxx = Port A, %1xxxxx = Port B (为以后使用保留)。在 Propeller 汇编语言中,APIN 域可通

过 MOVS 指令方便地写入。

注意向 CTRA 写入 0 会立刻禁用计数器 A,并停止相关的引脚输出和 PHSA 累加。

BPIN CTRx 的 BPIN 域选择了计数器的辅助 I/O 引脚。如果不使用可以被忽略。%0xxxxx

= Port A, %1xxxxx = Port B (为以后使用保留)。在 Propeller 汇编语言中,BPIN 域可通

过 MOVD指令方便地写入。

PLLDIV CTRx 的 PLLDIV 域选择一个 PLLx 输出 tap, 参见下表。这表明 VCO 频率与 2 的

幂相除后的结果会被用作 终的 PLLx 输出 (范围从 500 KHz 到 128 MHz)。 如果不使

用可以忽略。在 Propeller 汇编语言中 PLLDIV 域可以和 CTRMODE 一起,通过 MOVI指令写入。

表 4-6: PLLDIV Field PLLDIV %000 %001 %010 %011 %100 %101 %110 %111 输出 VCO ÷ 128 VCO ÷ 64 VCO ÷ 32 VCO ÷ 16 VCO ÷ 8 VCO ÷ 4 VCO ÷ 2 VCO ÷ 1

Page 211: Propeller Manual - Parallax Home

4: Spin语言参考– CTRA, CTRB

Propeller Manual v1.0 · Page 211

CTRMODE CTRA 和 CTRB 的 CTRMODE 域从 32 种操作模式中选择一种,如表 4-7,分别对

应计数器 A 或计数器 B。在 Propeller 汇编语言中,CTRMODE 域可以和 PLLDIV 一起

通过 MOVI 指令写入。

模式%00001 到%00011 会使 FRQx-to-PHSx, 每个时钟周期累加发生一次。这会在

PHS[31]中创建一个数控振荡器(NCO),其依赖于 PLLx 的参考输入。PLLx 会使用

压控振荡器(VCO) 将该频率16倍频。

要稳定操作,推荐 VCO 频率保持在 64 MHz 到 128 MHz 之间,该值转换为 NCO频率后为 4 MHz 到 8 MHz.

使用 CTRA 和 CTRB 在 Spin 语言中,CTRx 可以像其他寄存器或预定义的变量一样被读写。当该寄存器

被写入,新的操作模式会对该寄存器立即生效。参考下面的例子:

CTRA := %00100 << 26

上面的代码将 CTRA的 CTRMODE 域设置为 NCO 模式 (%00100) ,同时设置其它位

为 0。

Page 212: Propeller Manual - Parallax Home

CTRA, CTRB – Spin语言参考

Page 212 · Propeller Manual v1.0

表 4-7: 计数器模式 (CTRMODE 域值)

CTRMODE 描述 累加 FRQx to PHSx

APIN 输出*

BPIN 输出*

%00000 禁用计数器 (off) 0 (never) 0 (none) 0 (none)

%00001 %00010 %00011

PLL 内部(视频模式) PLL 单端 PLL 差分

1 (always) 1 1

0 PLLx PLLx

0 0 !PLLx

%00100 %00101

NCO/PWM single-ended NCO/PWM differential

1 1

PHSx[31] PHSx[31]

0 !PHSx[31]

%00110 %00111

DUTY single-ended DUTY differential

1 1

PHSx-Carry PHSx-Carry

0 !PHSx-Carry

%01000 %01001 %01010 %01011

POS detector POS detector with feedback POSEDGE detector POSEDGE detector w/ feedback

A1 A1 A1 & !A2 A1 & !A2

0 0 0 0

0 !A1 0 !A1

%01100 %01101 %01110 %01111

NEG detector NEG detector with feedback NEGEDGE detector NEGEDGE detector w/ feedback

!A1 !A1 !A1 & A2 !A1 & A2

0 0 0 0

0 !A1 0 !A1

%10000 %10001 %10010 %10011 %10100 %10101 %10110 %10111 %11000 %11001 %11010 %11011 %11100 %11101 %11110 %11111

LOGIC never LOGIC !A & !B LOGIC A & !B LOGIC !B LOGIC !A & B LOGIC !A LOGIC A <> B LOGIC !A | !B LOGIC A & B LOGIC A == B LOGIC A LOGIC A | !B LOGIC B LOGIC !A | B LOGIC A | B LOGIC always

0 !A1 & !B1 A1 & !B1 !B1 !A1 & B1 !A1 A1 <> B1 !A1 | !B1 A1 & B1 A1 == B1 A1 A1 | !B1 B1 !A1 | B1 A1 | B1 1

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

*必须设置相应的引脚的 DIR 位 A1 = APIN input delayed by 1 clock A2 = APIN input delayed by 2 clocks B1 = BPIN input delayed by 1 clock

Page 213: Propeller Manual - Parallax Home

4: Spin语言参考– DAT

Propeller Manual v1.0 · Page 213

DAT 声明一个数据块。 DAT ⟨Symbol⟩ Alignment ⟨Size⟩ ⟨Data⟩ ⟨, ⟨Size⟩ Data⟩… DAT ⟨Symbol⟩ ⟨Condition⟩ Instruction ⟨Effect(s)⟩

• Symbol 是可选的数据名,保留空间,或指令。 • Alignment 是希望的数据对齐方式和默认的大小(BYTE, WORD, 或 LONG)。 • Size 是数据希望的大小 (BYTE, WORD, 或 LONG);对齐方式不会改变。 • Data 是常量表达式或逗号分隔的常量表达式列表。也可以是引号中的字符;它

们会被作为逗号分隔的字符表进行处理。 • Condition 是汇编语言条件, IF_C, IF_NC, IF_Z, 等。 • Instruction 是汇编语言指令, ADD, SUB, MOV, 等, 以及其运算域。 • Effect(s) 是一个,两个或三个指定的汇编语言的效果,即是否使指令写入, NR, WR,

WC, 或 WZ。 解释

一个 Data 块是源代码的一部分,包含了预定义数据,为汇编代码保留的运行时内

存空间。这是 6 个特殊声明(CON, VAR, OBJ, PUB, PRI, 和 DAT) 为 Spin 语言提供了固有结

构。

数据块是源代码的多用途块,可用于数据表,运行时空间,和 Propeller 汇编代

码。如果有必要,汇编代码和数据可以混合,这样数据就会随着汇编代码一起载入

cog。

声明数据 (语法 1) 数据必须要被指定对齐方式和大小(BYTE, WORD, 或 LONG)来表明它应该如何在内存

中存储。因为数据是被编译进对象中作为编译代码的一部分的,所以数据实际存储的

位置与应用程序和对象的结构有关。

例如: DAT byte 64, "A", "String", 0

Page 214: Propeller Manual - Parallax Home

DAT – Spin语言参考

Page 214 · Propeller Manual v1.0

word $FFC2, 75000 long $44332211, 32

这个例子的第二行中,BYTE 表明接下来的数据是字节对齐,字节型的值。在编译

时,BYTE所声明的数据,也就是 64, “A”会从程序内存的下一个可用的地址开始,每次

存储一个。第三行指定的是字对齐和字节对齐数据。其数据$FFC2 和 75000,会从下一

个字边界位置开始存储,用零字节来填充从上一个数据到下一个字边界之间的空间。

第四行指定了长字对齐的数据;这些数据会从下一个长字边界开始存储,该长字边界

从之前的字对齐数据后开始。用零字填充到长字边界之间的空间。表 4-8 所示为上述

情况在内存中的情形(以十六进制显示)。

表 4-8: 内存中的数据 L 0 2 3 4 5 6 W 0 1 2 3 4 5 6 7 8 9 10 11 B 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 D 40 41 53 74 72 69 6E 67 00 00 C2 FF F8 24 00 00 11 22 33 44 20 00 00 00

L = 长字, W = 字, B = 字节, D = 数据

前 9 个字节(0-8)是第一行的数据;也就是$40 = 64 (十进制),$41 = “A”, $53 = “S”。第九字节用零填充以便将第一个字数据对齐到字的位置,就是在第 10 字节的

$FFC2。第 10 和第 11 字节(第 5 个字)包含了第一个字的值$FFC2,以低字节优先存

储的方式存储,也就是$C2,$FF。第 12 和第 13 字节(第 6 个字)是 75000 的 低的

字;第 14 和第 15(第 7 个字)用零填充,将第一个长字数据,$44332211,对齐到长

字的位置。第 16 字节到第 19 字节(第 5 个长字)包含的值是低字节优先存储的。

后,第 20 到第 23 字节(第 6 个长字)包含的数据 32 的第二个长字,低字节优先存

储。

你可能已经注意到了 75000 被指定为一个字型值。数值 75000 的十六进制形式是

$124F8,但是这个值比一个字(word)要大,只会有 低位的值($24F8)被存储。 这使

第 6 个字(第 12 和 13 字节)包含的是$F8 和$24,第 7 个字(第 14 和 15 字节)包含

的是$00 和$00,将下一个数据(长字)对齐到长字的位置。

这种现象不论是否是有意的,都出现在字节对齐/字节型数据中。例如:

DAT byte $FFAA, $BB995511

...结果是只能存储每个值得 低位,$AA 和 $11 被存储在连续的位置中。

Page 215: Propeller Manual - Parallax Home

4: Spin语言参考– DAT

Propeller Manual v1.0 · Page 215

有时候希望将一个较大的值以较小的单位存储,而不必对齐到该值自身的形式。要

做到这一点,可以先调整该值的类型。

DAT byte word $FFAA, long $BB995511

这个例子指定的是字节对齐的数据,但是有字型的数据和长字型数据。结果是内存

中会连续存储$AA 和 $FF,然后是 $11, $55, $99 和 $BB。

如果我们修改第三行的程序,改为下列内容:

word $FFC2, long 75000

...那么我们在第 12 到第 15 字节的值就是$F8, $24, $01, 和 $00。第 15 字节是高位 字节,它刚好对齐到下一个长字边界的左侧,所以不需要添加额外的 0 字节将其对齐

到下一个长字对齐位置。

语法 1 的 Symbol 域可以包含数据的名字(“name”),这样从 PUB 或 PRI 块中引

用这些数据就可以很容易。例如:

DAT MyData byte $FF, 25, %1010 PUB GetData | Temp Temp := MyData[0] '读取数据表的第一个字节

这个例子创建一个名为 MyData 的数据表,它由字节值$FF, 25 和 %1010 组成。公共

方法 GetData读取 MyData 的第一的个字节,并将其存储在本地变量 Temp中。

也可以使用 BYTE, WORD, 和 LONG 声明来读取主内存的位置,例如:

DAT MyData byte $FF, 25, %1010 PUB GetData | Temp Temp := BYTE[@MyData][0] '读取数据表的第一个字节

Page 216: Propeller Manual - Parallax Home

DAT – Spin语言参考

Page 216 · Propeller Manual v1.0

这个例子和前一个类似,不同之处在于它使用的是 BYTE 声明来读取存储在地址

MyData 处的值 。更多关于读写主内存数据的信息参考 169 页 BYTE, 338 页 WORD, 以及

242 页 LONG。

编写 Propeller 汇编代码 (语法 2) 除了数值和字符串,数据块也用于 Propeller 汇编代码。例如,

DAT org '重置地址指针

Loop rdlong t1, par WZ '等待命令

if_z jmp #Loop '为零则跳转

movd :arg, #arg0 '取得 8 个变量 :arg mov t2, t1

这个例子中包括了可选的符号“Loop”和 “:arg”,一个可选的条件“IF_Z”,必

须的指令域 ORG, RDLONG,及其操作数和效果语句“WZ”。

注意任何可同时用于 Propeller 汇编语言和 Spin 语言的命令如果写在 DAT 块中,那

它就被当成是汇编指令。相反,如果是写在 DAT 块之外,那就是 Spin 命令。

Page 217: Propeller Manual - Parallax Home

4: Spin语言参考– DIRA, DIRB

Propeller Manual v1.0 · Page 217

DIRA, DIRB 32 位端口 A 和 B 的方向寄存器。 ((PUB PRI)) DIRA ⟨[Pin(s)]⟩ ((PUB PRI)) DIRB ⟨[Pin(s)]⟩ (Reserved for future use) 返回: 如果用于源变量,返回端口 A 和 B I/O 引脚方向位的当前值。

• Pin(s) 是可选的表达式,或范围表达式,指出了一个或多个端口 A(0-31)或端口

B(32-63)中要访问的 I/O 引脚。如果给定了一个表达式,则只有指定的引脚可

以被访问。如果给出的是范围表达式(范围形式的两个表达式,x…y),那么

从表达式开始到结束的所有引脚都会被访问。 解释

DIRA 和 DIRB 是六个(DIRA, DIRB, INA, INB, OUTA 和 OUTB)直接影响 I/O 引脚的寄存器中

的两个。DIRA 寄存器中保持了端口 A 中 32 个 I/O 引脚的方向状态;寄存器的 Bit0 到

Bit31 分别代表了 P0 到 P31。DIRB 寄存器中保持了端口 A 中 32 个 I/O 引脚的方向状

态;寄存器的 Bit0 到 Bit31 分别代表了 P32 到 P63。.

NOTE: DIRB 是为将来使用而保留的; Propeller P8X32A 不包含端口 B,所以以下

只讨论 DIRA 。

DIRA 用于设置和取得当前端口 A 中一个或多个 I/O 引脚的方向状态。低(0) 位将相

应的 I/O 引脚设置为输入。高 (1) 位将相应的 I/O 引脚设置为输出。DIRA 寄存器默认为

0,在 cog 启动时所有的位设置为 0;所有的 I/O 引脚被设置为输入,除非有代码指令

修改。

每个 Cog 都可以访问所有的 I/O 引脚。所有的 I/O 引脚都直接连接到 Cog,所以没

有 Hub 相关的独占访问的问题。每个 cog 都会维护其自己的 DIRA 寄存器,这使得 cog可以在任何时候设置 I/O 引脚的方向。每个 cog 的 DIRA 寄存器都会与其他 cog 的寄存

器相“或”,所产生的 32 位值将成为端口 A P0 引脚到 P31 引脚的方向值。结果是每

个 I/O 引脚的方向状态是整个 cog 集线与的结果。参见 26 页上关于 I/O 引脚的更多信

息。

Page 218: Propeller Manual - Parallax Home

DIRA, DIRB – Spin语言参考

Page 218 · Propeller Manual v1.0

该配置可以简单地描述为下列规则:

A. 当没有活动的 cog 设置一个引脚为输出时,该引脚为输入。 B. 当 cog 设置一个引脚为输出时,该引脚就是输出。

如果 cog 被禁用,则该 cog 的方向寄存器会被清零,这样就不会影响 I/O 引脚方向

和状态。

注意,由于 I/O 引脚的“线或”特性,cog 之间没有电气连接,cog 可以同时访问

I/O 引脚。这依赖于程序开发员要确保在运行时没有在同一个 I/O 引脚上建立逻辑竞

争。

使用 DIRA Set or clear bit 将 DIRA 中位清零或置位,可以将 I/O 引脚设置为希望的方向。例如:

DIRA := %00000000_00000000_10110000_11110011

将 DIRA 置位或清零来改变 I/O 引脚的方向。参考下面的例子:

DIRA := %00000000_00000000_10110000_11110011

上面的代码将整个 DIRA 寄存器的值设定为一个值,使第 15,13,12,7,6,5,4,1 和 0 引脚被设置为输出,其他引脚为输入。

使用 the post-clear (~) 和 post-set (~~) 单目运算符,cog 可以设置所有的 I/O 引脚为

输入或输出;但通常不希望将所有的 I/O 引脚设置为输出。参考下面的例子:

DIRA~ '将 DIRA 寄存器清零 (所有的 I/O设置为输入) —和—

DIRA~~ '将 DIRA 寄存器置位 (所有的 I/O设置为输出)

第一个例子将整个 DIRA 寄存器清零 (所有 32 位,同时);所有的 I/O 引脚,P0 到

P31 设置为输入。第二个例子讲整个 DIRA 寄存器置位 (所有 32 位同时);所有 I/O 引

脚,P0 到 P31 设置为输出。

可以单独作用于一个 I/O 引脚(1 个位),方法是在可选的 Pin(s) 域中指定该引

脚。这种做法将整个 DIRA 寄存器视为一个 32 位数组。

DIRA[5]~~ '设置 DIRA 的 bit 5 (P5 为输出)

Page 219: Propeller Manual - Parallax Home

4: Spin语言参考– DIRA, DIRB

Propeller Manual v1.0 · Page 219

上面的代码将 P5 设置为输出。DIRA 的其它位(也就是与之对应的 I/O 引脚)仍然

保持其原有的状态。

DIRA 寄存器支持特殊的表达式形式,也就是范围表达式,它允许一次作用于一组

I/O 引脚,而在指定范围之外的引脚不会受影响。要一次作用于多个引脚,可以在 Pin(s) 域中使用范围表达式(形式如 x..y)。

DIRA[5..3]~~ '设置 DIRA 的 bits 5 到 3 (P5-P3 为输出)

这里将 P5,P4 和 P3 设置为输出; DIRA 的其它位仍然保持原有的状态。下面是另

一个例子:

DIRA[5..3] := %110 '将 P5 和 P4 设置为输出,P3 设置为输入

上面的例子将 DIRA 的 bits 5,4 和 3 设置等于 1,1,和 0,而其它位保持不变。现

在 P5 和 P4 是输出,P3 是输入。

重要提示:范围表达式中范围值的顺序会影响到效果,例如,下面的例子中交换了

上一个例子范围表达式中范围值的顺序:

DIRA[3..5] := %110 '将 P3 和 P4 设置为输出,P5 设置为输入

这里 DIRA 的 bits 3,4 和 5 设置等于 1,1,和 0,而其它位保持不变。现在 P3 和

P4 是输出,P5 是输入。

范围表达式是一个有用的特性,但是如果使用不当,可能会造成奇怪的结果。

通常,DIRA 是只被写入的,但它也可以被读取,以获得当前 I/O 引脚的方向的状

态。下面假定 Temp 是已经创建的变量:

Temp := DIRA[7..4] '取得 P7到 P4的方向状态

上面的代码将 Temp 设置为等于 DIRA 的第 7,6,5 和 4 位,也就是 Temp 的低四位被

设置为等于 DIRA7:4,Temp 的其它位被清零。

Page 220: Propeller Manual - Parallax Home

FILE – Spin语言参考

Page 220 · Propeller Manual v1.0

FILE 导入外部文件。 DAT FILE "FileName"

• FileName 是文件名,不带扩展名。在编译时,会在编辑器窗口,工作目录和库

目录中寻找该文件。FileName 可以包含任何有效的文件名字符,不允许的字符

是\, /, :, *, ?, ", <, >, 和 |。 解释

指令用于将外部数据文件(通常是二进制文件)导入到一个对象的 DAT 块。这些数

据可以像普通 DAT 块数据一样被访问。

使用 FILE 在 DAT 块中 FILE 使用类似于 BYTE,除了后面的引号中是文件名而不是数据值。如

下例:

DAT Str byte "This is a data string.", 0 Data file "Datafile.dat"

在这个例子中, DAT 块由一个字节型字符串和由来自文件 Datafile.dat 的数据组

成。编译时, Propeller 工具会在编辑栏中,工作目录或库目录中寻找一个名称为

Datafile.dat 的文件,并将其中的数据装载到一个由零结尾的字符串 Str 中。方法可以

访问导入的数据,方法是使用 BYTE, WORD 或 LONG 声明,将其作为普通数据处理。参

考下面的例子:

PUB GetData | Index, Temp Index := 0 repeat Temp := byte[Data][Index++] '将数据读取到 Temp中,每次 1 byte

<do something with Temp> '用 Temp中的值执行任务

while Temp > 0 '一直循环,直到发现终点

这个例子将会读取导入的数据,每次一个字节,直到发现一个等于 0 的字节。

Page 221: Propeller Manual - Parallax Home

4: Spin语言参考– FLOAT

Propeller Manual v1.0 · Page 221

FLOAT 将一个整型常量表达式转换为一个编译时浮点值。 ((CON VAR OBJ PUB PRI DAT)) FLOAT (IntegerConstant ) 返回:将整型表达式解析后的浮点值。

• IntegerConstant 是希望被用作常浮点值的整型常量表达式。 解释

FLOAT 是三条用于浮点常量表达式的指令 (FLOAT, ROUND 和 TRUNC) 之一。FLOAT 指令

将一个常整型值转换为一个常浮点值。

使用 FLOAT 大多数常量都是 32 位的整型常量,Propeller 编译器支持 32 位浮点值和常量表达

式。注意这只是用于常量表达式,并不是运行时变量表达式。

对典型的浮点常量声明,表达式必须以以下三种方式之一表达:1)整型值后有十

进制小数点和至少一位小数部分,2) 整型值后有字母 E,然后是指数的值,或 3) 1 和

2 的组合。参考下面的例子:

CON OneHalf = 0.5 Ratio = 2.0 / 5.0 Miles = 10e5

上面的代码建立了三个浮点常量。 OneHalf 等于 0.5, Ratio 等于 0.4 和 Miles 等于 1,000,000。

要注意在上面的例子中,每个表达式中的部分都是浮点值。现在来看下面的例子:

CON Two = 2 Ratio = Two / 5.0

Page 222: Propeller Manual - Parallax Home

FLOAT – Spin 语言参考

Page 222 · Propeller Manual v1.0

这里,Two 是已定义的整型常量,Ratio 看起来是定义为浮点常量的。但这会在

Ratio 的那一行产生错误,因为对浮点常量表达式来说,每个出现在表达式里的值都必

须是浮点值;不能将整型值和浮点值混在一起,就像 Ratio = 2 / 5.0。

但是您可以使用 FLOAT 指令将一个整型值转换为一个浮点值,如下面的例子:

CON Two = 2 Ratio = float(Two) / 5.0

例子中的 FLOAT 指令将整型常量 Two 转换为该值的浮点形式,所以可以被用在浮点

表达式中。

关于浮点数 Propeller 编译器将浮点常量当作一个单精度实数来处理,该方法在 IEEE-754 标准

中有描述。单精度实数以 32 位存储,有一位符号位,8 位的指数,和一个 23 位的尾数

(分数部分)。这样可以有大约 7.2 有效的十进制位。

浮点常量表达式可以被定义以及用于编译目的,但是对于运行时浮点运算, FloatMath 和 FloatString 对象提供了和单精度数兼容的数学函数。

参见 254 页运算符一节中常量赋值( 常量赋值 ‘=’),303 页的 ROUND,324 页的TRUNC,以及 FloatMath 和 FloatString 对象的更多信息。

Page 223: Propeller Manual - Parallax Home

4: Spin语言参考– _FREE

Propeller Manual v1.0 · Page 223

_FREE 预定义常量,用于指定应用程序的自由空间的大小。. CON _FREE = Expression

• Expression 是一个整型表达式 ,它指出了要保留为自由空间的长字个数。 解释

_FREE是可选的,预定义 one-time settable 的常量,它指出了要为应用程序保留的内

存空间。如果指定了_FREE 的值,它会和_STACK相加,所得到的结果是要为 Propeller 应用程序保留的空间(包括自由空间和堆栈空间)。如果一个应用程序要正常运行需要

一个 低量的内存空间,那么就该使用_FREE。如果编译后的程序过大没有留下足够的

自由空间,会显示一则错误信息。例如:

CON _FREE = 1000

在上面 CON 块中的_FREE 的声明表明了应用程序在编译后需要至少 1000 个长字的内

存空间。如果编译后的程序没有留下足够的空间,会显示一条错误信息,该信息会表

明程序超过的量。这可以有效地防止应用程序编译后由于缺少足够的内存而无法运

行。

要注意只有顶部对象文件可以设定_FREE 的值。任何子对象中的_FREE 声明都会被

忽略。

Page 224: Propeller Manual - Parallax Home

FRQA, FRQB – Spin语言参考

Page 224 · Propeller Manual v1.0

FRQA, FRQB 计数器 A 和计数器 B 的频率寄存器。 ((PUB PRI)) FRQA ((PUB PRI)) FRQB

返回:如果用作源变量,则返回计数器 A 和计数器 B 频率寄存器的当前值。 解释

FRQA 和 FRQB 是六个能影响 cog 的计数器单元行为的寄存器 (CTRA, CTRB, FRQA, FRQB, PHSA, 和 PHSB) 中的两个。每个 cog 都有两个相同的计数器单元(A 和 B)可知用于执

行重复的工作。FRQA 寄存器包含了将要累加到 PHSA 寄存器中的值。FRQB 寄存器包含了

将要累加到 PHSB 寄存器中的值。参见 204 页上关于 CTRA, CTRB 的更多信息。

使用 FRQA 和 FRQB FRQA 和 FRQB 可以像其他寄存器和预定义变量一样进行读写。例如:

FRQA := $00001AFF

上面的代码将 FRQA 设置为 $00001AFF。 依靠 CTRA 寄存器的 CTRMODE 域, FRQA 中的值可以以一定的频率被累加到 PHSA 寄存器,该频率值由系统时钟以及主 和/或 从I/O 引脚(primary and/or secondary I/O pins)决定。参见 204 页上关于 CTRA, CTRB 的更

多信息。

Page 225: Propeller Manual - Parallax Home

4: Spin语言参考– IF

Propeller Manual v1.0 · Page 225

IF 测试条件(一个或多个),如果条件有效(正逻辑),则执行代码。 ((PUB PRI)) IF Condition(s) IfStatement(s) ⟨ ELSEIF Condition(s) ElseIfStatement(s) ⟩… ⟨ ELSEIFNOT Condition(s) ElseIfNotStatement(s) ⟩… ⟨ ELSE ElseStatement(s) ⟩

• Condition(s) 是一个或多个要测试的布尔表达式。 • IfStatement(s) 是由一行或多行代码组成的代码块,当 IF的 Condition(s) 为逻辑真

时执行。 • ElseIfStatement(s) 是可选的代码块,由一行或多行代码组成,当之前所有的

Condition(s) 无效而 ELSEIF 的 Condition(s) 为逻辑真时执行。 • ElseIfNotStatement(s) 是可选的代码块,由一行或多行代码组成,当之前所有的

Condition(s) 无效且 ELSEIFNOT的 Condition(s) 为逻辑假时执行。 • ElseStatement(s) 是可选的代码块,由一行或多行代码组成,当之前所有的

Condition(s) 无效时执行。 解释

IF 是三条主要的条件命令 (IF, IFNOT, 和 CASE) 之一,可以有条件地执行代码块。IF 可以和一个或多个 ELSEIF 命令,一个或多个 ELSEIFNOT 命令,与/或一个 ELSE 命令组合

来形成复杂的条件结构。

IF 测试 Condition(s) ,如果为真,执行 IfStatement(s)。 如果 Condition(s) 为假,则

接下来可选的 ELSEIF Condition(s), 与/或 ELSEIFNOT Condition(s), 会被顺序测试,直到找

到一个有效的条件行,然后组合的 ElseIfStatement(s), 或 ElseIfNotStatement(s) 块会被执

行。可选的 ElseStatement(s) 块会在没有找到任何有效条件时执行。

一个“有效”条件是指被评估为 TRUE 的正逻辑条件表达(IF 或 ELSEIF) ,或者被评

估为 FALSE 的负逻辑条件表达 (ELSEIFNOT)。

Page 226: Propeller Manual - Parallax Home

IF – Spin语言参考

Page 226 · Propeller Manual v1.0

必不可少的缩进 重要: 缩进是必不可少的。Spin 语言依赖于紧跟条件命令后代码的缩进(一个或多

个空格)来确定它们是否属于该命令。要使 Propeller Tool 指示出这些逻辑分组的代码

块,可以按 Ctrl + I 来打开块组指示器。再次按 Ctrl + I 将关闭这一特性。参见 69 页上

的增加缩进和减少缩进, 以及 74 页上的块-组指示器。

简单 IF 表达 IF 条件命令的 普通形式是当(且仅当)一个条件为真时执行一个动作。该描述

可写作一个 IF 表达后跟随着一个或多个缩进行。例如:

if X > 10 '如果 X 大于 10

!outa[0] '触发 P0

!outa[1] '触发 P1

这个例子测试了 X 是否大于 10;如果是,I/O 引脚 0 被触发。而无论 IF 条件是否

为真, I/O 引脚 P1 都会被随后触发。

因为!outa[0] 是从 IF 行缩进的,那么它就属于 IfStatement(s) 块,且只有当 IF 条件为真时才会被执行。下一行, !outa[1], 没有从 IF 行缩进,所以不论 IF的 Condition(s) w 是真或假,它都会被执行。下面是同样例子的其他版本:

if X > 10 '如果 X 大于 10

!outa[0] '触发 P0

!outa[1] '触发 P1

waitcnt(2_000 + cnt) '等待 2000个周期

这个例子和第一个很相似,除了有两行代码都是从 IF 行缩进的。在这里,如果 X 大于 10,P0 会被触发,随后 P1 被触发, 后 waitcnt 行被执行。如果, X 不是大于

10 的, !outa[0] 和 !outa[1] 行会被跳过(因为它们是从 IF 行缩进,是 IfStatement(s) 块的一部分),waitcnt 行会被执行(因为该行没有缩进;它不是 IfStatement(s) 块的一

部分)。

组合条件 Condition(s) 域会被作为一个布尔条件评估,但是它可以由多个布尔表达式以 AND

和 OR 运算符组合而成。参见 272-273 页。例如:

if X > 10 AND X < 100 '如果 X 大于 10且小于 100

Page 227: Propeller Manual - Parallax Home

4: Spin语言参考– IF

Propeller Manual v1.0 · Page 227

这条 IF 表达在 X 大于 10 同时 X 小于 100 时为真。换句话说,如果 X 在 11 到 99

的范围内为真。有时候这种表述可能有点难读懂。为了让它更易于阅读,可以使用圆

括号来将子段分组,就如下所示:

if (X > 10) AND (X < 100)'如果 X 大于 10且小于 100

使用带有 ELSE 的 IF IF 条件命令的第二种常见形式是当一个条件为真时执行一个动作或当条件为假时

执行另一个动作。该描述可写作一个 IF 表述后跟随其 IfStatement(s) 块,然后是一个带

有 ElseStatement(s) 块的 ELSE语句,如下所示:

if X > 100 '如果 X 大于 100

!outa[0] '触发 P0

else '否则, X <= 100

!outa[1] '触发 P1

在这里,如果 X 大于 100,I/O 引脚 0 会被触发,否则, X 必须小于或等于 100,I/O 引脚 P1 才会被触发。这个 IF...ELSE 结构,就像所写的一样,总是执行触发 P0 或

P1;既不会同时触发也不会一个都不触发。

请记住,逻辑上属于 IfStatement(s) 或 ElseStatement(s) 的代码必须要从 IF 或 ELSE 缩进至少一个空格。也请注意, ELSE 必须和 IF 对齐;它们必须开始于相同的列,否

则编译器将不知道 ELSE 应该和哪一个 IF 配对。

每一个 IF 表述,可以有没有或有一个 ELSE 组件。在 IF 表述中, ELSE 必须是出现

在 ELSEIF后的 后一个组件。

使用带有 ELSEIF 的 IF IF 条件命令的第三种形式是当一个条件为真时执行一个动作,或当该条件为假单

其他条件为真时执行其他的动作。可以写作一个 IF 表述后跟随一个 IfStatement(s) 块,

然后是一个或多个带有相应 ElseIfStatement(s) 块的 ELSEIF 表达。下面是一个例子:

if X > 100 '如果 X 大于 100

!outa[0] '触发 P0

elseif X == 90 '否则 如果 X = 90

Page 228: Propeller Manual - Parallax Home

IF – Spin语言参考

Page 228 · Propeller Manual v1.0

!outa[1] '触发 P1

在这里,如果 X 大于 100, I/O 引脚 P0 会被触发,否则,如果 X 等于 90, I/O 引脚 1 会被触发,如果这些条件都不满足,P0 和 P1 都不会被触发。它是下面代码的简略的

写法:

if X > 100 '如果 X 大于 100

!outa[0] '触发 P0

else '否则, if X == 90 'If X = 90 !outa[1] '触发 P1

这些代码都执行了同样的动作,但是第一个更简短且更易于阅读。注意 ELSEIF,就

像 ELSE 一样, 必须和它所关联的 IF 开始于同一列。

每个 IF 条件表达可以由多个 ELSEIF 表述与之关联。看下面的例子:

if X > 100 '如果 X 大于 100

!outa[0] '触发 P0

elseif X == 90 '否则 如果 X = 90

!outa[1] '触发 P1

elseif X > 50 '否则 如果 X > 50

!outa[2] '触发 P2

我们有 3 个条件和 3 个可能的动作。就像前面的例子一样,如果 X 大于 100,P0 会

被触发,否则 如果 X 等于 90, P1 被触发,但如果上面两个条件都不满足,且 X 大于

50,P2 会被触发。如果这些条件都不满足,这些动作将都不会发生。

这是这个例子的一个很重要的概念。如果 X 等于 101 或更大,P0 会被触发,或者 X 等于 90,P1 会被触发,或者如果 X 是 51 到 89 之间的数字, 或 91 到 100 之间,P2 会被触发。这是因为 IF 和 ELSEIF 条件只能在一个时刻测试一个条件,以它们列出的顺

序,只有第一个为真的条件的代码块会被执行;此后不会再测试其他条件。这额就意

味着如果我们重新排列两个 ELSEIF 语句,使 “X > 50” 首先被检查,我们的代码中就会

出现错误。

Page 229: Propeller Manual - Parallax Home

4: Spin语言参考– IF

Propeller Manual v1.0 · Page 229

我们这么做:

if X > 100 '如果 X 大于 100

!outa[0] '触发 P0

elseif X > 50 '否则如果 X > 50

!outa[2] '触发 P2

elseif X == 90 '否则如果 X = 90 <-- ERROR, ABOVE COND.

!outa[1] '触发 P1 <-- SUPERSEDES THIS AND ' THIS CODE NEVER RUNS

上面的例子包含了一个错误,因为当 X 等于 90, elseif X == 90 表达式永远不会被

测试,因为上一条语句 elseif X > 50, 会被先测试,因为其为真,它的块会被执行,

而 IF 结构的其他条件将不会被测试。如果 X 等于 50 或小于 50, 后一条 ELSEIF 条件

会被测试,但是当然,它永远不会为真。

使用带有 ELSEIF 和 ELSE 的 IF IF 条件命令的另一种形式是:当多个不同的条件之一为真时执行多个不同动作之

一,或当之前的条件无一为真时执行一个可选的动作。写作一个 IF, 一个或多个

ELSEIF, 和一个 ELSE。下面是例子:

if X > 100 '如果 X 大于 100

!outa[0] '触发 P0

elseif X == 90 '否则,如果 X = 90

!outa[1] '触发 P1

elseif X > 50 '否则,如果 If X > 50

!outa[2] '触发 P2

else '否则,

!outa[3] '触发 P3

除了如果没有条件满足 IF 或 ELSEIF ,则触发 P3,这个例子和上一个很相似的。

ELSEIFNOT 条件 ELSEIFNOT 条件就像 ELSEIF 一样,除了 ELSEIFNOT 使用的是负逻辑;只有当其

Condition(s) 表达式评估为 FALSE 时才执行 ElseIfNotStatement(s) 块。多个 ELSEIFNOT 和

Page 230: Propeller Manual - Parallax Home

IF – Spin语言参考

Page 230 · Propeller Manual v1.0

ELSEIF 条件可以被组合进一个单独的 IF 条件命令,以任何顺序,在 IF 和可选的 ELSE 之间。

Page 231: Propeller Manual - Parallax Home

4: Spin语言参考– IFNOT

Propeller Manual v1.0 · Page 231

IFNOT 测试条件(一个或多个),若条件有效则执行一个代码块 (负逻辑). ((PUB PRI)) IFNOT Condition(s) IfNotStatement(s) ⟨ ELSEIF Condition(s) ElseIfStatement(s) ⟩… ⟨ ELSEIFNOT Condition(s) ElseIfNotStatement(s) ⟩… ⟨ ELSE ElseStatement(s) ⟩

• Condition(s) 是一个或多个要测试的布尔表达式。 • IfNotStatement(s) 是一行或多行的代码块,当 Condition(s) 为假时执行。 • ElseIfStatement(s) 是可选的代码块,由一行或多行组成,当所有的 Condition(s) 无

效且 ELSEIF 的 Condition(s) 为真时执行。 • ElseIfNotStatement(s) 是可选的代码块,由一行或多行组成,当所有的 Condition(s)

无效且 ELSEIFNOT 的 Condition(s) 为假时执行。 • ElseStatement(s) 是可选的代码块,由一行或多行组成,当全部的 Condition(s) 无

效时执行。 解释

IFNOT 是三条主要的条件命令之一 (IF, IFNOT, 和 CASE) ,可以有条件地执行代码块。 IFNOT 是 IF的补(反)命令。

IFNOT 测试 Condition(s) , 如果为假,则执行 IfNotStatement(s) 。 如果 Condition(s) 为真,随后可选 ELSEIF Condition(s), 和/或 ELSEIFNOT Condition(s), 将被顺序测试,直到找

到一个有效的条件,然后相关的 ElseIfStatement(s), 或 ElseIfNotStatement(s) 代码块将被

执行。如果没有找到有效的条件,则执行可选的 ElseStatement(s) 块。

一个 “有效” 条件是指对负条件表达(IFNOT, 或 ELSEIFNOT)而言计算的结果为 FALSE (假),或者对正条件表达(ELSEIF)而言,计算结果为真(TRUE)。

参见 220 页中 IF 的相关描述中关于 IFNOT 的条目。

Page 232: Propeller Manual - Parallax Home

INA, INB – Spin语言参考

Page 232 · Propeller Manual v1.0

INA, INB 32 位端口 A 和 B 的输入寄存器。 ((PUB PRI)) INA ⟨[Pin(s)]⟩ ((PUB PRI)) INB ⟨[Pin(s)]⟩ (为将来使用保留) 返回:端口 A 和 B I/O 引脚的当前状态。

• Pin(s) 是可选的表达式,或者范围表达式,可以指定一个或多个端口 A(0-31)或端口 B(32-63)的 I/O 引脚。如果给定的是一个单独的表达式,只有指定的

引脚会被访问。如果给定的是范围表达式(表达式形式为 x..y),那么表达式

中指定的连续引脚会被访问。 解释

INA 和 INB 是六个直接影响 I/O 引脚的寄存器 (DIRA, DIRB, INA, INB, OUTA 和 OUTB) 之中

的两个。 INA 寄存器包含了端口 A 的 32 个 I/O 引脚的当前值;位 0 到位 31 分别代表

P0 到 P31。 INB 寄存器包含了端口 B 的 32 个 I/O 引脚的当前值;位 0 到位 31 分别代

表 P32 到 P63

注: INB 是为将来使用而保留的;Propeller P8X32A 不包含端口 B I/O 引脚所以以下

只讨论 INA。

INA 是只读的,而且不是以寄存器方式实现的,当在表达式中作为数据源被访问

时,可以直接读取 Port A I/O 引脚。在结果中,低位 (0) 表明相应的 I/O 引脚被拉到

地,高位(1) 表明相应的 I/O 引脚上拉到 VDD(3.3 伏)。因为 Propeller 是 CMOS 器

件,I/O 引脚会将大于½ VDD 的电压值判定为高,所以“高”的意思是 1.65 伏或更高

的电压值。

每个 cog 都可以访问所有的 I/O 引脚。实质上,所有的 I/O 引脚都是直接连接每个

cog 的,所以不存在 Hub 相关的,互斥的访问。每个 cog 都有其独有的 INA 伪寄存器

(pseudo-register)可以用来读取 I/O 引脚的状态(低或高)。不论这些引脚是被指定

为输入或是输出状态,实际的 I/O 引脚的值会被读取。

注意,因为 I/O 引脚的线与特性,所以在 cog 之间没有电气连接,但是它们仍可以

同时访问 I/O 引脚。这需要程序员确保在运行时两个 cog 不会在同一个 I/O 引脚上有逻

Page 233: Propeller Manual - Parallax Home

4: Spin语言参考– INA, INB

Propeller Manual v1.0 · Page 233

辑竞争。因为所有的 cog 共享所有的 I/O 引脚,所以一个 cog 可能在使用 INA 读取引脚

时这些引脚可能正在被另外的 cog 使用。

使用 INA 读取 INA 来取得那个时刻的 I/O 引脚的状态。下面的例子假定 Temp 是已经创建的变

量。

Temp := INA '取得 P0 到 P31 的状态

这个例子将端口 A 的 32 个 I/O 引脚的状态读入 Temp。

使用可选的 Pin(s)域,cog 可以读取指定的 I/O 引脚。例如:

Temp := INA[16] '取得 P16的状态

上面的代码读取了 I/O 引脚 P16 的状态,并将其(0 或 1)存储在 Temp 的 低位

(low bit)中;Temp 的其它位被清零。

在 Spin 语言中 INA 寄存器支持特殊的表达式形式,称为范围表达式(range-expression),它允许一次读取一组 I/O 引脚,而不会读取在指定范围之外的引脚的状

态。要一次读取多个,连续的引脚,可以在 Pin(s)域使用范围表达式(x..y)。

Temp := INA[18..15] '取得 P18:P15的状态

这里,the lowest four bits of Temp 的低四位(3,2,1 和 0)被分别设置为 I/O 引脚

18,17,16,15 的状态,Temp 的其它位被清除为 0。

重要提示:在范围表达式中值的顺序会影响到其使用。例如,下面的例子交换了上

一个例子中范围的顺序:

Temp := INA[15..18] '取得 P15:P18的状态

这里,Temp 的位 3, 2, 1, 和 0 被设置分别为 I/O 引脚 15, 16, 17, 和 18 的状态。

这是范围表达式的一个有用的特性,但是如果使用不当,可能会造成奇怪的,非设

定的结果。

Page 234: Propeller Manual - Parallax Home

LOCKCLR – Spin语言参考

Page 234 · Propeller Manual v1.0

LOCKCLR 将一个锁清零并返回它之前的状态。 ((PUB PRI)) LOCKCLR ( ID ) 返回:锁的上一个状态(TRUE 或 FALSE)。

• ID 要清零的锁的 ID (0 – 7)。 解释

LOCKCLR 是四条锁指令(LOCKNEW, LOCKRET, LOCKSET,和 LOCKCLR)之一,它用于管理

用户定义的或被视为是互斥的资源。LOCKCLR 将锁 ID 设置为 FALSE 并返回其上一个状

态(TRUE 或 FALSE)。

锁的更多典型用法参见 236 页关于锁,和 237 页使用锁的建议规则,以及 LOCKxxx 命令。

下面假定一个 cog(或另一个)已经使用了 LOCKNEW 命令检出(取出)一个 ID,并

将这个 ID 和这个 cog 共享,ID 的名称为 SemID。同时也假定 1 这个 cog 有一个名为

LocalData的长字数组。

PUB ReadResource | Idx repeat until not lockset(SemID) '在锁定资源之前等待

repeat Idx from 0 to 9 '读取资源中的 10个长字 LocalData[Idx] := long[Idx] lockclr(SemID) '解除对资源的锁定 PUB WriteResource | Idx repeat until not lockset(SemID) '在锁定资源之前等待

repeat Idx from 0 to 9 '将 10个长字写入资源中 long[Idx] := LocalData[Idx] lockclr(SemID) '解除对资源的锁定

上面的两个方法 ReadResource 和 WriteResource,在访问资源前和访问后都遵循了

同样的规则。首先,它们会在第一个循环无限等待,直到锁定该资源,换句话说就是

Page 235: Propeller Manual - Parallax Home

4: Spin语言参考– LOCKCLR

Propeller Manual v1.0 · Page 235

它成功地“设置”了关联的锁位。如果 LOCKSET 返回 TRUE,则条件 “until not lockset…” 为 FALSE,意思是其他的 cog 正在访问该资源,所以第一个循环会重复尝

试。如果 LOCKSET 返回的是 FALSE,那么条件 “until not lockset…” 为真,意思是我们已

经“锁定了资源”,第一个循环结束。第二个循环通过 long[Idx] 和 LocalData[Idx] 语句读写资源。每个方法的 后一行 lockclr(SemID),将和资源相关联的锁位设置为

FALSE,将资源解锁供其他 cog 使用。

更多信息参见 236 页 LOCKNEW;239 页 LOCKRET;和 240 页 LOCKSET。

Page 236: Propeller Manual - Parallax Home

LOCKNEW – Spin语言参考

Page 236 · Propeller Manual v1.0

LOCKNEW 检出(取出)一个新的锁并取得它的 ID。 ((PUB PRI)) LOCKNEW

返回:锁的 ID (0-7) 被检出(取出),如果没有可用的锁,则返回-1。 解释

LOCKNEW 是四条锁指令(LOCKNEW, LOCKRET, LOCKSET,和 LOCKCLR)之一,它用于管理

用户定义的或是互斥的资源。 LOCKNEW 从 Hub 检出(取出)一个唯一的锁,返回该锁

的 ID 号,如果没有可用的锁,LOCKNEW 返回 -1。

关于锁 锁是一种信号机制,用于在两个实体之间通信。在 Propeller 芯片中,锁只是 Hub

的受保护的寄存器中的八个全局位。Hub 会维护一个清单,列出了每个锁是否被使用

以及其状态。Cog 可以在运行时按需要检出(取出),设置,清除,和归还一个锁,

用锁来表明一个客户共享的资源,比如内存块等,是否是可用的。因为锁是由 Hub 管

理的,每次只能有一个 cog 作用,所以形成了有效的控制机制。

如果在一个应用程序中两个以上的 cog 共享同一块内存,那么就需要类似于锁这样

的工具来阻止灾难性的冲突发生。Hub 会阻止这类冲突发生在元素数据上(如字节,

字,或长字),但是它不能阻止多个元素(比如字节块,字块,长字块以及与之类似

的组合)“逻辑”上的冲突。例如,如果两个 cog 在共享主内存的一个字节,那么每

一个 cog 都会获得访问该字节的权限。但是如果两个 cog 共享的是主内存的多个字

节,那么 Hub 就没办法预防一个 cog 在向这些字节中的某些写入值而另一个 cog 正要

读取这些值的情况发生;也就是说各个 cog 对这些字节的操作可能会交错(重叠)。

这样的情况下,程序员应该设计每个进程(每个共享了该内存段的 cog)保证 cog 可以

共享数据的同时不会带来损害。锁就像标志位一样,告诉每个 cog 一段内存是否是可

以被安全操作的。

使用 LOCKNEW 用户定义的,互斥的资源应该由 cog 初始化,然后同一个 cog 应该使用 LOCKNEW 命

令来检出(取出)一个(唯一)的锁,用于管理该资源,然后将锁的 ID 传递给需要使

用该资源的 cog 使用。例如:

Page 237: Propeller Manual - Parallax Home

4: Spin语言参考– LOCKNEW

Propeller Manual v1.0 · Page 237

VAR byte SemID PUB SetupSharedResource <建立用户定义的共享资源的代码> if (SemID := locknew) == -1 <错误,没有可用的锁> else <和其它的 cog共享 SemID的值>

这个例子调用了 LOCKNEW 并将结果存储在 SemID 中。如果结果是-1,会发生错误。

如果 SemID 不是-1,那么会有一个有效的锁被检出(取出),SemID 应该被其它 cog 共

享,以及 SemID 所代表的资源也该被共享。该方法用于传递 SemID 以及资源的地址,但

是统称情况下,它们会以参数的形式传递给 cog 所运行的 Spin 方法,或者要运行的是

汇编语言程序时则是 PAR 参数。参见 194 页 COGNEW。

使用锁的建议规则 下面是使用锁的建议的规则:

• 需要使用锁来管理用户定义和互斥资源的对象使用 LOCKNEW 检出(取出)一个

锁,并保存返回的 ID,我们在这里称之为 SemID。只有一个 cog 可以检出(取

出)该锁,然后这个 cog 必须将 SemID 传递给其它使用该资源的 cog。

• 任何要访问资源的 cog 都必须首先成功设定锁 SemID。一个成功的“设定”是

指 LOCKSET(SemID) 返回的是 FALSE;换句话说,该锁没有被设定。如果 LOCKSET 返回的是 TRUE,那么说明另一个 cog 正在访问该资源;所以必须等待和再次尝

试,直到 后成功地“设定”。

• 成功“设定”了锁的 cog 可以按需要操作该资源。操作完成后,cog 必须通过

LOCKCLR(SemID) 来清除锁位,以便其他 cog 可以访问该资源。在一些系统里,

LOCKCLR 的返回值可以被忽略,因为只有当前的 cog 是唯一有权去清除锁位的。

• 如果不再需要一个资源了,或该资源变成了非互斥资源,那么相关的锁就应该

被检入(退回)到锁池(lock pool),方法是 LOCKRET(SemID)。通常这也是由检

出(取出)锁的 cog 来执行。

应用程序应该要保证在锁未被检出(取出)的情况下,不会被 LOCKSET 或 LOCKCLR 指令访问。

Page 238: Propeller Manual - Parallax Home

LOCKNEW – Spin语言参考

Page 238 · Propeller Manual v1.0

注意,用户定义的资源实际上不是被 Hub 锁定的。锁特性只能提供给多个 cog 一

种协同操作资源的方法。所以应该由对象决定,和遵守,锁使用的规则和哪些资源应

该受到控制。此外,Hub 不会向调用 LOCKNEW 命令的 cog 直接指派一个锁,而是将该锁

标记为“已检出(取出)”,任何 cog 都可以向锁池返回可用的锁。同样的,任何 cog都可以在通过 LOCKCLR 和 LOCKSET 命令来访问锁,即使锁是没有被检出(取出)的。通

常不推荐这样做,因为这样有可能会导致损害其它对象。

更多信息参见 236 页 LOCKNEW;239 页 LOCKRET;和 240 页 LOCKSET。

Page 239: Propeller Manual - Parallax Home

4: Spin语言参考– LOCKRET

Propeller Manual v1.0 · Page 239

LOCKRET 将锁释放回锁池,使其可用于 LOCKNEW 请求。 ((PUB PRI)) LOCKRET ( ID )

• ID 是要返回锁池的锁 ID (0 – 7)。 解释

LOCKRET 是四条锁指令(LOCKNEW, LOCKRET, LOCKSET,和 LOCKCLR)之一,它用于管理

用户定义的或被视为是互斥的资源。LOCKRET 一个锁的 ID 释放回到 Hub 的锁池中,供

其它 cog 使用。例如:

LOCKRET(2)

这个例子将锁 2(Lock 2)释放回 Hub。这样不能阻止此后其它 cog 访问 Lock 2(锁 2),只是允许 Hub 能将其重新分配给使用了 LOCKNEW 命令的 cog。 应用程序应该

要保证在锁未被检出(取出)的情况下,不会被 LOCKSET 或 LOCKCLR 指令访问。

更多关于锁和 LOCKxxx 命令的信息参见 236 页关于锁和 237 页使用锁的建议规则。

注意,用户定义的资源实际上不是被 Hub 锁定的。锁特性只能提供给多个 cog 一

种协同操作资源的方法。所以应该由对象决定和遵守锁使用的规则和哪些资源应该受

到控制。此外,Hub 不会向调用 LOCKNEW 命令的 cog 直接指派一个锁,而是将该锁标记

为“已检出(取出)”,任何 cog 都可以向锁池返回可用的锁。同样的,任何 cog 都

可以在通过 LOCKCLR 和 LOCKSET 命令来访问锁,即使锁是没有被检出(取出)的。通常

不推荐这样做,因为这样有可能会导致损害其它对象。

更多信息参见 236 页 LOCKNEW;239 页 LOCKRET;和 240 页 LOCKSET。

Page 240: Propeller Manual - Parallax Home

LOCKSET – Spin语言参考

Page 240 · Propeller Manual v1.0

LOCKSET 将锁设置为真,并取得之前的状态。 ((PUB PRI)) LOCKSET ( ID ) 返回: 锁之前的状态(TRUE 或 FALSE)。

• ID 是要设置为 TRUE的锁的 ID (0 – 7)。 解释

LOCKSET 是四条锁指令(LOCKNEW, LOCKRET, LOCKSET,和 LOCKCLR)之一,它用于管理

用户定义的或被视为是互斥的资源。 LOCKSET 将锁 ID 设置为 TRUE,并取得锁之前的状

态(TRUE 或 FALSE)。

更多关于锁和 LOCKxxx 命令的信息参见 236 页关于锁和 237 页使用锁的建议规则。

下面假定有 cog(一个或多个)已经使用 LOCKNEW 命令检出(取出)了一个 cog 并

将其 ID(SemID)和其它 cog 共享。同时假定该 cog 有一个名为 LocalData 的长字型数

组。

PUB ReadResource | Idx repeat until not lockset(SemID) '在锁定资源前等待

repeat Idx from 0 to 9 '读取资源中的 10个长字 LocalData[Idx] := long[Idx] lockclr(SemID) '解除对资源的锁定 PUB WriteResource | Idx repeat until not lockset(SemID) '在锁定资源前等待

repeat Idx from 0 to 9 '将 10个长字写入资源 long[Idx] := LocalData[Idx] lockclr(SemID) '解除对资源的锁定

ReadResource 和 WriteResource 这两个方法在访问资源前/后都遵循了同样的规则。

首先,它们会在第一个循环无限等待,直到锁定资源位置;换句话说就是成功地设置

了相关的锁。如果 LOCKSET 返回 TRUE,条件“until not lockset…”为假,意思是有其它

Page 241: Propeller Manual - Parallax Home

4: Spin语言参考– LOCKSET

Propeller Manual v1.0 · Page 241

的 cog 正在访问资源,所以第一个 repeat 会继续循环。如果 LOCKSET 返回了 FALSE,那

么条件“until not lockset…”为真,意思是“已经锁定了资源”,第一个 repeat 循环结

束。每个方法中的第二个 repeat 循环通过语句 long[Idx] 和 LocalData[Idx] 开始读写资

源。每个方法的 后一行,lockclr(SemID),将资源相关的锁设置为 FALSE,逻辑上解

锁,释放了资源,供以后的程序使用。

更多信息参见 236 页 LOCKNEW;239 页 LOCKRET;和 240 页 LOCKSET。

Page 242: Propeller Manual - Parallax Home

LONG – Spin语言参考

Page 242 · Propeller Manual v1.0

LONG 声明长字型符号,长字对齐,长字型的数据或读写长字型的内存。 VAR LONG Symbol ⟨[Count ]⟩ DAT LONG Data ((PUB PRI)) LONG [BaseAddress] ⟨[Offset ]⟩

• Symbol 是希望的变量名称。 • Count 是可选的表达式,指出了 Symbol 的长字型元素的个数,它们排列在一个

数组中,数组下标从 0 开始,到 Count-1 结束。 • Data 是一个常量表达式或者逗号分隔的常量表达式列表。 • BaseAddress 是一个表达式,描述了要读写的主内存地址。如果忽略 Offset,

BaseAddress 就是实际要操作的地址,如果指定了 Offset,则 BaseAddress + Offset 是实际要操作的地址。

• Offset 是可选的表达式,指出了从 BaseAddress 开始的偏移量。 解释

LONG 是三条多用途声明(BYTE, WORD, and LONG) 之一,用于声明或操作内存。LONG 可

以被用于:

1) 在 VAR 块中声明一个长字(long-sized 32-bit)符号或多个长字符号数组,或 2) 在 DAT b 块中声明一个长字对齐(long-aligned)和/或长字型(long-sized)数

据,或 3) 使用基址和可选的偏移量读写主内存的长字区域。

长字变量声明 (语法 1) 在 VAR 块中,LONG 的语法 1 用于声明全局的符号变量,该变量可以是长字型的,或

长字型数组。例如:

VAR long Temp 'Temp 是长字 (2 个字,4字节)

long List[25] 'List 是一个长字数组

Page 243: Propeller Manual - Parallax Home

4: Spin语言参考– LONG

Propeller Manual v1.0 · Page 243

上面的例子声明了两个变量(符号),Temp 和 List。Temp 是一个长字型变量。

Temp 声明下方的语句使用了可选的 Count 域,建立了一个有 25 个元素,名为 List 的

数组。Temp 和 List 可以从 VAR 块所在对象中声明的 PUB 或 PRI 方法中访问,也就是说

它们对整个对象而言是全局的。参考下面的例子:

PUB SomeMethod Temp := 25_000_000 '将 Temp 设置为 25,000,000

List[0] := 500_000 '将 List的第一个元素设置为 500,000

List[1] := 9_000 '将 List的第二个元素设置为 9,000

List[24] := 60 '将 List 的 后一个元素设置为 60

更多这种 LONG 的用法请参考 321 页 VAR 一节中的变量声明 (语法 1),要记住在那里

的描述中 LONG 适用于 Size 域。

长字数据声明 (语法 2) 在 DAT 块中,LONG 的语法 2 用于声明主内存中长字对齐的,和/或长字型的常量数

据。DAT 块运行声明中允许在数值之前有可选的符号,这些符号可以用于饮用这些数

值。(参见 213 页 DAT)。例如:

DAT MyData long 640_000, $BB50 '长字对齐/类型数据

MyList byte long $FF995544, long 1_000 '字节对齐/类型数据

上面的例子声明了两个数据符号,MyData 和 MyList。MyData 指向主内存中长字对齐

和长字型的数据的起点。主内存中 MyData 的值分别是 640,000 和$0000BB50。MyList 使用了特殊的 LONG 语法,在主内存中建立了一个字节对齐的,但是是长字型的数据。 MyList 的值分别是$FF995544 和 1,000。在按字节值访问时,MyList 包含了$44, $55, $99, $FF, 232 和 3, 0 和 0,因为数据是以低字节优先的方式存储的。

注意:如果将“byte”替换为“word”,那么 MyList 也可以被定义为字对齐,长字

型的数据。

该数据会被编译到对象中,作为应用程序可执行代码的一部分,它们可以通过

LONG 的语法 3(见下)来读写。更多 LONG 的这种用法,参见 213 页 DAT 一节中的声明

数据 (语法 1) ,要记住在那些描述中 LONG 是用在 Size 域的。

Page 244: Propeller Manual - Parallax Home

LONG – Spin语言参考

Page 244 · Propeller Manual v1.0

读/写主内存的长字区域 (语法 3) 在 PUB 和 PRI 块中, LONG 的语法 3 用于读写主内存的长字型区域。在下面的例子

中,假定我们的对象包含的 DAT 块和上一个例子一样,我们会演示两种不同的方法访

问数据。

首先,我们来试试使用在数据块中提供的标签来访问数据。

PUB GetData | Index, Temp Temp := MyData '将 MyData的第一个长字读取到 Temp

<do something with Temp> '用 Temp的值执行任务 repeat Index from 0 to 1 '重复两次

Temp := MyList[Index] '将数据读取到 Temp中,每次 1个长字

<do something with Temp> '用 Temp的值执行任务

GetData 方法的第一行,Temp := MyData,读取 MyData 中的第一个值(长字型值,

640,000),并将其存储在 Temp中。之后在 REPEAT 循环中,Temp := MyList[Index] 语句

从内存位置 MyList + Index 读取一个字节。第一次循环后(Index = 0),读取的值是$44 ($FF995544 的第 0 个字节),第二次(Index = 1) 读取的是$55 ($FF995544 的第一个字

节)。为什么是字节而不是字呢? MyList 指向了我们想要的数据,我们的数据也是被指

定为长字型的,但是符号 MyList 是被指定为字节对齐的,所以它实际是一个字节型指

针,只能以字节方式处理数据。

也许你想像从 MyList 中读取长字数据,就像从 MyData中读取一样,如果 MyList 被

声明为字节对齐的长字型数据,它又恰好是长字对齐的,位于长字边界,那么就可以

通过使用 LONG 声明来达成我们的目标:

PUB GetData | Index, Temp Temp := LONG[@MyData] '将 MyData的第一个长字读取到 Temp

<do something with Temp> '用 Temp的值执行任务 repeat Index from 0 to 1 '重复两次

Temp := LONG[@MyList][Index] '将数据读取到 Temp中,每次 1个长字

<do something with Temp> '用 Temp的值执行任务

Page 245: Propeller Manual - Parallax Home

4: Spin语言参考– LONG

Propeller Manual v1.0 · Page 245

在这个例子中,GetData 方法的第一行使用了 LONG 声明来读取主内存中位于 MyData

的一个长字数据,并将其存储在 Temp中。之后,在 REPEAT 循环中,LONG 声明读取了主

内存中位于 MyData + Index 处的长字值,并将其存储在 Temp 中。因为循环中第一次迭

代时 Index 为 0,所以 MyList 的第一个长字会被读取,也就是$FF995544。下一次循

环时会读取位于@MyList + 1的长字值(1,000)。

要注意的是如果数据不是长字对齐的,不论是有意还是无意或是巧合,我们就会得

到和上面不同的结果。例如,如果 MyList h 碰巧向前移动的一个字节,那么第一次循

环读取的值就是$995544xx;这里,xx 的意思是未知的字节型值。同样的,第二个值

会变成 256255;它是由 MyList 的第一个值的高位字节$FF 和 MyList的第二个值的低两

位字节值,3 和 232,所组成的。所以请密切关注内存中数据的对齐方式,以避免这种

情况发生。

使用类似的语法,主内存的长字可以被写入。例如:

LONG[@MyList][0] := 2_000_000_000 '向 MyList的第一个字写入 20亿

该行代码向 MyList的第一个长字写入了数值 2,000,000,000。

Page 246: Propeller Manual - Parallax Home

LONGFILL – Spin语言参考

Page 246 · Propeller Manual v1.0

LONGFILL 向内存的指定区域填充长字。 ((PUB PRI)) LONGFILL(StartAddress, Value, Count )

• StartAddress是表达式指出了要填充的内存区域的第一个长字的地址。 • Value 是表达式,指出了要填充的值。 • Count 是表达式,指出了要填充的长字的个数,填充的区域从 StartAddress 开

始。 解释

LONGFILL 是三条用指定值填充内存区域的命令(BYTEFILL, WORDFILL,和 LONGFILL)之一。 WORDFILL 向从 StartAddress.开始的内存填充 Count 个 Value 值。

使用 LONGFILL LONGFILL是清除长字型内存块内容的很好的方法。例如:

VAR long Buff[100] PUB Main longfill(@Buff, 0, 100) 'Clear Buff to 0

上面 Main 方法将 100 个长字 (400-字节)的数组 Buff 全部清零。LONGFILL 在这种工

作中比一个复杂的 REPEAT 循环更有效。

Page 247: Propeller Manual - Parallax Home

4: Spin语言参考– LONGMOVE

Propeller Manual v1.0 · Page 247

LONGMOVE 在内存的两个区域间复制长字 ((PUB PRI)) LONGMOVE (DestAddress, SrcAddress, Count )

• DestAddress 指定了复制的目标区域的地址的表达式。 • SrcAddress 指定了要复制的内存区域的第一个长字的地址的表达式 • Count 是表达式,指出了要复制的长字的个数。

解释

LONGMOVE 是三条内存数据块复制指令(BYTEMOVE, WORDMOVE,和 LONGMOVE)之一。

LONGMOVE从内存的 SrcAddress 开始复制 Count 个长字到由 DestAddress 开始的内存处。

使用 LONGMOVE LONGMOVE 是复制长字型内存块的很好的方法。例如:

VAR long Buff1[100] long Buff2[100] PUB Main longmove(@Buff2, @Buff1, 100) '从 Buff1 复制到 Buff2

上面 Main 方法的第一行复制了 100 个长字(400-字节)数组 Buff1 到数组 Buff2。 LONGMOVE 在这种工作中比一个复杂的 REPEAT 循环更有效。

Page 248: Propeller Manual - Parallax Home

LOOKDOWN, LOOKDOWNZ – Spin语言参考

Page 248 · Propeller Manual v1.0

LOOKDOWN, LOOKDOWNZ 在列表中取得一个值的索引值。 ((PUB PRI)) LOOKDOWN ( Value : ExpressionList ) ((PUB PRI)) LOOKDOWNZ ( Value : ExpressionList ) 返回: 在 ExpressionList 中 Value 的索引值,从 1 开始的索引位置(LOOKDOWN)或从 0开始的索引位置(LOOKDOWNZ),如果 Value 没找到则返回 0。

• Value 是要在 ExpressionList 中查找的值的表达式。 • ExpressionList 是逗号分隔的表达式。也可使用写在引号内的字符串,它们都被

作为逗号分隔的字符列表。 解释

LOOKDOWN 和 LOOKDOWNZ 是从一个列表中查找某个值的索引的命令。LOOKDOWN 返回列

表 ExpressionList 中从 1 开始的 Value 的位置(1..N)。LOOKDOWNZ 类似于 LOOKDOWN,但它

返回的是从 0 开始 (0..N−1)的位置。如果在 ExpressionList 中没有发现 Value,则都返

回 0。

使用 LOOKDOWN 或 LOOKDOWNZ LOOKDOWN 和 LOOKDOWNZ 在将一个非连续数集(25, -103, 18, etc.) 映射到一个连续数集

(也就是 1, 2, 3, –或– 0, 1, 2,)时很有用,特别是很少有代数表达式可以简明地做到这

样的映射。 下面的例子假定 Print 是已经创建的方法。

PUB ShowList | Index Print(GetIndex(25)) Print(GetIndex(300)) Print(GetIndex(2510)) Print(GetIndex(163)) Print(GetIndex(17)) Print(GetIndex(8000)) Print(GetIndex(3)) PUB GetIndex(Value): Index Index := lookdown(Value: 25, 300, 2_510, 163, 17, 8_000, 3)

Page 249: Propeller Manual - Parallax Home

4: Spin语言参考– LOOKDOWN, LOOKDOWNZ

Propeller Manual v1.0 · Page 249

例子中的 GetIndex 方法使用 LOOKDOWN 来查找 Value,并返回该值在 ExpressionList

中的位置,如果没有找到则返回 0。ShowList 方法分别以不同的参数调用 GetIndex,

并将结果显示在显示器上。假定 Print 是用于显示一个值的方法,那么这个例子会在

显示器上显示 1, 2, 3, 4, 5, 6 和 7。

如果使用 LOOKDOWNZ 来代替 LOOKDOWN,那么将会显示 0, 1, 2, 3, 4, 5, 和 6。

如果没有找到 Value,LOOKDOWN 或 LOOKDOWNZ 会返回 0。所以如果 ShowList 方法中

有一行是 Print(GetIndex(50)),那么当该行执行时,会显示 0。

如果使用 LOOKDOWNZ,要记得返回是可能表明两种情况,Value 没有找到,或者

Value 的索引值为 0。取保这样做在你的程序中不会出错,或者使用 LOOKDOWN 来代替。

Page 250: Propeller Manual - Parallax Home

LOOKUP, LOOKUPZ – Spin语言参考

Page 250 · Propeller Manual v1.0

LOOKUP, LOOKUPZ 在一个列表中的按索引值取得一个数值。 ((PUB PRI)) LOOKUP ( Index : ExpressionList ) ((PUB PRI)) LOOKUPZ ( Index : ExpressionList ) 返回: 位于索引值 ExpressionList 处的值。当索引值从 1 开始时使用(LOOKUP),当索

引值从 0 开始时使用(LOOKUPZ)。如果超出范围,则返回 0。

• Index 是表明了 ExpressionList 中指定位置处的值的表达式。LOOKUP的 Index 是从

1 开始的(1..N)。 LOOKUPZ的 Index 从 0 开始(0..N-1)。 • ExpressionList 是逗号分隔的表达式。也可以将表达式写在引号内,它们会作为

逗号分隔的表达式进行处理。 解释

LOOKUP 和 LOOKUPZ 两条指令可以用于从一个列表中取得指定位置的值。LOOKUP 返回

基值为 1 的表达式 ExpressionList 的 Index 处的值。LOOKUPZ 类似于 LOOKUP,但是它的基

值是 0(0..N-1)。如果 Index 超过了范围,两条指令都会返回 0。

使用 LOOKUP or LOOKUPZ LOOKUP 和 LOOKUPZ 用于将一个连续数集(1, 2, 3, etc. –或– 0, 1, 2, etc.)映射到无法用

简明的代数表达式表示的非连续数 (45, -103, 18, etc.)。下面的例子假定 Print 是已

经建立的方法。

PUB ShowList | Index, Temp repeat Index from 1 to 7 Temp := lookup(Index: 25, 300, 2_510, 163, 17, 8_000, 3) Print(Temp)

这个例子查找 LOOKUP 的 ExpressionList 中的值,并将其显示出来。REPEAT 循环将

Index 的值从 1 增加到 7。 循环的每次迭代中 LOOKUP 使用 Index 来从列表中获取数值。

如果 Index 等于 1,则返回 25。如果 Index 等于 2,则返回 300。假定 Print 方法可以

将 Temp的值显示出来,那么这个例子会显示 25, 300, 2510, 163, 17, 8000 和 3。

Page 251: Propeller Manual - Parallax Home

4: Spin语言参考– LOOKUP, LOOKUPZ

Propeller Manual v1.0 · Page 251

如果使用 LOOKUPZ,那么列表是从 0 开始的,而不是从 1 开始;Index 为 0 返回的是

25, Index 为 1 返回是 300。

如果 Index 超出了范围,则返回 0。所以对于 LOOKUP而言,如果 REPEAT 语句从 0 到

8 而不是从 1 到 7,那么会在屏幕上显示 0, 25, 300, 2510, 163, 17, 8000, 3 和 0。

Page 252: Propeller Manual - Parallax Home

NEXT – Spin语言参考

Page 252 · Propeller Manual v1.0

NEXT 跳过 REPEAT 循环中剩下的指令,开始下一次迭代。 ((PUB PRI)) NEXT 解释

NEXT 是两条能影响 REPEAT 循环的命令(NEXT 和 QUIT)之一。NEXT 可以使跳过

REPEAT 循环内的命令,直接开始下一次迭代。

使用 NEXT NEXT 通常用于条件表达式中例外的情形,在 REPEAT 循环中快速移动到下一次迭

代。例如,假定 X 是已经创建的变量, Print() 方法用于在监视器上显示一个值:

repeat X from 0 to 9 '重复 10 次 if X == 4 next '如果 X = 4则跳过

byte[$7000][X] := 0 '将 RAM 位置清零

Print(X) '在屏幕上打印 X

上面的代码通过迭代将 RAM 位置清零,并在显示器上显示 X 的值,使用了一个例

外。如果 X 等于 4,那么 IF 语句就执行 NEXT ,命令,这会使循环略过之后的循环体,

直接进行下一次新的迭代。这样的操作会使 RAM 位置$7000 到 $7003 的值被清零, $7005 到 $7009 的值被清零,并在屏幕上打印 0, 1, 2, 3, 5, 6, 7, 8, 9。

NEXT 命令只能用在 REPEAT 循环中,否则会出现错误。

Page 253: Propeller Manual - Parallax Home

4: Spin语言参考– OBJ

Propeller Manual v1.0 · Page 253

OBJ 声明对象块。 OBJ Symbol ⟨[Count]⟩: "ObjectName" ⟨ Symbol ⟨[Count]⟩: "ObjectName"⟩…

• Symbol 是对象符号的希望的名称。 • Count 是可选的表达式,写在括号内,指出这是一个对象数组,有 Count 个元

素。在之后的程序中引用到这些元素时,这些元素索引号从 0 开始, 后一个

元素索引值为 Count-1。 • ObjectName 是希望对象的文件名,不带扩展名。编译时,会搜索使用该文件名

的对象,搜索的顺序是编辑栏,工作文件夹和库文件夹。对象名可以包含任何

有效的文件名字符,不允许使用下列字符:\, /, :, *, ?, ", <, >, 和 |。 解释

对象块是源代码的一部分,它声明了对象和代表这些对象的符号。它是六条特殊声

明(CON, VAR, OBJ, PUB, PRI, 和 DAT)之一,这些声明提供了 Spin 语言的内部结构。

对象声明由 OBJ 开始,之后是一个或多个声明。OBJ 必须从第一列开始( 左边的

列),我们推荐之后的代码至少缩进一个空格。例如:

OBJ Num : "Numbers" Term : "TV_Terminal"

这个例子将 Num 定义为 "Numbers" 类的对象符号,将 Term 定义为"TV_Terminal"类的

对象符号。Public 和 Private 方法可以使用符号名称引用这些符号。参考下面的例子:

PUB Print | S S := Num.ToStr(LongVal, Num#DEC) Term.Str(@S)

公有方法 Print 调用 Numbers 的 ToStr 方法,调用的方法是在对象符号(Num 和 Term)后加对象方法引用符(英文句号, ‘.’), 后加上要调用的方法的名称。例

如,Num.ToStr 就调用了 Numbers 对象的公共方法 ToStr。Term.Str 调用了 TV_Terminal

Page 254: Propeller Manual - Parallax Home

OBJ – Spin语言参考

Page 254 · Propeller Manual v1.0

的公共方法 Str。在这个例子中, Num.ToStr 有两个参数,写在括号内,Term.Str 有一

个参数。

也要注意到调用 Num.ToStr 的第二个参数是 Num#DEC。(井号)# 是对象常量引用

符;它可以访问对象的常量。在这里的例子中,Num#DEC 引用到了 Numbers 对象的常量

DEC (十进制)。

更多信息参见 318 页表 4-16: 符号,对象方法饮用‘.’ 和对象常量引用‘#’。

一个对象的多个实例可以声明为同名数组,访问的方法和普通数组一样。例如:

OBJ PWM[2] : "PWM" PUB GenPWM PWM[0].Start PWM[1].Start

这个例子将 PWM 声明为有两个对象的数组(有同一个对象的两个实例)。as an array of two objects (two instances of the same object). The object itself just happens to be called “PWM” as well. 公共方法,GenPWM,使用 PWM数组对象的索引 0 和 1 分别调用了每

个实例的 Start 方法。

PWM 对象的两个实例都被编译到应用程序中,但是在应用程序中只有一份程序代码

(PUB, PRI,和 DAT)但是有两份变量块的副本(VAR)。这是因为,对每个实例而

言,程序代码总是相同的,而每个对象实例都需要其独立的变量空间来运行程序。

重点是要理解在对象的多个实例中,只有一个 DAT 块的副本(这里副本的意思是指

运行在内存中的程序是实际代码,也就是固化在 EEPROM 中的程序的内存映像),因

为 DAT 块中可能包含了汇编语言代码。DAT 块也会包含了初始化数据,以及工作空间的

区间设定等。所以在一个对象的多个实例中, DAT 块是共享的。这也为多个对象的空

间共享提供了方便。

对象符号的作用域 在对象的对象块中定义的对象符号是全局的,但是它们在对象外不可见。意思是在

对象内部可以直接访问它们,但是它们的名称不会和其他父对象或子对象的名称相冲

突。

Page 255: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 255

运算符 Propeller 芯片有一系列功能强大的数学和逻辑运算符。Propeller 汇编语言支持这些

操作符的一个子集;而 Spin 语言可以支持这些运算符的各种形式,本节描述了每个运

算符的细节。390 页上的运算符一节给出了 Propeller 汇编支持的运算符列表。 表达式空间

Propeller 是 32 位的设备,除非特别声明,表达式的评估总是 32 位的,有符号的。

包括中间运算结果也是如此。如果有中间运算结果产生了溢出 ,包括上溢出

(overfloew,超过 2,147,483,647)和下溢出(underflow,超过-2,147,483,648),那么

表达式的 终结果可能会受到影响。一个 32 位的空间为中间结果提供了很多空间,但

是请仍然注意到溢出的情况。

如果出现了小数部分溢出,或在表达式中出现了实数而不是整数,浮点支持可以帮

忙。编译器支持 32 位浮点值和常量表达式,使其可以像整型常量表达式一样应用大部

分的数学运算符。注意,这只适用于常量表达式,而非运行时变量表达式。对于浮点

型运行时表达式,Propeller 芯片提供了 FloatMath 对象给与支持。参见常量赋值 ‘=’, 259;页 FLOAT, 221 页; ROUND,309;页 和 TRUNC, 320,页 以及 FloatMath 和 FloatString 对象的

更多信息。

运算符属性 运算符有如下属性,每一种属性都在下面的两个表格中列出,并在随后给出了进一

步解释:

• 一元/二元 • 正常 / 赋值 • 常量和/或变量表达式 • 优先级

Page 256: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 256 · Propeller Manual v1.0

表 4-9: 数学和逻辑运算符 常量表达式 1 Normal

Operator 赋值运算符 整型 浮点型

是否是

一元 描述,页码

= always n/a1 n/a1 常量赋值 (CON 块), 259 := always n/a1 n/a1 变量赋值 (PUB/PRI 块), 260 + += 加, 261 + never 正号 (+X);加的一元形式, 261 - -= 减, 261 - if solo 负号 (-X); 减的一元形式, 262 -- always Pre-decrement (--X) or post-decrement (X--), 262 ++ always Pre-increment (++X) or post-increment (X++), 263 * *= Multiply and return lower 32 bits (signed), 264 ** **= Multiply and return upper 32 bits (signed), 264 / /= 除 (有符号), 265 // //= 求模数 (有符号), 265 #> #>= Limit minimum (signed), 265 <# <#= Limit maximum (signed), 266 ^^ if solo 平方根, 266 || if solo 绝对值, 267 ~ always Sign-extend from bit 7 (~X) or post-clear to 0 (X~); all bits low, 267 ~~ always Sign-extend from bit 15 (~~X) or post-set to -1 (X~~); all bits high, 268 ~> ~>= Shift arithmetic right, 268 ? always Random number forward (?X) or reverse (X?), 269 |< if solo 位运算: Decode value (0 - 31) into single-high-bit long, 270 >| if solo 位运算: Encode long into value (0 - 32) as high-bit priority, 271 << <<= 位运算: Shift left, 271 >> >>= 位运算: Shift right, 272 <- <-= 位运算: Rotate left, 272 -> ->= 位运算: Rotate right, 273 >< ><= 位运算: Reverse, 274 & &= 位运算: AND, 274 | |= 位运算: OR, 275 ^ ^= 位运算: XOR, 276 ! if solo 位运算: NOT, 277

AND AND= 布尔运算: AND (promotes non-0 to -1), 277 OR OR= 布尔运算: OR (promotes non-0 to -1), 278 NOT if solo 布尔运算: NOT (promotes non-0 to -1), 279 == === 布尔运算: 等于, 279 <> <>= 布尔运算: 不等于, 280 < <= 布尔运算: 小于 (有符号), 281 > >= 布尔运算: 大于 (有符号), 282 =< =<= 布尔运算: 小于或等于 (有符号), 282 => =>= 布尔运算: 大于或等于 (有符号), 283 @ never 符号地址, 283 @@ never 对象地址加符号, 283

1 Assignment forms of operators are not allowed in constant expressions.

Page 257: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 257

.

表 4-10: 运算符优先级

级别 Notes 运算符 运算符名称

Highest (0) Unary --, ++, ~, ~~, ?, @, @@ Inc/Decrement, Clear, Set, Random, Symbol/Object Address 1 Unary +, -, ^^, ||, |<, >|, ! 正,负,平方根,绝对值,Decode, Encode, 位 NOT 2 ->, <-, >>, <<, ~>, >< Rotate Right/Left, Shift Right/Left, Shift Arithmetic Right, Reverse 3 & 位 AND 4 |, ^ 位 OR, 位 XOR 5 *, **, /, // Multiply-Low, Multiply-High, Divide, Modulus 6 +, - 加,减 7 #>, <# Limit Minimum/Maximum 8 <, >, <>, ==, =<, => 布尔运算: 小于/大于,不等于,等于,等于或小于/大于 9 Unary NOT 布尔 NOT

10 AND 布尔 AND 11 OR 布尔 OR

Lowest (12) =, :=, all other assignments 常量/变量赋值,二元运算符赋值

一元 / 二元 每个运算符都是一元或二元的。一元运算符是指只有一个操作数的运算符。例如:

!Flag ' bitwise NOT of Flag ^^Total ' square root of Total

二元运算符有两个操作数。例如:

X + Y ' add X and Y Num << 4 ' shift Num left 4 bits

注意,“二元运算符”意思是有“两个操作数”,不会影响一元的位。为了区分能

作用于一元位的运算符,我们会使用术语“位(bitwise)”以区别。

正常 / 赋值 正常运算符,比如加‘+’和左移‘<<’,作用于它们的运算对象,计算结果被接

下来的表达式继续使用,而不会影响到操作数。赋值运算符会将运算的结果写入所操

作的变量(一元运算符)或写入在其左侧的变量(二元运算符),并将结果提供给之

后的表达式继续运算。

Page 258: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 258 · Propeller Manual v1.0

这里是赋值运算符的例子:

Count++ ' (Unary) evaluate Count + 1 ' and write result to Count

Data >>= 3 ' (Binary) shift Data right 3 bits ' and write result to Data

二元运算符有特殊的以 ‘=’ 结尾的形式,这使它们可以作为赋值运算符。一元运算

符没有特殊赋值形式;它们之中有些是可赋值的,而另一些只有在特殊情况下才能赋

值。更多信息参见下表 4-9 以及运算符的解释。

常量和/或变量表达式 具有整型常量表达式的运算符可以被用于运行时变量表达式,和编译时常量表达

式。具有浮点常量表达式属性的运算符可以用于编译时常量表达式。不具有常量表达

式属性的运算符只能用于运行时变量表达式。大多数运算符都是普通,非赋值形式

的,这样它们就可以被用于常量和变量表达式。

优先级 每个运算符都被赋予了优先级,用以指出在用一表达式中和其它运算符之间的优先

关系。例如,大家都知道在算数规则里,加减法运算会在乘除法运算之后进行。在这

里,这称为乘除法比加减法有较高的优先级。此外,乘法和除法都是可交换的;它们

是处于同一优先级的,所以它们的运算结果不会因为执行的顺序而改变。(先乘法后除

法,或相反)。 可交换运算符总是从左到右评估,除非有括号改变这一规则。

Propeller 芯片使用像代数规则一样的运算顺序:表达式被从左到右评估,除非有括

号何不同优先级的运算符存在。

依据此规则,Propeller 会评估下面的表达式:

X = 20 + 8 * 4 – 6 / 2

...等于 49; 过程是,8 * 4 = 32, 6 / 2 = 3, and 20 + 32 – 3 = 49。如果希望以不同的方

式评估表达式,可以使用括号将需要的部分括住。

例子:

X = (20 + 8) * 4 – 6 / 2

这项改变会先评估括号内的表达式,20 + 8,使得计算的结果为 109,而不是 49。

Page 259: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 259

表 4-10 指出了每个运算符的优先级,从 高 (level 0) 到 低 (level 12)。有较高优先级

的运算符会比较低优先级的运算符先执行;乘法在加法之前,绝对值在乘法之前等

等。唯一的例外是,如果表达式中有括号,括号可以高于所有的优先级.

中间赋值 Propeller 芯片的表达式引擎允许,可以处理,在运算中间阶段的赋值运算符。这称

为“中间赋值”,可以在较少的代码中执行复杂的表达式计算。例如,下面的表达式

依赖 X,和 X + 1。

X := X - 3 * (X + 1) / ||(X + 1)

利用增量运算符的中间赋值特性,同样的语句可以被重写:

X := X++ - 3 * X / ||X

假定 X 初始值为-5,这两个语句计算结果都为-2,并在计算结束后将该值存储在 X 中。为了简化表达式,第二个语句则依赖中间赋值(X++的部分)。增量运算符‘++’会被首先计算(高优先级)将 X 的值从 -5 增为 -4。因为它是“后增量(Post increment,参见 263 页增量, pre- 或 post- ‘+ +’)”,它会先返回 X的原有值,-5,给表

达式,然后写入新的值,-4,给 X。所以表达式的这部分“X++ - 3…”就变成了“-5 – 3…”,然后是绝对值,乘法和除法运算符依次计算,但是 X 的值已经改变了,所以会

使用新的值,-4,进行运算:

-5 – 3 * -4 / ||-4 → -5 – 3 * -4 / 4 → -5 – 3 * -1 → -5 – -3 = -2

有时可以使用中间赋值来将多行表达式压缩为单行表达式,这样可以得到较小的代

码尺寸和稍微快一点的执行速度。

下面的章节将详细解释在表 4-9 中列出的数学和逻辑运算符的功能。

常量赋值 ‘=’ 常量赋值运算符用于在 CON 块中声明编译时常量。例如:

CON _xinfreq = 4096000 WakeUp = %00110000

该代码将符号 _xinfreq 设置 4,096,000,将符号 WakeUp 设置为%00110000。那么之

后的程序中,如果出现了这些符号。编译器将使用这些值来代替相应的符号。参见. 199 页,CON。

Page 260: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 260 · Propeller Manual v1.0

这些声明是常量表达式,很多普通运算符可以被用于在编译时计算 终常量值。例

如,可以将上面的例子清除或按如下方式重写:

CON _xinfreq = 4096000 Reset = %00100000 Initialize = %00010000 WakeUp = Reset & Initialize

这里,WakeUp 在编译时仍然会被设置为%00110000,但是很明显,读者能认识到

WakeUp 符号的值来自 Reset 和 Initialize。

上面的例子,建立了 32 位的有符号整型常量;也可以建立 32 位浮点常量。要建立

浮点常量,表达式必须表达为浮点值;1) 整型值小数点之后至少有一位小数 2) 整型值

后写 E,然后是指数值,或 3) 1 和 2 两种方式结合。例如:

CON OneHalf = 0.5 Ratio = 2.0 / 5.0 Miles = 10e5

上面的代码建立了 3 个浮点常量。OneHalf 等于 0.5,Ratio 等于 0.4,Miles 等于 1,000,000。注意如果 Ratio 的定义是 2 / 5 而不是 2.0 / 5.0,表达式将被作为整型常量,

那么结果将作为整型值,等于 0。对于浮点常量表达式,表达式中的每个值都必须是

浮点值;不能将整型和浮点值混合使用,例如 Ratio = 2 / 5.0 是错误的。但是可以使用

FLOAT 声明将整型值转换为浮点值,比如 Ratio = FLOAT(2) / 5.0。

Propeller 编译器会将所有的浮点值作为单精度实数处理(IEEE-574 标准)。单精

度实数以 32 位存储,1 位符号位,8 位指数位,23 位尾数(小数部分)。这样可以有

大约 7.2 有效的十进制位。

对于运行时浮点运算,FloatMath 和 FloatString 对象提供了兼容于单精度数的数学

函数。

参见 221 FLOAT;309 页 ROUND;320 页 TRUNC,以及 FloatMath 和 FloatString 对象的

更多信息。

变量赋值 ‘:=’ 变量赋值运算符用于在方法(PUB 和 PRI 块)中为变量赋值。例如:

Page 261: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 261

Temp := 21 Triple := Temp * 3

在运行时,该代码会将 Temp 变量设置为 21,将 Triple 设置为 21 * 3,也就是 63。

和其他赋值运算符一起,变量赋值运算符可以用在表达式中为中间结果赋值,例如:

Triple := 1 + (Temp := 21) * 3

这个例子首先将 Temp 设置为 21,然后将 Temp 乘 3 然后加 1。 后将结果,64,赋

值给 Triple。

加 ‘+’, ‘+=’ 加运算符将两个数值相加。它可以被用在变量和常量表达式中。例子:

X := Y + 5

加法有赋值形式,+=, 它将其左侧的变量作为第一个运算对象,并将结果写入该

变量 。例如,

X += 10 'Short form of X := X + 10

这里,X 的值加 10 后结果存储回 X 中。加法的赋值形式也可以在表达式中用于中

间结果;参见 259 页中间赋值, page 259。

正号 ‘+’ (加的一元形式) 正号是加法的一元形式,使用方法和负号类似,只有一点要注意那就是它不能作为

赋值运算符。正号一般情况下会被编译器忽略,但是当运算对象的符号被强调时则会

被处理。例如:

Val := +2 - A

减 ‘-’, ‘-=’ 减运算符将两个值相减。它可以被用在变量和常量表达式中。例子:

X := Y - 5

减法有赋值形式,-=, 它将其左侧的变量作为第一个运算对象,并将结果写入该

变量 例如:

Page 262: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 262 · Propeller Manual v1.0

X -= 10 'Short form of X := X - 10

这里,X 的值减 10 后结果存储回 X 中。减法的赋值形式也可以在表达式中用于中

间结果;参见 259 页中间赋值。

负号 ‘-’ (减的一元形式) 负号是减法的一元形式。负号将运算对象的负号取反;一个正值变成负值或一个负

值变成正值。例如:

Val := -2 + A

当负号单独出现在变量的左侧时,它就变成了一个赋值运算符,例如:

-A

这会使 A 的值取负,并将结果存储回 A。

减量, 前减(pre-) 或 后减(post- ‘- -’) 减量运算符是一种特殊的运算符,它将变量减一后的值赋值给同一个变量。它只能

用于运行时表达式。减量运算有两种形式,前减量(pre-decrement)和后减量(post-decrement),具体是哪一种形式依赖于运算符的位置,如果在变量的左边,则是前减

量,如果是在变量右边就是后减量。这在编程时很有用,很多时候需要在使用变量的

值之前或之后将变量的值减量。例如:

Y := --X + 2

上面的例子是前减量的形式;它的意思是“在为下一项运算提供数值之前减一”。

它将 X 减一,然后将结果写回到 X,将该结果提供给之后的表达式使用。这个例子中

如果 X 起始值为 5, --X 会将 4 存储进 X中,然后计算表达式 4 + 2, 后将计算结果 6写入 Y。这条语句执行后,X 等于 4,Y 等于 6。

Y := X-- + 2

上面的例子是后减量的形式;它的意思是“在为下一项运算提供数值后减一”。它

先将 X 的当前值提供给下一项运算,将当前值减一后结果写入 X。如果 X 开始的值是

5,X—会把当前的值提供给表达式 (5 + 2) 进行计算,然后将 4 存储到 X。表达式 5 + 2 被计算的结果是 7,存储到 Y。这条语句执行后,X 等于 4,Y 等于 7。

Page 263: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 263

因为减量是赋值运算符,所以也会应用(参见 253 页)中间赋值的规则。假定 X 初始值是 5,则:

Y := --X + X

这里,X 首先被设置为 4,计算 4 + 4 ,然后将结果 8 赋值给 Y 。

Y := X-- + X

这里 X 的当前值 5 会被用于计算(加法), X 自身减为 4,然后计算 5 + 4, 后 Y 被赋值为 9。

增量, pre- 或 post- ‘+ +’ 增量运算符是一种特殊的运算符,它将变量加一后的值赋值给同一个变量。它只能

用于运行时表达式。增量运算有两种形式,前增量(pre-increment)和后增量(post-increment),具体是哪一种形式依赖于运算符的位置,如果在变量的左边,则是前增

量,如果是在变量右边就是后增量。这在编程时很有用,很多时候需要在使用变量的

值之前或之后将变量的值增量。例如:

Y := ++X - 4

上面的例子是前增量的形式;它的意思是“在为下一项运算提供数值之前增一”。

它将 X 增一,然后将结果写回到 X,将该结果提供给之后的表达式使用。这个例子中

如果 X 起始值为 5, ++X 会将 6 存储进 X中,然后计算表达式 6 - 4, 后将计算结果 2写入 Y。这条语句执行后,X 等于 6,Y 等于 2。

Y := X++ - 4

上面的例子是后增量的形式;它的意思是“在为下一项运算提供数值后增一”。它

先将 X 的当前值提供给下一项运算,将当前值增一后结果写入 X。如果 X 开始的值是

5,X++会把当前的值提供给表达式 (5 - 4) 进行计算,然后将 6 存储到 X。表达式 5 - 4 被计算的结果是 7,存储到 Y。这条语句执行后,X 等于 6,Y 等于 1。

因为增量是赋值运算符,所以也会应用(参见 253 页)中间赋值的规则。假定 X 初始值是 5,则:

Y := ++X + X

这里,X 首先被设置为 6,计算 6 + 6 ,然后将结果 12 赋值给 Y

Page 264: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 264 · Propeller Manual v1.0

Y := X++ + X

这里 X 的当前值 5 会被用于计算(加法), X 自身增为 6,然后计算 5 + 6, 后 Y 被赋值为 11。

乘, 返回低位 ‘*’, ‘*=’ 该运算符也称作乘低(Multiply-Low),或简单的称为乘法。它可以被用于变量和

常量表达式。当用于变量表达式或整型常量表达式时,乘低将两个值相乘,返回 64 位

结果的低 32 位。当用于浮点常量表达式时,乘低运算将两个值相乘,返回 32 位单精

度浮点值。例如:

X := Y * 8

Multiply-Low 有赋值形式 *=, 它将其左侧的变量作为第一个运算对象,并将结果写

入该变量 例如,

X *= 20 ' X := X * 20的简写

这里,X 的值乘以 20,结果的低 32 位被存储回 X。Multiply-Low 的赋值形式也可

以在表达式中用于中间结果;参见 259 页中间赋值。

乘, Return High‘**’, ‘**=’ 该运算符也称为乘高(Multiply-High),它可以被用于变量和整型常量表达式,

但是不能用于浮点常量表达式。 Multiply High 将两个值相乘,返回 64 位结果的高 32位。例如:

X := Y ** 8

如果 Y 起始值是 536,870,912 (229),那么 Y ** 8 等于 1;也就是结果的高 32 位值。

Multiply-High 有赋值形式 **=, 它将其左侧的变量作为第一个运算对象,并将结果

写入该变量 例如,

X **= 20 ' X := X ** 20的简写

这里,X 的值乘 20,结果的高 32 位被存储回 X。Multiply-High 的赋值形式也可以

在表达式中用于中间结果;参见 259 页中间赋值。

Page 265: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 265

除 ‘/’, ‘/=’ Divide 可以被用于变量和常量表达式,当用于变量表达式或整型常量表达式时,它

将两个值相除,返回 32 位整型结果。当用于浮点常量表达式时,它返回两个值相除后

的 32 位单精度浮点结果。例如:

X := Y / 4

Divide 有赋值形式 /=, 它将其左侧的变量作为第一个运算对象,并将结果写入该变

量 例如,

X /= 20 ' X := X / 20的简写形式

这里,X 的值除以 20,计算的结果存储回 X。Divide 的赋值形式也可以在表达式中

用于中间结果; 参见 259 页中间赋值。

模数 ‘//’, ‘//=’ 模数运算符(Modulus)可以被用于变量和整型常量表达式, 但是不能用于浮点常

量表达式。 它返回两个值相除后的 32 位整型余数。例如

X := Y // 4

如果 Y 的值为 5,Y // 4 等于 1,意思是 5 除 4 的结果是一个实数,该实数的小数

部分等于¼或 .25。

Modulus 有赋值形式 //=, 它将其左侧的变量作为第一个运算对象,并将结果写入该

变量 例如,

X //= 20 ' X := X // 20的简写

这里,the value of X 的值除以 20,32 位余数被存储回 X。Modulus 的赋值形式也可

以在表达式中用于中间结果;参见 259 页中间赋值。

Limit Minimum ‘#>’, ‘#>=’ Limit Minimum 运算符比较两个值,返回 大的那个;Limit Minimum 可以被用于

变量和常量表达式。例如

X := Y - 5 #> 100

Page 266: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 266 · Propeller Manual v1.0

上面的例子从 Y 的值减 5,将结果 小值限制为 100。如果 Y 等于 120,则 120 – 5 = 115;大于 100,所以 X 被设置为 115。如果 Y 等于 102,则 102 – 5 = 97;小于 100,所以 X 被设置为 100。

Limit Minimum 有赋值形式 #>=, 它将其左侧的变量作为第一个运算对象,并将结果

写入该变量 例如,

X #>= 50 ' X := X #> 50的简写

这里,X 的值被限制为 小 50,结果存储回 X. Limit Minimum 的赋值形式也可以

在表达式中用于中间结果;参见 259 页中间赋值。

Limit Maximum ‘<#’, ‘<#=’ Limit Maximum 运算符运算符比较两个值,返回 小的那个;Limit Maximum 可以

被用于变量和常量表达式。例如

X := Y + 21 <# 250

上面的例子将 Y 的值加 21,将结果 大值限制为 250。如果 Y 等于 200,

则 200 + 21 = 221;小于 250,所以 X 被设置为 221。如果 Y 等于 240,则

240 + 21 = 261;大于 250,所以 X 被设置为 250。 Limit Maximum 有赋值形式 <#=, 它将其左侧的变量作为第一个运算对象,并将结

果写入该变量 例如,

X <#= 50 ' X := X <# 50的简写

这里,X 的值被限制为 大 50,结果存储回 X. Limit Maximum 的赋值形式也可以

在表达式中用于中间结果;参见 259 页中间赋值。

平方根 ‘^^’ 平方根运算符返回一个值的平方根。Square Root 可以被用于变量和常量表达式。

当与变量表达式或整型常量表达式一起使用时,Square Root 返回 32 位截去小数后的

结果。当与浮点常量表达式一起使用时,Square Root 返回 32 位单精度浮点结果。例

如:

X := ^^Y

当平方根运算符单独出现在变量的左侧时,它就变成了一个赋值运算符,例如:

Page 267: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 267

^^Y

这会使 Y 的平方根存储到 Y中。

绝对值 ‘||’ 绝对值运算符,也称为绝对值,返回一个数的绝对值(该数值的正值)。Absolute

Value 可以被用于变量和常量表达式。当与变量表达式或整型常量表达式一起使用

时, Absolute Value 返回 32 位整型结果。当与浮点常量表达式一起使用时,Absolute Value 返回 32 位单精度浮点结果。例如:

X := ||Y

如果 Y 等于 -15,绝对值 15 会存储到 X中。

当绝对值运算符单独出现在变量的左侧时,它就变成了一个赋值运算符,例如:

||Y

这会使 Y 的绝对值存储到 Y中。

Sign-Extend 7 或 Post-Clear ‘~’ 该运算符可以有两种用法,具体是哪一种用法取决于它出现在变量的左侧还是右

侧。它只能用于运行时变量表达式。当出现在变量左侧时,就是 Sign-Extend 7 的形

式;如果出现在变量的右侧则是 Post-Clear 形式。

下面的例子使用的是 Sign-Extend 7 运算符形式:

Y := ~X + 25

这个例子中的 Sign-Extend 7 运算符扩展了值 X 的符号,从 bit 7 移动到 bit 31。一

个 32 位有符号整数以对二的补码的形式存储, 高位(31)表明了值的符号(正或

负)。 有时在用简单的数据运算时,计算的字节型结果可能会在-128 到+127 的范围

内,需要作为有符号整数处理。当需要利用这些字节型值执行进一步的计算时,可以

使用 Sign-Extend 7 运算符将这些数转换为 32 位有符号整数的形式。在上面的例子

中,假定 X 代表值-20,以 8 位对二的补码的形式存储就是 236(%11101100)。表达

式中 ~X 会将 X 的符号从第 7 位扩展到第 31 位,形成-20 的 32 位对二的补码形式

(%11111111 11111111 11111111 11101100)。将该符号扩展后的数值与 25 相加,得

到的结果是 5,如果没有使用合适的符号扩展,那么结果就是 261。

Page 268: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 268 · Propeller Manual v1.0

下面的例子使用的是 Post-Clear 运算符形式:

Y := X~ + 2

这个例子中的 The Post-Clear 运算符在将变量的值提供给下一项运算后将变量清零

(所有的位为低),如果在例子中的 X 的初始值是 5,那么 X~ 会将当前 X 的值提供给

表达式(5 + 2)进行计算,然后将 X的值清零。表达式 5 + 2 计算结果是 7,被存储到 Y

中。这条语句执行后,X 等于 0,Y 等于 7。

因为 Sign-Extend 7 和 Post-Clear 运算符都是赋值运算符,所以中间赋值的规则也适

用于它们(参见 259 页)。

Sign-Extend 15 或 Post-Set ‘~~’ 该运算符可以有两种用法,具体是哪一种用法取决于它出现在变量的左侧还是右

侧。它只能用于运行时变量表达式。当出现在变量左侧时,就是 Sign-Extend 15 的形

式;如果出现在变量的右侧则是 Post-Set 形式。

下面的例子使用的是 Sign-Extend 15 运算符形式:

Y := ~~X + 50

这个例子中的 Sign-Extend 15 运算符扩展了值 X 的符号,从 bit 15 移动到 bit 31。一个 32 位有符号整数以对二的补码的形式存储, 高位(31)表明了值的符号(正或

负)。有时在用简单的数据运算时,计算的字型结果可能会在-32768 到 +32767 的范围

内,需要作为有符号整数处理。需要利用这些双字型值执行进一步的计算时,可以使

用 Sign-Extend 7 运算符将这些数转换为 32 位有符号整数的形式。在上面的例子中,

假定 X 代表值 -300,以 16 位对二的补码的形式存储就是 65236(%11111110 11010100)。表达式中 ~X 会将 X 的符号从第 15 位扩展到第 31 位,形成-300 的 32 位

对二的补码形式(%11111111 11111111 11111110 11010100)。将该符号扩展后的数值

与 50 相加,得到的结果是-250,如果没有使用合适的符号扩展,那么结果就是

65,286。

下面的例子使用的是 Post-Set 运算符形式。

Y := X~~ + 2

这个例子中的 Post-Set 运算符在将变量的值提供给下一项运算后将变量的值设置

为-1。(所有的位为高)如果在例子中的 X 初始值为 6,X~~ 会将当前 X 的值提供给表

Page 269: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 269

达式(6 + 2)进行计算,然后将-1 存储到 X 中。表达式 6 + 2 计算的结果是 9,被存储

到 Y中。该语句被执行后,X 等于-1,Y 等于 8。

因为 Sign-Extend 15 和 Post-Set 运算符都是赋值运算符,所以中间赋值的规则也适

用于它们(参见 259 页)。

算数右移 ‘~>’, ‘~>=’ 算数右移(Shift Arithmetic Right)运算符类似于右移运算符,不同之处在于它保留

了符号,就像将一个有符号数除以 2,4,8…一样。算数右移可以用于变量和整型常

量表达式,但是不能用于浮点常量表达式。例如:

X := Y ~> 4

上面的例子将 Y 右移了 4 位,并保留了符号位,如果 Y 等于-3200 (%11111111 11111111 11110011 10000000),那么 -3200 ~> 4 = -200 (%11111111 11111111 11111111 00111000)。如果使用右移运算符,那么结果将是 268,435,256(%00001111 11111111 11111111 00111000)。

Shift Arithmetic Right 有赋值形式 ~>=, 它将其左侧的变量作为第一个运算对象,并

将结果写入该变量 例如,

X ~>= 2 ' X := X ~> 2的简写

这里,X 的值右移了两位,保留了符号,结果存储回 X。算数右移运算符的赋值形

式也可以在表达式中用于中间结果;参见 259 页中间赋值。

Random ‘?’ 随机数(Random)运算符是一个特殊的运算符,它将变量的值作为伪随机数的种

子,据此产生一个随机数,将该随机数赋值给该变量。它只能用于运行时变量表达

式。随机数有两种形式,正向和逆向,具体是哪一种形式取决于它在变量的左侧还是

右侧。在变量左侧时是正向形式,在变量右侧则是逆向形式。

Random 运算符在-2,147,483,648 到+2,147,483,647 的范围内产生一个伪随机数。之

所以称之为伪随机数是因为虽然这个数看起来是随机的,但是它其实是由逻辑运算将

将“种子”值插入包含超过 40 亿个基础随机数列中(产生的)。如果再次使用用一个

种子,那么还是会产生同一个序列。Propeller 芯片的随机数输出是可逆的;实际上,

它使用的是一个 32 位长度,4 抽头的 LFSR(32-bit maximum-length, four-tap LFSR 线

Page 270: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 270 · Propeller Manual v1.0

性反馈移位寄存器),在 LSB ( 低位, 右侧的位) 和 MSB ( 高位, 左侧的位) 都有抽头,允许双向操作。

将伪随机数序列看成是 40 亿个数字的列表。从实际指定的种子的值开始,向前移

动会产生一个指定的数集。如果将 后一个产生的数字作为第一个种子值,并逆向移

动,就会得到同样的一个序列,但是方向相反。这在一些应用中很有用。

下面是一个例子:

?X

这是随机数运算符的正向形式;它用 X 的当前值来正向检索下一个伪随机数,并将

该数值存储回 X。再次执行?X 会产生一个不同的值,然后存储回 X。

X?

上面的例子为随机数运算符的逆向形式;它用 X 的当前值来逆向检索下一个伪随机

数,并将该数值存储到 X。 再次执行 X? 会产生一个不同的值,并存储到 X中。

因为 Random 是一个赋值运算符,所以也适用中间赋值的规则(参见 259 页)。

位运算 解码 ‘|<’ 位解码运算符将一个值(0-31)解码为 32 位的长字型值,该值对应于原有数值的

二进制值,但其中只有一位被设置为高。位解码运算符可以被用于变量和整型常量表

达式,但是不能用于浮点常量表达式。例如:

Pin := |<PinNum

上面的例子将 Pin 设置为 32 位值,它的高位是由 PinNum指定的。

If PinNum is 3, Pin is set equal to %00000000 00000000 00000000 00001000.

If PinNum is 31, Pin is set equal to %10000000 00000000 00000000 00000000.

位解码运算符有很多用途,其中 有用的一种是将 I/O 引脚号转换为 32 位模式,

转换后的值对应于每个引脚的 I/O 寄存器。例如,位解码运算符可以计算 WAITPEQ 和 WAITPNE 命令的掩码参数。

当位解码运算符单独出现在变量的左侧时,它就变成了一个赋值运算符,例如:

|<PinNum

Page 271: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 271

这使 PinNum 的值被解码后存储回 PinNum。

Bitwise Encode ‘>|’ 位运算编码运算符将一个 32 位长字型值编码为数值,该数的值加一后表示相应的

位为高。位编码运算符可以被用于变量和整型常量表达式,但是不能用于浮点常量表

达式。例如

PinNum := >|Pin

上面的例子将 PinNum 设置为等于 Pin的 高位的索引值加 1。

如果 Pin 是 %00000000 00000000 00000000 00000000, PinNum 被设置为等于 0;不

需要置位。

如果 Pin 是 %00000000 00000000 00000000 10000000, PinNum 等于 8,第 7 位置位。

如果 Pin 是 %10000000 00000000 00000000 00000000, PinNum 等于 32,第 31 位置

位。

如果 Pin 是 %00000000 00010011 00010010 00100000, PinNum 等于 21,第 20 位是

高的位,会被置位。

位左移 ‘<<’, ‘<<=’ 位左移运算符将第一个运算对象的位左移,移动的位数由第二个运算对象决定。原

有的 高位(MSB, 左边的位)变成 低位(LSB, 右边的位),并且被置 0。Bitwise Shift Left 可以被用于变量和整型常量表达式,但不能用于浮点常量表达式。例

如:

X := Y << 2

如果 Y 起始值为:

%10000000 01110000 11111111 00110101

...那么 Bitwise Shift Left 运算符会将将该值左移两位,X 变为:

%00000001 11000011 11111100 11010100

因为二进制的基数是 2,左移就相当于将该值乘以 2,也就是 2b,这里 b 是位移动

的个数。

Page 272: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 272 · Propeller Manual v1.0

Bitwise Shift Left 有赋值形式 <<=, 它将其左侧的变量作为第一个运算对象,并将结

果写入该变量 例如,

X <<= 4 ' X := X << 4的简写

这里,X 的值左移了四位后存储回 X。Bitwise Shift Left 的赋值形式也可以在表达式

中用于中间结果; 参见 259 页中间赋值。

位右移 ‘>>’, ‘>>=’ 位右移运算符将第一个运算对象的位右移,移动的位数由第二个运算对象决定。原

有的 低位(LSB, 右边的位)变成 高位(MSB, 左边的位),并且被置 0. Bitwise Shift Right 可以被用于变量和整型常量表达式,但不能用于浮点常量表达式。

例如:

X := Y >> 3

如果 Y 起始值为:

%10000000 01110000 11111111 00110101

...那么 Bitwise Shift Right 运算符运算符会将将该值右移三位, X 变为:

%00010000 00001110 00011111 11100110

因为二进制的基数是 2,左移就相当于将该值除以 2,也就是 2b,这里 b 是位移动

的个数。

Bitwise Shift Right 有赋值形式 >>=, 它将其左侧的变量作为第一个运算对象,并将

结果写入该变量 例如,

X >>= 2 ' X := X >> 2的简写

这里,X 的值右移了两位后存储回 X。Bitwise Shift Right 的赋值形式也可以在表达

式中用于中间结果;参见 259 页中间赋值。

位左转 ‘<-’, ‘<-=’ 位左转运算符类似于位左移运算符。除了 高位(MSB, 左边的位)被移动到

低位(LSB, 右边的位)会保存原有的位之外,两者没什么不同。Bitwise Rotate Left 可以被用于变量和整型常量表达式,但不能用于浮点常量表达式。例如:

X := Y <- 4

Page 273: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 273

如果 Y 起始值为:

%10000000 01110000 11111111 00110101

Bitwise Rotate Left 运算符会将该值左移四位,将原有的 高位四位移动到 低四

位,X 变为:

%00000111 00001111 11110011 01011000

Bitwise Rotate Left 有赋值形式 <-=, 它将其左侧的变量作为第一个运算对象,并将

结果写入该变量 例如,

X <-= 1 'Short form of X := X <- 1

这里,X 的值左转一位后存储回 X。Bitwise Rotate Left 的赋值形式也可以在表达式

中用于中间结果;参见 259 页中间赋值。

位右转 ‘->’, ‘->=’ 位右转运算符类似于位右移运算符。除了 低位(LSB, 右边的位)被移动到

高位(MSB, 左边的位)会保存原有的位之外,两者没什么不同。Bitwise Rotate Right 可以被用于变量和整型常量表达式,但不能用于浮点常量表达式。例如:

X := Y -> 5

如果 Y 起始值为:

%10000000 01110000 11111111 00110101

... Bitwise Rotate Right 运算符运算符会将该值右移五位,将原来的低五位移动到高

五位,X 变为:

%10101100 00000011 10000111 11111001

Bitwise Rotate Right 有赋值形式 ->=, 它将其左侧的变量作为第一个运算对象,并将

结果写入该变量。例如,

X ->= 3 'Short form of X := X -> 3

这里,X 的值右转三位后存储回 X 。Bitwise Rotate Right 的赋值形式也可以在表达

式中用于中间结果;参见 259 页中间赋值。

Page 274: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 274 · Propeller Manual v1.0

Bitwise Reverse ‘><’, ‘><=’ 位反转运算符将第一个操作数的指定位反转,反转的位数由第二个操作数决定。未

反转的位会被清零。Bitwise Reverse 可以被用于变量和整型常量表达式,但不能用于

浮点常量表达式。例如

X := Y >< 6

如果 Y 起始值为:

%10000000 01110000 11111111 00110101

... Bitwise Reverse 运算符会将它的低 6 位反转,将其它的位清零,X变为:

%00000000 00000000 00000000 00101011

Bitwise Reverse 有赋值形式 ><=, 它将其左侧的变量作为第一个运算对象,并将结果

写入该变量 例如,

X ><= 8 ' X := X >< 8的简写

这里,X 的低 8 位被反转,其它的位被清零,运算结果存储回 X. Bitwise Reverse 的赋值形式也可以在表达式中用于中间结果;参见 259 页中间赋值。

位与 ‘&’, ‘&=’ Bitwise AND 运算符将将第一个运算对象的位和第二个运算对象的位作 Bitwise

AND 可以被用于变量和整型常量表达式,但是不能用于浮点常量表达式。

两个操作数的每一位都受下面所列出的逻辑的支配:

表 4-11: Bitwise AND 真值表

Bit 状态 结果

0 0 0

0 1 0

1 0 0

1 1 1

例如:

X := %00101100 & %00001111

Page 275: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 275

上面的例子将%00101100 和 %00001111 做与运算,运算结果%00001100 写回到

X。

Bitwise AND 有赋值形式 &=, 它将其左侧的变量作为第一个运算对象,并将结果写

入该变量 例如,

X &= $F ' X := X & $F的简写

这里,X 的值和$F 做与运算 结果存储回 X。Bitwise AND 的赋值形式也可以在表达

式中用于中间结果;参见 259 页中间赋值, page 259。

注意,不要将位运算与 ‘&’ 运算符和布尔与运算符 ‘AND’相混淆。Bitwise AND 是用

于位操作的,而 Boolean AND 是用于比较的 (参见 277 页)。

位或 ‘|’, ‘|=’ Bitwise OR 运算符执行位或(Bitwise OR),将第一个运算对象的位和第二个运算

对象的位作或运算。Bitwise OR 可以被用于变量和整型常量表达式, 但是不能用于浮

点常量表达式。

两个操作数的每一位都受下面所列出的逻辑的支配

表 4-12: Bitwise OR 真值表

Bit 状态 结果

0 0 0

0 1 1

1 0 1

1 1 1

例如:

X := %00101100 | %00001111

上面的例子将%00101100 和 %00001111 做或运算,运算结果%00101111,写回到X。

Bitwise OR 有赋值形式 |=, 它将其左侧的变量作为第一个运算对象,并将结果写入

该变量 例如,

Page 276: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 276 · Propeller Manual v1.0

X |= $F 'Short form of X := X | $F

这里,X 的值与$F 做或运算,结果存储回 X。Bitwise OR 的赋值形式也可以在表达

式中用于中间结果;参见 259 页中间赋值, page 259。

注意,不要将 Bitwise OR ‘|’和 Boolean OR ‘OR’混淆。Bitwise OR 是用于位操作

的, 而 Boolean OR 是用于比较的 (参见 278 页)。

位异或 ‘^’, ‘^=’ Bitwise XOR 运算符执行位异或(bitwise XOR)运算。它将第一个运算对象的位和

第二个运算对象的位作异或。Bitwise XOR 可以被用于变量和整型常量表达式,但是

不能用于浮点常量表达式。

两个操作数的每一位都受下面所列出的逻辑的支配。

表 4-13: Bitwise XOR 真值表

Bit 状态 结果

0 0 0

0 1 1

1 0 1

1 1 0

例如:

X := %00101100 ^ %00001111

上面的例子将%00101100 和 %00001111 异或,将结果%00100011 存储到 X。

Bitwise XOR 有赋值形式 ^=, 它将其左侧的变量作为第一个运算对象,并将结果写

入该变量。例如,

X ^= $F ' X := X ^ $F的简写

这里,X 的值与 $F 异或,结果存储回 X. Bitwise XOR 的赋值形式也可以在表达式

中用于中间结果;参见 259 页中间赋值。

Page 277: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 277

位非 ‘!’ 位运算非 ‘!’ 运算符将它的操作数逐位取反(反向,或互补),它可以被用于变量

和整型常量表达式,但是不能用于浮点常量表达式。

两个操作数的每一位都受下面所列出的逻辑的支配

表 4-14: Bitwise NOT 真值表

Bit 状态 结果

0 1

1 0

例如:

X := !%00101100

上面的例子将 %00101100 的值取非,并将结果%11010011,写回到 X。

当位非运算符单独出现在变量的左侧时,它就变成了一个赋值运算符,例如:

!Flag

这将使 Flag 的值取反后存储回 Flag中。

注意,不要将位非运算符‘!’和布尔非运算符‘NOT’相混淆。位非运算符是用于位操

作的, 而布尔非运算符是用于比较的 (参加 279)。

布尔与 ‘AND’, ‘AND=’ Boolean AND ‘AND’ 运算符比较两个操作数,如果两个值都是 TRUE (非零),则返回

TRUE (-1), 否则如果其中一个或两个操作数是 FALSE (0),则返回 FALSE (0)。布尔与可以

被用于变量和常量表达式。例如

X := Y AND Z

上面的例子比较 Y 和 Z 的值,并根据比较的结果将 X 设置为:如果 Y 和 Z 是非

零值,则 X 的值为 TRUE (-1),如果 Y 和 Z 是零,则 X 为 FALSE (0)。比较期间,如果两个

值都是非零的,会将两个值调整为-1,这样所有的值都会是 0 或-1,所以比较就变成

了:“如果 Y 为真且 Z 为真…”。

Page 278: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 278 · Propeller Manual v1.0

该运算符常常和其他比较运算符结合使用,参考下面的例子。

IF (Y == 20) AND (Z == 100)

这个例子计算 Y == 20 和 Z == 100的结果,如果都为真,则布尔与运算符返回 TRUE (-1)。

Boolean AND 有赋值形式 AND=, 它将其左侧的变量作为第一个运算对象,并将结果

写入该变量 例如,

X AND= True ' X := X AND True的简写

这里,如果 X 的值是非零的,会被调整为 TRUE,然后和 TRUE 相比较,布尔结果

(TRUE / FALSE, -1 / 0) 会存储回 X中。Boolean AND 的赋值形式也可以在表达式中用于中

间结果;参见 259 页中间赋值。

注意,不要将 Boolean AND ‘AND’ 和 Bitwise AND ‘&’相混淆。Boolean AND 是用于

比较的 而 Bitwise AND 是用于位操作的, (see page 274).

布尔或 ‘OR’, ‘OR=’ 布尔或运算符(Boolean OR) ‘OR’ 比较两个操作数,如果两个值有一个是 TRUE (非零),则返回 TRUE (-1),如果两个操作数都是 FALSE (0),则返回 FALSE (0)。Boolean OR 可以被用于变量和常量表达式。例如

X := Y OR Z

上面的例子比较 Y 和 Z 的值,并根据比较的结果设置 X 的值:如果 Y 或 Z 是非

零值,则返回 TRUE (-1) 。如果 Y 和 Z 都是零,则返回 FALSE (0)。在比较时,它会将两

个值都做调整,如果是非零值,则调整为-1,这样,比较就变成了:“如果 Y 为真或 Z 为真…”。

该运算符常常和其他比较运算符组合使用,参考下面的例子。

IF (Y == 1) OR (Z > 50)

这个例子计算 Y == 1 和 Z > 50 的结果,如果结果为真,布尔或运算符返回 TRUE (-1)。

Boolean OR 有赋值形式 OR=, 它将其左侧的变量作为第一个运算对象,并将结果写

入该变量。例如,

Page 279: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 279

X OR= Y ' X := X OR Y的简写

这里,如果 X 的值是非零的,那就会被提升(promote)为 TRUE,然后会与 Y (如果

是非零值,同样会被提升为 TRUE)作比较,比较所得的布尔结果(TRUE / FALSE, -1 / 0)存储到 X 中。 Boolean OR 的赋值形式也可以在表达式中用于中间结果;参见 259 页中

间赋值。

注意,不要将 Boolean OR ‘OR’ 和 Bitwise OR‘|’.相混淆。Boolean OR 是用于比较的 而 Bitwise OR 是用于位操作的, (参见 275 页).

布尔非 ‘NOT’ 布尔非 ‘NOT’ 运算符,如果操作数是 FALSE (0),则返回 TRUE (-1),如果操作数是

TRUE (非零),则返回 FALSE (0)。它可以被用于变量和常量表达式。例如

X := NOT Y

上面的例子返回 Y 的布尔相反值。如果 Y 是零,则返回 TRUE (-1),如果 Y 是非零

的,则返回 FALSE (0)。比较时,如果 Y 是非零数,则将其的值调整为-1,这样,比较

就变成了“如果非真”或“如果非假”。

该运算符常常和其他比较运算符组合使用,参考下面的例子。

IF NOT ( (Y > 9) AND (Y < 21) )

这个例子计算(Y > 9 AND Y < 21)的结果,返回该结果的布尔相反值。如果 Y 是在

10 到 20 的范围内,则返回 TRUE (-1)。

当位布尔非运算符单独出现在变量的左侧时,它就变成了一个赋值运算符,例如:

NOT Flag

这将使 Flag 的值取反(布尔非),结果存储回 Flag中。

请不要把布尔非 ‘NOT’ 和位运算非 ‘!’混淆。布尔非用于比较,而位运算非是进行位

操作的。(参见 277 页)。

布尔等于 ‘==’, ‘===’ 布尔运算符 Is Equal 比较两个操作数,如果第一个值等于第二个值,则返回 TRUE (-

1) ,否则返回 FALSE (0)。Is Equal 可以被用于变量和常量表达式。例如

Page 280: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 280 · Propeller Manual v1.0

X := Y == Z

上面的例子比较 Y 和 Z 的值,并根据比较的结果设置 X 的值:如果 Y 等于 Z,则 X 等于 TRUE (-1),或者如果 Y 不等于 Z 则 X 等于 FALSE (0)。

该运算符常常用于条件表达式, 参考下面的例子。

IF (Y == 1)

这里,如果 Y 等于 1,Is Equal 运算符 TRUE。

Is Equal 有赋值形式 ===, 它将其左侧的变量作为第一个运算对象,并将结果写入该

变量 例如,

X === Y ' X := X == Y的简写 这里,X 和 Y 作比较,如果相等 X 被设置为 TRUE (-1),否则 X 被设置为 FALSE (0)。Is Equal 的赋值形式也可以在表达式中用于中间结果;参见 259 页中间赋值。

布尔不等于 ‘<>’, ‘<>=’ 布尔运算符 Is Not Equal 比较两个操作数,如果第一个值不等于或小于第二个值,

则返回 True (-1),否则返回 FALSE (0)。Is Not Equal 可以被用于变量和常量表达式。例

X := Y <> Z

上面的例子比较 Y 和 Z 的值,并根据比较的结果设置 X 的值:如果 Y 不等于 Z,

则 X等于 TRUE (-1) ,或者如果 Y 等于 Z则 X等于 FALSE (0) 。

该运算符常常用于条件表达式, 参考下面的例子。

IF (Y <> 25)

这里,如果 Y 不等于 25,Is Not Equal 运算符返回 TRUE。

Is Not Equal 有赋值形式 <>=, 它将其左侧的变量作为第一个运算对象,并将结果写

入该变量 例如,

X <>= Y ' X := X <> Y的简写

Page 281: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 281

这里,X 和 Y 作比较,如果它们不相等,X 被设置为 TRUE (-1),否则 X 被设置为

FALSE (0)。Is Not Equal 的赋值形式也可以在表达式中用于中间结果;参见 259 页中间

赋值。

布尔小于 ‘<’, ‘<=’ 布尔小于运算符(Is Less Than)比较两个操作数,如果第一个值小于第二个值,

则返回 TRUE (-1) 否则返回 FALSE (0)。Is Less Than 可以被用于变量和常量表达式。例如

X := Y < Z 上面的例子比较 Y 和 Z 的值,并根据比较的结果设置 X 的值:如果 Y 小于 Z,则 X 等

于 TRUE (-1),或如果 Y 等于或大于 Z,则 X等于 FALSE (0) 。

该运算符常常用于条件表达式, 参考下面的例子。

IF (Y < 32)

这里,如果 Y 小于 32,Is Less Than 运算符返回 TRUE。

Is Less Than 有赋值形式 <=, 它将其左侧的变量作为第一个运算对象,并将结果写

入该变量 例如,

X <= Y ' X := X < Y的简写

这里,X 和 Y 作比较,如果 X 小于 Y, X 被设置为 TRUE (-1),否则 X 被设置为 FALSE (0)。 Is Less Than 的赋值形式也可以在表达式中用于中间结果; 参见 259 页中间赋

值。

布尔大于 ‘>’, ‘>=’ 布尔运算符大于(Is Greater Than)比较两个操作数,如果第一个值大于第二个

值,则返回 TRUE (-1) ,否则返回 FALSE (0)。它可以被用于变量和常量表达式。例如

X := Y > Z

上面的例子比较 Y 和 Z 的值,并根据比较的结果设置 X 的值:如果 Y 大于 Z,则 X

等于 TRUE (-1),或如果 Y 等于或小于 Z,则 X等于 FALSE (0) 。

该运算符常常用于条件表达式, 参考下面的例子。

IF (Y > 50)

Page 282: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 282 · Propeller Manual v1.0

这里,如果 Y 大于 50,则 Is Greater Than 运算符返回 TRUE。

Is Greater Than 有赋值形式 >=, 它将其左侧的变量作为第一个运算对象,并将结果

写入该变量 例如,

X >= Y ' X := X > Y的简写

这里,X 和 Y 作比较,如果 X 大于 Y, X 被设置为 TRUE (-1),否则 X 被设置为 FALSE (0)。 Is Greater Than 的赋值形式也可以在表达式中用于中间结果;参见 259 页中间赋

值。

布尔小于等于 ‘=<’, ‘=<=’ 布尔运小于等于运算符(Is Equal or Less)比较两个操作数,如果第一个值等于或

小于第二个值,则返回 TRUE (-1) ,否则返回 FALSE (0)。它可以被用于变量和常量表达

式。例如:

X := Y =< Z

上面的例子比较 Y 和 Z 的值,并根据比较的结果设置 X 的值:如果 Y 等于或小于

Z,则 X等于 TRUE (-1),或如果 Y 大于 Z,则 X等于 FALSE (0) 。

该运算符常常用于条件表达式, 参考下面的例子。

IF (Y =< 75)

这里,如果 Y 等于或小于 75,则 Is Equal or Less 运算符返回 TRUE。

Is Equal or Less 有赋值形式 =<=, 它将其左侧的变量作为第一个运算对象,并将结果

写入该变量 例如,

X =<= Y ' X := X =< Y的简写

这里,X 和 Y 作比较,如果 X 等于或小于 Y, X 被设置为 TRUE (-1),否则 X 被设置为 FALSE (0)。Is Equal or Less 的赋值形式也可以在表达式中用于中间结果;参见 259 页中

间赋值。

Page 283: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 283

布尔大于等于 ‘=>’, ‘=>=’ 布尔运算符 Is Equal or Greater 比较两个操作数,如果第一个值等于或大于第二个

值,则返回 TRUE (-1),否则返回 FALSE (0)。Is Equal or Greater 可以被用于变量和常量

表达式。例如

X := Y => Z

上面的例子比较 Y 和 Z 的值,并根据比较的结果设置 X 的值:如果 Y 等于或大于

Z,则 X等于 TRUE (-1),或如果 Y小于 Z,则 X等于 FALSE (0) 。

该运算符常常用于条件表达式,参考下面的例子。

IF (Y => 100)

这里,如果 Y 等于或大于 100,则 Is Equal or Greater 运算符返回 TRUE。

Is Equal or Greater 有赋值形式 =>=, 它将其左侧的变量作为第一个运算对象,并将

结果写入该变量 例如,

X =>= Y ' X := X => Y的简写

这里,X 和 Y 作比较,如果 X 等于或大于 Y, X 被设置为 TRUE (-1),否则 X 被设置为 FALSE (0). Is Equal or Greater 的赋值形式也可以在表达式中用于中间结果;参见 259 页

中间赋值。

符号地址 ‘@’ 符号地址运算符返回该运算符之后的符号的地址。符号地址可以用于变量和整型常

量表达式,但是不能用于浮点常量表达式。例如:

BYTE[@Str] := "A"

在上面的例子中,符号地址运算符返回符号 Str 的地址,该地址由 BYTE 内存数组

引用,将字符 "A" 存储在该地址中。

符号地址通常被用于将在 DAT 块中定义的字符串和数据结构的地址传递给一个方

法。

要注意到的是这是一个特殊的运算符,它在常量表达式和变量表达式中的行为是不

一样的。在运行时,就像上面的例子一样,它会返回富豪的绝对地址。这个运行时绝

对地址由对象程序的基址加上符号的偏移地址后形成。

Page 284: Propeller Manual - Parallax Home

(运算符)Operators – Spin语言参考

Page 284 · Propeller Manual v1.0

在常量表达式中,该运算符返回的是符号在对象内的偏移地址(offset)。它不能

返回运行时绝对地址,因为该地址会随对象的实际地址改变。要在常量中正确地使用

该运算符,例如数据表等,参见下面的对象地址加符号(Object Address Plus Symbol)运算符。

对象地址加符号 ‘@@’ 对象地址加符号(Object Address Plus Symbol)运算符返回当前对象程序的基址。

对象地址加符号运算符可以被用在变量表达式中。

先创建偏移地址表,然后在运行时,使用这些偏移来引用它们所表示的绝对运行时

地址。 例如,一个 DAT 块可以包含多个字符串,这些字符串可能会被直接或间接访

问。这里的示例 DAT 块中包含了字符串。

DAT Str1 byte "Hello.", 0 Str2 byte "This is an example", 0 Str3 byte "of strings in a DAT block.",0

在运行时,我们可以使用@Str1, @Str2, 和 @Str3,来直接访问这些字符串,但是要想间

接访问就会有麻烦,因为每个字符串的长度都不同;这就使得难于将它们中的一个作

为间接地址的基址进行计算。

看起来比较合理的解决方案是再建立一个地址自己的地址表例如:

DAT StrAddr word @Str1, @Str2, @Str3

该语句创建了一个字型表(table of words),它位于 StrAddr,每个字(word)都

包含了一个字符串的地址。不幸的是,对于编译时常量而言(比如 StrAddr 表中的常

量),运算符 @ 只能得到编译时偏移地址,而不是符号的运行时绝对地址。要取得真

实的运行时地址,我们需要将对象程序的基址地址和符号的偏移地址相加。这就是对

象地址加符号运算符所做的事情。例如:

REPEAT Idx FROM 0 TO 2 PrintStr(@@StrAddr[Idx])

上面的例子使 Idx 从 0 增加到 2。 StrAddr[Idx] 解析存储在表 StrAddr 中 Idx 的字

符串的编译时地址偏移量。StrAddr[Idx] 之前的@@ 运算符将对象的基址加到编译时偏

Page 285: Propeller Manual - Parallax Home

4: Spin语言参考– (运算符)Operators

Propeller Manual v1.0 · Page 285

移值上,形成一个有效的运行时字符串地址。PrintStr 方法的代码没有列出,它使用

该地址处理字符串的每一个字符。

Page 286: Propeller Manual - Parallax Home

OUTA, OUTB – Spin语言参考

Page 286 · Propeller Manual v1.0

OUTA, OUTB 32 位端口 A 和端口 B 的输出寄存器。 ((PUB PRI)) OUTA ⟨[Pin(s)]⟩ ((PUB PRI)) OUTB ⟨[Pin(s)]⟩ (Reserved for future use) 返回:如果用作源变量,将返回端口 A 和 B 的输出引脚的当前值。

• Pin(s) 是可选的表达式,或是一个范围表达式,其指定的引脚将会被访问,端口

A(0-31)或端口 B(32-63)。如果给定的是一个单独的表达式,则只有指定

的引脚会被访问。如果给定的是一个范围表达式(以范围形式给出的两个表达

式;x..y),则从开始表达式到结尾表达式之间所有的引脚都会被访问。 解释

OUTA 和 OUTB 是六个可以直接影响 I/O 引脚的六个寄存器 (DIRA, DIRB, INA, INB, OUTA 和 OUTB) 中的两个。 OUTA 寄存器保存了端口 A 中的 32 个 I/O 引脚的输出状态;位 0 到

位 31 对应于 P0 到 P31。 OUTB 寄存器保存了端口 B 中的 32 个 I/O 引脚的输出状态;位

0 到位 31 对应于 P32 到 P63。

注: OUTB 是为将来使用而保留的,Propeller P8X32A 不包含端口 B I/O 引脚,所以

以下我们只讨论 OUTA 。

OUTA 用于取得和设置端口 A 中一个或多个引脚的输出状态寄存器状态。一个低

(0)位会将 I/O 引脚下拉到地。一个高(1)位将 I/O 引脚上拉到 VDD (3.3 伏)。 OUTA 寄存器中的所有值在 cog 启动时都默认为 0。

每个 Cog 都可以访问所有的 I/O 引脚。实质上,所有的 I/O 引脚都是直接连接到每

个 cog 的,所以没有 Hub 相关的彼此独占/互斥访问(Hub-related mutually-exclusive access)。每个 cog 维护其自己的 OUTA 寄存器,这使得 cog 可以设置任意 I/O 引脚的输

出状态(低或高)。每个 cog 的输出状态都会与其它 cog 的输出状态相或,形成的 32位会成为端口 A 中引脚 P0 到 P31 的输出状态。每个 I/O 引脚的输出状态都是整个 cog集合相应 I/O 引脚的输出状态“线或”后的结果。参见 27 页上关于 I/O 的更多信息。

注意,每个 cog 的输出状态都是由其内部 I/O 硬件(输出寄存器,视频发生器等)

相或后的结果和所有的方向寄存器的状态相与后的结果组成的。

Page 287: Propeller Manual - Parallax Home

4: Spin语言参考– OUTA, OUTB

Propeller Manual v1.0 · Page 287

一个 I/O 引脚的实际输出是高或低,就像 cog 的输出状态所指定的那样,当且仅当

在同一个 cog 的方向寄存器的位(值)是高。该引脚的相应的方向寄存器(DIRA)的位是

高(1)。否则,该 cog 会指定引脚的状态为输入,其输出状态(的配置)会被忽略。

该配置可以被描述为如下简单规则:

A. 一个引脚的输出为低,当且仅当所有的活动的 cog 将其设置为输出,同时将其

设置为低。 B. A 一个引脚的输出为高,当有活动的 cog 将其设置为输出,同时将其设置为

高。

如果一个 cog 被禁止,那么它的方向寄存器会被清零,使其不会对 I/O 引脚的方向

和状态产生影响。

注意,因为 I/O 引脚的线或(Wired-OR)特性,实际上 cog 之间没有电气连接,所

以这些 cog 可以同时访问 I/O 引脚。这需要开发人员确保在运行时,不会在同一个 I/O引脚上产生逻辑冲突。

使用 OUTA 将 OUTA 置位或清零将会影响到 I/O 引脚的输出状态。同时请确保设置 DIRA 的相应

位,使其为输出。参考下例:

DIRA := %00000100_00110000_00000001_11110000 OUTA := %01000100_00110000_00000001_10010000

上面的 DIRA 行将 I/O 引脚 25,21,20,8,7,6,5 和 4 设置为输出,将其它引脚

设置为输入。OUTA 行将 I/O 引脚 30,25,21,20,8,7 和 4 设置为高,其它引脚为

低。其结果是 I/O 引脚 25,21,20,8,7 和 4 输出高,引脚 6 和 5 输出低。I/O 引脚

30 被设置为输入(DIRA 设定),所以在 OUTA 中 30 位所设置的高会被忽略,在该 cog上,该引脚仍然为输入。

使用可选的 Pin(s) 域,一元运算符 post-clear (~) 和 post-set (~~),cog 可以每次影响

一个 I/O 引脚 (1 位)。 Pin(s) 域将 I/O 引脚寄存器作为 32 位数组进行操作。例如:

DIRA[10]~~ '将 P10 设置为输出

OUTA[10]~ '使 P10 输出低

OUTA[10]~~ '使 P10 输出高

Page 288: Propeller Manual - Parallax Home

OUTA, OUTB – Spin语言参考

Page 288 · Propeller Manual v1.0

上面代码第一行将 I/O 引脚 10 设置为输出。第二行将 P10 的输出锁定位清零,使

P10 输出低(地)。第三行设置 P10 的输出锁定位,使 P10 输出高(VDD)。

在 Spin 语言中,OUTA 寄存器支持一种特殊形式的表达式,称为范围表达式,它允

许一次作用于一组 I/O 引脚,而不会影响其它的引脚。要做到这一点,在 Pin(s)域使用

范围表达式(如 x..y)。

DIRA[12..8]~~ '设置 DIRA12:8 (P12-P8 为输出)

OUTA[12..8] := %11001 '将 P12:8 设置为 1, 1, 0, 0, 和 1

第一行,“DIRA…,” 将 P12,P11,P10,P9 和 P8 设置为输出;所有其它的引脚

仍然保持其原有状态。第二行“OUTA…,”将 P12,P11,和 P8 设置为输出高,P10 和 P9 设置为输出低。

重要提示:范围表达式的值的顺序会影响到它如何使用。例如,下面的代码中交换

了范围表达式中的顺序:

DIRA[8..12]~~ '设置 DIRA8:12 (P8-P12 为输出)

OUTA[8..12] := %11001 '将 OUTA8:12 设置为 1, 1, 0, 0, 和 1

在这里,DIRA 第 8 位到第 12 位被设置为高(如前),但是 OUTA 的第 8, 9, 10, 11 和12 位被设置成 1, 1, 0, 0, 和 1, 这使得 P8, P9 和 P12 输出高,P10 和 P11 输出低。

这是范围表达式非常有用的特性,但是如果不注意,它同样会导致奇怪的结果。

通常,OUTA 只能写入,但它也可以被读取,以获得当前 I/O 引脚的输出锁定状态。

但是该状态只是锁定(latch)状态,可能不是该引脚的实际输出状态。因为他们之后

可以被其它 cog 或者是该 cog 的其它 I/O 硬件(视频发生器,计数器 A 等)等所影

响。下面的代码中假定 Temp 是已经在其它地方被创建的变量:

Temp := OUTA[15..13] '获取 P15到 P13的输出锁定状态 上面的代码中将 Temp 设置为等于 OUTA 的第 15, 14, 和 13 位;现在 Temp 的低 3 位

等于 OUTA15:13,Temp的其它位被清零。

Page 289: Propeller Manual - Parallax Home

4: Spin语言参考– PAR

Propeller Manual v1.0 · Page 289

PAR Cog 启动参数寄存器。 ((PUB PRI)) PAR

返回: 在使用 COGINIT 或 COGNEW.命令启动新 cog 的时候,要传递的地址值。 解释

PAR 寄存器包含了要传递到 COGINIT 或 COGNEW 命令的 Parameter 域中的地址值;参

见 187 页中 COGINIT 和 1929 页的 COGNEW。PAR 寄存器的内容被用于 Propeller 汇编语言

代码中,用于定位和操作 Spin 代码和汇编代码之间的内存。

因为 PAR 寄存器是要保存 cog 启动时的地址,所以其存储的值(通过 COGINIT 和 COGNEW)被限制为 14 位;也就是一个 16 位的字,其低两位被清零。

使用 PAR PAR 由 Spin 代码使用,而汇编代码将其作为内存指针机制指向两者之间的主内存。

COGINIT 或 COGNEW 命令会在 Propeller 汇编代码被载入 cog 时影响 PAR 寄存器。举例如

下:

VAR long Shared '共享变量 (Spin & Assy) PUB Main | Temp cognew(@Process, @Shared) '载入 assy, 传递 Shared地址 repeat <do something with Shared vars> DAT org 0 Process mov Mem, PAR '获取共享内存地址 :loop <do something> wrlong ValReg, Mem '将 ValReg的值移动到 Shared jmp :loop jmp :loop

Page 290: Propeller Manual - Parallax Home

PAR – Spin语言参考

Page 290 · Propeller Manual v1.0

Mem res 1 ValReg res 1

上面的例子中,通过 COGNEW,Main 方法将 Process 汇编程序载入一个新的

cog,COGNEW 的第二个参数被 Main 用作传递变量 Shared 的地址。汇编程序 Process, 从 PAR 寄存器获取该参数后将其存储在本地的 Mem 中。随后它执行一些任务,更新本

地 ValReg 寄存器(在 DAT 块的 后创建)以及 终通过 wrlong ValReg, Mem来更新变

量 Shared。

Page 291: Propeller Manual - Parallax Home

4: Spin语言参考– PHSA, PHSB

Propeller Manual v1.0 · Page 291

PHSA, PHSB 计数器 A 和计数器 B 的锁相环寄存器(PLL Registers) ((PUB PRI)) PHSA ((PUB PRI)) PHSB

返回: 如果用作源变量,则返回计数器 A 和计数器 B 锁相环寄存器的当前值。 解释

PHSA 和 PHSB 是六个影响 cog 计数器模块行为的寄存器(CTRA, CTRB, FRQA, FRQB, PHSA, 和 PHSB) 中的两个。每个 cog 都有两个相同的计数器模块(A 和 B),可以执行重复性

的任务。PHSA 和 PHSB 寄存器包含的值可以直接被 cog 读取或写入,也可以在每个系统

时钟周期分别与 FRQA 和 FRQB 的值累加。参见 204 页上关于 CTRA 的更多信息。

使用 PHSA 和 PHSB PHSA 和 PHSB 可以像其它寄存器或预定义变量一样被读写。例如:

PHSA := $1FFFFFFF

上面的代码将 PHSA 设置为 $1FFFFFFF。依据 CTRA 寄存器 CTRMODE 域的不同,

该值可能保持不变,或者以一定的频率自动累加 FRQA 中的值,该频率值由系统时钟

和主和/或从 I/O 引脚决定。参见 204 页上关于 CTRA, CTRB 的更多信息。

请注意,向 PHSA 或 PHSB 写入的数据会立刻覆盖当前累加值和任何潜在的累加计

划。

Page 292: Propeller Manual - Parallax Home

PRI – Spin语言参考

Page 292 · Propeller Manual v1.0

PRI 声明一个私有的方法块。 ((PUB PRI)) PRI Name ⟨(Param ⟨, Param⟩…)⟩ ⟨:RValue⟩ ⟨| LocalVar ⟨[Count]⟩⟩ ⟨,LocalVar ⟨[Count]⟩⟩… SourceCodeStatements

• Name 是希望的私有方法名。 • Param 是一个参数名称(可选)。声明的方法可以包含 0 个或多个逗号分割的

参数,这些参数写在圆括号内。 Param 必须是全局唯一的,但是其它方法也可

以使用同样的符号名。每个参数都是长字型变量。 • RValue 是方法返回值的名称(可选)。它是该方法内建的 RESULT 变量的别

名。RValue 必须是全局唯一的,但是其它方法也可以使用同样的符号名。 RValue (和/或 RESULT 变量) 在每次方法调用时会被初始化为 0。

• LocalVar 是本地变量的名称(可选)。LocalVar 必须是全局唯一的,但是其它

方法也可以使用同样的符号名。所有的变量都是长字型的(4 个字节),且在

方法调用时,这些变量不会被初始化。方法可以包含 0 个或更多个逗号分割的

本地变量。 • Count 是可选的表达式,写在方括号内,用以表明这是一个有 Count 个元素的数

组变量;每个元素都是长字型的。当引用到这些元素的时候,请注意他们开始

于元素 0,结束于元素 Count-1。 • SourceCodeStatements 是一行或多行可执行代码,至少有一个空格缩进,这些代

码执行该方法的功能。 解释

PRI 是私有方法块声明。一个私有方法是一段源代码,该代码执行特殊的功能并返

回一个值。 PRI 是六个声明 (CON, VAR, OBJ, PUB, PRI, 和 DAT) 之一,他们提供了 Spin 语言

的固有结构。

每个对象都可以包含多个私有 (PRI) 和公有 (PUB) 方法。私有方法只能在对象内部

被访问,用于执行对象的重要的,受保护的函数。对比私有方法和公有方法,除了声

明语句从 PUB 变为 PRI,以及不能在对象外部被访问之外,大体相同。参见 287 页上关

于 PUB 的更多信息。

Page 293: Propeller Manual - Parallax Home

4: Spin语言参考– PUB

Propeller Manual v1.0 · Page 293

PUB 声明一个公共方法块。 ((PUB PRI)) PUB Name ⟨(Param ⟨,Param⟩…)⟩ ⟨:RValue⟩ ⟨| LocalVar ⟨[Count ]⟩⟩ ⟨,LocalVar ⟨[Count ]⟩⟩… SourceCodeStatements

• Name 是公共方法的名称。 • Param 是参数名称(可选)。声明的方法可以包含多个写在括号中,逗号分隔

的参数, Param 必须是全局唯一的,其他方法也可以使用相同的符号名称。每

个参数都是 Long 变量。 • Value 是方法的返回值名称(可选)。它是方法内建 RESULT 变量的别名。RValue 必

须是全局唯一的,其他方法也可以使用相同的符号名称。RValue (和/或 RESULT 变量) 在方法被调用时会被初始化为零(0)。

• LocalVar 本地变量名称 (可选)。LocalVar 必须是全局唯一的,其他方法也可以使

用相同的符号名称。所有的本地变量都是长字型的(四个字节),在方法调用

时都未被初始化。方法可以不包含或包含多个逗号分隔的本地变量。 • Count 是可选的表达式,写在括号中,指出了这是个本地变量,有 Count 个元

素;都是长字型值。后面的程序引用到这些元素时,由元素 0 开始,元素

Count-1 结束。 • SourceCodeStatements 是一行或多行可执行源代码,至少由一个空格缩进,执行

方法的功能。 解释

PUB 是公共方法块声明。一个公共方法块是一段源代码,这段代码执行了特殊的功

能并返回一个值。PUB 是六个特殊声明 (CON, VAR, OBJ, PUB, PRI, 和 DAT) 之一,它们提供

了 Spin 语言的内在结构。

每个对象都包含了一定数量的公共(PUB) 和私有(PRI) 方法。公共方法可以在对象外

部被访问,用作对象的接口。

PUB 和 PRI 声明不会向自身返回值,但是公共和私有方法在被调用时总会返回值。

Page 294: Propeller Manual - Parallax Home

PUB – Spin语言参考

Page 294 · Propeller Manual v1.0

公共方法声明 公共方法声明由 PUB 开始,在一行的第一列,随后是一个唯一的名称和可选的集

合,包括了参数,一个返回变量,和本地变量。

例子:

PUB Init <initialization code> PUB MotorPos : Position Position := <code to retrieve motor position> PUB MoveMotor(Position, Speed) : Success | PosIndex <code that moves motor to Position at Speed and returns True/False>

这个例子包含了三个公共方法,Init, MotorPos 和 MoveMotor。 Init 方法没有参数,

也没有声明返回值和本地变量。MotorPos 方法没有参数,但是声明了一个名为

Position 的返回值。MoveMotor 方法有两个参数,Position 和 Speed, 一个返回值,

Success, 和本地变量, PosIndex。

所有属于 PUB 方法的可执行代码应该出现在声明的下方,由至少一个空格缩进。

返回值 不论 PUB 声明是否指定了 RValue,总会隐含返回一个值,默认为 0。在每一个 PUB

方法中,都会有一个预定义的返回值变量 RESULT。 方法中的 RESULT 可以像普通变量一

样更新,在退出方法时, RESULT 的值会回传给调用者。此外,如果方法声明了

RESULT,那么该名称可以和方法内建的 RESULT 变量互换。例如,上面的 MotorPos 方法

设置了“Position := …”也使用了“Result := …”。通常都希望能为返回值(在 PUB

声明中) 指定描述性的名称,这样方法的返回值就更容易被理解,变得更有意义。同

样的,如果一个方法的返回值对程序不重要或没有被使用,那么 好不要重新命名返

回值。

Page 295: Propeller Manual - Parallax Home

4: Spin语言参考– PUB

Propeller Manual v1.0 · Page 295

参数和本地变量 参数和本地变量均为长字型 (四个字节)。 实际上,参数是一类特殊的变量,它们

被相应地初始化为方法的调用者所指定的值。本地变量则不被初始化;在方法被调用

时,它们包含的是随机数。

所有的参数按值传递进方法,不是按引用,所以对参数值的改变不会反应到方法外

面。例如,如果我们以变量 Pos 作为方法 MoveMotor 的第一个参数,可能看起来像下面

的样子:

Pos := 250 MoveMotor(Pos, 100)

当 MoveMotor 方法执行时,它会接收 Pos 的值存储在 Position 参数中,Speed 参数

的值为 100。在 MoveMotor 方法内部,可以改变 Position 和 Speed 的值,但是 Pos 的值

(调用者变量) 仍然是 250。

如果程序要修改变量,调用者就必须传递变量的引用;也就是必须传递变量的地

址,而不是变量的值,程序必须将该参数作为要操作的内存地址。变量的地址,或寄

存器符号,都可以用符号地址运算符‘@’ 取得地址。例如:

Pos := 250 MoveMotor(@Pos, 100)

调用者将 Pos 的地址作为第一个参数传递给 MoveMotor。 MoveMotor 接收到的 Position 参数是调用者的 Pos 变量的地址。地址是一串数字,所以 MoveMotor 方法必须

被设计成将这一参数作为地址来处理,而不是地址。 MoveMotor 方法必须用下面的方

式:

PosIndex := LONG[Position]

...来取得 Pos 变量的值,以及:

LONG[Position] := <some expression>

...来修改 Pos 变量。

将字符串变量传递给方法时,常用的方法是用符号地址运算符进行引用。因为字符

串变量其实是字节数组,所以不能用值传递的方法将它们传递给方法;如果按值传递

的方法只能传递第一个字符的值。因为会访问多个数据,所以即使一个方法不需要修

改字符串,或逻辑数组,也应该通过引用来将整个数组传递给方法。

Page 296: Propeller Manual - Parallax Home

PUB – Spin语言参考

Page 296 · Propeller Manual v1.0

退出方法 当一个方法执行到 后一条语句或执行 RETURN 或 ABORT 命令时就会退出。一个方

法可以只有一个退出点( 后一条语句),或者有多个退出点(除了 后一条可执行

语句外,有任意个 RETURN 或 ABORT 命令)。 RETURN 和 ABORT c 命令也可以被用于设置

退出时的 RESULT 变量;参见 301 页 RETURN,161 页 ABORT。

Page 297: Propeller Manual - Parallax Home

4: Spin语言参考– QUIT

Propeller Manual v1.0 · Page 297

QUIT 从 REPEAT 循环立刻退出。 ((PUB PRI)) QUIT 解释

QUIT 是能影响 REPEAT 循环的两条命令之一 (NEXT 和 QUIT) 。QUIT 使一个 REPEAT 循环

立刻终止。

使用 QUIT QUIT 通常用在条件表达式中,作为一种例外情况,在 REPEAT 循环中终止循环。例

如,假定 DoMore 和 SystemOkay 是在已经创建的方法,它们都返回布尔值:

repeat while DoMore '重复执行

!outa[0] '触发状态灯

<do something> '执行一些任务 if !SystemOkay quit '如果系统故障,退出

<more code here> '执行其它任务

上面的代码触发了一个在 P0 引脚上的状态指示灯,并当 DoMore 返回 FALSE 时执行

一些任务。但是如果 SystemOkay 方法在循环中途返回 FALSE,则 IF 表达执行 QUIT 命令,该命令会使循环立刻终止。

QUIT 命令只能被用在 REPEAT 循环中;否则会产生错误。

Page 298: Propeller Manual - Parallax Home

REBOOT – Spin语言参考

Page 298 · Propeller Manual v1.0

REBOOT 重置 Propeller 芯片。 ((PUB PRI)) REBOOT 解释

该命令是软件控制的重置,但是其功能与通过 RESn 引脚触发的硬件重置是一样

的。

如果需要将 Propeller 芯片重置到上电(Power-up)状态就可以使用 REBOOT。它与通

过 RESn 引脚触发的硬件重置或上电周期一样会有 上电/重置延迟,以及启动(boot-up)过程。

Page 299: Propeller Manual - Parallax Home

4: Spin语言参考– REPEAT

Propeller Manual v1.0 · Page 299

REPEAT 反复执行代码块。 ((PUB PRI)) REPEAT ⟨Count⟩ Statement(s) ((PUB PRI)) REPEAT Variable FROM Start TO Finish ⟨STEP Delta⟩ Statement(s) ((PUB PRI)) REPEAT (( UNTIL WHILE )) Condition(s) Statement(s) ((PUB PRI)) REPEAT Statement(s) ((UNTIL WHILE)) Condition(s)

• Count 是可选的表达式,指出了要执行 Statement(s) 的次数。如果 Count 被忽

略,语法 1 会建立一个无穷循环来执行 Statement(s)。 • Statement(s) 是可选的,要重复执行的代码块。很少将 Statement(s) 省略,但是在

语法 3 和语法 4 中,可以通过配合 Condition(s) 来达到所需要的效果。 • Variable 是变量,通常用是用户定义的,它会从 Start 开始迭代,直到 Finish,

Delta 是可选的迭代步长。Variable 可以用在 Statement(s) 中,以测定或利用迭

代次数。 • Start 是表达式,指出了语法 2 中 Variable 的起始值。如果 Start 小于 Finish,

Variable 会每次迭代后增加(加 Delta);否则会减少(减 Delta)。 • Finish 是表达式,指出了语法 2 中 Variable 的终值。如果 Finish 大于 Start,

Variable 会在每次迭代后增加(加 Delta);否则会减少(减 Delta)。 • Delta 是可选的表达式,指出了每次迭代时 Variable 增加或减少的单位(语法

2)。如果忽略,则 Variable 默认每次增/减一。 • Condition(s) 由语法 3 和 4 使用的一个或多个布尔表达式,用以继续或终止循

环。如果加在 UNTIL 之前,当 Condition(s) 为真时,循环终止。如果加在 WHILE

之前,当 Conditions(s) 为假(FALSE)时,循环终止。

Page 300: Propeller Manual - Parallax Home

REPEAT – Spin语言参考

Page 300 · Propeller Manual v1.0

解释 REPEAT 是 Spin 语言中非常灵活的循环结构。可以用于创建各种类型的循环,包

括:有限循环,无限循环,带有/不带有循环计数器,和条件 zero-to-many/one-to-many 循环等。

缩进 重要提示:缩进是很重要的。Spin 语言依靠缩进(一个或多个空格)来检查该行语

句是否属于一个条件命令。要让 Propeller 工具显示这些逻辑分组,可以按 Ctrl + I 来打

开块-组指示器。再次按下 Ctrl + I 会关闭这一特性。参见 69 页增加缩进和减少缩进,

以及 74 页块-组指示器。

无限循环 (语法 1) 的确,四种形式的 REPEAT 都可以用于表达无限循环,但是 常用的是语法 1 中的

方法,该方法没有 Count 域。例如:

repeat '无限循环

!outa[25] '触发 P25

waitcnt(2_000 + cnt) '暂停 2,000 周期

这段代码不断重复执行 !outa[25] 和 waitcnt(2_000 + cnt) 两行代码。这两行代码

都从 REPEAT 所在的行缩进,所以它们是属于 REPEAT 循环的。

因为 Statement(s) 是 REPEAT的可选部分,REPEAT 命令自身可以被用作无限循环,它

不做任何事,只是保持 cog 为活动状态。有时是有意产生这种循环,但有时这是由于

错误地缩进造成的(缺失可执行语句)。例如:

repeat '无限循环

!outa[25] '触发 P25 <-- 永远不会执行

上面的例子是错误的表达; 后一行程序永远不会执行,因为它上面的 REPEAT 语句是没有 Statement(s)的无限循环;它之后没有缩进的语句行,所以 cog 会陷入 REPEAT 的无限循环中,不做任何事,只是保持 cog 为活动状态,消耗电力。

简单的有限循环 (语法 1) 大多数的循环都是有限的;它们执行有限的迭代次数。 简单的形式是带有 Count

域的语法 1。

Page 301: Propeller Manual - Parallax Home

4: Spin语言参考– REPEAT

Propeller Manual v1.0 · Page 301

例如:

repeat 10 '重复 10 次

!outa[25] '触发 P25

byte[$7000]++ '增加 RAM 地址$7000处的值

上面的代码会触发 P25 10 次,然后使在 RAM 地址$7000 的值增加。

计数有限循环 (语法 2) 常常需要数出当前迭代的次数,这样循环内的代码可以根据它来执行不同的动作。

REPEAT 命令可以使用语法 2 来达到这一目的。下面的例子假定变量 Index 已经被创

建。

repeat Index from 0 to 9 '重复 10 次

byte[$7000][Index]++ '增加从$7000 到$7009地址中的值

就向上一个例子一样,代码循环了 10 次,但是它每次都会修改变量 Index。 第一

次循环时,Index 会是 0 (如同代码所指出的那样,“从 0 开始”) ,每次迭代后, Index 都会比之前的值增大一 ( 后“到 9”): ..1, 2, 3…9. 9 次迭代后,Index 会增大到

10,循环终止,然后执行 REPEAT 循环结构之后的代码。循环内的代码使用 Index 作为

内存地址的偏移量,byte[$7000][Index]++;这样,使 RAM 地址$7000 到$7009 的值

(字节 byte)增加一,每次一个。

REPEAT 命令自动检查 Start 和 Finish 指定的范围是增大还是减小。上面的代码使用

的是从 0 到 0,所以范围是增大;每次使 Index 加 1。 要使次数反转,只要互换 Start 和 Finish 的值。例如:

repeat Index from 9 to 0 '重复 10次

byte[$7000][Index]++ '增加从$7009 到$7000地址中的值

这个例子也是循环 10 次,但是 Index 会从 9 减少到 0;每次使 Index 减 1。RAM 中

的内容仍然会增大,但是是从$7009 到 $7000。在 10 次迭代后,Index 将等于-1。

因为 Start 和 Finish 域可以是表达式,可以包含变量。下一个例子假定 S 和 F 是已

经创建的变量。

Page 302: Propeller Manual - Parallax Home

REPEAT – Spin语言参考

Page 302 · Propeller Manual v1.0

S := 0 F := 9 repeat 2 '重复两次

repeat Index from S to F '重复 10次

byte[$7000][Index]++ '增加从$7000..$7009地址的值 S := 9 F := 0

上面的例子使用了嵌套循环。外层循环(第一个)重复了两次。内层循环由 Index

指定, Index 的值从 S 到 F,在前面的例子中,对应于从 0 到 9。内层循环按顺序(0-9)使 RAM 位置$7000 到 $7009 的值增大,因为内层循环从 0 开始迭代到 9。然后内层

循环终止(Index 为 10) , 后两行中将 S 设置为 9,将 F 设置为 0,交换了 Start 和 Finish 的值。 因为这仍然是在外层循环的内部,所以外层循环会再次执行(循环体)

的内容,这时的内层循环按 Index 从 9 到 0 迭代。内层循环按顺序(和上一次顺序相

反)使 RAM 位置 $7009 到 $7000 的值增大,当结束时 Index 等于 -1。 后两行再次

设置 S 和 F,但是外层循环不会再次执行了。

REPEAT 循环不必被限制于每次增量等于 1。如果 REPEAT 命令使用了可选的 STEP Delta 语法,则会按 Delta 的值增大或减小 Variable。在语法 2 的形式中,REPEAT 实际

上一直都在使用 Delta 值,但是当“STEP Delta”省略时,会自动使用+1 或-1 作为

Delta 的值,选择+1 还是-1 取决于 Start 和 Finish 所指定的范围。 下面的例子中使用了

可选的 Delta 值,增量为 2。

repeat Index from 0 to 8 step 2 '重复 5 次

byte[$7000][Index]++ '增加$7000到$7008之间偶数地址值

这里,REPEAT 循环了 5 次, Index 的值分别设置为 0,2,4,6,和 8。该代码从

RAM 位置$7000 开始,增加偶数位置(地址)中的字节值,到$7008 结束(Index 等于

10)。

Delta 域的值可正可负,无论 Start 和 Finish 所指定的范围是升序或逆序,可以在循

环中被修改,达到特殊的效果。例如,假设 Index 和 D 是已经定义的变量,下面的代

码将 Index 设定为序列:5,6,6,5,3。

D := 2 repeat Index from 5 to 10 step D --D

Page 303: Propeller Manual - Parallax Home

4: Spin语言参考– REPEAT

Propeller Manual v1.0 · Page 303

这个循环从 Index 等于 5, Delta (D) 等于+2 开始。循环每次迭代都会将 D 的值减

1,所以在第一次迭代完成后,Index = 5,D = +1。第二次迭代完成后 Index = 6,D = 0。第三次迭代后 Index = 6,D = -1。第四次迭代后 Index = 5,D = -2。第五次迭代后

Index = 3,D = -3。当 Index 加 Delta (3 + -3) 超出 Start 到 Finish (5 到 10)所设定的范围

后,循环终止。

有条件循环 (语法 3 和 4) REPEAT 的 后形式,语法 3 和 4,是有条件的有限循环,可以灵活地用于正逻辑或

负逻辑,以及 zero-to-many 或 one-to-many 迭代循环。这两种形式的 REPEAT 通常被称

为是“当…循环(repeat while)”或“循环…直到(repeat until)”循环。

我们来看看语法 3 中描述的 REPEAT。 这种形式包含了 REPEAT 命令和紧跟在它后面

的 WHILE 或 UNTIL,然后是 Condition(s)。在这一行之下,是可选的 Statement(s)。 因为

这种形式会在每次迭代开始前测试 Condition(s),它创建了一个 zero-to-many 循环; Statement(s) 语句块会执行 0 次或多次,执行的次数取决于 Condition(s)。例如,假定 X 是已经创建的变量:

X := 0 repeat while X < 10 '当 X小于 10的时候重复

byte[$7000][X] := 0 '增加 RAM 地址处的值

X++ '增加 X

该例子中首先将 X 设置为 0,当 X 小于 10 的时候会一直循环。 代码的内部将指定

的内存位置清零 (起始于$7000) ,偏移增量 X。10 次迭代后,X 等于 10,这会使条件 X < 10 为假,所以循环终止。

这个循环是使用“正逻辑(positive logic)”,因为它包含了的是 “当(WHILE)” 一个条件为真时执行。也可以使用“直到(UNTIL)”来代替 While,这就是负逻辑。例

如:

X := 0 repeat until X > 9 '重复执行,直到 X 大于 9

byte[$7000][X] := 0 '增加 RAM 地址处的值

X++ '增加 X

Page 304: Propeller Manual - Parallax Home

REPEAT – Spin语言参考

Page 304 · Propeller Manual v1.0

上面的例子执行了和前一个例子一样的功能,但是循环使用了负逻辑,因为它包含

的是“直到(UNTIL)”一个条件为真时执行;即当一个条件为假时继续执行。

在这两个例子中,如果在第一次迭代开始前,X 等于 10 或更大的值,则循环永远不会

执行。这就是我们称之为 zero-to-many 循环的原因。

语法 4 中描述的 REPEAT 和语法 3 中的类似,但是条件会在每次迭代 后才被测

试,这是一个 one-to-many 循环。例如:

X := 0 repeat byte[$7000][X] := 0 '增加 RAM 地址处的值

X++ '增加 X

while X < 10 '当 X小于 10的时候重复

这个例子和前一个例子一样,循环 10 次,除了一点,就是条件表达式会在每次迭

代完成后才被测试。所以即使在第一次迭代之前 X 等于或大于 10,循环也会执行一次

然后才终止,这也就是为什么我们称之为 one-to-many 循环。

其他 REPEAT 选项 有两条语句可以影响 REPEAT 循环的行为:NEXT 和 QUIT。参见 246 页 NEXT,291 页

QUIT。

Page 305: Propeller Manual - Parallax Home

4: Spin语言参考– RESULT

Propeller Manual v1.0 · Page 305

RESULT 方法的返回值变量。 ((PUB PRI)) RESULT 解释 RESULT 变量是为每个 PUB 和 PRI 方法预定义的本地变量。RESULT 保存了方法的返回

值;当该方法结束后,此值会传回给该方法的调用者。

当一个公有或私有方法被调用的时候,其内建立的 RESULT 变量会被清零。如果该

方法不修改 RESULT,或不会用指定值调用 RETURN 或 ABORT,则零(0)将成为该方法结

束时的返回值。

使用 RESULT 在下面的例子中, DoSomething 方法在结束是将 RESULT 设置为 100。Main 方法调用

DoSomething 方法,将本地变量 Temp 设为等于 DoSomething 的结果;所以当 DoSomething 退出时,Temp 将等于 100。

PUB Main | Temp Temp := DoSomething '调用 DoSomething, 将 Temp 设置为返回值 PUB DoSomething <do something here> result := 100 '将返回值设置为 100

也可以提供一个方法内 RESULT 变量的别名,这样做的目的是使方法返回值更清

晰。我们推荐使用该方法,因为这样可以使阅读者更容易分辨该方法的意图。如下

例:

PUB GetChar : Char <do something> Char := <retrieved character> '将 Char (result) 设置为字符

Page 306: Propeller Manual - Parallax Home

RESULT – Spin语言参考

Page 306 · Propeller Manual v1.0

上面的方法, GetChar,声明了 Char 作为其内建 RESULT 变量的别名;参见 287 页 PUB, 或 286 页 PRI获得更多的信息。 GetChar 方法随后执行了一些任务获取了一个字

符,然后将 Char 的值设为该字符。当然也可以使用 “result := …” 来设置返回值。

RESULT 变量或其别名,在方法退出前可以被多次修改,因为他们都可以影响

RESULT,在退出时只有 RESULT 的 后修改值会被使用。

Page 307: Propeller Manual - Parallax Home

4: Spin语言参考– RETURN

Propeller Manual v1.0 · Page 307

RETURN 从 PUB/PRI 方法退出,可选返回值 Value. ((PUB PRI)) RETURN ⟨Value⟩ 返回: 返回当前的 RESULT 值或提供的 Value。

• Value 是可选的表达式,其值将从 PUB 或 PRI 方法返回。 解释

RETURN 是两条终止 PUB 或 PRI 方法的命令(ABORT 和 RETURN)之一。RETURN 会使程序从

PUB 或 PRI 方法中正常退出;意思是它会弹出调用堆栈并返回到该方法的调用者,同时

传递一个值。

每个 PUB 或 PRI 方法都会在其结尾处暗含一个 RETURN。RETURN 也可以多次在程序中

手动输入,以创建多个退出点。

当 RETURN 不带有可选的 Value 时,它会返回 PUB/PRI的内建 RESULT 变量的当前值。

如果 Value 域有指定值,则返回该指定值。

关于调用堆栈 要调用方法,只要在其他方法中引用就可以,所以必须有某些机制存储了调用结束

后要返回的地址。该机制被称为“堆栈(Stack)”,但是我们在这里会使用“调用堆

栈(Call Stack)”这一术语。其实就是简单的使用 RAM 空间,存储返回地址,返回

值,参数和中间结果。随着调用的增多,调用堆栈会越来越大。随着越来越多的调用

返回(通过 RETURN 或到达方法的末尾),调用堆栈会越来越小。这分别被称之为“压

入(Pushing)”堆栈和从堆栈中“弹出(Poping)”。

RETURN 从调用堆栈中弹出 近使用的数据,这些数据回返回给调用者;也就是调

用该方法的程序。

使用 RETURN 下面的例子演示了使用两个 RETURN 语句。假定 DisplayDivByZeroError 是已经定义

的方法。

PUB Add(Num1, Num2)

Page 308: Propeller Manual - Parallax Home

RETURN – Spin语言参考

Page 308 · Propeller Manual v1.0

Result := Num1 + Num2 ' Num1 + Num2 return PUB Divide(Dividend, Divisor) if Divisor == 0 '检查是否 Divisor = 0

DisplayDivByZeroError '如果等于 0,显示错误

return 0 '并返回 0

return Dividend / Divisor '否则返回商数

Add 方法将其内建的 RESULT 变量设置为等于 Num1 加 Num2, 然后执行 RETURN。 RETURN 会使 Add 方法将 RESULT 的值返回给调用者。要注意这里的 RETURN 并不是真正需

要的,因为 Propeller 工具编译器会自动为所有的没有 RETURN的方法添加该语句。

Divide 方 法 检 查 Divisor 的 值 。 如 果 Divisor 等 于 0 , 它 会 调 用 DisplayDivByZeroError 方法然后执行 return 0,这会使方法立刻返回,同时返回值为

0。如果 Divisor 不等于 0,它将执行 return Dividend / Divisor,这会使方法的返回值

变为这次除法的结果。这个例子中, RETURN 被用于执行计算并返回结果,这些过程一

步完成,而不需要事先修改内建 RESULT 变量。

Page 309: Propeller Manual - Parallax Home

4: Spin语言参考– ROUND

Propeller Manual v1.0 · Page 309

ROUND 将一个浮点数四舍五入。 ((CON VAR OBJ PUB PRI DAT)) ROUND ( FloatConstant ) 返回: 距离原有浮点常量值 近的整数值。

• FloatConstant 是要被四舍五入的浮点常量表达式。 解释

ROUND 是三条作用于浮点常量表达式的指令(FLOAT, ROUND 和 TRUNC) 之一。ROUND 会返

回一个整型常量,该常量在数轴上距离给定的浮点表达式 近。小数值 ½ (.5) 或更大

的值会进位到 近的整数,而小于此值的小数部分会被舍去。

使用 ROUND ROUND 可以被用于将一个浮点常量四舍五入到 近的整数。请注意该命令只能用于

编译时常量表达式,而不是运行时变量表达式。例如:

CON OneHalf = 0.5 Smaller = 0.4999 Rnd1 = round(OneHalf) Rnd2 = round(Smaller) Rnd3 = round(Smaller * 10.0) + 4

上面的代码建立了两个浮点常量, OneHalf 和 Smaller, 分别等于 0.5 和 0.4999。下

面的三个常量, Rnd1, Rnd2 和 Rnd3, 是基于使用了 ROUND 指令后的 OneHalf 和 Smaller 的整型常量。 Rnd1 = 1, Rnd2 = 0, 和 Rnd3 = 9。

关于浮点常量 Propeller 编译器会将浮点常量以单精度实数的方式来处理,处理的方法在 IEEE-

754 标准中有描述。单精度实数以 32 位存储,带有 1 位符号位,8 位指数位,和 23 位

对数的尾数。这样可以有大约 7.2 有效的十进制位。

浮点常量表达式可以被定义和用于编译时应用,但是不能用于运行时浮点运算,

FloatMath 和 FloatString 对象提供了对单精度数的数学函数。

Page 310: Propeller Manual - Parallax Home

ROUND – Spin 语言参考

Page 310 · Propeller Manual v1.0

参见 254 页运算符一节中常量赋值 ‘=’,216 页 FLOAT,320 页 TRUNC,以及

FloatMath 和 FloatString 对象的更多信息。

Page 311: Propeller Manual - Parallax Home

4: Spin语言参考– SPR

Propeller Manual v1.0 · Page 311

SPR 特殊用途寄存器数组;提供了对 cog 的特殊寄存器的直接访问。 ((PUB PRI)) SPR [Index] 返回:位于 Index 的特殊寄存器中的值。

• Index 是一表达式,该表达式指定了要访问的特殊寄存器的索引号(0-15)(PAR 寄存器通过 VSCL).

解释

SPR 是 cog 中的一个有 16 个特殊用途寄存器的数组,元素 0 是 PAR 寄存器,元素

15 是 VSCL 寄存器。参见下表 4-15。 SPR 提供了 cog 的特殊用途寄存器的直接访问方

法。

表 4-15: Cog RAM 特殊用途寄存器

名称 索引号 类型 描述 PAR 0 只读 启动参数 CNT 1 只读 系统计数器 INA 2 只读 P31 - P0 的输入状态 INB 3 只读 P63 – P321

的输入状态 OUTA 4 读/写 P31 - P0 的输出状态 OUTB 5 读/写 P63 – P321

的输出状态 DIRA 6 读/写 P31 - P0 的方向状态 DIRB 7 读/写 P63 - P321

的方向状态 CTRA 8 读/写 计数器 A 控制 CTRB 9 读/写 计数器 B 控制 FRQA 10 读/写 计数器 A 频率 FRQB 11 读/写 计数器 B 频率 PHSA 12 读/写 计数器 A 相位 PHSB 13 读/写 计数器 B 相位 VCFG 14 读/写 视频配置 VSCL 15 读/写 视频比例

Note 1: 保留

Page 312: Propeller Manual - Parallax Home

SPR – Spin语言参考

Page 312 · Propeller Manual v1.0

使用 SPR SPR 可以像其他长字型数组一样被访问。下面假定 Temp 是已经被定义的变量。

spr[4] := %11001010 '配置 outa 寄存器

Temp := spr[2] '取得 ina 的值

该例子将 OUTA 寄存器(SPR 索引号为 4)设置为%11001010,然后将 Temp 设为等于

INA 寄存器(SPR 索引号为 2)。

Page 313: Propeller Manual - Parallax Home

4: Spin语言参考– _STACK

Propeller Manual v1.0 · Page 313

_STACK 预定义,用于指定应用程序的堆栈大小。 CON _STACK = Expression

• Expression 是整型表达式,指出了要保留的单位为 Long 的堆栈空间大小。 解释

_STACK 是一个预先确定的,一次性可设定,可选择的常量,用于指定应用程序必需

的堆栈空间。该值会被加到_FREE (如果已指定)上,以指出应用程序所需要的堆栈/要保留的自由内存空间的大小。如果应用程序需要 小量的堆栈空间来保证正常运

行,就应该使用_STACK。如果编译产生的应用程序太大覆盖了指定的堆栈空间,系统

会提示一条错误信息。例如:

CON _STACK = 3000

上面 CON 块中_STACK 声明指出应用程序在编译结束后需要保留至少 3000 个 Long 长

度的堆栈空间。如果编译后没有留下足够的空间,一条错误信息会提示超过了多少预

订值。这样做会有效地防止一个成功编译的应用程序由于缺少内存而不能正常工作。

要注意的是只有顶部对象文件可以设置_STACK 的值。任何子对象中设置的_STACK 值都会被忽略。由该常量所指定的保留堆栈会被主 cog 所运行的应用程序用于存储临时

文件,如堆栈,参数和表达式中间值。

Page 314: Propeller Manual - Parallax Home

STRCOMP – Spin语言参考

Page 314 · Propeller Manual v1.0

STRCOMP 比较两个字符串是否相等。 ((PUB PRI)) STRCOMP (StringAddress1, StringAddress2 ) 返回:如果两个字符串相等则返回 TRUE 否则返回 FALSE。

• StringAddress1 是一表达式,指定了要比较的第一个字符串的起始地址。 • StringAddress2 是一表达式,指定了要比较的第二个字符串的起始地址。

解释

STRCOMP 是两条能取得字串信息的命令(STRCOMP 和 STRSIZE) 之一。STRCOMP 将位于

StringAddress1 的字符串的内容和位于 StringAddress2 的字符串的内容作比较(比较两

个字符串的内容,直到字符串结尾字符 0)。如果两个字符串相等,则返回 TRUE,否

则返回 FALSE。该比较是大小写敏感的。

使用 STRCOMP 下面的例子假定 PrintStr 是已经创建的方法。

PUB Main if strcomp(@Str1, @Str2) PrintStr(string("Str1 and Str2 are equal")) else PrintStr(string("Str1 and Str2 are different")) DAT Str1 byte "Hello World", 0 Str2 byte "Testing.", 0

上面的例子在 DAT 块中,有两个以 0 结尾的字符串 Str1 和 Str2。Main 方法调用

STRCOMP 比较每个字符串的内容。假设 PrintStr 方法可以显示字符串,该例子中该方法

在显示器上显示“Str1 and Str2 are different”。

Page 315: Propeller Manual - Parallax Home

4: Spin语言参考– STRCOMP

Propeller Manual v1.0 · Page 315

零结尾的字符串 STRCOMP 命令只能作用于以零结尾的字符串;也就是一个字符串结尾必须有一个等

于 0 的字节。这样做很常见而且被推荐这样做,因为大多数字符串处理方法(函数)

依赖于零字符终止符。

Page 316: Propeller Manual - Parallax Home

STRING – Spin语言参考

Page 316 · Propeller Manual v1.0

STRING 声明内联字符串常量并取得其地址。 ((PUB PRI)) STRING (StringExpression ) 返回: 内联字符串常量的地址。

• StringExpression 是希望的使用的,内联的,临时的表达式。 解释

DAT 块常常用于创建用语各种目的的,可重用得字符串或字符串缓冲,但有时,需

要临时使用的字符串,例如用于调试或对象中一次使用的字符串等。STRING 指令用于

这些一次使用的字符串;它将一个内联的,以 0 结尾的字符串编译进内存,并返回该

字符串的地址。

使用 STRING STRING 指令在创建一次性使用的字符串和将该字符串的地址传递给其他方法时是

很有用的。例如,假定 PrintStr 是已经创建的方法。

PrintStr(string("This is a test string."))

上面的例子使用 STRING 指令将字符串“This is a test string。”编译进内存中,并返

回该字符串的地址,将该地址作为虚拟的 PrintStr 方法的参数。

如果一个字符串在程序中需要多次使用,则 好在 DAT 块中定义,这样地址就可以

多次被使用.

Page 317: Propeller Manual - Parallax Home

4: Spin语言参考– STRSIZE

Propeller Manual v1.0 · Page 317

STRSIZE 取得字符串的长度(大小)。 ((PUB PRI)) STRSIZE ( StringAddress ) 返回: 零结尾的字符串的长度(字节)。

• StringAddress 是表达式,指定了要测量的字符串的初始地址。 解释

STRSIZE 是两条取得字符串信息的命令(STRCOMP 和 STRSIZE) 之一。STRSIZE 测量位于

StringAddress 的字符串的长度,单位为字节,不包括结尾零字符字节。

使用 STRSIZE 下面的例子假定 Print 是已经声明并创建的方法。

PUB Main Print(strsize(@Str1)) Print(strsize(@Str2)) DAT Str1 byte "Hello World", 0 Str2 byte "Testing.", 0

上面的例子的 DAT 块中有两个以零结尾的字符串,Str1 和 Str2。 Main 方法调用 STRSIZE 取得每个字符串的长度。假定 Print 方法可以用于显示一个值,本例中会在显

示器上显示 11 和 8。

零结尾的字符串 STRSIZE 命令只能作用于以零结尾的字符串;也就是一个字符串结尾必须有一个等

于 0 的字节。这样做很常见而且被推荐这样做,因为大多数字符串处理方法(函数)

依赖于零字符终止符。

Page 318: Propeller Manual - Parallax Home

符号 Symbols – Spin语言参考

Page 318 · Propeller Manual v1.0

符号 表 4-16 中所列出的符号可用于 Spin 代码的一种或多个目的。每个符号的用途都有简明

的描述,以及到使用符号的例子的引用。

表 4-16: 符号

符号 目的

% 二进制指示器: 用于指出一个值是以二进制的形式表示的(基数 2)。参见 159 页,值的表

达。

%% 四进制指示器: 用于指出一个值是以四进制的形式表示的(基数 4)。参见 159 页,值的表

达。

$ 十六进制指示器: 用于指出一个值是以十六进制的形式表示的(基数 16)。参见 159 页,值

的表达。

" 字符串指示器: 用于指出一个字符串的开始和结尾。通常用在对象块中(247 页),数据块

(208 页),或公共/私有块中的 STRING 指令(316 页)。

_ 1) 分隔符: 在常量值中用于组分隔符(逗号 ‘,’ 或句号 ‘.’ 一般用作数字组分隔符)参见

159 页值的表达。 2) 下划线: 用作对象的一部分。参见 159 页符号规则。

#

1) 对象-常量参考: 用于引用一个子对象的常量。参见 199 页 CON 段中常量的作用域,以及

247 页 OBJ。 2) 枚举集: 用在 CON 块中设置一个符号枚举集的起始位置。参见 197 页 CON 段中的枚举。 3) 汇编语言字符: 用于指出一个表达式或符号是一个字符值而不是寄存器地址。

. 1) 对象方法引用: 用于引用一个子对象的方法。参见 247 页 OBJ。 2) 小数点: 用在浮点常量表达式中。参见 194 页 CON。

.. 范围指示器: 在 CASE 表达或一个 I/O 寄存器索引中指出其范围,范围的值由表达式指

定。参见 280 页 OUTA, OUTB, 226 页 INA, INB,212 页 DIRA, DIRB。

Page 319: Propeller Manual - Parallax Home

4: Spin语言参考–符号 Symbols

Propeller Manual v1.0 · Page 319

表 4-16: 符号 (续)

符号 目的

:

1) 返回值分隔符: 出现在 PUB 或 PRI 声明中符号返回值的前面。参见 287 页 PUB, 286 页

PRI, 299 页 RESULT。 2) 对象赋值: 用于 OBJ 块中的对象引用参考。参见 247 页 OBJ。 3) Case 表达式分隔符: 出现在 CASE 结构中匹配表达式的后面。参见 171 页 CASE。

| 1) 本地变量分隔符: 现在 PUB 或 PRI 声明中本地变量列表前。参见 287 页 PUB,286 页

PRI。 2) 位或(Bitwise OR): 用在表达式中。参见 270 页位与(位或 ‘|’, ‘|=’。

\ 中止陷阱: 出现在一个可能会中止的方法调用之前。参见 161 页 ABORT。

, 列表分隔符: 用于列表中分隔内容。参见 244 页 LOOKUP, LOOKUPZ,242 页 LOOKDOWN, LOOKDOWNZ 以及 208 页 DAT 段的声明数据。

( ) 参数列表指示符: 用于列出方法参数。参见 287 页 PUB, 以及 286 页 PRI。

[ ] 数组索引指示符: 用于指出变量数组或主内存引用的索引,参见 315 页 VAR, 165 页 BYTE, 331 页 WORD, 以及 236 页 LONG。

' 代码注释指示符: 用于输入单行代码注释(非编译文本),该注释将用于代码浏览。参见 100页练习 3: Output.spin -注释。

'' D 文档注释指示符: 用于输入单行文档注释(非编译文本),该注释将用于文档浏览。参见

100 页练习 3: Output.spin -注释。

内联/多行代码注释指示符: 用于输入多行代码注释(非编译文本),该注释将用于代码浏览。

内联/多行文档注释指示符: 用于输入多行文档注释(非编译文本),该注释将用于文档浏览。

参见 100 页 练习 3: Output.spin -注释。

Page 320: Propeller Manual - Parallax Home

TRUNC – Spin 语言参考

Page 320 · Propeller Manual v1.0

TRUNC 删除,“截除”浮点常量的小数部分。 ((CON VAR OBJ PUB PRI DAT)) TRUNC ( FloatConstant ) Returns: 给定浮点常量值从小数点开始截除,形成的整数作为返回值。

• FloatConstant 是将要被转换为整数的浮点常量表达式。 解释

TRUNC 是三条用于浮点常量表达式的指令 (FLOAT, ROUND 和 TRUNC) 之一。 TRUNC 返回整型常量,该整型常量是给定的浮点常量表达式去掉小数部分后形成的。

使用 TRUNC TRUNC 可以用于获取浮点常量的整数部分。例如:

CON OneHalf = 0.5 Bigger = 1.4999 Int1 = trunc(OneHalf) Int2 = trunc(Bigger) Int3 = trunc(Bigger * 10.0) + 4

上面的代码建立了两个浮点常量,OneHalf 和 Bigger,分别等于 0.5 和 1.4999。下

面的三个常量,Int1,Int2 和 Int3,是使用过 TRUNC 指令后产生的整型常量。 Int1 = 0,Int2 = 1,和 Int3 = 18。

关于浮点常量 Propeller 编译器在处理浮点常量时将其作为单精度实数处理,如 IEEE-754 标准中

所描述的那样。单精度实数以 32 位存储,带有 1 位符号,一个 8 位指数,以及一个 23位尾数(小数部分)。这种做法提供了 这样可以有大约 7.2 有效的十进制位。

浮点常量表达式可以被定义和被用于编译时,对编译时操作而言,FloatMath 和 FloatString 对象提供了兼容于单精度数的数学函数。参见 254 页常量赋值 常量赋值 ‘=’ ,216 页 FLOAT,303 页 ROUND,以及 FloatMath 和 FloatString 对象的更多信息。

Page 321: Propeller Manual - Parallax Home

4: Spin语言参考– VAR

Propeller Manual v1.0 · Page 321

VAR 声明一个变量块。 VAR Size Symbol ⟨[Count ]⟩ ⟨ Size Symbol ⟨ [Count ]⟩⟩... VAR Size Symbol ⟨[Count ]⟩ ⟨ , Symbol ⟨ [Count ]⟩⟩...

• Size 是希望的变量的大小(类型),BYTE,WORD 或 LONG。 • Symbol 是希望的变量名。 • Count 是可选的表达式,写在括号中,指出了该变量是一个数组变量,有 Count

个元素;类型为 byte,word 或 long。 在引用这些元素时,下标从 0 开始,到

Count-1 结束。 解释

VAR 是变量块声明。变量块是一段源代码块,它声明了全局变量符号。它是六条特

殊声明(CON, VAR, OBJ, PUB, PRI, 和 DAT)之一,这些声明提供了 Spin 语言的内

在结构。

变量声明 (语法 1) 变量声明 常见的形式是先写 VAR 占一行,随后写一行或多行声明。VAR 必须开始

于该行的第一列( 左列),随后的声明必须至少缩进一个空格。

VAR byte Str[10] word Code long LargeNumber

这个例子将 Str 定义为有 10 个元素的字节数组,Code 为字型变量(2 个字节),

LargeNumber 为长字型变量(4 个字节)。公共和私有方法可以按如下方法引用这些变

量:

Page 322: Propeller Manual - Parallax Home

VAR – Spin语言参考

Page 322 · Propeller Manual v1.0

PUB SomeMethod Code := 60000 LargeNumber := Code * 250 GetString(@Str) if Str[0] == "A" <more code here>

注意 Code 和 LargeNumber 在表达式中是被直接使用的。 Str reference in the GetString 方法的参数列表中对 Str 的引用看起来不太一样;它前面有一个@符号,也

就是取符号地址运算符。这是因为我们的虚拟的 GetString 方法需要向 Str 变量回写

数据。如果我们写 GetString(Str),那么只有 Str 的第一个字节,元素 0,会被传递给

GetString。而通过使用取符号地址运算符,@,我们可以把 Str 的地址传递给

GetString; GetString 可以使用该地址向 Str 的元素写数据。 后,我们在一个 IF 表

达式中使用 Str[0] 来判断第一个字节是否是字符“A”。请记住,一个数组的第一个

元素下标总是零。

变量声明(语法 2) 语法 1 中的声明允许逗号分隔的多个同类型变量。下面的声明也类似,但是我们声

明了两个字型变量,Code 和 Index。

VAR byte Str[10] word Code, Index long LargeNumber

变量的作用域 变量块中定义的符号变量对对象内而言是全局的。这就是说这些变量在对象内部的

任意位置被访问,而这些变量的名称不会与父对象或子对象的同名对象冲突。

公共和私有方法可以声明它们自己的本地变量。参见 287 页 PUB,以及 286 页

PRI。

全局变量在对象外是不可访问的,除非另一个对象通过方法调用将其该变量地址传

递出去,或传递回对象。

变量的组织 在对象编译时,在变量块中的所有声明都会被按类型分组。在 RAM 中,首先排列

的是全部的长字,然后是全部的字, 后是全部的字节。这样做的目的是为了提高

Page 323: Propeller Manual - Parallax Home

4: Spin语言参考– VAR

Propeller Manual v1.0 · Page 323

RAM 空间的利用率,尽可能不出现数据之间的空隙。在编写代码时请记住这一点,在

访问变量时可以直接使用相对位置进行访问。

Page 324: Propeller Manual - Parallax Home

VCFG – Spin语言参考

Page 324 · Propeller Manual v1.0

VCFG 视频配置寄存器。 ((PUB PRI)) VCFG

Returns: 如果用作源变量,则返回 cog 视频配置寄存器的当前值。 解释

VCFG 是两条会影响 cog 视频发生器行为的寄存器(VCFG 和 VSCL) 之一。每个 cog 都有

一个视频发生器模块,可以以稳定的速率传输视频图像。VCFG 寄存器包含视频发生器

的配置设定,如表 4-17: 表 4-17: VCFG 寄存器

VCFG Bits 31 30..29 28 27 26 25..23 22..12 11..9 8 7..0 - VMode CMode Chroma1 Chroma0 AuralSub - VGroup - VPins

在 Propeller 汇编语言中,VMode 域到 AuralSub 域可以通过 MOVI 指令方便地访

问。VGroup 域可以用 MOVD 指令访问, VPins 域 使用 MOVS 指令访问。

VMode 2 位的 VMode (视频模式) 域选择了视频输出的类型和方向。请参考表 4-18。

表 4-18: 视频模式域

VMode 视频模式 00 禁用,无视频。 01 VGA 模式;在 VPins7:0 输出 8 位并行信号。 10 合成模式 1; VPins 7:4 上传输 broadcast,VPins 3:0 上传输 baseband 11 合成模式 2; VPins 7:4 上传输 baseband,VPins 3:0 上传输 broadcast

Page 325: Propeller Manual - Parallax Home

4: Spin语言参考– VCFG

Propeller Manual v1.0 · Page 325

CMode CMode (颜色模式) 域选择选择双色或四色模式。0 代表双色;像素数据是 32 位

的,只有颜色 0 和 1 可用。1 表示四色模式;像素数据为 16 位,可以使用颜色 0 到

3。

Chroma1 Chroma1 (broadcast chroma) 位在 broadcast 信号上启用或禁用 chroma (色度) 。0 =

禁用, 1 =启用。

Chroma0 Chroma0 (baseband chroma) 位在 broadcast 信号上启用或禁用 chroma (色度) 。0 =

禁用, 1 =启用。

AuralSub AuralSub (aural sub-carrier) 域选择了要调制(叠加)的 FM 音频 sub-carrier 频率

源。该源是一个 cog 的 PLLA,由 AuralSub 的值指定。

表 4-19: AuralSub 域 AuralSub Sub-Carrier 频率源

000 Cog 0 的 PLLA 001 Cog 1’的 PLLA 010 Cog 2 的 PLLA 011 Cog 3 的 PLLA 100 Cog 4 的 PLLA 101 Cog 5 的 PLLA 110 Cog 6 的 PLLA 111 Cog 7 的 PLLA

Page 326: Propeller Manual - Parallax Home

VCFG – Spin语言参考

Page 326 · Propeller Manual v1.0

VGroup VGroup (视频输出引脚组) 域选择哪个 I/O 引脚组(8 个引脚)要输出视频信号。

表 4-20: VGroup 域 VGroup 引脚组

000 组 0: P7..P0 001 组 1: P15..P8 010 组 2: P23..P16 011 组 3: P31..P24

100-111 <保留>

VPins VPins (视频输出引脚) 域是 VGroup 所使用的掩码,该掩码指出了 VGroup 中哪些

引脚将用于输出视频信号。

表 4-21: The VPins 域 VPins Effect

00001111 只在低 4 位引脚上传输视频;合成模式 11110000 只在高 4 位引脚上传输视频;合成模式 11111111 在 8 个引脚上传输视频;VGA 模式

使用 VCFG VCFG 可以像其他寄存器或预定义的变量一样被读写。例如:

VCFG := %0_10_1_0_1_000_00000000000_001_0_00001111

该命令设置了视频配置寄存器,将视频设置为 4 色合成模式 1,在引脚组 1 的前四

个引脚(引脚 P11:8)上启用基址色度(颜色)。

Page 327: Propeller Manual - Parallax Home

4: Spin语言参考– VSCL

Propeller Manual v1.0 · Page 327

VSCL 视频比例寄存器. ((PUB PRI)) VSCL

返回: 如果用作源变量,会返回 cog 的视频比例寄存器的当前值。 解释

VSCL 是两个能影响 cog 的视频发生器行为的寄存器(VCFG 和 VSCL) 之一。每个 cog 都

有一个视频发生器模块,它可以以固定的速率传输视频图像数据。 VSCL 寄存器用于设

定视频数据的速率。

表 4-22: VSCL 寄存器 VSCL Bits

31..20 19..12 11..0 − PixelClocks FrameClocks

PixelClocks 8 位的 PixelClocks 域指出了每个象素(传输)的时钟数;时钟数是指在每个象素

被移出视频发生器模块之前要消耗的时钟数。这些时钟是 PLLA 时钟,不是系统时

钟。

FrameClocks 12 位的 FrameClocks 域指出了每帧的时钟数;即在每一帧被移出视频发生器模块

之前的时钟数。这些时钟是 PLLA 时钟,不是系统时钟。 一帧是指一个长字容量的象

素数据(通过 WAITVID 指令)。因为象素信息是 2 位模式 16 位,1 位模式 32 位(意思

是 4 色模式 16 象素,或双色模式 32 象素),FrameClocks 通常是 PixelClocks 的 16 倍

或 32 倍。

使用 VSCL VSCL 可以像其他寄存器或预定义变量一样被读写。例如:

VSCL := %000000000000_10100000_101000000000

Page 328: Propeller Manual - Parallax Home

VCSL – Spin语言参考

Page 328 · Propeller Manual v1.0

上面的命令将视频比例寄存器设置为 160 PixelClocks 和 2,560 FrameClocks(2 位

颜色帧,16 象素)。当然,实际的象素移出速率与 PLLA 的频率和比例因子的组合有

关。

Page 329: Propeller Manual - Parallax Home

4: Spin语言参考– WAITCNT

Propeller Manual v1.0 · Page 329

WAITCNT 临时暂停 cog 的执行。 ((PUB PRI)) WAITCNT ( Value )

• Value 是希望要等待的 32 位系统计数器值。 解释

WAITCNT, “等待系统计数器”,是四条等待指令(WAITCNT, WAITPEQ, WAITPNE, 和 WAITVID)之一,用于暂停 cog 的执行,直到一个条件满足。WAITCNT 暂停 cog 执行,

直到全局系统计数器等于 Value。

当执行时, WAITCNT 激活了 cog 内部特殊的“等待”硬件,该硬件会阻止 cog 运行

下一条代码的执行,直到系统计数器的值等于 Value。该硬件会在每个系统时钟周期检

查系统计数器,cog 的电源消耗此时会降低大概 7/8ths 。在正常的应用程序中,WAITCNT 可以在程序中被用来在等待低带宽事件发生时降低电源损耗。

有两种类型的 WAITCNT 延迟: 固定延迟和同步延迟。下面分别解释:

固定延迟 固定延迟是指这样一段时间,它和一个特定时间点无关,只用于暂停指定时间段。

一个固定延迟,例如,可以用于事件发生后,在另一个动作之前,等待 10 毫秒。例如:

CON _clkfreq = xtal1 '设置为低速晶振

_xinfreq = 5_000_000 '使用 5 MHz 晶振 repeat !outa[0] '触发引脚 0

waitcnt(50_000 + cnt) '等待 10 ms

这段代码触发了 I/O 引脚 P0,并在下一个循环前等待 50000 个系统时钟周期。记

住,参数 Value 必须是 32 位的,以匹配系统时钟的值。因为系统时钟是全局资源,它

会在每个时钟周期发生改变,所以要从“现在”开始延迟一定的时间,我们就需要一

个值来加到当前系统计数器的值上。“50_000 + cnt” 中的 cnt 是系统计数器寄存器变

Page 330: Propeller Manual - Parallax Home

WAITCNT – Spin语言参考

Page 330 · Propeller Manual v1.0

量;它会返回那一刻系统计数器的值。所以我们的代码里写道要等待 50,000 个周期

加上系统计数器的当前值;换言之,从现在开始等待 50,000 个周期。假如使用的是

外部 5MHz 的晶振,从时间上来看,50,000 个周期大约是 10ms (1/100th 秒)。

重要提示: 因为 WAITCNT 会暂停 cog,直到系统计数器匹配给定的值,必须要小心确

保不会给定一个小于系统计数器的值,如果在等待硬件被激活之前,系统计数器已经

大于给定值,cog 会永久挂起,事实上,cog 是在等待计数器超过 32 位,然后回卷到

给定的值。即使是在 80MHz 的频率下,仍然需要超过 53 秒的时间来等待系统计数器

回卷!

与此相关的是,在 Spin 代码中使用 WAITCNT 时候,确保向 Value 表达式写入的值是

按我们的方式进行的:格式为“offset + cnt”,而不是“cnt + offset.” 这是因为 Spin翻译器会从左到右计算表达式的值,每个表达式中间值都需要时间来计算。如果 cnt 在表达式的开始,系统计数器会首先被读取,然后会计算表达式的剩下部分,这会占

用未知个时钟周期,使得在 终结果中的 cnt 的值过旧。无论如何,在 WAITCNT 表达式

中保持 cnt 为 新的值能确保固定的时间能大于系统计数器和激活等待硬件间的时

间。事实上,当该命令以 waitcnt(offset + cnt) 的形式执行时,解释器会占用 381 个

周期。这就是说,offset 的值必须至少是 381,以避免不可预料的长时间等待。

同步延迟 同步延迟是指直接和某个指定时间点相关,一个“基本(base)”的时间,用于将

事件从时间上与该时间点对齐。一个同步延迟,例如,可以用于按指定间隔输入和输

出一个信号,而不考虑未知的代码的重叠。为了能明白它和固定延迟的区别,我们来

看下面的时序图:

图 4-1: 固定延迟时序

图 4-1 中展示的是上一个例子,固定延迟,的输出。请注意 I/O 引脚 P0 大概每 10

毫秒触发一次,但是为什么没有精确触发呢?实际上,这里有累积错误使以后的状态

失去了同步。延迟的长度是 10ms,但由于延迟不能抵消剩下的循环的长度,所以错误

Page 331: Propeller Manual - Parallax Home

4: Spin语言参考– WAITCNT

Propeller Manual v1.0 · Page 331

产生了。repeat, !outa[0] 和 WAITCNT 表达都需要一点时间来执行,所有额外的时间

都会累加到 WAITCNT 指定的 10ms 的时间上。

对同步延迟而言,使用 WAITCNT 的方法稍有不同,这样做可以消除时序错误。下面

的例子假定我们使用的是 5MHz 的外部晶振。

CON _clkfreq = xtal1 '设置低速晶振

_xinfreq = 5_000_000 '使用 5 MHz 晶振 PUB Toggle | Time Time := cnt '取得当前系统计数器的值 repeat waitcnt(Time += 50_000) '等待 10 ms

!outa[0] '触发引脚 0

该代码首先取得系统计数器的值,Time := cnt, 然后当系统计数器的值达到 Time + 50,000 时开始 repeat 循环,触发 I/O 引脚,再次循环。语句 Time += 50_000 实际上

是赋值;它将 Time 的值加 50,000 后将结果储存回 Time,然后以此为参数执行

WAITCNT 命令。请注意我们只在例子的开始取了一次系统计数器的值;它就是我们的基

本时间。然后我们等待系统计数器等于该基本时间加 50,000,然后执行循环中的动

作。该方法会自动补偿循环语句: repeat, !outa[0] 和 waitcnt所消耗的时间。 终的

输出如图 4-2 所示。

图 4-2: 同步延迟时序

使用同步延迟方法,我们的输出信号可以保持和“基本时间加上多个间隔”对齐。

只要基本时间足够精确(使用外部晶振),同时循环本身所消耗的时间不会超过时间

间隔,那么该方法就会一直有效。要注意的是我们在第一次触发前使用 WAITCNT 来等

Page 332: Propeller Manual - Parallax Home

WAITCNT – Spin语言参考

Page 332 · Propeller Manual v1.0

待,这样在第一次和第二次触发之间的时间就可以和以后的时间匹配(时间间隔相

同)。

计算时间 即使应用程序会频繁地改变系统时钟,一个对象仍可以延迟指定的时间。要做到这

一点,可以使用带有组合表达式的 WAITCNT 命令,该组合表达式包含了当前系统时钟

频率(CLKFREQ)。例如,即使不需要知道使用对象的应用程序的确切时钟,下面的代码

仍然可以用于使 cog 延迟 1 毫秒;只要时钟频率足够快就行。

waitcnt(clkfreq / 1000 + cnt) '使 cog 延迟 1 毫秒

更多的信息请参见 175 页 CLKFREQ。

Page 333: Propeller Manual - Parallax Home

4: Spin语言参考– WAITPEQ

Propeller Manual v1.0 · Page 333

WAITPEQ 暂停 cog 的执行,直到一个或多个 I/O 引脚满足指定的状态。 ((PUB PRI)) WAITPEQ (State, Mask, Port )

• State 是要与引脚状态作比较的逻辑状态。它是一个 32 位的值,指出了 32 个

I/O 引脚的高,低状态。State 会与指定端口(Port)的(INA & Mask),或 (INB & Mask)作比较。

• Mask 是希望要监控的引脚。Mask 是 32 位的值,包含了 I/O 引脚的每个高位,

高位表示相对应的引脚将被监控。低位(0)表示与之相对应的引脚会被忽

略。Mask 会与 32 位端口的输入状态做“位与(Bitwised ANDed)”,计算所

得的结果会与 State 的值作比较。 • Port 是 1 位的值,指出要监控的 I/O 端口; 0 = Port A,1 = Port B。在当前的

P8X32A 芯片中只有端口 A。 解释

WAITPEQ,“等待引脚等于”,是四条用于暂停 cog 执行,直到满足某一指定条件

的指令(WAITCNT,WAITPEQ,WAITPNE,和 WAITVID) 之一。它会暂停 cog 的执行,直到 Port 的 I/O 引脚状态的值,与 Mask 做位与运算,匹配 State。

当执行时,WAITPEQ 激活了 cog 中特殊的“等待”硬件,该硬件阻止了系统时钟进

一步执行代码,直到希望的一个或多个引脚等于设定的状态。“等待”硬件会在每个

系统时钟周期检查 I/O 引脚的状态,此时 cog 的电源消耗会降低大约 7/8ths

使用 WAITPEQ WAITPEQ是将代码和外部事件同步的很好的方法,例如:

waitpeq(%0100, %1100, 0) '等待 P3 & P2 变为 低 & 高

outa[0] := 1 '将 P0 设置为高

上面的代码暂停了 cog 运行,直到 I/O 引脚 3 为低,引脚 2 为高,然后将 I/O 引脚

0 设置为高。

Page 334: Propeller Manual - Parallax Home

WAITPEQ – Spin语言参考

Page 334 · Propeller Manual v1.0

使用可变引脚数 对 Propeller 对象而言,经常需要监控一个由对象外部指定的引脚。一个简单的方

法是通过 Bitwise Decode 运算符“|< (参见 270 页)”将引脚数转换为正确的 32 位 State 和 Mask 值,例如,如果引脚数由变量 Pin指定,要我们等待该引脚为高,我们可以这

样写代码:

waitpeq(|< Pin, |< Pin, 0) '等待引脚变为高

参数 Mask,|< Pin,会计算成 Long 值,只有一位为高;该位对应于由 Pin 指定的

引脚。

过渡等待 如果我们需要等待从一个状态转换到另一个状态(比如从高到低),我们可以使用

下面的代码:

waitpeq(%100000, 5, 0) '等待引脚 5 变为高

waitpeq(%000000, 5, 0) '然后等待引脚 5变为低

上面的例子首先等待 P5 变为高,然后再等待其变为低;一个高到低的过渡。如果

我们没有使用第一行程序而直接使用第二行,如果 P5 已经为低,cog 将不会暂停。

Page 335: Propeller Manual - Parallax Home

4: Spin语言参考– WAITPNE

Propeller Manual v1.0 · Page 335

WAITPNE 暂停 cog 的执行,直到一个或多个 I/O 引脚不满足指定的状态。 ((PUB PRI)) WAITPNE (State, Mask, Port )

• State 是要与引脚状态作比较的逻辑状态。它是一个 32 位的值,指出了 32 个

I/O 引脚的高,低状态。State 会与指定端口(Port)的(INA & Mask),或 (INB & Mask)作比较。

• Mask 是希望要监控的引脚。Mask 是 32 位的值,包含了 I/O 引脚的每个高位,

高位表示相对应的引脚将被监控。低位(0)表示与之相对应的引脚会被忽

略。Mask 会与 32 位端口的输入状态做“位与(Bitwised ANDed)”,计算所

得的结果会与 State 的值作比较。 • Port 是 1 位的值,指出要监控的 I/O 端口; 0 = Port A,1 = Port B。在当前的

P8X32A 芯片中只有端口 A。 解释

WAITPNE, “等待引脚不等于”,是四条用于暂停 cog 执行,直到满足某一指定条

件的指令(WAITCNT,WAITPEQ,WAITPNE,和 WAITVID) 之一。WAITPNE 是 WAITPEQ 的互补形

式。 它会暂停 cog 的执行,直到 Port 的 I/O 引脚状态的值,与 Mask 做位与运算,不

匹配 State。

当执行时,WAITPNE 激活了 cog 种特殊的“等待”硬件,该硬件阻止了系统时钟进

一步执行代码,直到希望的一个或多个引脚不等于设定的状态。“等待”硬件会在每

个系统时钟周期检查 I/O 引脚的状态,此时 cog 的电源消耗会降低大约 7/8ths 。

使用 WAITPNE WAITPNE 是将代码和外部事件同步的很好的方法,例如:

waitpeq(%0100, %1100, 0) '等待 P3 & P2 变为低和高

waitpne(%0100, %1100, 0) '等待 P3 & P2 不匹配 prev. 状态

outa[0] := 1 '将 P0 设置为高

上面的代码暂停 cog 的执行,直到 P3 为低,P2 为高,然后再次暂停 cog,直到一

个或多个引脚改变状态,然后将 P0 设置为高。

Page 336: Propeller Manual - Parallax Home

WAITVID – Spin语言参考

Page 336 · Propeller Manual v1.0

WAITVID 暂停 cog 的执行,直到其视频发生器准备好读取下一个像素数据。 ((PUB PRI)) WAITVID (Colors, Pixels )

• Colors 是 Long 值,包含了 4 个字节型颜色值,每一个都描述了四种可能的像素

模式。 • Pixels 是下一个要显示的 2 位模式的 16 位像素(或 1 位模式的 32 位像素)。

解释

WAITVID, “等待视频发生器” ,是四条等待指令(WAITCNT, WAITPEQ, WAITPNE, 和 WAITVID) 之一,这些等待指令用于暂停 cog 运行,直到某一条件满足。WAITVID 暂停

cog 运行,直到其视频发生器硬件已经准备好处理下一个像素数据,然后视频发生器

会接收该数据,cog 继续执行下一行代码。

当被执行时,WAITVID 会激活 cog 内部特殊的“等待”硬件,它会阻止系统时钟继

续执行下一条指令,直到视频发生器准备好。等待硬件会在每个系统时钟周期检查视

频发生器的状态,此时 cog 的电源消耗会大幅度降低。

使用 WAITVID WAITVID 是一种向 cog 的视频发生器传送数据的简单机制。因为视频发生器独立于

cog 工作,所以在显示设备需要数据时,两者必须同步。同步的频率取决于显示设备

和视频发生器的设置,但是总的来说,cog 必须在视频发生器准备好时为其提供数

据。Cog 使用 WAITVID 命令来等待合适的时间,然后将数据传递给视频发生器。

参数 Colors 是一个 32 位的值,它包含了 4 个 8 位颜色值(4 色模式)或 2 个 8 位

颜色值(低 16 位,用于 2 色模式)。对 VGA 而言,每个颜色值的高 6 位包括了 2 位

红色,2 位绿色,和 2 位蓝色,由它们来描述(组成)希望的颜色;低 2 位是无关位。

每种颜色值都对应于 2 位像素颜色的四种可能值之一(2 位像素值公有四种可能值:

00,01,10,11;Pixels 被用作 16x2 位 像素模式) 或者作为 1 位像素颜色的两种可能

值之一( Pixels 被用作 32x1 位 像素模式)。

Pixels 描述了要显示的像素模式,视频发生器的色彩深度决定了是采用 16 像素或

32 像素模式(原文为:Pixels describes the pixel pattern to display, either 16 pixels or 32 pixels depending on the color-depth configuration of the Video Generator)。.

Page 337: Propeller Manual - Parallax Home

4: Spin语言参考– WAITVID

Propeller Manual v1.0 · Page 337

请复习 TV 和 VGA 对象的例子来学习如何使用 WAITVID。

在执行 WAITVID 前请确保已经启动了 cog 的视频发生器和计数器 A,否则 WAITVID 命令会陷入无限等待。

Page 338: Propeller Manual - Parallax Home

WORD – Spin语言参考

Page 338 · Propeller Manual v1.0

WORD 声明 Word 型的符号,字型对齐/大小的数据,或读/写内存中的字。 VAR

WORD Symbol ⟨[Count ]⟩ DAT WORD Data ((PUB PRI)) WORD [BaseAddress] ⟨[Offset ]⟩ ((PUB PRI)) Symbol.WORD ⟨[Offset ]⟩

• Symbol 是希望的变量名 (语法 1) 或已经存在变量名 (语法 4). • Count 是可选的表达式,指明了 Symbol 的字型元素的数量,被以数组形式存

储,数组下标从 0 到 Count-1 。 • Data 是常量表达式或逗号分隔的常量表达式列表。 • BaseAddress 是表达式,描述了要进行读写的主内存的地址。如果 Offset 被忽

略,那么 BaseAddress 就是是要操作的地址。如果制定了 Offset ,则实际操作

的地址为 BaseAddress + Offset 。 • Offset 是可选的表达式,指出了将从 BaseAddress 的偏移量,或者从符号的第 0

个(第一个符号)字的偏移。 解释

WORD 是 3 个多用途声明之一 (BYTE, WORD, 和 LONG),可以用于声明或操作内。 WORD 可以被用于:

1) 在 VAR块中声明一个字型 (16 位) 的符号或多字符号数组,或 2) 在 DAT 块中声明字对齐,以及/或字型的数据,或 3) 在主内存中读或写一个字(word),以基址加可选偏移的方式,或 4) 在一个长字型变量中访问一个字(word)。

Word 变量声明 (语法 1) 在 VAR 块中,WORD 的语法 1 用于声明全局的符号变量,该变量可以是字型,或任何

字型数组。例如:

Page 339: Propeller Manual - Parallax Home

4: Spin语言参考– WORD

Propeller Manual v1.0 · Page 339

VAR word Temp 'Temp是一个字 (2 字节)

word List[25] 'List是一个字型数组

上面的例子声明了两个变量(符号),Temp 和 List。 Temp 是一个 word-型变量。

Temp 声明的下一行使用了可选的 Count 域来创建了一个有 25 个字型变量元素的数组,

称为 List。 Temp 和 List 可以被任何 PUB 或 PRI 方法访问,只要这些方法是和 VAR 块在

同一个对象中声明的。下面是一个例子:

PUB SomeMethod Temp := 25_000 '将 Temp 设置为 25,000

List[0] := 500 '将 List 的第一个元素设置为 500

List[1] := 9_000 '将 List 的第二个元素设置为 9,000

List[24] := 60_000 '将 List 的 后一个元素设置为 60,000

要获得这种方式的 WORD 的用法,请参考 315 页 VAR 一节中的变量声明 (语法 1),要

记住在该描述中, WORD 是用于 Size 域的。

Word 数据声明(语法 2) 在 DAT 块中,WORD 的语法 2 用于声明字对齐,和/或字型的数据,这些数据会被编

译为内存常量。 DAT 块允许该声明前有可选的符号,可以用于以后的引用。参见 208页 DAT。例如:

DAT MyData word 640, $AAAA, 5_500 '字对齐/字型数据

MyList byte word $FF99, word 1_000 '字节对齐/字型数据

上面的例子中声明了两个数据符号,MyData 和 MyList。 MyData 指向字对齐和字型

数据的内存起始处。主内存中 MyData的值,分别是是 640, $AAAA 和 5,500。MyList 使用了特殊的 DAT 块中的 WORD 语法,在内存中创建了 byte-aligned 但是是字型数据的

集合:主内存中 MyList的值,分别是$FF99 和 1,000。当被访问时, MyList 包含 $99, $FF, 232 和 3,因为数据是以低位优先(little-endian)的格式存储的。

该数据被编译进对象中,他,它们作为可执行代码的一部分可以通过 WORD 的语法

3 来读/写(见下)。更多 WORD 这种方式的用法信息,参见 208 页 DAT 的声明数据 (语法 1) ,要记住在 WORD 是用于 Size 域的。

Page 340: Propeller Manual - Parallax Home

WORD – Spin语言参考

Page 340 · Propeller Manual v1.0

读/写主内存中的字 (语法 3) PUB 和 PRI 块中, WORD 的语法 3 用于读写主内存中的字型值。在下面的两个例子

中,我们假定我们的对象包含上面两个例子中的 DAT 块,我们会演示两种不同的访问

数据的方法。

首先,我们试着用在数据块中提供的 Label 来直接访问数据。

PUB GetData | Index, Temp

Temp := MyData '将 MyData的第一个字读入 Temp

<do something with Temp> '用 Temp执行一些任务 repeat Index from 0 to 1 '重复两次

Temp := MyList[Index] '将数据读入 Temp,每次 1 byte

<do something with Temp> '用 Temp的值执行一些任务

GetData方法中的第一行,Temp := MyData,读取了 MyData 列表中的第一个字(字型

值 640),并将其存储在 Temp 中。之后在 REPEAT 循环中,Temp := MyList[Index] 语句

读取了位于主内存 MyList + Index 处的一个字节。第一次循环时(Index=0),读取的

值是$99 ($FF99 的低字节),第二次(Index=1)读取下一个字节$FF($FF99 的高字

节)为什么读取的是字节而不是字呢?虽然 MyList 指向的是我们所希望的数据,而且

数据本身也是字型的,但是在声明 MyList 的符号时,指定的是字节对齐,所以 MyList 只能作为字节型指针进行操作。

也许您想想读取 MyData 一样来从 MyList 中读取字型的数据。如果碰巧 MyList 是声

明为字节对齐的字型数据,而前一个数据又刚好在字边界的位置结束,那么就可以用

WORD 声明来达到目的:

PUB GetData | Index, Temp

Temp := WORD[@MyData] '将 MyData的第一个字读入 Temp

<do something with Temp> '用 Temp执行一些任务 repeat Index from 0 to 1 '重复执行两次

Temp := WORD[@MyList][Index] '将数据读入 Temp,每次 1 word

<do something with Temp> '用 Temp的值执行一些任务

Page 341: Propeller Manual - Parallax Home

4: Spin语言参考– WORD

Propeller Manual v1.0 · Page 341

在这个例子中, GetData 方法的第一行用 WORD 声明从主内存地址 MyData 处读取了

一个字,并将其存储在 Temp中,这里是 640。 然后在 REPEAT 循环中,WORD 声明从主内

存的地址 MyList + Index 处读取一个字并将其存储在 Temp 中。因为循环第一次迭代时

Index 设置为 0,MyList 的第一个字($FF99)会被读取。下一次迭代时读取下一个

字,字的地址是@MyList + 1(1,000)。

请注意如果数据不是字对齐的,不论是有意或是偶然,我们将会得到和上面的叙述

不同的结果。例如,如果 MyList h 恰好向前移动了一个字节,那么在循环中读取的第

一个字节就变成了$99xx;xx 是未知的字节值。与此类似,第二个值将变成 59647;它

是由 MyList 的第一个值的高字节位$FF 和 MyList 的第二个值的低字节 232 组成的。所

以请密切注意内存中数据的对齐方法以避免出现这种结果。

使用类似的语法,就可以向内存的字写入数据,只要它们是 RAM 位置就可以。例

如:

WORD[@MyList][0] := 8_192 '将 8192 写入到 MyList的第一个字

这行代码将 8,192 写入到位于 MyList的第一个字。

访问长字变量中的字 (语法 4) 在 PUB 和 PRI 块中,WORD 的语法 4 用于读写长字型变量中的字。例如:

VAR long LongVar PUB Main LongVar.word := 65000 '将 LongVar 的第一个字设置为 65000

LongVar.word[0] := 65000 '和上面一样

LongVar.word[1] := 1 '将 LongVar 的第二个字设置为 1

上面的例子分别访问了 LongVar 中的字型数据部分。每行的注释都表明了该行的作

用。在 Main 方法的结尾,LongVar 等于 130,536。

Page 342: Propeller Manual - Parallax Home

WORFILL – Spin语言参考

Page 342 · Propeller Manual v1.0

WORDFILL 向主内存写入字型数据。 ((PUB PRI)) WORDFILL (StartAddress, Value, Count )

• StartAddress 是一表达式,该表达式指出了要写入的 Value 的内存中的第一个字

的位置。 • Value 是一表达式,指出了要写入的字(Word)的值。 • Count 是一表达式,指出了要写入的字的个数,从 StartAddress 开始。

解释

WORDFILL 是三条用于主内存数据填充指定值的指令 (BYTEFILL, WORDFILL, 和 LONGFILL) 之一。WORDFILL 向 Value 以主内存填充 Count 个字,从 StartAddress 开始。

使用 WORDFILL WORDFILL 是将指定个字的的内存块清零。例如:

VAR word Buff[100] PUB Main wordfill(@Buff, 0, 100) '将 Buff 清零

上述 Main 方法的第一行,将 100 个字(200 字节)的数组 Buff 清零。在执行这种

任务时,WORDFILL 比一个复杂的 REPEAT 循环更有效。

Page 343: Propeller Manual - Parallax Home

4: Spin语言参考– WORDMOVE

Propeller Manual v1.0 · Page 343

WORDMOVE 在主内存的两个区域间复制字。 ((PUB PRI)) WORDMOVE (DestAddress, SrcAddress, Count )

• DestAddress 是一表达式,该表达式指出了要复制的主内存区域。 • SrcAddress 是一表达式,该表达式指出了复制的目标主内存区域的第一个字的地

址。 • Count 是一表达式,该表达式指出了要复制的字的个数。

解释

WORDMOVE 是三条用于块复制的命令(BYTEMOVE, WORDMOVE, 和 LONGMOVE)之一。

WORDMOVE 将 Count 个字的主内存,起始于 SrcAddress ,复制到起始于 DestAddress 的内

存中。

使用 WORDMOVE 在复制大块的字型内存时,WORDMOVE 是很有效的方法。例如:

VAR word Buff1[100] word Buff2[100] PUB Main wordmove(@Buff2, @Buff1, 100) '将 Buff1复制到 Buff2

在 Main 方法的第一行,将 100 个字(200 字节)的数组 Buff1 复制到数组 Buff2。在处理这种任务时,WORDMOVE 比一个复杂的 REPEAT 循环有效。

Page 344: Propeller Manual - Parallax Home

_XINFREQ – Spin 语言参考

Page 344 · Propeller Manual v1.0

_XINFREQ 预定义,可设置的常量,用于指定外部晶振频率。 CON _XINFREQ = Expression

• Expression 是一个整型的表达式,指出了外部晶振频率(XI 引脚);在程序启

动时会使用该值。 解释

_XINFREQ 指出了外部晶振的频率,与时钟模式一起决定了启动时系统时钟的频率。

它是预定义的常量符号,其值由应用程序的顶部对象文件指定。_XINFREQ 可以由应用

程序直接设定,或由_CLKMODE 和_CLKFREQ 设定的结果间接设定。

应用程序的顶部对象文件(编译的起始点) 中的 CON 块中设定了_XINFREQ 的值。该值

与时钟模式一起,定义了在应用程序启动和执行时会使用的系统时钟频率的值。

该应用程序在 CON 块中指定了_XINFREQ 或 _CLKFREQ 的值;_XINFREQ 和 _CLKFREQ 是互

斥的,也就是说只能指定其中的一个,未被指定的一个会被自动计算,并作为被指定

的那个的结果。

下面的例子假定它们被包含在顶部对象文件中,任何在子对象的_XINFREQ 设置会被

编译器忽略。

例如:

CON _CLKMODE = XTAL1 + PLL8X _XINFREQ = 4_000_000

CON 块中第一行的声明,将时钟模式设置为外部低速晶振,以及将时钟 PLL 倍加器

设置为 8。第二行声明指出外部晶振频率为 4MHz,这样设置的意思是系统时钟频率会

被设置为 32MHz,因为 4 MHz * 8 = 32 MHz。由于这些声明,_CLKFREQ 的值会被自动

设置为 32 MHz。

Page 345: Propeller Manual - Parallax Home

4: Spin语言参考– _XINFREQ

Propeller Manual v1.0 · Page 345

CON _CLKMODE = XTAL2 _XINFREQ = 10_000_000

这两个声明将时钟模式设置为外部中速晶振(频率为 10MHz),不使用时钟 PLL倍加器。因为这些声明,_CLKFREQ 值,以及系统时钟频率,被自动设置为 10MHz.

Page 346: Propeller Manual - Parallax Home

_XINFREQ – Spin 语言参考

Page 346 · Propeller Manual v1.0

Page 347: Propeller Manual - Parallax Home

5: 汇编语言参考

Propeller Manual v1.0 · Page 347

Chapter 5: 汇编语言参考 本章描述了 Propeller 芯片汇编语言的所有要素,本章 好作为这些要素的参考。

有些指令会有相应的 Spin 命令,为了能获得进一步的信息,推荐参考 Spin 语言的参

考。

汇编语言参考会被分为两节:

1) Propeller 汇编的结构.。 Propeller 汇编代码是 Propeller 对象的可选部分。这一节描

述了 Propeller 汇编代码的一般结构和如何在对象中使用它.

2) Propeller 汇编语言分类。所有的元素,包括操作符,都按功能分组。这是认识这

种语言的幅度和特殊应用的快速而有效的方法。每个被列出的元素都会有一页参考

信息。有些元素被作了上标“s”,表明这些元素也可以用于 Spin 语言,尽管语法

有很大不同。这些标注过的元素也包括在第四章:Spin 语言参考中。

3) 汇编语言元素。在 Master 表中列出的所有指令中,大多数元素都有其精巧的子段

结构,按字母顺序排列,以方便查找。没有子结构的单独元素,比如操作符,被以

功能分组,但仍然可以通过列表容易的找到。

Propeller 汇编结构 每个 Propeller 对象都包含了 Spin 代码和可选的地汇编代码和数据。一个对象的

Spin 代码用一些特殊用途的块提供了程序结构。数据和 Propeller 汇编代码存放于 DAT 块(数据块)中。参见 208 页 DAT。

Spin 代码由运行 Spin 解释器的 cog 执行,而 Propller 汇编代码则是由 cog 以纯态执

行(不需要解释执行)。因为这一特性,Propeller 汇编代码和属于它的数据必须被

(全部)载入 cog 才能运行。载入时,不会区分汇编代码和数据。下面的例子演示了

一个对象中的 Spin 代码,Main 方法,启动了另外一个 cog 来运行 Propeller 汇编程序

Toggle。

AssemblyToggle.spin CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000

Page 348: Propeller Manual - Parallax Home

汇编语言参考

Page 348 · Propeller Manual v1.0

PUB Main Launch cog to toggle P16 endlessly cognew(@Toggle, 0) '启动新的 cog DAT Toggle P16 ORG 0 '从 Cog RAM 的 addr 0开始

Toggle mov dira, Pin '将引脚设置为输出

mov Time, cnt '计算延迟时间

add Time, #9 '设置 小延迟时间

:loop waitcnt Time, Delay '等待

xor outa, Pin '触发引脚

jmp #:loop '无限循环 Pin long |< 16 '引脚号

Delay long 6_000_000 '要延迟的时钟个数

Time res 1 '系统计数器空间

在 DAT 块中,汇编代码和数据可以混合排列,但是应该注意一些关键的元素载入

cog 的顺序(因为顺序不同可能导致运算结果不同)。COGNEW 和 COGINIT 命令,当被用

于启动 Propeller 汇编代码时,会使 cog 从指定地址开始载入 496 个连续的长字型值。

不论代码是否需要,混杂在这 496 个 Long 值中的数据都会被载入。

每条 Propeller 汇编指令都具有通用的语法结构,包括了一个可选的 Label,可选的

条件,指令和可选的效果。更多信息参见 348 页通用语法元素。

Page 349: Propeller Manual - Parallax Home

5: 汇编语言参考

Propeller Manual v1.0 · Page 349

Propeller 汇编语言分类列表

命令 ORG 调整编译时 Cog 地址指针; 400 页. FIT 验证前一条指令/数据在 cog 空间内; p 380. RES 为符号保留长字空间; p 405.

配置 CLKSETs 在运行时设定时钟模式; p 369.

Cog 控制 COGIDs 取得当前 cog 的 ID; p 373. COGINITs 通过 ID 启动,或重启动一个 cog; p 374. COGSTOPs 通过 ID 停止一个 cog; p 375.

程序控制 LOCKNEWs 检出一个新的锁; p 384. LOCKRETs 返回一个锁; p 384. LOCKCLRs 清除指定 ID 的锁; p 383. LOCKSETs 设定指定 ID 的锁; p 385. WAITCNTs 临时暂停执行; p 419. WAITPEQs 暂停执行,直到引脚满足设定的状态; p 420. WAITPNEs 暂停执行,直到引脚不满足设定的状态; p 421. WAITVIDs 暂停执行,直到视频发生器准备好象素信息; p 422.

条件 IF_ALWAYS 总是; p 377. IF_NEVER 永不; p 377. IF_E 如果等于 (Z = 1); p 377. IF_NE 如果不等于 (Z = 0); p 377.

Page 350: Propeller Manual - Parallax Home

汇编语言参考

Page 350 · Propeller Manual v1.0

IF_A If above (!C & !Z = 1); p 377. IF_B If below (C = 1); p 377. IF_AE If above or equal (C = 0); p 377. IF_BE If below or equal (C | Z = 1); p 377. IF_C 如果 C 置位; p 377. IF_NC 如果 C 清零; p 377. IF_Z 如果 Z 置位; p377. IF_NZ 如果 Z 清零; p 377. IF_C_EQ_Z 如果 C 等于 Z; p 377. IF_C_NE_Z 如果 C 不等于 Z; p 377. IF_C_AND_Z 如果 C 置位且 Z 置位; p 377. IF_C_AND_NZ 如果 C 置位且 Z 清零; p 377. IF_NC_AND_Z 如果 C 清零且 Z 置位; p 377. IF_NC_AND_NZ 如果 C 清零且 Z 清零; p 377. IF_C_OR_Z 如果 C 置位或 Z 置位; p 377. IF_C_OR_NZ 如果 C 置位或 Z 清零; p 377. IF_NC_OR_Z 如果 C 清零或 Z 置位; p 377. IF_NC_OR_NZ 如果 C 清零或 Z 清零; p 377. IF_Z_EQ_C 如果 Z 等于 C; p 377. IF_Z_NE_C 如果 Z 不等于 C; p 377. IF_Z_AND_C 如果 Z 置位且 C 置位; p 377. IF_Z_AND_NC 如果 Z 置位且 C 清零; p 377. IF_NZ_AND_C 如果 Z 清零且 C 置位; p 377. IF_NZ_AND_NC 如果 Z 清零且 C 清零; p 377. IF_Z_OR_C 如果 Z 置位或 C 置位; p 377. IF_Z_OR_NC 如果 Z 置位或 C 清零; p 377. IF_NZ_OR_C 如果 Z 清零或 C 置位; p 377. IF_NZ_OR_NC 如果 Z 清零或 C 清零; p 377.

Page 351: Propeller Manual - Parallax Home

5: 汇编语言参考

Propeller Manual v1.0 · Page 351

流程控制 CALL 跳转到指定地址,返回到下一条指令; p 368. DJNZ 将一个值减 1,如果结果非零则跳转到指定的地址; p 378. JMP 无条件跳转到指定地址; p 382. JMPRET 跳转到指定地址,“返回”到另一个地址; p 382. TJNZ 测试一个值,如果不为 0 则跳转到指定地址; p 417. TJZ 测试一个值,如果为 0 则跳转到指定地址; p 418. RET 返回到存储的地址; p 407.

效果 NR 无结果 (不写结果); p 379. WR 写结果; p 379. WC 写 C 状态; p 379. WZ 写 Z 状态; p 379.

主内存访问 RDBYTE 从主内存读取一个字节; p 402. RDWORD 从主内存读取一个字; p 404. RDLONG 从主内存读取一个长字; p 403. WRBYTE 向主内存写入一个字节; p 422. WRWORD 向主内存写入一个字; p 424. WRLONG 向主内存写入一个长字; p 423.

普通运算 ABS 取得一个数的绝对值; p 362. ABSNEG 取得一个数的负绝对值; p 363. NEG 取得一个数的负数; p 394. NEGC 取一个数值或该数值的加法逆元值,取决于 C; p 394. NEGNC 取一个数值或该数值的加法逆元值,取决于!C; p 395.

Page 352: Propeller Manual - Parallax Home

汇编语言参考

Page 352 · Propeller Manual v1.0

NEGZ 取一个数值或该数值的加法逆元值,取决于 Z; p 397. NEGNZ 取一个数值或该数值的加法逆元值,取决于!Z; p 396. MIN 限制两个无符号数的 小值; p 387. MINS 限制两个有符号数的 小值; p 388. MAX 限制两个无符号数的 大值; p 386. MAXS 限制两个有符号数的 大值; p 386. ADD 将两个无符号值相加; p 363. ADDABS 将一个数的绝对值加到另一个数上; p 364. ADDS 两个有符号数相加; p 365. ADDX 两个无符号数相加后与 C 寄存器的值相加; p 366. ADDSX 两个有符号数相加后与 C 寄存器的值相加; p 365. SUB 两个无符号值相减; p 411. SUBABS 将一个数的绝对值从另一个值中减去; p 412. SUBS 两个有符号值相减; p 412. SUBX 无符号值加 C 和另一个无符号值相减; p 414. SUBSX 有符号值加 C 和另一个有符号值相减; p 413. SUMC 将两个有符号值相加,第二个有符号值的符号由 C 标志位决定是否

反转; p 414. SUMNC 将两个有符号值相加,第二个有符号值的符号由!C 决定是否反转;

p 415. SUMZ 将两个有符号值相加,第二个有符号值的符号由 Z 标志位决定是否

反转; p 416. SUMNZ 将两个有符号值相加,第二个有符号值的符号由!Z 决定是否反转;

p 416. MUL <保留> MULS <保留> AND 将两个值位与; p 367. ANDN 一个值与另一个值的非值做“位与”运算; p 367. OR 将两个值位或; p 400.

Page 353: Propeller Manual - Parallax Home

5: 汇编语言参考

Propeller Manual v1.0 · Page 353

XOR 两个值按位异或; p 425. ONES <保留> ENC <保留> RCL 将 C 左转入原有值的指定位; p 401. RCR 将 C 右转入原有值的指定位; p 402. REV 使数值或 0 扩展型值的 LSB 反转; p 407. ROL 将值左转指定的位数; p 408. ROR 将值右转指定的位数; p 408. SHL 将值按指定的位数左移; p 410. SHR 将值按指定的位数右移; p 410. SAR 将值按指定的位数右移; p 409. CMP 比较两个无符号值; p 370. CMPS 比较两个有符号值; p 370. CMPX 比较第一个无符号值第二个无符号值加 C 的大小; p 372. CMPSX 比较第一个有符号值第二个有符号值加 C 的大小; p 372. CMPSUB 比较两个无符号值,若第二个值小于等于第一个值,则用第一个值

减去第二个值; p 371. TEST 两个值“位与”,结果只影响标志位; p 417. MOV 将寄存器的值设为某个值; p 388. MOVS 将寄存器的源域设定为一个值; p 390. MOVD 将一个寄存器的目标域设定为一个值; p 389. MOVI 将一个寄存器的指令域设置为一个值; p 389. MUXC 将指定值的离散位设置为 C 的状态; p 391. MUXNC 将指定值的离散位设置为!C 的状态; p 392. MUXZ 将指定值的离散位设置为 Z 的状态; p 393. MUXNZ 将指定值的离散位设置为!Z 的状态; p 392. HUBOP 执行 HUB 操作; p 381. NOP 无操作,只是消耗四个时钟周期; p 397.

Page 354: Propeller Manual - Parallax Home

汇编语言参考

Page 354 · Propeller Manual v1.0

寄存器 DIRAs 32 位端口 A 的方向寄存器 ; p 405. DIRBs 32 位端口 B 的方向寄存器 (只读,保留); p 405. INAs 32 位端口 A 的输入寄存器 (只读); p 405. INBs 32 位端口 B 的输入寄存器 (只读,保留); p 405. OUTAs 32 位端口 A 的输出寄存器; p 405. OUTBs 32 位端口 B 的输出寄存器 (保留); p 405. CNTs 32 位系统计数器(只读); p 405. CTRAs 计数器 A 控制寄存器; p 405. CTRBs 计数器 B 控制寄存器; p 405. FRQAs 计数器 A 频率寄存器; p 405. FRQBs 计数器 B 频率寄存器; p 405. PHSAs 计数器 A 锁相环寄存器; p 405. PHSBs 计数器 B 锁相环寄存器; p 405. VCFGs 视频配置寄存器; p 405 VSCLs Video Scale Register; p 405. PARs Cog 启动参数寄存器 (只读); p 405.

常量 注: 请参考第四章:Spin 语言参考中的常量(预定义)一节。. TRUEs 逻辑真: -1 ($FFFFFFFF); p 207. FALSEs 逻辑假: 0 ($00000000); p 207. POSXs 大正整数: 2,147,483,647 ($7FFFFFFF); p 208. NEGXs 大负整数: -2,147,483,648 ($80000000); p 208. PIs 圆周率(PI)的浮点值: ~3.141593 ($40490FDB); p 208.

一元运算符 注: 所列出的运算符是常量表达式运算符。 + 正号(+X)加法的一元形式; p 399.

Page 355: Propeller Manual - Parallax Home

5: 汇编语言参考

Propeller Manual v1.0 · Page 355

- 符号(-X)减法的一元形式; p 399. ^^ 平方根; p 399. || 绝对值; p 399. |< 将一个值(0-31)编码为单高位长字(只有一个高位); p 399. >| 将一个长字解码为高位优先数值(0-32); p 399. ! 位运算: 非(NOT); p 399. @ 符号的地址; p 399..

Page 356: Propeller Manual - Parallax Home

汇编语言参考

Page 356 · Propeller Manual v1.0

二元运算符 注: 所列出的运算符是常量表达式运算符。 + 加; p 399. - 减; p 399. * 乘,并返回结果的低 32 位 (有符号); p 399. ** 乘,并返回结果的高 32 位 (有符号); p 399. / 除,并返回商数(有符号); p 399. // 除,并返回余数(有符号); p 399. #> Limit minimum (有符号); p 399. <# Limit maximum (有符号); p 399. ~> Shift arithmetic right; p 399. << 位运算: 左移(Shift left); p 399. >> 位运算: 右移(Shift right); p 399. <- 位运算: 左转(Rotate left); p 399. -> 位运算: 右转(Rotate right); p 399. >< 位运算: Reverse; p 399. & 位运算: AND; p 399. | 位运算: OR; p 399. ^ 位运算: XOR; p 399. AND 布尔运算: 与(AND,将非零值提升为-1); p 399. OR 布尔运算: 或(OR,将非零值提升为-1); p 399. = = 布尔运算: 相等; p 399. <> 布尔运算: 不相等; p 399. < 布尔运算: 小于(有符号); p 399. > 布尔运算: 大于(有符号); p 399. =< 布尔运算: 小于或等于 (有符号); p 399. => 布尔运算: 大于或等于 (有符号); p 399.

Page 357: Propeller Manual - Parallax Home

5: 汇编语言参考

Propeller Manual v1.0 · Page 357

汇编语言元素

语法定义 除了细节描述,下面的页面中还包括了很多元素的语法定义,以术语描述,以及该

元素的所有可选项。语法定义使用了特殊符号来标明何时以及如何使用该元素的特

性。

粗体大写 以粗体大写书写的内容应该准确无误地输入。

粗斜体 以粗斜体书写的内容可以由用户文本,符号,运算符,表达式

等替换。

. : , # 句号,冒号,逗号和英镑符号应该在其出现的位置输入。

⟨ ⟩ 角括号内是可选内容。如果需要输入内容,不要输入角括号。

双线 区分指令和结果的值。

公共语法元素 在阅读本章的语法定义时,请记住所有的 Propeller 汇编指令都有 3 个公共的,可

选的元素;一个标号,一个条件式和作用对象。每个 Propeller 汇编指令都有如下基本

语法:

⟨标签⟩ ⟨条件⟩ 指令 ⟨作用对象⟩

• 标签 是可选的声明标签(statement label)。 标签 可以是全局的(由下划线或

字母开始)或是本地的(由冒号开始)。本地标签能由至少一个全局标签和同

名本地标签相区别。标签必须由 JMP,CALL 和 COGINIT 这样的指令调用,

用来指明目标目的地。 • 条件是可选的执行条件(IF_C, IF_Z, 等) 它控制指令执行与否。见 368 页中关

于条件的更多信息。 • 指令 是 Propeller 汇编指令 (MOV, ADD, COGINIT, 等) 及其运算域。 • 效果 是可选的一个或三个作用对象的列表 (WZ, WC, WR, 和 NR) 。它们会使指令修

改 Z 标志位,C 标志位,以及是否将指令的结果写入相应的寄存器。见 371 页

中关于效果的更多信息。

Page 358: Propeller Manual - Parallax Home

汇编语言参考

Page 358 · Propeller Manual v1.0

因为每条指令都包含了这三个可选域(标签,条件和效果),为简化起见,这些公

共域会在语法描述时被忽略。.

所以,当您看到如下形式的语法描述时: WAITCNT Target, ⟨#⟩ Delta

... 记得真正的语法描述为: ⟨Label⟩ ⟨Condition⟩ WAITCNT Target, ⟨#⟩ Delta ⟨Effects⟩

这条规则只适用于 Propeller 汇编指令;而不适用于 Propeller 汇编命令。

一些语法定义就像下面的表格一样。这个表格列举了指令的 32 位 opcode,输出和

时钟周期数。Opcode 由下述位组成:指令位(-INSTR-),Z 标志位的“效果”状

态,C 标志位,结果和间接/立即状态(ZCRI),条件执行位(-CON-),和目标位,

源位(-DEST- 和 –SRC-)。Z 和 C 标志位的意义是,如果 Z 或 C 标志位有值,表明这

些标志位是 1。Result 域表明了指令的默认行为是否写入指令结果的值。Clock 域的值

表明了指令执行需要的时钟周期。

0 1 零和一意思是二进制 0 和 1. i 小写“i”意思是一个位的值会被当前状态影响. d s 小写“d”和“s”意思是目标位和源位(Destination and source

bits). ? 问号意思是该位的值会被编译器动态改变. --- 连字符指出的内容是不可用或不重要的. .. 两个句号代表一系列连续的值.

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000011 0001 1111 ddddddddd ------000 --- --- Not Written 7..22

Propeller 汇编指令表 接下来的两页是 Propeller 汇编指令主表。在该表内,D 和 S 的意思是指指令的目

标域和源域,也就是 d-field 和 s-field。对标注了星号的条目,请阅读 352 页上的主表

注释。

Page 359: Propeller Manual - Parallax Home

5: 汇编语言参考

Propeller Manual v1.0 · Page 359

指令 -INSTR- ZCRI -CON- -DEST- -SRC- Z 结果 C 结果 结果 时钟

ABS D, S 101010 001i 1111 ddddddddd sssssssss Result = 0 S[31] 写入 4ABSNEG D, S 101011 001i 1111 ddddddddd sssssssss Result = 0 S[31] 写入 4ADD D, S 100000 001i 1111 ddddddddd sssssssss Result = 0 无符号进位 写入 4ADDABS D, S 100010 001i 1111 ddddddddd sssssssss Result = 0 无符号进位 写入 4ADDS D, S 110100 001i 1111 ddddddddd sssssssss Result = 0 有符号溢出 写入 4ADDSX D, S 110110 001i 1111 ddddddddd sssssssss Z & (Result = 0) 有符号溢出 写入 4ADDX D, S 110010 001i 1111 ddddddddd sssssssss Z & (Result = 0) 无符号进位 写入 4AND D, S 011000 001i 1111 ddddddddd sssssssss Result = 0 结果的奇偶性 写入 4ANDN D, S 011001 001i 1111 ddddddddd sssssssss Result = 0 结果的奇偶性 写入 4CALL #S 010111 0011 1111 ????????? sssssssss Result = 0 --- 写入 4CLKSET D 000011 0001 1111 ddddddddd ------000 --- --- 不写入 7..22 *CMP D, S 100001 000i 1111 ddddddddd sssssssss Result = 0 无符号借位 不写入 4CMPS D, S 110000 000i 1111 ddddddddd sssssssss Result = 0 有符号借位 不写入 4CMPSUB D, S 111000 000i 1111 ddddddddd sssssssss D = S 有符号 (D => S) 不写入 4CMPSX D, S 110001 000i 1111 ddddddddd sssssssss Z & (Result = 0) 有符号借位 不写入 4CMPX D, S 110011 000i 1111 ddddddddd sssssssss Z & (Result = 0) 无符号借位 不写入 4COGID D 000011 0011 1111 ddddddddd ------001 Result = 0 --- 写入 7..22 *COGINIT D 000011 0001 1111 ddddddddd ------010 Result = 0 无 Cog 空闲 不写入 7..22 *COGSTOP D 000011 0001 1111 ddddddddd ------011 --- --- 不写入 7..22 *DJNZ D, S 111001 001i 1111 ddddddddd sssssssss Result = 0 无符号借位 写入 4 or 8 **HUBOP D, S 000011 000i 1111 ddddddddd sssssssss Result = 0 --- 不写入 7..22 *JMP S 010111 000i 1111 --------- sssssssss Result = 0 --- 不写入 4JMPRET D, S 010111 001i 1111 ddddddddd sssssssss Result = 0 --- 写入 4LOCKCLR D 000011 0001 1111 ddddddddd ------111 --- 优先锁状态 不写入 7..22 *LOCKNEW D 000011 0011 1111 ddddddddd ------100 Result = 0 无 Lock 空闲 写入 7..22 *LOCKRET D 000011 0001 1111 ddddddddd ------101 --- --- 不写入 7..22 *LOCKSET D 000011 0001 1111 ddddddddd ------110 --- 优先锁状态 不写入 7..22 *MAX D, S 010011 001i 1111 ddddddddd sssssssss D = S 无符号 (D < S) 写入 4MAXS D, S 010001 001i 1111 ddddddddd sssssssss D = S 有符号(D < S) 写入 4MIN D, S 010010 001i 1111 ddddddddd sssssssss D = S 无符号 (D < S) 写入 4MINS D, S 010000 001i 1111 ddddddddd sssssssss D = S 有符号(D < S) 写入 4MOV D, S 101000 001i 1111 ddddddddd sssssssss Result = 0 S[31] 写入 4MOVD D, S 010101 001i 1111 ddddddddd sssssssss Result = 0 --- 写入 4MOVI D, S 010110 001i 1111 ddddddddd sssssssss Result = 0 --- 写入 4MOVS D, S 010100 001i 1111 ddddddddd sssssssss Result = 0 --- 写入 4MUXC D, S 011100 001i 1111 ddddddddd sssssssss Result = 0 结果的奇偶性 写入 4MUXNC D, S 011101 001i 1111 ddddddddd sssssssss Result = 0 结果的奇偶性 写入 4MUXNZ D, S 011111 001i 1111 ddddddddd sssssssss Result = 0 结果的奇偶性 写入 4MUXZ D, S 011110 001i 1111 ddddddddd sssssssss Result = 0 结果的奇偶性 写入 4

Page 360: Propeller Manual - Parallax Home

汇编语言参考

Page 360 · Propeller Manual v1.0

指令 -INSTR- ZCRI -CON- -DEST- -SRC- Z 结果 C 结果 结果 时钟

NEG D, S 101001 001i 1111 ddddddddd sssssssss Result = 0 S[31] 写入 4 NEGC D, S 101100 001i 1111 ddddddddd sssssssss Result = 0 S[31] 写入 4 NEGNC D, S 101101 001i 1111 ddddddddd sssssssss Result = 0 S[31] 写入 4 NEGNZ D, S 101111 001i 1111 ddddddddd sssssssss Result = 0 S[31] 写入 4 NEGZ D, S 101110 001i 1111 ddddddddd sssssssss Result = 0 S[31] 写入 4 NOP ------ ---- 0000 --------- --------- --- --- --- 4 OR D, S 011010 001i 1111 ddddddddd sssssssss Result = 0 结果的奇偶性 写入 4 RDBYTE D, S 000000 001i 1111 ddddddddd sssssssss Result = 0 --- 写入 7..22 *RDLONG D, S 000010 001i 1111 ddddddddd sssssssss Result = 0 --- 写入 7..22 *RDWORD D, S 000001 001i 1111 ddddddddd sssssssss Result = 0 --- 写入 7..22 *RCL D, S 001101 001i 1111 ddddddddd sssssssss Result = 0 D[31] 写入 4 RCR D, S 001100 001i 1111 ddddddddd sssssssss Result = 0 D[0] 写入 4 RET 010111 0001 1111 --------- --------- Result = 0 --- 不写入 4 REV D, S 001111 001i 1111 ddddddddd sssssssss Result = 0 D[0] 写入 4 ROL D, S 001001 001i 1111 ddddddddd sssssssss Result = 0 D[31] 写入 4 ROR D, S 001000 001i 1111 ddddddddd sssssssss Result = 0 D[0] 写入 4 SAR D, S 001110 001i 1111 ddddddddd sssssssss Result = 0 D[0] 写入 4 SHL D, S 001011 001i 1111 ddddddddd sssssssss Result = 0 D[31] 写入 4 SHR D, S 001010 001i 1111 ddddddddd sssssssss Result = 0 D[0] 写入 4 SUB D, S 100001 001i 1111 ddddddddd sssssssss Result = 0 无符号借位 写入 4 SUBABS D, S 100011 001i 1111 ddddddddd sssssssss Result = 0 无符号借位 写入 4 SUBS D, S 110101 001i 1111 ddddddddd sssssssss Result = 0 有符号下溢出 写入 4 SUBSX D, S 110111 001i 1111 ddddddddd sssssssss Z & (Result = 0) 有符号下溢出 写入 4 SUBX D, S 110011 001i 1111 ddddddddd sssssssss Z & (Result = 0) 无符号借位 写入 4 SUMC D, S 100100 001i 1111 ddddddddd sssssssss Result = 0 有符号溢出 写入 4 SUMNC D, S 100101 001i 1111 ddddddddd sssssssss Result = 0 有符号溢出 写入 4 SUMNZ D, S 100111 001i 1111 ddddddddd sssssssss Result = 0 有符号溢出 写入 4 SUMZ D, S 100110 001i 1111 ddddddddd sssssssss Result = 0 有符号溢出 写入 4 TEST D, S 011000 000i 1111 ddddddddd sssssssss Result = 0 结果的奇偶性 不写入 4 TJNZ D, S 111010 000i 1111 ddddddddd sssssssss Result = 0 0 不写入 4 or 8 **TJZ D, S 111011 000i 1111 ddddddddd sssssssss Result = 0 0 不写入 4 or 8 **WAITCNT D, S 111110 001i 1111 ddddddddd sssssssss Result = 0 无符号进位 写入 5+ WAITPEQ D, S 111100 000i 1111 ddddddddd sssssssss Result = 0 --- 不写入 5+ WAITPNE D, S 111101 000i 1111 ddddddddd sssssssss Result = 0 --- 不写入 5+ WAITVID D, S 111111 000i 1111 ddddddddd sssssssss Result = 0 --- 不写入 5+ WRBYTE D, S 000000 000i 1111 ddddddddd sssssssss --- --- 不写入 7..22 *WRLONG D, S 000010 000i 1111 ddddddddd sssssssss --- --- 不写入 7..22 *WRWORD D, S 000001 000i 1111 ddddddddd sssssssss --- --- 不写入 7..22 *XOR D, S 011011 001i 1111 ddddddddd sssssssss Result = 0 结果的奇偶性 写入 4

Page 361: Propeller Manual - Parallax Home

5: 汇编语言参考

Propeller Manual v1.0 · Page 361

Propeller 汇编指令表注释 * Hub 指令的时钟周期

Hub 指令执行时需要 7 到 22 个时钟周期,这取决于 Hub 访问窗口和指令执行的时

机。Hub 为每个 cog 提供了 16 时钟周期的“Hub 访问窗口”。因为每个 cog 独立于

Hub 运行,所以在 Hub 指令时 cog 必须同步到 Hub。序列中的第一条 Hub 指令将占用0~15

个时钟周期来同步到 Hub 访问窗口,在其后的 7 个时钟周期执行;因此 7 到 22(15+7)的时钟周期在执行命令。第一个 Hub 指令后,会有 9 个(16-7)自由时钟周

期供 cog 使用,直到下一个 Hub 访问窗口到来;有足够的时间来执行两条 4 个时钟周

期的指令,而不会错过下一个 Hub 访问窗口。为了 小化时钟浪费,您可以在两条

otherwise-contiguous Hub 指令之间插入两条正常的指令,而不会增加执行的时间。请

注意 Hub 指令会导致执行时序不确定,特别是序列中的第一条 Hub 指令。

**修改分支指令的时钟周期

如果一条指令修改了某个值并有可能基于此结果跳转,需要不同的时钟周期,这取

决于是否需要跳转。如果要跳转则需要 4 个时钟周期,如果不跳转则需要 8 个时钟周

期。因为通常循环会利用这些指令快速执行,所以它们专为此而优化过。

Page 362: Propeller Manual - Parallax Home

汇编语言参考

Page 362 · Propeller Manual v1.0

ABS 指令: 取数的绝对值。 ABS AValue, ⟨#⟩ SValue 结果: SValue 的绝对值存储在 AValue 中。

• AValue (d-field) 是存贮了 SValue 绝对值的寄存器。 • SValue (s-field) 一个寄存器或 9-bit 的字符,其绝对值将被写入 AValue。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks101010 001i 1111 ddddddddd sssssssss Result = 0 SValue[31] Written 4

解释

取 SValue 值的绝对值并将结果写入 AValue。

如果 WZ 效果被指定,那么若 SValue 是 0,Z 标志位会被置 1。如果 WC 效果被指

定,若 SValue 值为负,C 标志为会被置 1。结果会被写入 AValue,除非 NR 效果被指

定。

字符型 SValue 是非零扩展的,所以 ABS 好被应用于寄存器型的 SValue 值。

Page 363: Propeller Manual - Parallax Home

5: 汇编语言参考– ABSNEG, ADD

Propeller Manual v1.0 · Page 363

ABSNEG 指令: 取数的负绝对值。 ABSNEG NValue, ⟨#⟩ SValue 结果: SValue 的负绝对值存储在 NValue 中。

• NValue (d-field) 是存贮了 SValue 负绝对值的寄存器。 • SValue (s-field) 一个寄存器或 9-bit 的字符,其负绝对值将被写入 NValue。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks101011 001i 1111 ddddddddd sssssssss Result = 0 S[31] Written 4

解释 ABSNEG 取 SValue 值的负绝对值,将结果写入 NValue。

如果 WZ 效果被指定,那么若 SValue 是 0,Z 标志位会被置 1。如果 WC 效果被指

定,若 SValue 值为负,C 标志位会被置 1;若 SValue 值为正,C 标志位会被置 0。除

非 NR 效果被指定,结果会被写入 NValue。

字符型 SValue 是非零扩展的,所以 ABSNEG 好被应用于寄存器型的 SValue值。

ADD 指令: 将两个无符号值相加。 ADD Value1, ⟨#⟩ Value2 结果: 无符号值 Value1 和无符号值 Value2 的和存储在 Value1 中。

• Value1 (d-field) 存储了加数的寄存器,计算的结果将写入该寄存器。 • Value2 (s-field) 一个寄存器或 9-bit 的字符,作为被加数。.

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks100000 001i 1111 ddddddddd sssssssss Result = 0 Unsigned Carry Written 4

Page 364: Propeller Manual - Parallax Home

ADDABS – 汇编语言参考

Page 364 · Propeller Manual v1.0

解释 ADD 将两个无符号数求和,将结果写入 Value1 寄存器。

如果 WZ 效果被指定,那么若 Value1+Value2 等于 0,Z 标志位会被置 1。如果 WC效果被指定,若求和的结果导致一个无符号进位(32 位溢出),C 标志位会被置 1。除非 NR 效果被指定,结果会被写入 Value1。

ADDABS 指令: 将一个数的绝对值加到另一个数上。 ADDABS Value, ⟨#⟩ SValue 结果: Value 和 SValue 的绝对值之和存储在 Value 中。

• Value (d-field) 是一寄存器,包含了要与 SValue 的绝对值相加的值,计算结果将

写入该寄存器。 • SValue (s-field) 是一寄存器或 9 位字符, 其绝对值将与 Value 相加。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks100010 001i 1111 ddddddddd sssssssss Result = 0 Unsigned Carry Written 4

解释

ADDABS Value 与 SValue 的绝对值之和将存储在 Value 寄存器中。

如果指定了 WZ 效果, 若 Value + |SValue| 等于 0,则 Z 标志位置 1。如果指定了

WC 效果, 若计算的和产生无符号进位(32 位溢出),则 C 标志位置 1。除非指定了

NR 效果,结果将被写入 Value。

Page 365: Propeller Manual - Parallax Home

5: 汇编语言参考 – ADDS, ADDSX

Propeller Manual v1.0 · Page 365

ADDS 指令: 将两个带符号数相加。 ADDS SValue1, ⟨#⟩ SValue2 结果: 带符号数 SValue1 和 带符号数 SValue2 之和存储在 SValue1 中。

• SValue1 (d-field) 包含了被加数的寄存器,计算的结果将写入该寄存器。 • SValue2 (s-field) 是一个寄存器或 9 为的字符 is a register or a 9-bit literal whose

value is added into SValue1.

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks110100 001i 1111 ddddddddd sssssssss Result = 0 Signed Overflow Written 4

解释

ADDS两个带符号数 SValue1 和 SValue2 相加,结果存储在 SValue1 寄存器中。

如果指定了 WZ 效果, 若 SValue1 + SValue2 等于 0,则 Z 标志位置 1。如果指定

了 WC 效果, 若计算结果产生了一个带符号溢出,则 C 标志位置 1。除非指定了 NR 效果,否则结果将存储在 SValue1 中。

ADDSX 指令: 两个有符号数相加再与 C 标志位求和。 ADDSX SValue1, ⟨#⟩ SValue2 结果: 有符号数 SValue1 和有符号数 SValue2 加 C 标志位的和存储在 SValue1 中。

• SValue1 (d-field) 是一寄存器,包含了将要与 SValue2 以及标志位 C 求和的值,

计算的结果将写入该寄存器。 • SValue2 (s-field) 是一寄存器或 9 位字符,其值与标志位 C 之和将与 SValue1 相

加。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks110110 001i 1111 ddddddddd sssssssss Z & (Result = 0) Signed Overflow Written 4

Page 366: Propeller Manual - Parallax Home

ADDX – 汇编语言参考

Page 366 · Propeller Manual v1.0

解释 ADDSX (加符号,扩展) 将两个有符号数 SValue1 和 SValue2 和标志位 C 求和,将结

果存储在寄存器 SValue1 中。例如,在 ADD 或 ADDX ( WC, 和可选的 WZ 效果) 指令后使用

ADDSX 指令来执行多个长字型值,带符号加法;也就是 64 位加法。

如果指定了 WZ 效果, 若 Z 标志位已置位,且 SValue1 + SValue2 + C 等于 0(在上

述 ADD 或 ADDX 指令之前使用 WC 和 WZ), 则 Z 标志位置 1。 如果指定了 WC 效果, 若求和产生一个有符号溢出,则 C 标志位置 1。 除非指定了 NR 效果,否则结果将写入

SValue1。

注意在多个有符号长字型值加法中,第一条指令是无符号的(ex: ADD),任何中间

指令都是无符号,扩展的指令(ex: ADDX), 后一条指令是有符号,扩展的指令(ex: ADDSX)。

ADDX 指令: 两个无符号数相加再与 C 标志位求和。 ADDX Value1, ⟨#⟩ Value2 结果: 无符号数 Value1 和 Value2 之和加 C 标志位,结果存储在 Value1 中。

• Value1 (d-field) 是一寄存器,包含了将要与 Value2 加 C 标志位求和的值,运算

的结果将存储在这里。 • Value2 (s-field) 是一寄存器或 9 位字符,其值加 C 标志位后加到 Value1 上。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks110010 001i 1111 ddddddddd sssssssss Z & (Result = 0) Unsigned Carry Written 4

解释

ADDX (加扩展) 将两个无符号数 Value1 和 Value2 求和并与 C 标志位相加,将结果存

储在 Value1 寄存器中。在 ADD 或 ADDX 指令后使用 ADDX 指令(使用 WC 以及可选

的 WZ 效果)来执行超长加法;例如 64 位加法。

如果指定了 WZ 效果, 若 Z 标志位已置位,Value1 + Value2 + C 等于 0(在 ADD和 ADDX 之前使用 WZ 和 WC 效果),则 Z 标志位置 1。如果指定了 WC 效果, 若加

Page 367: Propeller Manual - Parallax Home

5: 汇编语言参考 – AND, ANDN

Propeller Manual v1.0 · Page 367

法产生了一个无符号进位(32 位溢出),则 C 标志位置 1。除非指定了 NR 效果,结

果将被写入 Value1。

AND 指令: 将两个值位“与”。 AND Value1, ⟨#⟩ Value2 结果: Value1 和 Value2 与运算后将结果存储在 Value1 中。

• Value1 (d-field) 是一寄存器,包含了将要与 Value2 进行位与运算的值以及运算

的结果。 • Value2 (s-field) 是一寄存器或 9 位字符,其值将与 Value1 进行“位与”运算。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks011000 001i 1111 ddddddddd sssssssss Result = 0 Parity of Result Written 4

解释

AND (bitwise AND) 将 Value2 中的值与 Value1 中的值进行“位与”运算。

如果指定了 WZ 效果, 若 Value1 和 Value2 与运算后结果为 0 ,则 Z 标志位置 1。如果指定了 WC 效果, 若运算结果包含了奇数个高(1)位,则 C 标志位置 1。 除非

指定了 NR 效果,结果将被写入 Value1。

ANDN 指令: 一个值与另一个值的非值做“位与”运算。 ANDN Value1, ⟨#⟩ Value2 结果: Value1 和 !Value2 做与运算,结果存储在 Value1 中。

• Value1 (d-field) 是一寄存器,包含了将要与!Value2 做“位与”运算的值以及运

算结果。

Page 368: Propeller Manual - Parallax Home

CALL – 汇编语言参考

Page 368 · Propeller Manual v1.0

• Value2 (s-field) 是一寄存器或 9 位字符,其值将被反向(逐位反向),然后和

Value1 的值做“位与”。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks011001 001i 1111 ddddddddd sssssssss Result = 0 Parity of Result Written 4

解释

ANDN (bitwise AND NOT) 将 Value2 的值逐位反向后与 Value1 的值做“位与”。

如果指定了 WZ 效果, 若 Value1 和 !Value2 “位与”运算结果为 0,则 Z 标志位

置 1。 Value1 AND !Value2 equals zero. 如果指定了 WC 效果, 若结果包含了奇数个高

位(1),则 C 标志位置 1。除非指定了 NR 效果,结果将被写入 Value1。

CALL 指令: 跳转到指定地址,之后返回到下一条指令。 CALL #Address 结果: PC + 1 被写入由 d-field 域指定的寄存器的 s-field。

• Address (s-field) 是寄存器,或 9 位的字符值,其值为要跳转的地址。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks010111 0011 1111 ????????? sssssssss Result = 0 --- Written 4

解释

CALL 会记录下一条指令的地址(PC + 1),然后跳转到 Address。位于 Address 的程序

(子程序) 后应该执行 RET 指令来返回到之前记录的地址 (该指令位于 CALL指令之

后)。

Propeller 芯片不使用调用堆栈(call stack),所以返回地址会以不同(不同于调用

堆栈)的方式存储;它会被子程序的 RET 命令自身记录。对 CALL 指令,汇编器会在地

址中寻找一个附上了“_ret” 的标签。然后解码 Address_ret ,将结果传递给 CALL 指令,

就像在执行跳转时一样。在运行时,当执行到 CALL 指令,Cog 会首先将返回地址(PC +

Page 369: Propeller Manual - Parallax Home

5: 汇编语言参考– CLKSET

Propeller Manual v1.0 · Page 369

1)存储到“RET” 指令的源域(地址:Address_ret ),然后跳转到 Address。参考下面的

例子:

call #Routine <other code here> Routine <more code> . . . Routine_ret ret

这个例子中,第一条指令是对 Routine的调用。汇编器会寻找一个名为 Routine_ret

的标签,将其解码,将 Routine的地址传递给 CALL 指令。在运行时,当执行 CALL 指令

时,cog 会首先将地址 <other code here> 写到地址位于 Routine_ret的指令的源域中,

然后跳转到 Routine。位于 Routine_ret 的 RET 指令实际上成为一条跳转(JMP)指令,

目标域为<other code here>。

CALL 是 JMPRET 指令的子集;实际上,它和 JMPRET 的操作码是一样的,不同之处在

于 i-field 的设置 (因为 CALL 只使用立即数) 以及 d-field 设置为 Address_ret的地址。

除非指定了 NR 效果,返回地址将被写入 Address_ret 寄存器。

CLKSET 指令: 设置运行时的时钟设置。 CLKSET Mode

• Mode (d-field) 是一寄存器,包含了将要写入 CLK 寄存器的 8 位时钟模式的值。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000011 0001 1111 ddddddddd ------000 --- --- Not Written 7..22

解释

CLKSET 在运行时改变系统时钟设置。 CLKSET 指令与在 Spin 语言中的同名指令相似 ( 见 183 页 CLKSET ) ,除了在这里 CLKSET 只设定时钟模式,而不设定频率。

Page 370: Propeller Manual - Parallax Home

CMP, CMPS – 汇编语言参考

Page 370 · Propeller Manual v1.0

执行过一条 CLKSET 指令后,更新系统时钟频率设定就很重要,更新的方法是在主

内存(long 0)的相应位置写入对应的值:WRLONG freqaddr, #0。 如果系统时钟频率

值没有被更新,其他的对象可能因为无效的时钟频率数据而误动作。

CLKSET 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息。

CMP 指令: 比较两个无符号值。 CMP Value1, ⟨#⟩ Value2 结果: 可指定相等或大于/小于状态写入 Z 标志位和 C 标志位。

• Value1 (d-field) 是一寄存器,包含了将要与 Value2 作比较的值。 • Value2 (s-field) 是一寄存器或 9 位字符, 其值与 Value1 作比较。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks100001 000i 1111 ddddddddd sssssssss Result = 0 Unsigned Borrow Not Written 4

解释

CMP (无符号比较) 比较两个无符号值 Value1 和 Value2 。如果 Z 和 C 标志位被写

入,则表明相等,大于或小于的关系。

如果指定了 WZ 效果, 若 Value1 等于 Value2 ,则 Z 标志位置 1。如果指定了 WC效果, 若 Value1 小于 Value2 ,则 C 标志位置 1。

CMPS 指令: 比较两个有符号值。 CMPS SValue1, ⟨#⟩ SValue2 结果: 可指定相等,和大于/小于状态写入 Z 和 C 寄存器。

• SValue1 (d-field) 是一寄存器,包含了将要与 SValue2 作比较的值。 • SValue2 (s-field) 是一寄存器或 9 位字符,其值与 SValue1 作比较。

Page 371: Propeller Manual - Parallax Home

5: 汇编语言参考 – CMPSUB

Propeller Manual v1.0 · Page 371

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks110000 000i 1111 ddddddddd sssssssss Result = 0 Signed Borrow Not Written 4

解释

CMPS (有符号比较) 比较两个有符号值 SValue1 和 SValue2。 如果 Z 和 C 标志位被写

入,则表明相应的相等,大于或小于的关系。

如果指定了 WZ 效果, 若 SValue1 等于 SValue2,则 Z 标志位置 1。如果指定了

WC 效果, 若 SValue1 小于或等于 SValue2 ,则 C 标志位置 1。

CMPSUB 指令: 比较两个无符号值,若第二个值小于等于第一个值,则用第一个值减去第二个

值。 CMPSUB Value1, ⟨#⟩ Value2 结果: 可指定 Value1 = Value1 – Value2, 以及 Z 和 C 标志位等于比较结果。

• Value1 (d-field) 是一寄存器,包含了将要与 Value2 作比较的值,也是减法运算

(如果有执行)结果的目标寄存器。 • Value2 (s-field) 是一寄存器或 9 位字符,其值将要与 Value1 作比较并可能作为

减数。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks111000 000i 1111 ddddddddd sssssssss D = S Unsigned (D => S) Not Written 4

解释

CMPSUB 比较两个无符号值 Value1 和 Value2, 如果 Value2 等与或小于 Value1 ,则从

Value1 中减去(如果指定了 WR 效果)。如果 Z 和 C 标志位被写入,则表明相应的相等,

大于或小于的关系。

如果指定了 WZ 效果, 若 Value1 等于 Value2 ,则 Z 标志位置 1。如果指定了 WC效果,(若 Value1 等于或大于 Value2)减法可用,则 C 标志位置 1。如果指定了 WR 效果,如果有结果的话,将被存入 Value1 。

Page 372: Propeller Manual - Parallax Home

CMPSX, CMPX – 汇编语言参考

Page 372 · Propeller Manual v1.0

CMPSX 指令: 比较第一个有符号值第二个有符号值加 C 的大小。 CMPSX SValue1, ⟨#⟩ SValue2 结果: 相等,大于/小于状态可选择写入 Z 和 C 标志位。

• SValue1 (d-field) 是一寄存器,包含了将要与 SValue2 作比较的值。 • SValue2 (s-field) 是一寄存器或 9 位字符,其值将与 SValue1 作比较。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks110001 000i 1111 ddddddddd sssssssss Z & (Result = 0) Signed Borrow Not Written 4

解释

CMPSX (比较有符号值,扩展) 比较两个有符号值,SValue1 和 SValue2 + C 的大小。

在一条 CMP 或 CMPX (使用 WC,和可选的 WZ效果) 指令后使用 CMPSX 指令来执行多长字型

值,有符号比较;例如 64 位有符号值比较。如果 Z 和 C 标志位被写入,则表明了相

等,大于或小于的关系。

如果指定了 WZ 效果, 若 Z 已经置位且 SValue1 等于 SValue2 + C (在 CMP 或 CMPX 指令前使用 WC 和 WZ ),则 Z 标志位置 1。如果指定了 WC 效果, 若 SValue1 小于 SValue2 (多-长字型值),则 C 标志位置 1。

注意在有符号多-长字型值运算时,第一条指令是无符号的(ex: CMP), 任何中间指令

也是无符号, 扩展的 (ex: CMPX), 后一条指令时有符号,扩展的(ex: CMPSX)。

CMPX 指令: 比较第一个无符号值第二个无符号值加 C 的大小。 CMPX Value1, ⟨#⟩ Value2 结果: 可指定相等或大于/小于状态写入 Z 标志位和 C 标志位。

• Value1 (d-field) 是寄存器,包含了要与 Value2 作比较的值。 • Value2 (s-field) 是一寄存器或 9 位字符,其值与 Value1 作比较。

Page 373: Propeller Manual - Parallax Home

5: 汇编语言参考– COGID

Propeller Manual v1.0 · Page 373

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks110011 000i 1111 ddddddddd sssssssss Z & (Result = 0) Unsigned Borrow Not Written 4

解释

CMPX (扩展比较) 比较无符号值 Value1 和 Value2 + C 的值。在一条 CMP 或 CMPX (with the WC, and optionally WZ, effect)指令后使用 CMPX 指令来执行多长字型值的比较。例

如 64 位无符号值的比较。如果 Z 和 C 标志位被写入,则表明了两者间相等,大于或小

于的关系。

如果指定了 WZ 效果, 若 Z 标志位之前被置位且 Value1 等于 Value2 + C (CMP 或 CMPX 指令之前使用 WC 和 WZ 效果),则 Z 标志位置 1。如果指定了 WC 效果, 若Value1 小于 Value2 (多个长字组成的值) ,则 C 标志位置 1。

COGID 指令: 取得 cog 的 ID。 COGID Destination 结果: 当前 cog 的 ID (0-7) 被写入 Destination。

• Destination (d-field) 是将写入 cog ID 的寄存器。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000011 0011 1111 ddddddddd ------001 Result = 0 --- Written 7..22

解释

COGID 返回执行该条命令的 COG 的 ID。 COGID 指令与同名的 Spin 语言命令相似;

参见 186 页的 COGID 命令。

如果指定了 WZ 效果,如果 cog ID 是 0,则 Z 标志位置位。除非指定了 NR 效果,

否则结果将写入 Destination 。

COGID 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息。

Page 374: Propeller Manual - Parallax Home

COGINIT –汇编语言参考

Page 374 · Propeller Manual v1.0

COGINIT 指令: 可由 ID 指定启动或重启动一个 cog,来运行 Propeller 汇编语言或 Spin 语言代码。 COGINIT Destination 结果: 可指定启动/重启动的 cog 的 ID 写入 Destination。

• Destination (d-field) 是寄存器,包含了目标 cog 的启动信息,启动后可选择将

被启动的 COG 的 ID 写入该寄存器。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000011 0001 1111 ddddddddd ------010 Result = 0 No Cog Free Not Written 7..22

解释

COGINIT 指令类似于另外两条 Spin 命令, COGNEW 和 COGINIT组合在一起。Propeller 汇编的 COGINIT 指令可以被用于启动一个新的 cog 或重启动一个活动的 cog。 Destination 寄存器有四个域来制定哪一个 cog 会被启动,启动的 cog 要运行的程序在内存中的位

置,和 PAR 寄存器的内容。下表描述了这些域的内容。

表 5-1: Destination 寄存器域 31:18 17:4 3 2:0

PAR 寄存器地址,14 位(Long) 要载入的代码的地址,14 位

(Long) New Cog ID

第一个域,bits 31:18,会被写入要启动的 cog 的 PAR 寄存器的 bits 15:2。这 14 位会

成为 16 位长字型地址的高位(Upper bits)。类似于 Spin 语言中的 COGINIT 命令的 Parameter 域,Destination 的第一个域用于向 cog 传递指定内存或结构的的 14 位地

址。

第二个域, bits 17:4,保存了要载入 cog 的 16 位汇编代码地址的高 14 位。从这个

地址开始,Cog 寄存器$000 到$1EF 会被顺序载入,特殊目的寄存器会被清零,cog 会

开始执行位于$000 的代码。

第三个域,bit 3,如果要启动新的 cog,应该被置位(1),如果要启动或重启动指

定的 cog,该位应该被清零(0)。

Page 375: Propeller Manual - Parallax Home

5: 汇编语言参考– COGSTOP

Propeller Manual v1.0 · Page 375

如果第三个域被置位,Hub 会启动下一个可用的 cog( 低数字顺序的,非活动的

cog),并将该 cog 的 ID 写入到 Destination (如果已经指定了 WR 效果)。

如果第三个域被清零(0),Hub 会启动,或重启动由 Destination 的第四个域,

bits2:0,指定的 cog。

如果指定了 WZ 效果,若 cog ID 返回为 0,则 Z 标志位将被置 1。如果指定了 WC效果,若没有可用的 cog,C 标志位将被置位。如果指定了 WR 效果, Destination 会被

写入 Hub 启动的 cog 的 ID,或者指定的 cog 的 ID。

如果您希望同步更新标志位或 Destination,在使用 COGINIT 指令时就应该指定 WC, WZ, 和/或 WR 效果。

从用户的 Propeller 汇编代码中载入 Spin 代码是不实际的,所以我们推荐使用该指

令时只载入汇编代码。

COGINIT 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息。

COGSTOP 指令: 通过 ID 停止一个 cog。 COGSTOP CogID

• CogID (d-field) 是一寄存器,包含了将要停止的 cog 的 ID(0 - 7 )。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000011 0001 1111 ddddddddd ------011 --- --- Not Written 7..22

解释

The COGSTOP 指令会停止一个在 CogID 中指出的 ID 的 cog,使该 Cog 进入休眠状

态。在休眠状态中,Cog 停止接收系统时钟脉冲,这样可以有效的降低电源消耗。

COGSTOP 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息。

Page 376: Propeller Manual - Parallax Home

Conditions ( 条件) – 汇编语言参考

Page 376 · Propeller Manual v1.0

条件 ( IF_x ) 每个 Propeller 汇编指令都有一个可选的条件域,用于在运行时到达该语句时动态

的决定是否执行。其基本的语法是:

⟨Label⟩ ⟨Condition⟩ Instruction ⟨Effects⟩

可选的 Condition 域可以包含 32 个条件之一(见表 5-2),默认的条件是 IF_ALWAYS。每个条件的 4-bit 的 Value 是用于指令的操作码中–CON– 域的。

这一特性,结合对指令效果域(Effects field)的正确使用使得 Propeller 汇编语言

更强大。标志位可以被置位(0 或 1),随后的指令可以据此有条件地执行。下面是一

个例子:

test _pins, #$20 wc and _pins, #$38 shl t1, _pins shr _pins, #3 movd vcfg, _pins if_nc mov dira, t1 if_nc mov dirb, #0 if_c mov dira, #0 if_c mov dirb, t1

第一条指令,test _pins, #$20 wc,执行其操作,同时因为指定了 WC 效果所以调

整 C 标志位的状态。下面的四条指令执行的操作可以影响 C 标志位,但是因为没有指

定 WC 效果,所以不会影响标志位。就是说 C 标志位的会保留自上一次修改的状态。

后的四条指令会基于 C 标志的状态有条件执行。 后的几条指令中 先两条 mov 指令有 if_nc 条件,这会使他们只有在 “如果 C 标志位非真 if not C (if C = 0)”的条件下

执行。 后两条 mov 指令有 if_c 条件,这会使他们只有在“如果 C 标志位为真”的条

件下执行。在这个例子里,这两对 mov 指令在以独占方式执行。

当一条指令的条件计算出为 FALSE,那这条指令会自动转换为一条空指令(NOP),

消耗 4 个时钟周期,但不会影响任何标志位和寄存器。这使得多决策代码,如上一个

例子,可以被精确计时。

Page 377: Propeller Manual - Parallax Home

5: 汇编语言参考– ( 条件) Conditions

Propeller Manual v1.0 · Page 377

表 5-2: 条件 条件 指令执行 值 同义字

IF_ALWAYS always 1111

IF_NEVER never 0000

IF_E if equal (Z = 1) 1010 IF_Z

IF_NE if not equal (Z = 0) 0101 IF_NZ

IF_A if above (!C & !Z = 1) 0001 IF_NC_AND_NZ –and– IF_NZ_AND_NC IF_B if below (C = 1) 1100 IF_C

IF_AE if above or equal (C = 0) 0011 IF_NC

IF_BE if below or equal (C | Z = 1) 1110 IF_C_OR_Z –and– IF_Z_OR_C IF_C 如果 C 置位 1100 IF_B

IF_NC 如果 C 清零 0011 IF_AE

IF_Z 如果 Z 置位 1010 IF_E

IF_NZ 如果 Z 清零 0101 IF_NE

IF_C_EQ_Z 如果 C 等于 Z 1001 IF_Z_EQ_C

IF_C_NE_Z 如果 C 不等于 Z 0110 IF_Z_NE_C

IF_C_AND_Z 如果 C 置位且 Z 置位 1000 IF_Z_AND_C

IF_C_AND_NZ 如果 C 置位且 Z 清零 0100 IF_NZ_AND_C

IF_NC_AND_Z 如果 C 清零且 Z 置位 0010 IF_Z_AND_NC

IF_NC_AND_NZ 如果 C 清零且 Z 清零 0001 IF_A –and– IF_NZ_AND_NC IF_C_OR_Z 如果 C 置位或 Z 置位 1110 IF_BE –and– IF_Z_OR_C IF_C_OR_NZ 如果 C 置位或 Z 清零 1101 IF_NZ_OR_C

IF_NC_OR_Z 如果 C 清零或 Z 置位 1011 IF_Z_OR_NC

IF_NC_OR_NZ 如果 C 清零或 Z 清零 0111 IF_NZ_OR_NC

IF_Z_EQ_C 如果 Z 等于 C 1001 IF_C_EQ_Z

IF_Z_NE_C 如果 Z 不等于 C 0110 IF_C_NE_Z

IF_Z_AND_C 如果 Z 置位且 C 置位 1000 IF_C_AND_Z

IF_Z_AND_NC 如果 Z 置位且 C 清零 0010 IF_NC_AND_Z

IF_NZ_AND_C 如果 Z 清零且 C 置位 0100 IF_C_AND_NZ

IF_NZ_AND_NC 如果 Z 清零且 C 清零 0001 IF_A –and– IF_NC_AND_NZ IF_Z_OR_C 如果 Z 置位或 C 置位 1110 IF_BE –and– IF_C_OR_Z IF_Z_OR_NC 如果 Z 置位或 C 清零 1011 IF_NC_OR_Z

IF_NZ_OR_C 如果 Z 清零或 C 置位 1101 IF_C_OR_NZ

IF_NZ_OR_NC 如果 Z 清零或 C 清零 0111 IF_NC_OR_NZ

Page 378: Propeller Manual - Parallax Home

DJNZ –汇编语言参考

Page 378 · Propeller Manual v1.0

DJNZ 指令: value 值减一,若非零则跳转到地址 address 。 DJNZ Value, ⟨#⟩ Address 结果: Value-1 is written to Value.

• Value (d-field) 是寄存器,其值会减一并测试。 • Address (s-field) 是一个寄存器或 9 位字符,其值是 Value 减一后非零时将要跳

转的地址。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks111001 001i 1111 ddddddddd sssssssss Result = 0 Unsigned Borrow Written 4 or 8

解释

DJNZ使 Value 寄存器减一,若结果非零则跳转到 Address。

如果指定了 WZ 效果, 若 Value 减一后为 0,则 Z 标志位置 1。 如果指定了 WC 效

果,若减量后产生了下溢出(underflow),则 C 标志位置 1。 除非指定了 NR 效果,

减一的结果将被写入 Value。

DJNZ 执行时需要不同的时钟周期,这取决于是否需要跳转。如果必须要跳转则消

耗 4 个时钟周期,如果不跳转,则消耗 8 个。因为循环使用了 DJNZ ,所以的 DJNZ 专

为此(跳转)优化过。

Page 379: Propeller Manual - Parallax Home

5: 汇编语言参考– (效果) Effects

Propeller Manual v1.0 · Page 379

效果 每条 Propeller 汇编指令都有一个可选的“效果(Effects)域”,它可以使该指令执

行时修改标志位或寄存器。Propeller 汇编语言的这条基本语法是: ⟨Label⟩ ⟨Condition⟩ Instruction ⟨Effects⟩

可选的 Effects 域可以包含 4 个效果之一,如下表。如果不指定任何效果,默认的

行为仍然可以由指令的操作码(opcode)中 ZCRI域的相应的位(Z, C, or R)来表明。

表 5-3: 效果

效果 结果是 WC C 标志位被修改

WZ Z 标志位被修改

WR 目标寄存器被修改

NR 目标寄存器不被修改

一条指令后可以有一到三个空格分割的效果域来对指定的内容作修改。举例而言:

and temp1, #$20 wc andn temp2, #$38 wz, nr

第一条指令执行了“位与(bitwise AND),将 temp1 寄存器的值与 $20 做位与,

结果存储在 temp1 中,并根据结果的奇偶性修改了 C 标志位。第二条指令对存储 temp2 寄存器中的值和 $38 执行了“位与非(bitewise AND NOT)”,同时依据结果是否为

0 修改了 Z 标志位,但是并不把结果写入 temp2 。 在第一条指令执行过程中,Z 标志位

不会被修改。第二条指令执行期间,C 标志位不会被修改。如果这些指令不包括 WC和 WZ 效果,那么这些标志位就不会被修改。

在指令中使用 Effects ,结合后面指令的 Conditions 条件,使得代码比通常的汇编

语言代码更强大。见 368 页 条件 更多的信息。

Page 380: Propeller Manual - Parallax Home

FIT –汇编语言参考

Page 380 · Propeller Manual v1.0

FIT 命令: 验证上一条指令/数据在指定的地址范围内。 FIT ⟨Address⟩ 结果:如果前一条指令/数据超过了 Address-1 则出现编译时错误。

• Address 是可选的 Cog RAM 地址(0-$1F0),之前的汇编代码不应该达到此地

址。如果没有给定 Address,则默认使用$1F0(第一个特殊用途寄存器的地

址)。 解释

FIT 指令检查当前编译时 cog 的地址指针是否在地址 Address-1 内或$1EF(通用

Cog RAM 的末端)内。该指令可以用于保证之前的指令和数据在 Cog RAM 的范围

内,或在 Cog RAM 的区域内。注意:任何不在 Cog RAM 范围内的指令在汇编代码被

载入 cog 时会被忽略。考虑下面的代码:

DAT ORG 492 Toggle mov dira, Pin :Loop mov outa, Pin mov outa, #0 jmp #:Loop Pin long $1000 FIT

这段代码使用了 ORG 语句,以手动方式被推入 Cog RAM 的高段,这使得代码和第

一个特殊用途寄存器($1F0)重叠,所以 FIT指令会产生一个编译时错误。

Page 381: Propeller Manual - Parallax Home

5: 汇编语言参考– HUBOP

Propeller Manual v1.0 · Page 381

HUBOP 指令: 执行一项 Hub 操作。 HUBOP Destination, ⟨#⟩ Operation 结果: 所执行的操作不同结果有所不同。

• Destination (d-field) 是包含了要用于 Operation 的值。 • Operation (s-field) 是寄存器或 3 位的字符,指出了要执行的 Hub 操作。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000011 000i 1111 ddddddddd sssssssss Result = 0 --- Not Written 7..22

解释

在 Propeller 芯片中,HUBOP 是所有 Hub 操作指令的模板: CLKSET, COGID, COGINIT, COGSTOP, LOCKNEW, LOCKRET, LOCKSET, 和 LOCKCLR。指令执行 Hub 操作将 Operation 域 (opcode 的 s-field)设置为 3 位立即数,该数值用来表示希望的操作(更多的信息参

考 Hub 指令的语法描述中 opcode 的部分)。HUBOP 指令自身很少被使用,但是在一些

特殊情况下可能很有用。

HUBOP 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息。

IF_x 见 368 页 条件。

Page 382: Propeller Manual - Parallax Home

JMP –汇编语言参考

Page 382 · Propeller Manual v1.0

JMP 指令: 无条件跳转到一个地址。 JMP ⟨#⟩ Address

• Address (s-field) 是一个寄存器或 9 位字符,其值是将要跳转到的地址。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks010111 000i 1111 --------- sssssssss Result = 0 --- Not Written 4

解释

JMP 将程序计数器(Program Counter (PC))设置为 Address 的值,使得程序跳转到

Cog RAM 中相应的位置。

JMPRET 指令: 跳转到地址,然后“返回”到另一个地址。 JMPRET RetInstAddr, ⟨#⟩ DestAddress 结果: PC + 1 被写入到由 d-field 指定的寄存器的 s-field 域中。

• RetInstAddr (d-field) 是存储了返回地址( PC+1 )的寄存器;它应该是

DestAddress 的 RET 或 JMP 指令的地址。 • DestAddress (s-field) 是寄存器或 9 位的字符,其值是要跳转到的地址。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks010111 001i 1111 ddddddddd sssssssss Result = 0 --- Written 4

解释 JMPRET 将下一条指令的地址(PC + 1) 存储到指令的 RetInstAddr 域,然后跳转到

DestAddress。位于 DestAddress 的程序 终会执行 RET 或 JMP 指令返回到存储的地址

(JMPRET之后的指令)。

Page 383: Propeller Manual - Parallax Home

5: 汇编语言参考– LOCKCLR

Propeller Manual v1.0 · Page 383

Propeller 不使用调用堆栈,所以返回地址必须存储在程序的 RET 中,或 JMP 命令自

身。JMPRET 是 CALL 指令的超集,它和 CALL 的操作码相同,但是 i-field 和 d-field 可以

由用户,而不是汇编程序,来配置。更多信息参见 360 页 CALL。

除非指定了 NR 效果,否则返回地址将被写入 RetInstAddr。

LOCKCLR 指令: 清除锁位为 False,取得其原有状态。 LOCKCLR ID 结果: 可选将原有锁状态写入 C 标志位。

• ID (d-field) 是包含了要清除的的锁位 ID(0-7)的寄存器

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000011 0001 1111 ddddddddd ------111 --- Prior Lock State Not Written 7..22

解释

LOCKCLR 是四条锁指令(LOCKNEW, LOCKRET, LOCKSET, 和 LOCKCLR) 之一,用于管理用户

定义的和互斥的资源。 LOCKCLR 将寄存器 ID 所指定的锁位置位(0),如果指定了 WC 效果,LOCKSET 会将该锁位的原有状态写入 C 标志位。 LOCKCLR指令类似于 Spin 语言中

的 LOCKCLR 命令;参见 228 页 LOCKCLR。

LOCKCLR 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息。

Page 384: Propeller Manual - Parallax Home

LOCKNEW, LOCKRET –汇编语言参考

Page 384 · Propeller Manual v1.0

LOCKNEW 指令: 检出(取出)一个新的锁,取得锁号(ID)。 LOCKNEW NewID 结果: 新锁的 ID (0-7) 写入 NewID.

• NewID (d-field) 是新检出(取出)的锁号(ID)将写入的寄存器。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000011 0011 1111 ddddddddd ------100 Result = 0 No Lock Free Written 7..22

解释

LOCKNEW是四条锁指令(LOCKNEW, LOCKRET, LOCKSET, 和 LOCKCLR) 之一,用于管理用户

定义的和互斥的资源。LOCKNEW 从 Hub 检出(取出)一个唯一的锁,并返回改锁的

ID。 LOCKNEW 指令类似于 Spin 语言中的 LOCKNEW;参见 230 页 LOCKNEW。

如果指定了 WZ 效果,若返回的 ID 为零(0),Z 标志位置位。如果指定了 WC 效

果, 若没有可用的 check-out 锁,C 标志位置位。除非指定了 NR 效果,否则新检出

(取出)的锁的 ID 写入到 NewID。

LOCKNEW 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息。

LOCKRET 指令: 释放锁。 LOCKRET ID

• ID (d-field) 是寄存器,包含了要检入(退回)锁池的锁号 ID (0 – 7)。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000011 0001 1111 ddddddddd ------101 --- --- Not Written 7..22

Page 385: Propeller Manual - Parallax Home

5: 汇编语言参考– LOCKSET

Propeller Manual v1.0 · Page 385

解释 LOCKRET是四条锁指令(LOCKNEW, LOCKRET, LOCKSET, 和 LOCKCLR) 之一,用于管理用户

定义的和互斥的资源。 LOCKRET 通过 ID 检入(退回)一个锁,将其写入 Hub 的锁池

中,这样它就可以被另外一个 cog 使用。LOCKRET 指令类似于 Spin 语言的 LOCKRET 命令;参见 233 页 LOCKRET。

LOCKRET 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息。

LOCKSET 指令: 将锁位置 true,返回其原有状态。 LOCKSET ID 结果: 可选择将锁原有状态写入标志位 C。

• ID (d-field) 是包含了要设置的锁 ID(0-7)的寄存器。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000011 0001 1111 ddddddddd ------110 --- Prior Lock State Not Written 7..22

解释

LOCKSET 是四条锁指令(LOCKNEW, LOCKRET, LOCKSET, 和 LOCKCLR) 之一,用于管理用户

定义的和互斥资源。LOCKSET 将寄存器 ID 所指定的锁位置位(1),如果指定了 WC 效果,LOCKSET 会将该锁位的原有状态写入 C 标志位。 LOCKSET 指令类似于 Spin 语言中的 LOCKSET 命令;参见 234 页 LOCKSET。

LOCKSET 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息。

Page 386: Propeller Manual - Parallax Home

MAX, MAXS –汇编语言参考

Page 386 · Propeller Manual v1.0

MAX 指令: 限制两个无符号数的 大值。 MAX Value1, ⟨#⟩ Value2 结果: 无符号数 Value1 和 无符号数 Value2 中较小者存入 Value1.

• Value1 (d-field) 是包含了要与 Value2 做比较的值的寄存器,也是比较后较小者

要写入的寄存器。 • Value2 (s-field) 是一寄存器或 9 位字符,其值将与 Value1 做比较。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks010011 001i 1111 ddddddddd sssssssss D = S Unsigned (D < S) Written 4

解释

MAX 比较无符号数 Value1 和 Value2 的大小,将较小者存储入 Value1 寄存器,将

Value1 限制到 Value2 的 大值。

如果指定了 WZ 效果, 若 Value1 等于 Value2 ,则 Z 标志位置 1。如果指定了 WC效果, 若无符号值 Value1 小于无符号值 Value2,则 C 标志位置 1。除非指定了 NR 效果,否则较小的值将被写入 Value1。

MAXS 指令: 限制两个有符号数的 大值。 MAXS SValue1, ⟨#⟩ SValue2 结果: 有符号数 SValue1 和 有符号数 SValue2 中较小者存入 SValue1。

• SValue1 (d-field) 是包含了要与 SValue2 做比较的值的寄存器,也是比较后较小

者要写入的寄存器。 • SValue2 (s-field) 是一寄存器或 9 位字符,其值将与 SValue1 做比较。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks010001 001i 1111 ddddddddd sssssssss D = S Signed (D < S) Written 4

Page 387: Propeller Manual - Parallax Home

5: 汇编语言参考– MIN

Propeller Manual v1.0 · Page 387

解释 MAXS比较有符号数 SValue1 和 SValue2 的大小,将较小者存储入 SValue1 寄存器,

将 SValue1 限制到 SValue2 的 大值。

如果指定了 WZ 效果, 若 SValue1 和 SValue2 相等,则 Z 标志位置 1。如果指定了 WC效果, 若有符号数 SValue1 小于有符号数 SValue2,则 C 标志位置 1。除非指定了 NR效果,否则两者较小的写入 SValue1 。

MIN 指令: 限制两个无符号数的 小值。 MIN Value1, ⟨#⟩ Value2 结果: 无符号数 Value1 和 无符号数 Value2 中较大者存入 Value1.

• Value1 (d-field) 是包含了要与 Value2 做比较的值的寄存器,也是比较后较小者

要写入的寄存器。 • Value2 (s-field) 是一寄存器或 9 位字符,其值将与 Value1 做比较。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks010010 001i 1111 ddddddddd sssssssss D = S Unsigned (D < S) Written 4

解释

MIN 比较无符号数 Value1 和 Value2 的大小,将较大者存储入 Value1 寄存器,将

Value1 限制到 Value2 的 小值。

如果指定了 WZ 效果,若 Value1 等于 Value2 ,则 Z 标志位置 1。如果指定了 WC效果, 若无符号数 Value1 小于无符号数 Value2,则 C 标志位置 1。除非指定了 NR 效果,否则较大的值将被写入 Value1。

Page 388: Propeller Manual - Parallax Home

MINS, MOV –汇编语言参考

Page 388 · Propeller Manual v1.0

MINS 指令: 限制两个有符号数的 小值。 MINS SValue1, ⟨#⟩ SValue2 结果: 带符号数 SValue1 和 带符号数 SValue2 中较大者存入 SValue1.

• SValue1 (d-field) 包含了要和 SValue2 作比较的值的寄存器,两者较大的值写入

该寄存器。 • SValue2 (s-field) 是一个寄存器或 9 位的字符,其值与 SValue1 作比较。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks010000 001i 1111 ddddddddd sssssssss D = S Signed (D < S) Written 4

解释

MINS 将带符号数 SValue1 和 SValue2 的值作比较,并将两者中较大的值写入

SValue1 寄存器,将 SValue1 限制到 SValue2 的 小值。

如果指定了 WZ 效果, 若 SValue1 和 SValue2 相等,则 Z 标志位置 1。如果指定了

WC 效果, 若有符号数 SValue1 小于有符号数 SValue2,则 C 标志位置 1。除非指定了

NR 效果,否则较大的值将被写入 SValue1。

MOV 指令: 将寄存器的值设为某个值。 MOV Destination, ⟨#⟩ Value 结果: Value 被存储在 Destination 中。

• Destination (d-field) 存储 Value 值的寄存器。 • Value (s-field) 是一寄存器或 9 位的字符,其值写入 Destination。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks101000 001i 1111 ddddddddd sssssssss Result = 0 S[31] Written 4

Page 389: Propeller Manual - Parallax Home

5: 汇编语言参考– MOVD

Propeller Manual v1.0 · Page 389

解释 MOV 将 Value 的数值复制或存储到 Destination。

如果指定了 WZ 效果,若 Value 等于 0,Z 标志寄存器被置 1。如果指定了 WC 效果,

C 标志位的被置为 Value 的 高位。除非指定了 NR效果,结果将被写入 Destination 。

MOVD 指令: 将一个寄存器的目标域(d-field)设定为一个值。 MOVD Destination, ⟨#⟩ Value 结果: Value 被存储在 Destination 的 d-field (bits 17..9)。

• Destination (d-field) 是一寄存器,其目标域(bits 17..9)被设置为 Value’s 的值。 • Value (s-field) 是一寄存器或 9 位的字符,其值被存储在 Destination 的 d-field

中。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks010101 001i 1111 ddddddddd sssssssss Result = 0 --- Written 4

解释

MOVD 将 Value 中 9 位的值复制到 Destination 的 d-field (destination field) 的 17..9位。Destination 的 后一位没有被改变。这条指令在设置 CTRA 和 VCFG 等寄存器时

很方便,也可以在能修改自身的代码中用于更新指令的目标域(d-field)。

如果指定了 WZ 效果, 若 Value 等于 0,则 Z 标志位置 1。除非指定了 NR 效果,

结果将写入 Destination。

Page 390: Propeller Manual - Parallax Home

MOVI, MOVS –汇编语言参考

Page 390 · Propeller Manual v1.0

MOVI 指令: 将一个寄存器的指令域(instruction field)设置为一个值。 MOVI Destination, ⟨#⟩ Value 结果: Value 存储在 Destination 的 i-field 和 effects-field (bits 31..23)中。

• Destination (d-field) 是一寄存器,其指令和 effects fields 域(bits 31..23) 将被设置

为 Value 的值。 • Value (s-field) 是一寄存器或 9 位字符, 其值将被存储到 Destination 的指令和

effects field 中。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks010110 001i 1111 ddddddddd sssssssss Result = 0 --- Written 4

解释

MOVI 将 9 位的 Value 值复制到 Destination 指令和 effects fields 域的 31..23 位中。 Destination 的其他位没有改变。该指令用于设定诸如 CTRA 和 VCFG 等寄存器,以及升级

指令和在可自修改代码中指令的效果域。

如果指定了 WZ 效果, 若 Value 和 zero 相等,则 Z 标志位置 1。除非指定了 NR 效果,结果将被写入 Destination。

MOVS 指令: 将寄存器的源域设定为一个值。 MOVS Destination, ⟨#⟩ Value 结果: Value 存储在 Destination 的源域(s-field,bits 8..0)。

• Destination (d-field) 是一寄存器,其源域 (bits 8..0) 将被设置为 Value 的值。 • Value (s-field) 是一寄存器或 9 位字符, 其值将被存储在 Destination 的源域。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks010100 001i 1111 ddddddddd sssssssss Result = 0 --- Written 4

Page 391: Propeller Manual - Parallax Home

5: 汇编语言参考– MUXC

Propeller Manual v1.0 · Page 391

解释

MOVS复制 9 位的 Value 值到 Destination 指令和源域的 8..0 位中。 Destination 的其

他位没有改变。该指令用于设定诸如 CTRA 和 VCFG 等寄存器,以及升级在可自修改代

码中指令的源域。.

如果指定了 WZ 效果, 若 Value 等于零,则 Z 标志位置 1。除非指定了 NR 效果,

结果将被写入 Destination。

MUXC 指令: 将指定值的离散位设置为 C 的状态。 MUXC Destination, ⟨#⟩ Mask 结果: 由 Mask 值指定的 Destination 的位(bits)被设置为 C 的状态。

• Destination (d-field) 是寄存器,由 Mask 指定的位会被 C 所影响。 • Mask (s-field) 是一寄存器或 9 位字符,其值包含的高位(1)所对应的

Destination 中的位将被设置为 C 标志位的状态。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks011100 001i 1111 ddddddddd sssssssss Result = 0 Parity of Result Written 4

解释

MUXC将 Destination 的值的所有位对应于 Mask 的高位(1)的位,设置为 C 状态。

Mask 的值中为低的位所对应的 Destination 值的位不会受影响。该指令可用于将指定值

中的离散的位或一组位清除或置位。

如果指定了 WZ 效果,若 Destination 的 终结果为 0,则 Z 标志位置 1。如果指定

了 WC 效果, 若 终结果中 Destination 包含奇数个高位(1),则 C 标志位置 1。 除非指定了 NR 效果,否则结果将写入 Destination。

Page 392: Propeller Manual - Parallax Home

MUXNC, MUXNZ –汇编语言参考

Page 392 · Propeller Manual v1.0

MUXNC 指令: 将指定值的离散位设置为!C 的状态。 MUXNC Destination, ⟨#⟩ Mask 结果: 由 Mask 值指定的 Destination 的位(bits)被设置为!C 的状态。

• Destination (d-field) 是寄存器,由 Mask 指定的位会被!C 所影响。 • Mask (s-field) 是一寄存器或 9 位字符,其值包含的高位(1)所对应的

Destination 中的位将被设置为 C 标志位的逆状态。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks011101 001i 1111 ddddddddd sssssssss Result = 0 Parity of Result Written 4

解释

MUXNC 将 Destination 的值的所有位对应于 Mask 的高位(1)的位,设置为!C 状

态。Mask 的值中为低的位所对应的 Destination 值的位不会受影响。该指令可用于将指

定值中的离散的位或一组位清除或置位。

如果指定了 WZ 效果,若 Destination 的 终结果为 0,则 Z 标志位置 1。如果指定

了 WC 效果, 若 终结果中 Destination 包含奇数个高位(1),则 C 标志位置 1。 除非指定了 NR 效果,否则结果将写入 Destination。

MUXNZ 指令: 将指定值的离散位设置为!Z 的状态。 MUXNZ Destination, ⟨#⟩ Mask 结果: 由 Mask 值指定的 Destination 的位(bits)被设置为!Z 的状态。

• Destination (d-field) 是寄存器,由 Mask 指定的位会被!Z 所影响。 • Mask (s-field) 是一寄存器或 9 位字符,其值包含的高位(1)所对应的

Destination 中的位将被设置为 Z 标志位的逆状态。

Page 393: Propeller Manual - Parallax Home

5: 汇编语言参考– MUXZ

Propeller Manual v1.0 · Page 393

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks011111 001i 1111 ddddddddd sssssssss Result = 0 Parity of Result Written 4

解释 MUXNZ 将 Destination 的值的所有位对应于 Mask 的高位(1)的位,设置为!Z 状

态。Mask 的值中为低的位所对应的 Destination 值的位不会受影响。该指令可用于将指

定值中的离散的位或一组位清除或置位。

如果指定了 WZ 效果,若 Destination 的 终结果为 0,则 Z 标志位置 1。如果指定

了 WC 效果, 若 终结果中 Destination 包含奇数个高位(1),则 C 标志位置 1。 除非指定了 NR 效果,否则结果将写入 Destination。

MUXZ 指令: 将指定值的离散位设置为 Z 的状态。 MUXZ Destination, ⟨#⟩ Mask 结果: 由 Mask 值指定的 Destination 的位(bits)被设置为 Z 的状态。

• Destination (d-field) 是寄存器,由 Mask 指定的位会被标志位 Z 所影响。 • Mask (s-field) 是一寄存器或 9 位字符,其值包含的高位(1)所对应的

Destination 中的位将被设置为 Z 标志位的状态。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks011110 001i 1111 ddddddddd sssssssss Result = 0 Parity of Result Written 4

解释

MUXZ 将 Destination 的值的所有位对应于 Mask 的高位(1)的位,设置为 Z 状态。

Mask 的值中为低的位所对应的 Destination 值的位不会受影响。该指令可用于将指定值

中的离散的位或一组位清除或置位。

如果指定了 WZ 效果,若 Destination 的 终结果为 0,则 Z 标志位置 1。如果指定

了 WC 效果, 若 终结果中 Destination 包含奇数个高位(1),则 C 标志位置 1。 除非指定了 NR 效果,否则结果将写入 Destination。

Page 394: Propeller Manual - Parallax Home

NEG, NEGC –汇编语言参考

Page 394 · Propeller Manual v1.0

NEG 指令: 取数值的负数. NEG NValue, ⟨#⟩ SValue 结果: -SValue 存储在 NValue 中。

• NValue (d-field) 是一寄存器,存储了 SValue 的负值。 • SValue (s-field) 是一寄存器或 9 位字符,其负值将被写入 NValue。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks101001 001i 1111 ddddddddd sssssssss Result = 0 S[31] Written 4

解释

NEG 将 SValue 的负值存储入 NValue。

如果指定了 WZ 效果,若 SValue 值为 0,则 Z 标志位被置 1,如果指定了 WC 效

果,若 SValue 是负值则 C 标志位被置 1,若 SValue 为正则 C 标志位被清零。除非指

定了 NR 效果,结果将被写入 NValue。

NEGC 指令: 取一个数值或该数值的加法逆元值,取决于 C. NEGC RValue, ⟨#⟩ Value 结果: Value 或-Value 存储在 RValue。

• RValue (d-field) 是一寄存器,存储了 Value 或-Value。 • Value (s-field) 是一寄存器或 9 位字符,其值(若 C=0)或加法逆元值(若 C=1

)将被写入 RValue。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks101100 001i 1111 ddddddddd sssssssss Result = 0 S[31] Written 4

Page 395: Propeller Manual - Parallax Home

5: 汇编语言参考– NEGNC

Propeller Manual v1.0 · Page 395

解释 NEGC 将 Value(如果 C=0)或-Value(如果 C=1)存储到 RValue。

如果指定了 WZ 效果,若 Value 值为 0,则 Z 标志位置 1。如果指定了 WC 效果,

若 Value 的值为负则 C 标志位被置 1,若 Value 值为正则 C 标志位被清零。除非指定

了 NR 效果,结果将被写入 RValue。

NEGNC 指令: 取一个数值或该数值的加法逆元值,取决于!C。 NEGNC RValue, ⟨#⟩ Value 结果: -Value 或 Value 存储在 RValue。

• RValue (d-field) 是一寄存器,存储了-Value 或 Value。 • Value (s-field) 是一寄存器或 9 位字符,其加法逆元值(若 C=0)或值(若 C=1

)将被写入 RValue。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks101101 001i 1111 ddddddddd sssssssss Result = 0 S[31] Written 4

解释

NEGNC 将-Value(如果 C=0)或 Value(如果 C=1)存储到 RValue。

如果指定了 WZ 效果,若 Value 值为 0,则 Z 标志位置 1。如果指定了 WC 效果,

若 Value 的值为负则 C 标志位被置 1,若 Value 值为正则 C 标志位被清零。除非指定

了 NR 效果,结果将被写入 RValue。

Page 396: Propeller Manual - Parallax Home

NEGNZ –汇编语言参考

Page 396 · Propeller Manual v1.0

NEGNZ 指令: 取一个数值或该数值的加法逆元值,取决于!Z NEGNZ RValue, ⟨#⟩ Value 结果: -Value 或 Value 存储在 RValue 中。

• RValue (d-field) 是一寄存器,存储了-Value 或 Value。 • Value (s-field) 是一寄存器或 9 位字符,其加法逆元值(若 Z=0)或值(若 Z=1

)将被写入 RValue。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks101111 001i 1111 ddddddddd sssssssss Result = 0 S[31] Written 4

解释

NEGNZ 将-Value(如果 Z=0)或 Value(如果 Z=1)存储到 RValue。

如果指定了 WZ 效果,若 Value 值为 0,则 Z 标志位置 1。如果指定了 WC 效果,

若 Value 的值为负则 C 标志位被置 1,若 Value 值为正则 C 标志位被清零。除非指定

了 NR 效果,结果将被写入 RValue。

Page 397: Propeller Manual - Parallax Home

5: 汇编语言参考– NEGZ, NOP

Propeller Manual v1.0 · Page 397

NEGZ 指令: 取一个数值或该数值的加法逆元值,取决于 Z。 NEGZ RValue, ⟨#⟩ Value 结果: Value 或-Value 存储在 RValue 中。

• RValue (d-field) 是一寄存器,存储了 Value 或-Value。 • Value (s-field) 是一寄存器或 9 位字符,其值(若 Z=0)或加法逆元值(若 Z=1

)将被写入 RValue。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks101110 001i 1111 ddddddddd sssssssss Result = 0 S[31] Written 4

解释

NEGZ 将-Value(如果 Z=0)或 Value(如果 Z=1)存储到 RValue。

如果指定了 WZ 效果,若 Value 值为 0,则 Z 标志位置 1。如果指定了 WC 效果,

若 Value 的值为负则 C 标志位被置 1,若 Value 值为正则 C 标志位被清零。除非指定

了 NR 效果,结果将被写入 RValue.

NOP 指令: 无操作,消耗 4 个时钟周期。 NOP

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks------ ---- 0000 --------- --------- --- --- --- 4

解释

NOP 不执行操作,但是消耗 4 个时钟周期。NOP 有其-CON-域被置为 0,NEVER 条

件;每条带有 NEVER 条件的指令都是一条 NOP 指令。因此,NOP 指令不能被类似

IF_Z 或 IF_C_AND_Z 这样的条件所处理,因为这样的条件永远不得到执行。

Page 398: Propeller Manual - Parallax Home

Operators (运算符) –汇编语言参考

Page 398 · Propeller Manual v1.0

运算符 Propeller 汇编代码能包含常量表达式,这些表达式可以使用任何允许出现在常量表

达式中运算符。表 5-4 总结了允许在 Propeller 汇编代码中出现的运算符。请参考 Spin语言参考运算符一节关于运算符功能的细节描述;表 5-4 中列出了每个运算符的描述

所在的页码:

Page 399: Propeller Manual - Parallax Home

5: 汇编语言参考– (运算符) Operators

Propeller Manual v1.0 · Page 399

表 5-4: 常量表达式 数学/逻辑 运算符 Normal Operator 一元运算符 描述,页码

+ 加, 261 + 正 (+X); 加的一元形式, 261 - 减, 261 - 负 (-X); 减的一元形式, 262 * 乘,返回低 32 位 (有符号), 264 ** 乘,返回高 32 位 (有符号), 264 / 除 (有符号), 265 // 模数 (有符号), 265 #> 两数比较取较大者 (有符号), 265 <# 两数比较取较小者 (有符号), 266 ^^ 平方根, 266 || 绝对值, 267 ~> 算数右移, 268 |< 位运算: 将 value (0-31) 解码为单高位长字型, 270 >| 位运算: 将 value (0 - 32) 编码为高位优先编码, 271 << 位运算: 左移, 271 >> 位运算: 右移, 272 <- 位运算: 左转, 272 -> 位运算: 右转, 273 >< 位运算: 反相, 274 & 位运算: AND, 274 | 位运算: OR, 275 ^ 位运算: XOR, 276 ! 位运算: NOT, 277

AND 布尔: AND (promotes non-0 to -1), 277 OR 布尔: OR (promotes non-0 to -1), 278 NOT 布尔: NOT (promotes non-0 to -1), 279 == 布尔: 等于, 279 <> 布尔: 不等于, 280 < 布尔: 小于 (有符号), 281 > 布尔: 大于 (有符号), 281 =< 布尔: 等于或小于 (有符号), 282 => 布尔: 等于或大于 (有符号), 283 @ 符号地址, 283

Page 400: Propeller Manual - Parallax Home

OR, ORG –汇编语言参考

Page 400 · Propeller Manual v1.0

OR 指令: 将两个值位或(Bitwise OR)。 OR Value1, ⟨#⟩ Value2 结果: Value1 与 Value2“或”运算后存贮在 Value1 中。

• Value1 (d-field) 是一寄存器,包含了将要与 Value2 进行位或运算的值以及运算

的结果。 • Value2 (s-field) 是一寄存器或 9 位字符,其值将与 Value1 进行“位或”运算。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks011010 001i 1111 ddddddddd sssssssss Result = 0 Parity of Result Written 4

解释

OR (bitwise inclusive OR) 将 Value2 中的值与 Value1 中的值进行“位或”运算。

如果指定了 WZ 效果,若 Value1“或”Value2 等于 0,则 Z 标志位置 1。如果指定

了 WC 效果,如果结果中包含了奇数个高(1)位,则 C 标志位置 1。除非指定了 NR效果,结果将被写入 Value1。

ORG 命令: 调整编译时 cog 的地址指针。 ORG ⟨Address⟩

• Address 是可选的 Cog RAM 地址 (0-495) ,会使接下来的代码汇编到指定的地

址。如果 Address 的值没有给定,将会使用 0。 解释

ORG (origin) 将 Propeller 工具的汇编指针设置为指向一个新的值,该值代表了接下

来的代码将使用的 cog RAM 的位置(地址)。 ORG 通常出现在一段新的 cog 汇编代码

的起始处。

Page 401: Propeller Manual - Parallax Home

5: 汇编语言参考– RCL

Propeller Manual v1.0 · Page 401

当汇编代码载入到 cog 中,Cog 从 cog RAM 的位置 0 开始执行代码,所以必须至

少有一条指出该位置的指令。通常,一个完整的汇编程序会从位置 0 开始。例如:

DAT ORG 0 Toggle mov dira, Pin :Loop mov outa, Pin mov outa, #0 jmp #:Loop

例子中的 ORG 表述将汇编指针设置为零(0),所以下一条指令,mov dira, Pin, 会被汇编到 Cog RAM 的位置 0,之后的指令将顺序汇编到 Cog RAM 的位置 1。

RCL 指令: 将 C 左转入原有值的指定位。 RCL Value, ⟨#⟩ Bits 结果: Value 具有 Bits 份左转后 C 的副本。

• Value (d-field) 是一寄存器,其值将被执行 C 前(左)转运算。 • Bits (s-field) 是一寄存器或 5 位字符,其值是 C 要转到 Value 中的位数。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks001101 001i 1111 ddddddddd sssssssss Result = 0 D[31] Written 4

解释

RCL (Rotate Carry Left) 将 Value 的值执行左转 Bits 次,C 标志位的原有值会依次成

为 LSB。

如果指定了 WZ 效果,若运算使 Value 等于 0,则 Z 标志位置 1。如果指定了 WC效果,运算结束后,C 标志位的值将被设置为原先 Value 的 bit 31。除非指定了 NR 效

果,结果将被写入 Value。

Page 402: Propeller Manual - Parallax Home

RCR, RDBYTE –汇编语言参考

Page 402 · Propeller Manual v1.0

RCR 指令: 将 C 右转入原有值的指定位。 RCR Value, ⟨#⟩ Bits 结果: Value 有 Bits 份右转后 C 的副本。

• Value (d-field) 是一寄存器,其值将被执行 C 右转运算。 • Bits (s-field) 是一寄存器或 5 位字符,其值是 C 要转到 Value 中的位数。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks001100 001i 1111 ddddddddd sssssssss Result = 0 D[0] Written 4

解释

RCR (Rotate Carry Right) 将 Value 的值执行右转 Bits 次,C 标志位的原有值会依次成

为 MSB。

如果指定了 WZ 效果,若运算结果使 Value 等于 0,则 Z 标志位置 1。如果指定了

WC 效果,运算结束后,C 标志位的值会被设置为原先 Value 的 bit 0。 除非指定了 NR效果,结果将被写入 Value。

RDBYTE 指令: 从主内存读取一个字节。 RDBYTE Value, ⟨#⟩ Address 结果: 一个被零字符扩展(Zero-extended)的字节存储在 Value 中。

• Value (d-field) 是一寄存器,存储了被读取的零扩展的字节。 • Address (s-field) 是一寄存器或 9 位字符,其值为要读取的主内存地址。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000000 001i 1111 ddddddddd sssssssss Result = 0 --- Written 7..22

Page 403: Propeller Manual - Parallax Home

5: 汇编语言参考– RDLONG

Propeller Manual v1.0 · Page 403

解释 RDBYTE 同步到 Hub,读取位于 Address 处的零字符扩展字节,并将其存储在寄存器

Value 中。

如果指定了 WZ 效果,若从主内存读取的值是零,则 Z 标志位将被置 1。除非指定

了 NR 效果,从主内存读取的结果将被写入 Value 。

RDBYTE 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息。

RDLONG 指令: 从主内存中读取一个长字。 RDLONG Value, ⟨#⟩ Address 结果: Long is stored in Value.

• Value (d-field) 是要存储所读取的长字的寄存器。 • Address (s-field) 是一寄存器或 9 位字符,其值是要读取的主内存的地址。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000010 001i 1111 ddddddddd sssssssss Result = 0 --- Written 7..22

解释

RDLONG 同步到 Hub,读取位于 Address 处的长字,并将其存储在寄存器 Value 中

如果指定了 WZ 效果,若所读取的值是零,则 Z 标志位将被置 1。除非指定了 NR效果,否则结果将被写入 Value。

RDLONG 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息.

Page 404: Propeller Manual - Parallax Home

RDWORD –汇编语言参考

Page 404 · Propeller Manual v1.0

RDWORD 指令: 从主内存读取字(word)。 RDWORD Value, ⟨#⟩ Address 结果: 0 扩展后的字(Zero-extended word)被存储在寄存器 Value 中。

• Value (d-field) 是将会存储 0 扩展型字的寄存器。 • Address (s-field) 是一寄存器或 9 位字符,其值是要读取的主内存地址。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000001 001i 1111 ddddddddd sssssssss Result = 0 --- Written 7..22

解释

RDWORD 同步到 HUB,读取位于地址 Address 的字(word),该字为零扩展型

( zero-extends),读取的结果存储在寄存器 Value 中。

如果指定了 WZ 效果,若从主内存读到的值是 0, 则 Z 标志位将被置 1。 除非指

定了 NR 效果,从主内存读取的结果将被写入寄存器 Value。

RDWORD 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息。

Page 405: Propeller Manual - Parallax Home

5: 汇编语言参考– (寄存器) Registers

Propeller Manual v1.0 · Page 405

寄存器 每个 Cog 包含了 16 个特殊用途寄存器用于访问 I/O 引脚,内建的计数器和视频发

生器,以及在 Cog 启用时用于参数传递。所有的这些寄存器都在 Spin 语言参考中解释

过,其中的大部分信息可同时用于 Spin 语言和 Propeller 汇编语言。下面的表格所列出

了 16 个特殊用途寄存器,其中指出了在何处可以找到详细信息及细节,以及不适用于

Propeller 汇编语言的情况。

除了一些被设计成只读的寄存器,每个寄存器都可以像其他寄存器一样按照目标域

和源域的方式访问。只读寄存器只能用于指令中的源域。

表 5-5: 寄存器

寄存器 描述

DIRA, DIRB 32 位端口 A 和 32 位端口 B 的方向寄存器。参见 212 页上关于 DIRA, DIRB 的解释。 可选的 “[Pin(s)]”参数不能应用于 Propeller 汇编语言;整个寄存器的所有位被一次读取

或写入,除非使用了 MUXx 指令

INA, INB 32 位端口 A 和 32 位端口 B 的输入寄存器(只读)。 参见 226 页上 INA, INB 的解释。 可选的 “[Pin(s)]”参数不能应用于 Propeller 汇编语言;整个寄存器的所有位被一次读取.

OUTA, OUTB 32 位端口 A 和 32 位端口 B 的输出寄存器。参见 280 页上 OUTA, OUTB 的解释。可选

的 “[Pin(s)]”参数不能应用于 Propeller 汇编语言;整个寄存器的所有位被一次性的读/写,除非使用了 MUXx 指令.

CNT 32 位系统计数器寄存器(只读)。见 184 页 CNT 的解释

CTRA, CTRB 计数器 A 和计数器 B 的控制寄存器。见 204 页 CTRA, CTRB 。

FRQA, FRQB 计数器 A 和计数器 B 的频率寄存器。见 219 页 FRQA, FRQB 。

PHSA, PHSB 计数器 A 和计数器 B 锁相环寄存器。见 285 页的 PHSA, PHSB 。

VCFG 视频配置寄存器。见 317 页 VCFG 。

VSCL 视频比例寄存器。见 320 页 VSCL。

PAR Cog 启动参数寄存器。参见 283 页 PAR 。

Page 406: Propeller Manual - Parallax Home

RES –汇编语言参考

Page 406 · Propeller Manual v1.0

RES 命令: 为符号保留长型(long)空间。 ⟨Symbol⟩ RES ⟨Count⟩

• Symbol 是可选的,要在 cog RAM 中保留的长字空间的名字。 • Count 是可选的,要为 symbol 保留的个数。如果没有指定,RES 将保留一个。

解释

RES 作用是通过将编译时 cog 地址指针增大 Count 来保留一个或多个 Cog RAM 中

的长字空间,通常该命令用于为汇编符号保留内存。例如:

DAT ORG 0 <some code here> mov Time, cnt add Time, Delay waitcnt Time, Delay <some code here> Delay long 6_000_000 Time RES 1

上面代码的 后一行为符号 Time 保留了 cog RAM 中的一个长字空间。该例子中,

汇编代码将该符号作为一个长字的变量;以产生一个 600 万时钟周期的延迟。

Page 407: Propeller Manual - Parallax Home

5: 汇编语言参考– RET, REV

Propeller Manual v1.0 · Page 407

RET 指令: 返回到地址。 RET

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks010111 0001 1111 --------- --------- Result = 0 --- Not Written 4

解释

RET 是 JMP 指令的子指令,但是其指定了 i-field 而没有指定 s-field。RET 指令应该与

“ label_ret”形式的标号一起使用,一条 CALL 指令调用了 RET 所在的程序

“label”。参见 360 页中关于 CALL 的更多信息。

REV 指令: 使数值或 0 扩展型值的 LSB 反转。 REV Value, ⟨#⟩ Bits 结果: Value 的 LSB 的低 32 位值被保留,高位被清除。

• Value (d-field) 是寄存器,包含了要进行位反转操作的值。 • Bits (s-field) 是一寄存器或 5 位字符,其值从 32 中减去(32 - Bits),就是要反

转的 Value 的 LSB 的位。Value 的高位(MSB)Bits 会被清零。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks001111 001i 1111 ddddddddd sssssssss Result = 0 D[0] Written 4

解释

REV (反转 Reverse) 反转 Value 的 LSB 低 32 位,将 Value 的 MSB 高位清零。

如果指定了 WZ 效果, 若 Value 等于 0,则 Z 标志位置 1。如果指定了 WC 效果,

C 标志位被设置为 Value 的 bit 0。 除非指定了 NR 效果,结果将被写入 Value。

Page 408: Propeller Manual - Parallax Home

ROL, ROR –汇编语言参考

Page 408 · Propeller Manual v1.0

ROL 指令: 将值左转指定的位数。 ROL Value, ⟨#⟩ Bits 结果: Value 左转 Bits 位。

• Value (d-field) 是要执行左转的寄存器。 • Bits (s-field) 是一寄存器或 5 位字符,其值是要左转的位数。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks001001 001i 1111 ddddddddd sssssssss Result = 0 D[31] Written 4

解释

ROL (Rotate Left) 将 Value 左转,次数由 Bits 指定。一次左转后 Value 的 MSB 成为

Value 的 LSB(这里的左移不涉及 C 标志位)。

如果指定了 WZ 效果, 若左移后 Value 等于 0,则 Z 标志位置 1。如果指定了 WC效果,则在运算结束后,C 标志位 会被设置为 Value 原有的 bit 31 的值。除非指定了

NR 效果,否则结果将被写入 Value。

ROR 指令: 将值右转指定的位数。 ROR Value, ⟨#⟩ Bits 结果: Value 右转 Bits 位。

• Value (d-field) 是要执行右转的寄存器。 • Bits (s-field) 是一寄存器或 5 位字符,其值是要右转的位数。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks001000 001i 1111 ddddddddd sssssssss Result = 0 D[0] Written 4

Page 409: Propeller Manual - Parallax Home

5: 汇编语言参考– SAR

Propeller Manual v1.0 · Page 409

解释 ROR (Rotate Right) 将 Value 右转,次数由 Bits 指定。一次右转后 Value 的 LSB 成为

Value 的 MSB(这里的左移不涉及 C 标志位)。

如果指定了 WZ 效果,若右移后 Value 等于 0,则 Z 标志位置 1。如果指定了 WC效果,则在运算结束后,C 标志位 会被设置为 Value 原有的 bit 0 的值。除非指定了

NR 效果,否则结果将被写入 Value。

SAR 指令: 将值按指定的位数右移。 SAR Value, ⟨#⟩ Bits 结果: Value 算术右移 Bits 位。

• Value (d-field) 是要执行算术右移的寄存器。 • Bits (s-field) 是一寄存器或 5 位字符,其值是要执行算术右移的位数。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks001110 001i 1111 ddddddddd sssssssss Result = 0 D[0] Written 4

解释

SAR (Shift Arithmetic Right) 将 Value 右移 Bits 个空间,将 MSB 扩展。再有符号数

中,会影响符号位。

如果指定了 WZ 效果, 若运算使 Value 等于 0,则 Z 标志位置 1。如果指定了 WC效果,C 标志位被设置为运算前 Value 的 bit 0。除非指定了 NR 效果,结果将被写入

Value。

Page 410: Propeller Manual - Parallax Home

SHL, SHR –汇编语言参考

Page 410 · Propeller Manual v1.0

SHL 指令: 将值按指定的位数左移。 SHL Value, ⟨#⟩ Bits 结果: Value is 左移 Bits 位。

• Value (d-field) 是要左移的寄存器。 • Bits (s-field) 是一寄存器或 5 位字符,其值是要左移的位数。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks001011 001i 1111 ddddddddd sssssssss Result = 0 D[31] Written 4

解释

SHL (Shift Left) 将 Value 左移 Bits 个空间,将新的 LSB(所有的 低位,移动后的

Bits 低位)设置为 0。

如果指定了 WZ 效果,若运算使 Value 等于 0,则 Z 标志位置 1。如果指定了 WC效果,C 标志位将被设置为运算前 Value 的 bit 31。除非指定了 NR 效果,结果将被写

入 Value。

SHR 指令: 将值按指定的位数右移。 SHR Value, ⟨#⟩ Bits 结果: Value 右移 Bits 位。

• Value (d-field) 是要右移的寄存器。 • Bits (s-field) 是一寄存器或 5 位字符,其值指定了要右移的位数。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks001010 001i 1111 ddddddddd sssssssss Result = 0 D[0] Written 4

Page 411: Propeller Manual - Parallax Home

5: 汇编语言参考– SUB

Propeller Manual v1.0 · Page 411

解释 SHR (Shift Right) 将 Value 右移 Bits 位空间,将新的 MSB(所有的 低位,移动后

的 Bits 低位)设置为 0。。

如果指定了 WZ 效果, 若运算使 Value 等于 0,则 Z 标志位置 1。如果指定了 WC效果,C 标志位将被设置为运算前 Value 的 bit 0。除非指定了 NR 效果,结果将被写入

Value。

SUB 指令: 两个无符号值相减。 SUB Value1, ⟨#⟩ Value2 结果: 无符号值 Value1 和无符号值 Value2 的差存储在 Value1 中。

• Value1 (d-field) 是寄存器,包含了要减 Value2 的值,计算结果将写入的该寄存

器。 • Value2 (s-field) 是一寄存器或 9 位字符,其值将与 Value1 相减。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks100001 001i 1111 ddddddddd sssssssss Result = 0 Unsigned Borrow Written 4

解释

SUB 将无符号数 Value2 从无符号数 Value1 中减去,将结果存储在 Value1 寄存器

中。

如果指定了 WZ 效果, 若 Value1 − Value2 等于 0,则 Z 标志位置 1。如果指定了

WC 效果, 若减法产生了一个无符号借位(32 位下溢出),则 C 标志位置 1。除非指

定了 NR 效果,结果将写入 Value1。

Page 412: Propeller Manual - Parallax Home

SUBABS, SUBS –汇编语言参考

Page 412 · Propeller Manual v1.0

SUBABS 指令:将一个数的绝对值从另一个值中减去。 SUBABS Value, ⟨#⟩ SValue 结果: Value 和有符号数 SValue 的绝对值之差存储在 Value 中。

• Value (d-field) 是一寄存器,其值将要和 SValue 的绝对值相减,计算的结果写入

该寄存器。 • SValue (s-field) 是一寄存器或 9 位字符,其值的绝对值和 Value 作减法。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks100011 001i 1111 ddddddddd sssssssss Result = 0 Unsigned Borrow Written 4

解释

SUBABS 将 SValue 的绝对值从 Value 中减去,将结果写入 Value 寄存器。

如果指定了 WZ 效果, 若 Value − |SValue| 等于 0,则 Z 标志位置 1。如果指定了

WC 效果,若减法产生了无符号借位(32 位下溢出),则 C 标志位置 1。除非指定了

NR 效果,结果将被写入 Value。

SUBS 指令: 两个有符号值相减。 SUBS SValue1, ⟨#⟩ SValue2 结果: 有符号数 SValue1 和有符号数 Value2 的差存储在 SValue1 中。

• SValue1 (d-field) 寄存器,包含了要与 SValue2 做减法的值,计算的结果将写入

该寄存器。 • SValue2 (s-field) 是一寄存器或 9 位字符,其值要从 SValue1 中减去。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks110101 001i 1111 ddddddddd sssssssss Result = 0 Signed Underflow Written 4

Page 413: Propeller Manual - Parallax Home

5: 汇编语言参考– SUBSX

Propeller Manual v1.0 · Page 413

解释 SUBS 将有符号值 SValue2 从有符号值 SValue1 中减去,将结果存储在 SValue1 寄存

器中。

如果指定了 WZ 效果,若 SValue1 − SValue2 等于 0,则 Z 标志位置 1。如果指定了

WC 效果, 若减法运算产生了一个有符号下溢出,则 C 标志位置 1。除非指定了 NR 效果,否则计算结果将写入 SValue1。

SUBSX 指令: 有符号值加 C 和另一个有符号值相减。 SUBSX SValue1, ⟨#⟩ SValue2 结果: 有符号值 SValue1 和有符号值 SValue2 + C 标志位的差值存储在 SValue1 中。

• SValue1 (d-field) 寄存器,包含的值要与 SValue2+C 相减,计算的结果将写入该

寄存器。 • SValue2 (s-field) 是一寄存器或 9 位字符,其值与 C 的和将从 SValue1 中减去。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks110111 001i 1111 ddddddddd sssssssss Z & (Result = 0) Signed Underflow Written 4

解释

SUBSX (Subtract Signed, Extended) 将 SValue2 加 C 从 SValue1 中减去,将结果存储在

SValue1 寄存器中。在一条 SUB 或 SUBX(使用 WC和可选使用的 WZ效果)指令之后使用 SUBSX 指令来执行多个长字,有符号的,64 位的减法运算。例如:

如果指定了 WZ 效果, 若 Z 标志位之前被置位,SValue1 − (SValue2 + C) 等于 0(在 SUB or SUBX 指令之前使用 WC 和 WZ),则 Z 标志位置 1。如果指定了 WC 效果, 若减法产生了一个下溢出,则 C 标志位置 1。除非指定了 NR 效果,否则计算结果将写

入 SValue1。

注意,在多个长字的有符号运算中,第一条指令应该是无符号的(如 SUB),中间

指令是无符号扩展的(如 SUBX), 后一条指令应该是有符号扩展的(SUBSX)。

Page 414: Propeller Manual - Parallax Home

SUBX, SUMC –汇编语言参考

Page 414 · Propeller Manual v1.0

SUBX 指令: 无符号值加 C 和另一个无符号值相减。 SUBX Value1, ⟨#⟩ Value2 结果: 无符号值 Value1 和无符号数 Value2 加 C 标志位的差存储在 Value1 中。

• Value1 (d-field) 是寄存器,包含要减去 Value2 加 C 标志位的值,计算的结果将

写入该寄存器。 • Value2 (s-field) 是一寄存器或 9 位字符,其值加上 C 标志位的值被从 Value1 中

减去。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks110011 001i 1111 ddddddddd sssssssss Z & (Result = 0) Unsigned Borrow Written 4

解释

SUBX (Subtract Extended) 将 Value2 + C 形成的无符号值从无符号值 Value1 中减去,

将结果存储在寄存器 Value1 中。在 SUB 或 SUBX (使用 WC和可选的 WZ效果)指令之后

执行 SUBX 指令来完成多个长字值的减法;例如 64 位减法。

如果指定了 WZ 效果, 若 Z 标志位之前曾被置位,且 Value1 − (Value2 + C) 等于 0(在 SUB 和 SUBX 指令之前使用 WC 和 WZ),则 Z 标志位置 1。如果指定了 WC 效

果, 若减法产生了一个无符号借位 (32 位下溢出),则 C 标志位置 1。除非指定了 NR 效果,结果将被写入 Value1。

SUMC 指令: 将两个有符号值相加,第二个有符号值的符号由 C 标志位决定是否反转。 SUMC SValue1, ⟨#⟩ SValue2 结果: 有符号值 SValue1 和 ±SValue2 的和存储在 SValue1 中。

• SValue1 (d-field) 是要与–SValue2 或 SValue2 求和的寄存器,计算的结果将写入

该寄存器。

Page 415: Propeller Manual - Parallax Home

5: 汇编语言参考– SUMNC

Propeller Manual v1.0 · Page 415

• SValue2 (s-field) 是一寄存器或 9 位字符,其值将与 SValue1 求和,自身的符号由

C 决定。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks100100 001i 1111 ddddddddd sssssssss Result = 0 Signed Overflow Written 4

解释

SUMC (Sum with C-affected sign) 将两个有符号数 SValue1 和 –SValue2 (如果 C = 1) 或 SValue2 (如果 C = 0) 相加,将结果存储在 SValue1 寄存器中。

如果指定了 WZ 效果,若 SValue1 ± SValue2 等于 0, 则 Z 标志位置 1。如果指定

了 WC 效果, 若求和产生了一个有符号溢出,则 C 标志位置 1。除非指定了 NR 效果,

否则结果将写入 SValue1 寄存器。

SUMNC 指令: 将两个有符号值相加,第二个有符号值的符号由!C 决定是否反转。 SUMNC SValue1, ⟨#⟩ SValue2 结果: 有符号值 SValue1 和 ±SValue2 的和存储在 SValue1 中。

• SValue1 (d-field) 要与–SValue2 或 SValue2 求和的寄存器,计算的结果将写入该

寄存器。 • SValue2 (s-field) 是一寄存器或 9 位字符,其值将与 SValue1 求和,自身的符号

由!C 决定。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks100101 001i 1111 ddddddddd sssssssss Result = 0 Signed Overflow Written 4

解释

SUMNC (Sum with !C-affected sign) 将两个有符号数 SValue1 和 SValue2 (如果 C = 1) 或 -SValue2 (如果 C = 0) 相加,将结果存储在 SValue1 寄存器中。

Page 416: Propeller Manual - Parallax Home

SUMNZ, SUMZ –汇编语言参考

Page 416 · Propeller Manual v1.0

如果指定了 WZ 效果,若 SValue1 ± SValue2 等于 0,则 Z 标志位置 1。如果指定了

WC 效果, 若计算的结果产生了有符号溢出,则 C 标志位置 1。除非指定了 NR 效果,

否则结果会写入 SValue1。

SUMNZ 指令: 将两个有符号值相加,第二个有符号值的符号由!Z 决定是否反转 SUMNZ SValue1, ⟨#⟩ SValue2 结果: 有符号值 SValue1 和 ±SValue2 的和存储在 SValue1 中。

• SValue1 (d-field) 是要与–SValue2 或 SValue2 求和的寄存器,计算的结果将写入

该寄存器。 • SValue2 (s-field) 是一寄存器或 9 位字符,其值将与 SValue1 求和,自身的符号

由!Z 决定。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks100111 001i 1111 ddddddddd sssssssss Result = 0 Signed Overflow Written 4

解释

SUMNZ (Sum with !Z-affected sign) 将两个有符号数 SValue1 和 SValue2 (如果 Z = 1) 或 -SValue2 (如果 Z = 0) 相加,将结果存储在 SValue1 寄存器中。

如果指定了 WZ 效果, 若 SValue1 ± SValue2 等于 0,则 Z 标志位置 1。如果指定

了 WC 效果, 若总和产生了一个有符号溢出,则 C 标志位置 1。除非指定了 NR 效果,结果将写入 SValue1。

SUMZ 指令: 将两个有符号值相加,第二个有符号值的符号由 Z 标志位决定是否反转。 SUMZ SValue1, ⟨#⟩ SValue2 结果: 有符号值 SValue1 和 ±SValue2 的和存储在 SValue1 中。

Page 417: Propeller Manual - Parallax Home

5: 汇编语言参考– TEST

Propeller Manual v1.0 · Page 417

• SValue1 (d-field) 是要与–SValue2 或 SValue2 求和的寄存器,计算的结果将写入

该寄存器。 • SValue2 (s-field) 是一寄存器或 9 位字符,其值将与 SValue1 求和,自身的符号由

Z 决定。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks100110 001i 1111 ddddddddd sssssssss Result = 0 Signed Overflow Written 4

解释 SUMZ (Sum with Z-affected sign) 将两个有符号数 SValue1 和 –SValue2 (如果 Z = 1) 或

SValue2 (如果 Z = 0) 相加,将结果存储在 SValue1 寄存器中。

如果指定了 WZ 效果,若 SValue1 ± SValue2 等于 0, 则 Z 标志位置 1。如果指定

了 WC 效果, 若求和产生了一个有符号溢出,则 C 标志位置 1。除非指定了 NR 效果,

否则结果将写入 SValue1 寄存器。

TEST 指令: 两个值“位与(Bitwise AND)”,结果只影响标志位。 TEST Value1, ⟨#⟩ Value2 结果: 可选将零结果和 结果的奇偶型写入到 Z 和 C 标志位。

• Value1 (d-field) 是寄存器,包含了要与 Value2 做“位与”的值。 • Value2 (s-field) 是一寄存器或 9 位字符,其值要与 Value1 做位与。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks011000 000i 1111 ddddddddd sssssssss Result = 0 Parity of Result Not Written 4

解释

TEST类似于 AND ,除了它不会将结果写入 Value1;它执行 Value1 和 Value2 的“位

与”,并可以指定在 Z 和 C 寄存器中存储 0 结果和结果的奇偶性。

如果指定了 WZ 效果, 若 Value1 与 Value2 等于 0,则 Z 标志位置 1。如果指定了

WC 效果, 若结果包含奇数个高(1)位,则 C 标志位置 1。

Page 418: Propeller Manual - Parallax Home

TJNZ, TJZ –汇编语言参考

Page 418 · Propeller Manual v1.0

TJNZ 指令: 测试一个值,如果非 0 则跳转到某一地址。 TJNZ Value, ⟨#⟩ Address

• Value (d-field) 是要测试的寄存器。. • Address (s-field) 是一个寄存器或 9 位字符,其值是 Value 包含非 0 值时要跳转

的地址。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks111010 000i 1111 ddddddddd sssssssss Result = 0 0 Not Written 4 or 8

解释

TJNZ测试 Value 寄存器,若寄存器包含非零数,则跳转到地址 Address 。

如果指定了 WZ 效果, 若 Value 寄存器包含了零,则 Z 标志位置 1。

TJNZ执行时需要不同的时钟周期,取决于是否需要跳转。如果跳转则需要 4 个时钟

周期,如果不跳转则需要 8 个时钟周期。因为循环指令利用了 TJNZ , 该指令专为此优

化过。

TJZ 指令: 测试一个值,如果为 0 则跳转到某一地址。 TJZ Value, ⟨#⟩ Address

• Value (d-field) 是要测试的寄存器。 • Address (s-field) 是一个寄存器或 9 位字符,其值是若 Value 包含 0 时跳转的地

址。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks111011 000i 1111 ddddddddd sssssssss Result = 0 0 Not Written 4 or 8

Page 419: Propeller Manual - Parallax Home

5: 汇编语言参考– WAITCNT

Propeller Manual v1.0 · Page 419

解释 TJZ测试 Value 寄存器,如果它包含 0 则跳转到 Address。

当指定了 WZ 效果, 若 Value 包含 0 ,则 Z 标志位置 1。

TJZ 执行时需要不同的时钟周期,取决于是否需要跳转。如果跳转则需要 4 个时钟

周期,如果不跳转则需要 8 个时钟周期

WAITCNT 指令: 临时暂停 cog 的执行。 WAITCNT Target, ⟨#⟩ Delta 结果: Target + Delta 被存储在 Target.中。

• Target (d-field) 是一寄存器,其值为将要与系统计数器数(CNT)之作比较的值。当

系统计数器到达 Target 的值, Delta 就被加到 Target • Delta (s-field) 是一个寄存器或 9 位字符,其值被加到 Target 的值上,为下一条

WAITCNT 指令作准备。这将会创建一个同步延时窗口。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks111110 001i 1111 ddddddddd sssssssss Result = 0 Unsigned Carry Written 5+

解释

WAITCNT, “等待系统计数器,” 是四条等待指令 (WAITCNT, WAITPEQ, WAITPNE, 和 WAITVID) 之一,用于暂停 cog 的执行,直到某个条件满足。 WAITCNT 指令暂停 cog 执行,直到全

局系统计数器等于存储在 Target 寄存器中的某个值,然后它将 Delta 与 Target 相加,

然后继续执行下一条指令。WAITCNT 指令与 Spin 语言中用于同步延时的 WAITCNT 命令类

似,参见 322 页上 WAITCNT 的信息。

如果指定了 WZ 效果,若 Target 与 Delta 之和为 0,则 Z 标志位将被置 1。如果指

定了 WC 效果,若 Target 与 Delta 之和产生了一个 32 位进位(溢出),则 C 标志位置

一。除非指定了 NR效果,否则结果将被写入 Target。

Page 420: Propeller Manual - Parallax Home

WAITPEQ –汇编语言参考

Page 420 · Propeller Manual v1.0

WAITPEQ 指令: 暂停一个 cog 的执行,直到某个(些)I/O 引脚满足某一(些)状态。 WAITPEQ State, ⟨#⟩ Mask

• State (d-field) 是一寄存器,其值要和 Inx“与”Mask 后的结果作比较。 • Mask (s-field) 是一个寄存器或 9 位字符,其值与 INx 相与。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks111100 000i 1111 ddddddddd sssssssss Result = 0 --- Not Written 5+

解释

WAITPEQ, “等待引脚等于,” 是四条等待命令 (WAITCNT, WAITPEQ, WAITPNE, 和 WAITVID) 之一,用于暂停 cog 的执行,直到满足某个条件。 WAITPEQ 指令暂停 cog 的执行,直到

Inx 与 mask 相与的结果等于 State 寄存器中的值。Inx 是 INA 或 INB,取决于执行时 C标志位的值;若 C 标志位等于 0,则为 INA;若 C 标志位等于 1,则为 INB(P8X32A一个特例,它总是测试 INA)。

WAITPEQ 指令与 Spin 命令 WAITPEQ 命令相似;参见 326 页上 WAITPEQ 的信息。

如果指定了 WZ 效果,若 Inx 与 Mask 相与的结果为 0,则 Z 标志位将被置 1。

Page 421: Propeller Manual - Parallax Home

5: 汇编语言参考– WAITPNE

Propeller Manual v1.0 · Page 421

WAITPNE 指令: 暂停 cog 执行指令,直到 I/O 引脚不匹配指定的状态。 WAITPNE State, ⟨#⟩ Mask

• State (d-field) 是寄存器,其值要和 Inx 与 Mask 后的结果作比较。 • Mask (s-field) 是一个寄存器或 9 位字符,其值与 INx 相与。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks111101 000i 1111 ddddddddd sssssssss Result = 0 --- Not Written 5+

解释

WAITPNE, “等待引脚不等于某个状态”,是四条等待指令 (WAITCNT, WAITPEQ, WAITPNE, 和 WAITVID) 用于暂停 cog 执行,直到一个条件满足。WAITPNE 指令暂停 cog 执

行直到 INx 与 Mask 相“与”后的结果不匹配 State 寄存器中的值。. INx 是 INA 或 INB 之一,取决于上一次的指令执行后 C 标志位的值;若 C=0 则为 INA ,若 C=1 则为 INB ( P8X32A 是个特例,它总是测试 INA)。 WAITPNE 指令类似于 Spin 语言中的 WAITPNE 命

令;参见 328 页上的 WAITPNE 。

如果指定了 WZ 效果,若 INx 与 Mask 相“与”的结果为 0, 则 Z 标志位将被置

1。

Page 422: Propeller Manual - Parallax Home

WAITVID, WRBYTE –汇编语言参考

Page 422 · Propeller Manual v1.0

WAITVID 指令: 暂停一个 cog 执行指令,直到其视频发生器可用于产生像素数据。 WAITVID Colors, ⟨#⟩ Pixels

• Colors (d-field) 是一寄存器,其中为 4 位大小的颜色值,每一个颜色值都描述了 Pixels 中可能的四种像素模式。

• Pixels (s-field) 是一个寄存器或 9 位字符,其值是下一个要显示的 2 位模式 16 像

素(或 1 位模式 32 位像素)。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks111111 000i 1111 ddddddddd sssssssss Result = 0 --- Not Written 5+

解释

WAITVID, “等待视频发生器,” 是四条等待指令中的一个 (WAITCNT, WAITPEQ, WAITPNE, 和 WAITVID) 用于暂停 cog 执行指令直到某一条件满足。WAITVID 指令暂停 cog 执行指令,

直到视频发生器硬件已经准备好下一个像素数据,然后视频发生器接受数据 (Colors 和 Pixels) ,Cog 继续执行下一条指令。WAITVID 指令与 Spin 语言中 WAITVID 命令相似;参

建 329 页 WAITVID。

如果指定了 WZ 效果,若 Colors 和 Pixels 相等,则 Z 标志位将被置 1。 在执行该

指令前请确认 cog 的视频发生器模块在运行,否则 WAITVID 会一直等待。

WRBYTE 指令: 将一个字节(byte)写入到主内存。 WRBYTE Value, ⟨#⟩ Address

• Value (d-field) 是一个寄存器,包含了将要写入主内存的 8 位的值。 • Address (s-field) 是一个寄存器或 9 位字符,其值是将要写入的主内存地址。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000000 000i 1111 ddddddddd sssssssss --- --- Not Written 7..22

Page 423: Propeller Manual - Parallax Home

5: 汇编语言参考– WRLONG

Propeller Manual v1.0 · Page 423

解释 WRBYTE 同步到 Hub,并将 Value 中 低的字节写入到主内存的 Address 处。

WRBYTE 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息。

WRLONG 指令: 将一个长字(long)写入到主内存。 WRLONG Value, ⟨#⟩ Address

• Value (d-field) 是寄存器,包含了将要写到主内存的 32 位值。 • Address (s-field) 是一寄存器或 9 位字符,其值是将要写入的主内存地址。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000010 000i 1111 ddddddddd sssssssss --- --- Not Written 7..22

解释

WRLONG同步到 Hub,将 value 中的长型值写入到主内存的地址 Address 处。

WRLONG 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息。

Page 424: Propeller Manual - Parallax Home

WRWORD –汇编语言参考

Page 424 · Propeller Manual v1.0

WRWORD 指令: 将一个字(word)写入主内存。 WRWORD Value, ⟨#⟩ Address

• Value (d-field) 是一寄存器,包含了将要写入主内存的 16 位值。 • Address (s-field) 是一寄存器或 9 位字符,其值是将要写入的主内存地址。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks000001 000i 1111 ddddddddd sssssssss --- --- Not Written 7..22

解释

WRWORD 同步到 Hub,并将 Value 中 低的字写入到内中的 Address 处。

WRWORD 是一条 Hub 指令。Hub 指令需要 7 到 22 个时钟周期来执行,取决于 cog 的

Hub 访问窗口和指令执行的时刻之间的关系。见 24 页上 Hub 一节更多的信息。

Page 425: Propeller Manual - Parallax Home

5: 汇编语言参考 – XOR

Propeller Manual v1.0 · Page 425

XOR 指令: 两个值按位异或。 XOR Value1, ⟨#⟩ Value2 结果: Value1 XOR Value2 ,结果存储在 Value1 中。

• Value1 (d-field) 是一寄存器,包含了将要与 Value2 进行异或运算的值,运算结

果将写入该寄存器。 • Value2 (s-field) 是一寄存器或 9 位的字符,其值将与 Value1 进行异或。

–INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks011011 001i 1111 ddddddddd sssssssss Result = 0 Parity of Result Written 4

解释

XOR (按位异或) 将 Value2 的值与 Value1 的值异或。

如果指定了 WZ 效果,若 Value1 XOR Value2 的值为 0,则 Z 标志位值 1。如果指定

了 WC 效果,若结果中包含了奇数个高(1)位,则 C 标志位置 1。除非指定了 NR 效果,结果将被写入 Value1 。

Page 426: Propeller Manual - Parallax Home

附录 A: 保留字列表

Page 426 · Propeller Manual v1.0

附录 A: 保留字列表 下面的单词在 Spin 或汇编语言中都是保留字:

表 A-0-1: Propeller 保留字列表 _CLKFREQs _CLKMODEs _FREEs _STACKs _XINFREQs ABORTs ABSa ABSNEGa ADDa ADDABSa ADDSa ADDSXa ADDXa ANDd ANDNa BYTEs BYTEFILLs BYTEMOVEs CALLa CASEs CHIPVERs CLKFREQs CLKMODEs CLKSETd CMPa CMPSa CMPSUBa CMPSXa CMPXa CNTd COGIDd COGINITd COGNEWs COGSTOPd

CONs

CONSTANTs CTRAd CTRBd DATs DIRAd DIRBd DJNZa ELSEs ELSEIFs ELSEIFNOTs ENCa FALSEd FILEs FITa FLOATs FROMs FRQAd FRQBd HUBOPa IFs IFNOTs IF_Aa IF_AEa IF_ALWAYSa IF_Ba IF_BEa IF_Ca IF_C_AND_NZa IF_C_AND_Za IF_C_EQ_Za IF_C_NE_Za IF_C_OR_NZa IF_C_OR_Za IF_Ea IF_NCa

IF_NC_AND_NZa

IF_NC_AND_Za IF_NC_OR_NZa IF_NC_OR_Za IF_NEa IF_NEVERa IF_NZa IF_NZ_AND_Ca IF_NZ_AND_NCa IF_NZ_OR_Ca IF_NZ_OR_NCa IF_Za IF_Z_AND_Ca IF_Z_AND_NCa IF_Z_EQ_Ca IF_Z_NE_Ca IF_Z_OR_Ca IF_Z_OR_NCa INAd INBd JMPa JMPRETa LOCKCLRd LOCKNEWd LOCKRETd LOCKSETd LONGs LONGFILLs LONGMOVEs LOOKDOWNs LOOKDOWNZs LOOKUPs LOOKUPZs MAXa MAXSa

MINa

MINSa MOVa MOVDa MOVIa MOVSa MULa MULSa MUXCa MUXNCa MUXNZa MUXZa NEGa NEGCa NEGNCa NEGNZa NEGXd NEGZa NEXTs NOPa NOTs NRa OBJs ONESa ORd ORGa OTHERs OUTAd OUTBd PARd PHSAd PHSBd PId PLL1Xs

PLL2Xs

PLL4Xs PLL8Xs PLL16Xs POSXd PRIs PUBs QUITs RCFASTs RCLa RCRa RCSLOWs RDBYTEa RDLONGa RDWORDa REBOOTs REPEATs RESa RESULTs RETa RETURNs REVa ROLa RORa ROUNDs SARa SHLa SHRa SPRs STEPs STRCOMPs STRINGs STRSIZEs SUBa SUBABSa SUBSa

SUBSXa SUBXa SUMCa SUMNCa SUMNZa SUMZa TESTa TJNZa TJZa TOs TRUEd TRUNCs UNTILs VARs VCFGd VSCLd WAITCNTd WAITPEQd WAITPNEd WAITVIDd WCa WHILEs WORDs WORDFILLs WORDMOVEs WRa WRBYTEa WRLONGa WRWORDa WZa XINPUTs XORa XTAL1s XTAL2s XTAL3s

a =汇编语言元素; s = Spin 语言元素; d =两者(在汇编和 Spin 中都可用)

Page 427: Propeller Manual - Parallax Home

附录 B: 访问数学函数表

Propeller Manual v1.0 · Page 427

附录 B: 访问数学函数表

对数和反对数表 ($C000-DFFF) 在数值和指数形式转换时,对数和反对数表是很有用的。 当数字记为指数形式时,简单的数学运算就需要更复杂的步骤。比如,

“加”和“减”变成了“乘”和“除”,“左移一位”变成了平方,“右移一

位”变成了“平方根”,“除 3”变成了“三次方根”。当指数转换回数字,

结果就会出现。这个过程是不完美的,但是快速。 如果一个应用中有大量的乘除运算而加减运算不多,那么采用指数编码的方

式会提高运算速度。指数编码在压缩大数据时也很有用—在数值较大时牺牲一

定精度。在一些应用中,比如音频合成,信号的频率和音量本身就是以对数形

式存储的。以指数形式处理这些数据就十分自然和高效。 下面给出的例子代码逐个地使用了每个函数表的样本。要达到高精度可以通

过在样本中线性插值的方法达到,因为样本间的斜率变化不大。这样做付出的

代价是更大的代码和较低的执行速度。 对数表 ($C000-$CFFF)

对数表包含了将无符号数转换为以 2 的指数时所用的数据。 对数表由 2048 个无符号字(unsigned word)组成,它们是以 2 为底的以分数为指

数的对数值。要使用该表,必须首先指定要转换数值的指数的整数部分,也就是在前

面的位。对$60000000 而言,就是 30 ($1E)。这个整数部分总是 5 位(5 bits)。将这 5位写入结果的 bit 20…bit 16。在我们的例子 $60000000 中,现在就有了一部分结果 $001E0000。下一步,将前 5 位之后的 11 位(11bits)写入 bit11…bit1。在我们的例子

中就是$0800。与对数表的基址$C000 相加,这就是小数指数的实际字地址(word address)。读取位于$C800 的字,我们得到的值是$95C0。把它加到之前得到的结果上

就得到了$001E95C0 – 这就是$60000000 的指数形式。注意 bits 20..16 组成了指数的整

数部分, bit 15 是½,bit 14 是¼,等,直到 bit 0。指数可以进行加,减和移位运算。

请确保所使用的数学运算不会使指数小于 0 或从 bit 20 溢出,否则可能不能将其转换

回原有的值。

Page 428: Propeller Manual - Parallax Home

附录 B: 访问数学函数表

Page 428 · Propeller Manual v1.0

以下是一段程序,使用对数表将无符号数转换为 2 的指数: ' Convert number to exponent ' ' on entry: num holds 32-bit unsigned value ' on exit: exp holds 21-bit exponent with 5 integer bits and 16 fractional bits ' numexp mov exp,#0 'clear exponent test num,num4 wz 'get integer portion of exponent muxnz exp,exp4 'while top-justifying number if_z shl num,#16 test num,num3 wz muxnz exp,exp3 if_z shl num,#8 test num,num2 wz muxnz exp,exp2 if_z shl num,#4 test num,num1 wz muxnz exp,exp1 if_z shl num,#2 test num,num0 wz muxnz exp,exp0 if_z shl num,#1 shr num,#30-11 'justify sub-leading bits as word offset and num,table_mask 'isolate table offset bits add num,table_log 'add log table address rdword num,num 'read fractional portion of exponent or exp,num 'combine fractional & integer portions numexp_ret ret '91..106 clocks '(variance due to HUB sync on RDWORD) num4 long $FFFF0000 num3 long $FF000000 num2 long $F0000000 num1 long $C0000000 num0 long $80000000 exp4 long $00100000 exp3 long $00080000 exp2 long $00040000 exp1 long $00020000 exp0 long $00010000 table_mask long $0FFE 'table offset mask table_log long $C000 'log table base

Page 429: Propeller Manual - Parallax Home

附录 B: 访问数学函数表

Propeller Manual v1.0 · Page 429

num long 0 'input exp long 0 'output

反对数表 ($D000-$DFFF)

反对数表包含了将 2 的指数转换为无符号数时所用的数据。 反对数表由 2048 个无符号字组成,这些无符号字是一个 17 位尾数中的低 16 位

(第 17 位是隐含的,必须被单独设置)。 要使用该表,将指数小数部分的高 11 位

(bits 15..5)移位到 bits 11..1 并分离。在反对数表基址上加 $D000。将该位置的字

(word)读取到结果中 – 这就是尾数(对数的小数部分)。下一步,将尾数左移到

bits 30..15,将 bit 31(也即是尾数的第 17 位)置位。 后一步是右移结果 31 减去

20...16 位的指数整数。这样,这个指数就被转换为无符号数了。

这里是一个使用反对数表将以 2 为底的指数值转换为无符号数的例子: ' Convert exponent to number ' ' on entry: exp holds 21-bit exponent with 5 integer bits and 16 fraction bits ' on exit: num holds 32-bit unsigned value ' expnum mov num,exp 'get exponent into number shr num,#15-11 'justify exponent fraction as word offset and num,table_mask 'isolate table offset bits or num,table_antilog 'add anti-log table address rdword num,num 'read mantissa word into number shl num,#15 'shift mantissa into bits 30..15 or num,num0 'set top bit (17th bit of mantissa) shr exp,#20-4 'shift exponent integer into bits 4..0 xor exp,#$1F 'inverse bits to get shift count shr num,exp 'shift number into final position expnum_ret ret '47..62 clocks '(variance is due to HUB sync on RDWORD) num0 long $80000000 '17th bit of the mantissa table_mask long $0FFE 'table offset mask table_antilog long $C000 'anti-log table base exp long 0 'input num long 0 'output

Page 430: Propeller Manual - Parallax Home

附录 B: 访问数学函数表

Page 430 · Propeller Manual v1.0

正弦表 ($E000-$F001) 正弦表提供了 2049 个无符号 16 位从 0°到 90°正弦采样值(精度为 0.0439°)

只需要很少量的汇编代码就可以对正弦表做镜像和反转,得到全周期的正弦/余弦

查找程序,它有 13 位的角度精度和 17 位的采样精度: ' Get sine/cosine ' ' quadrant: 1 2 3 4 ' angle: $0000..$07FF $0800..$0FFF $1000..$17FF $1800..$1FFF ' table index: $0000..$07FF $0800..$0001 $0000..$07FF $0800..$0001 ' mirror: +offset -offset +offset -offset ' flip: +sample +sample -sample -sample ' ' on entry: sin[12..0] holds angle (0° to just under 360°) ' on exit: sin holds signed value ranging from $0000FFFF ('1') to ' $FFFF0001 ('-1') ' getcos add sin,sin_90 'for cosine, add 90° getsin test sin,sin_90 wc 'get quadrant 2|4 into c test sin_sin_180 wz 'get quadrant 3|4 into nz negc sin,sin 'if quadrant 2|4, negate offset or sin,sin_table 'or in sin table address >> 1 shl sin,#1 'shift left to get final word address rdword sin,sin 'read word sample from $E000 to $F000 negnz sin,sin 'if quadrant 3|4, negate sample getsin_ret getcos_ret ret '39..54 clocks '(variance due to HUB sync on RDWORD) sin_90 long $0800 sin_180 long $1000 sin_table long $E000 >> 1 'sine table base shifted right sin long 0

如同对数和反对数表,使用线性插值可以获得更高的精度。

Page 431: Propeller Manual - Parallax Home

附录 B: 访问数学函数表

Propeller Manual v1.0 · Page 431

索引 _

_CLKFREQ, 133, 134 _CLKFREQ (spin), 182–83 _CLKMODE, 133 _CLKMODE (spin), 185–87 _FREE (spin), 223 _STACK (spin), 313 _XINFREQ, 133, 134 _XINFREQ (spin), 344–45

A Abort

Status, 165 Trap, 166, 319

ABORT (spin), 165–68 Absolute Value ‘||’, 267 Access collisions, 236 ADC, 209 Add ‘+’, ‘+=’, 261 ADDABS (asm), 364 Address ‘@’, 283 Address Plus Symbol ‘@@’, 284 ADDS (asm), 365 ADDSX (asm), 365–66 ADDX (asm), 366–67 Align

Text, 68 Values, 214

Analog-to-digital conversion, 209 AND (asm), 367 AND (spin), 226 AND, Bitwise ‘&’, ‘&=’, 274 AND, Boolean ‘AND’, ‘AND=’, 277 ANDN (asm), 367–68 Anti-Log Table, 429 Application

Defined, 89 Applications and objects, 89 Architecture, 15–36 Archive (menu), 47 Array index designators, [ ], 319 Assembly language, 347

ADDABS, 364 ADDS, 365 ADDSX, 365–66 ADDX, 366–67 AND, 367 ANDN, 367–68 Binary operators, 356 CALL, 368–69 CLKSET, 369 CMP, 370 CMPS, 370–71 CMPSUB, 371 CMPSX, 372 CMPX, 372 CNT, 405 COGID, 373 COGINIT, 374 COGSTOP, 375 Common syntax elements, 357 Conditions, 349, 376–77 Conditions (table), 377 Configuration, 349 CTRA, CTRB, 405 DIRA, DIRB, 405 Directives, 349 DJNZ, 378 Effects, 351, 378–79 Effects (table), 379 FIT, 380 Flow control, 351 FRQA, FRQB, 405 HUBOP, 381 IF_x (conditions), 376–77 INA, INB, 405 JMP, 382 JMPRET, 382–83 Literal, #, 318 LOCKCLR, 383 LOCKNEW, 384 LOCKRET, 384–85 LOCKSET, 385 Main memory access, 351 Master table, 359–60 MAX, 386 MAXS, 386–87

Page 432: Propeller Manual - Parallax Home

Index

Page 432 · Propeller Manual v1.0

MIN, 387 MINS, 388 MOV, 388–89 MOVD, 389 MOVI, 390 MOVS, 390–91 MUXC, 391 MUXNC, 392 MUXNZ, 392–93 MUXZ, 393 NEG, 394 NEGC, 394–95 NEGNC, 395 NEGNZ, 396 NEGZ, 397 NOP, 397 NR, 378–79 Operators, 398–99 OR, 400 ORG, 400–401 OUTA, OUTB, 405 PAR, 405 PHSA, PHSB, 405 Process control, 349 RCL, 401 RCR, 402 RDBYTE, 402–3 RDLONG, 403 RDWORD, 404 Registers, 405 RES, 406 RET, 407 REV, 407 ROL, 408 ROR, 408–9 SAR, 409 SHL, 410 SHR, 410–11 Structure, 347 SUB, 411 SUBABS, 412 SUBS, 412–13 SUBSX, 413 SUBX, 414 SUMC, 414–15 SUMNC, 415–16 SUMNZ, 416 SUMZ, 416–17

Syntax definitions, 357 TEST, 417 TJNZ, 418 TJZ, 418–19 Unary operators, 354 VCFG, 405 VSCL, 405 WAITCNT, 419 WAITPEQ, 420 WAITPNE, 421 WAITVID, 422 WC, 378–79 WR, 378–79 WRBYTE, 422–23 WRLONG, 423 WRWORD, 424 WZ, 378–79 XOR, 425

Assignment Constant ‘=’, 259 Variable ‘:=’, 260

B Bases, numerical, 163 Binary indicator, %, 318 Binary operators (asm), 356 Binary operators (spin), 161 Bitwise operators

AND ‘&’, ‘&=’, 274 AND Truth Table (table), 274 Decode ‘|<’, 270 Encode ‘>|’, 271 NOT ‘!’, 277 NOT Truth Table (table), 277 OR ‘|’, ‘|=’, 275 OR Truth Table (table), 275 Reverse ‘><’, ‘><=’, 274 Rotate Left ‘<-’, ‘<-=’, 272 Rotate Right ‘->’, ‘->=’, 273 Shift Left ‘<<’, ‘<<=’, 271 Shift Right ‘>>’, ‘>>=’, 272 XOR ‘^’, ‘^=’, 276 XOR Truth Table (table), 276

Block designators, 100, 156 Block Diagram (figure), 22–23 Block selection and moving, 70–71

Page 433: Propeller Manual - Parallax Home

附录 B: 访问数学函数表

Propeller Manual v1.0 · Page 433

Block Selection and Moving (figure), 71 Block-group indicators, 75 Block-Group Indicators (figure), 76 BOEn (pin), 17 Bookmarks, 65 Bookmarks (figure), 65 Boolean operators

AND ‘AND’, ‘AND=’, 277 Is Equal ‘==’, ‘===’, 279 Is Equal or Greater ‘=>’, ‘=>=’, 283 Is Equal or Less ‘=<’, ‘=<=’, 282 Is Greater Than ‘>’, ‘>=’, 281 Is Less Than ‘<’, ‘<=’, 281 Is Not Equal ‘<>’, ‘<>=’, 280 NOT ‘NOT’, 279 OR ‘OR’, ‘OR=’, 278

Boot parameter, 25 Boot up procedure, 20 Boot-up time, 95 Brown Out Enable (pin), 17 Byte

Data declaration, 170 Memory type, 169 Reading/writing, 171, 402, 422 Variable declaration, 170

BYTE (spin), 169–73 BYTEFILL (spin), 174 BYTEMOVE (spin), 175

C Calculating time, 332 CALL (asm), 368–69 Call Stack, 165, 307 Case (find), 52 CASE (spin), 176–78 Case statement separator, :, 319 Categorical listing

Propeller Assembly language, 349 Spin language, 154, 156

Character Chart (figure), 62 Definitions, 33 Interleaving, 34 Interleaving (figure), 35

CHIPVER (spin), 179 Clear, Post ‘~’, 267

CLK Register Structure (table), 29 CLKFREQ (spin), 137, 180–81 CLKMODE (spin), 184 CLKSELx (table), 31 CLKSET (asm), 369 CLKSET (spin), 137, 188 Clock

Frequency range, 31 Mode Setting Constants (table), 185, 186 PLL, 24 Related timing, 135 Settings, 133

Close (menu), 47 Close All (menu), 47 CMP (asm), 370 CMPS (asm), 370–71 CMPSUB (asm), 371 CMPSX (asm), 372 CMPX (asm), 372 CNT, 25, 311 CNT (asm), 405 CNT (spin), 189–90 Code Block Indenting (figure), 73 Cog

RAM Map (figure), 25 Registers (table), 405

Cog control (spin), 157 Cog ID, 191, 373 Cog-Hub interaction, 23 Cog-Hub Interaction (figure), 27 COGID (asm), 373 COGID (spin), 191 COGINIT (asm), 374 COGINIT (spin), 192 COGNEW (spin), 194–97 Cogs (processors), 24, 98 COGSTOP (asm), 375 COGSTOP (spin), 198 Combining conditions, 226 Comments, 101 Common syntax elements (asm), 357 Compile Current (menu), 49, 114 Compile information, 150 Compile Information (figure), 150 Compile Menus (figure), 115 Compile Top (menu), 49 CON (spin), 199–204

Page 434: Propeller Manual - Parallax Home

Index

Page 434 · Propeller Manual v1.0

Conditional loops, 303 Conditions (asm), 349, 376–77 Conditions, Assembly (table), 377 Configuration (asm), 349 Configuration (spin), 156 CONSTANT (spin), 205–6 Constant Assignment ‘=’, 259 Constant block, 100 Constant Expression Math/Logic Oper. (table), 399 Constants, 99 Constants (pre-defined), 207–8 Context-sensitive compile information, 150 Copy (menu), 48 Counted finite loops, 301 Counter

Control, 25 Frequency, 25 Modes (table), 212 Phase, 25 Registers, 209

Crystal Input (pin), 17 Crystal Output (pin), 17 CTRA and CTRB Registers (table), 210 CTRA, CTRB, 25, 311 CTRA, CTRB (asm), 405 CTRA, CTRB (spin), 209–12 Cut (menu), 48

D DAC, 209 DAT (spin), 213–16 Data block, 100 Data tables, 171, 213, 243, 248, 250, 339 Decimal point, ., 318 Declaring data, 171, 213, 243, 339 Decode, Bitwise ‘|<’, 270 Decrement, pre- or post- ‘- -’, 262 Delay

Fixed, 329 Fixed (figure), 330 Synchronized, 330 Synchronized (figure), 331

Delimiter, _, 318 Digital-to-analog conversion, 209 DIRA, DIRB, 25, 311 DIRA, DIRB (asm), 405

DIRB, DIRB (spin), 217–19 Direction (find), 52 Directives (asm), 349 Directives (spin), 159 Divide ‘/’, ‘/=’, 265 DJNZ (asm), 378 Documentation view mode, 43 Downloading (figure), 91 Downloading to RAM vs. EEPROM, 94 Duty-cycle measurement, 209

E Edit modes, 67–70 Edit Modes (figure), 67 Effects (asm), 351, 378–79 Effects, Assembly (table), 379 ELSE (spin), 227 ELSEIF (spin), 227 ELSEIFNOT (spin), 229 Encode, Bitwise ‘>|’, 271 Enumeration Set, #, 318 Enumerations, 202 Example Application (figure), 113 Example Data in Memory (table), 214 Exit (menu), 48 Exiting a method, 296 Expression workspace, 255 External files, 220

F FALSE, 207 Figures

Block Diagram, 22–23 Block Selection and Moving, 71 Block-Group Indicators, 76 Bookmarks, 65 Character Chart, 62 Character Interleaving, 35 Code Block Indenting, 73 Compile Information, 150 Compile Menus, 115 Downloading, 91 Edit Modes, 67 Example Application, 113 Find/Replace, 51

Page 435: Propeller Manual - Parallax Home

附录 B: 访问数学函数表

Propeller Manual v1.0 · Page 435

Fixed Delay Timing, 330 Integrated Explorer, 40 Line Numbers, 66 Main Memory Map, 32 Object Files, 89 Object Hierarchy, 90 Object Info, 57, 59, 130 Object View, 54 Parentheses Matching, 121 Propeller Font Characters, 34 Propeller Library Browsing, 140 Propeller Object, 89 Propeller Tutorial Schematic, 92 Screen Organization, Propeller Tool, 39 Single Cog, Running, 98 Status Bar, 46 Synchronized Delay Timing, 331 Top Object, Setting, 116 Two Cogs, Running, 109 View Modes, 64 Viewing Multiple Objects, 44, 45 Work and Library Folders, 144

File format, 37 Find, 51 Find button, 52 Find Next (menu), 48 Find/Replace (figure), 51 Find/Replace… (menu), 48 Finite loops, 105 FIT (asm), 380 Fixed delay, 329 Fixed Delay Timing (figure), 330 FLOAT (spin), 221 Floating-point, 147, 309 Flow control (asm), 351 Flow control (spin), 157 Free space, 223 Frequency measurement, 209 Frequency register, 224 Frequency synthesis, 209 FROM (spin), 299, 301 FRQA, FRQB, 25, 311 FRQA, FRQB (asm), 405 FRQA, FRQB (spin), 224 Full Source view mode, 43, 63 Functional Block Diagram (figure), 22

G Go To Bookmark (menu), 49 Guarantee, 2

H Hardware connections, 19 Hex view, 58 Hexadecimal indicator, $, 318 Hide/Show Explorer (menu), 48 Hollow folders, 55 Host communication, 20 Hub, 23, 26 Hub instructions, clock cycles for, 361 HUBOP (asm), 381

I I/O pin rules, 218 I/O pins, 27 ID of cog, 191, 373 Identify Hardware… (menu), 50 IEEE-754, 222 IF (spin), 225–29 IF_x (asm) (conditions), 376–77 IFNOT (spin), 231 Import external file, 220 INA, INB, 25, 311 INA, INB (asm), 405 INA, INB (spin), 231–33 Increment, pre- or post- ‘+ +’, 263 Indenting and outdenting, 71–75 Indention, 176, 226, 300 Infinite loops, 300 Init method, the, 118 Input states, 25 Insert edit mode, 67 Integer and real numbers, 146 Integrated Explorer (figure), 40 Intermediate assignments, 259 Is Equal or Greater, Boolean ‘=>’, ‘=>=’, 283 Is Equal or Less, Boolean ‘=<’, ‘=<=’, 282 Is Equal, Boolean ‘==’, ‘===’, 279 Is Greater Than, Boolean ‘>’, ‘>=’, 281 Is Less Than, Boolean ‘<’, ‘<=’, 281 Is Not Equal, Boolean ‘<>’, ‘<>=’, 280

Page 436: Propeller Manual - Parallax Home

Index

Page 436 · Propeller Manual v1.0

J JMP (asm), 382 JMPRET (asm), 382–83

L Launching a new cog, 192, 194, 374 Least Significant Bit (LSB), 270 Level of precedence, 255, 258 LFSR, 269 Library folder, 54 Library objects, 140 Limit Maximum ‘<#’, ‘<#=’, 266 Limit Minimum ‘#>’, ‘#>=’, 265 Line numbers, 63, 66 Line Numbers (figure), 66 Linear Feedback Shift Register (LFSR), 270 List delimiter (,), 319 Load EEPROM (menu), 49 Load EEPROM button, 59 Load RAM (menu), 49 Load RAM button, 59 Local variable separator, |, 319 Local variables, 295 Lock, 31, 383, 384, 385 Lock, rules, 237 LOCKCLR (asm), 383 LOCKCLR (spin), 234 LOCKNEW (asm), 384 LOCKNEW (spin), 236–37 LOCKRET (asm), 384–85 LOCKRET (spin), 239 LOCKSET (asm), 385 LOCKSET (spin), 240 Log and anti-log tables, 35 Log table, 427 Long

Data declaration, 243 Reading/writing, 244, 403, 423 Variable declaration, 242

LONG (spin), 242–43 LONGFILL (spin), 246 LONGMOVE (spin), 247 LOOKDOWN, LOOKDOWNZ (spin), 248–49 LOOKUP, LOOKUPZ (spin), 250 Loops

Conditional, 303 Examples, 128, 299 Finite, counted, 301 Finite, simple, 300 Infinite, 300

LSB, 270

M Main memory, 32 Main memory access (asm), 351 Main Memory Map (figure), 32 Main RAM, 32 Main ROM, 33 Match (find), 51 Math function tables, 427 Math/Logic Operators (table), 256 MAX (asm), 386 Maximum, Limit ‘<#’, ‘<#=’, 266 MAXS (asm), 386–87 Memory

Copying, 175, 247 Filling, 174, 246, 342

Memory type Byte, 169 Word, 338

Menu items, 47–50 MIN (asm), 387 Minimum, Limit ‘#>’, ‘#>=’, 265 MINS (asm), 388 Modulus ‘//’, ‘//=’, 265 Most Significant Bit (MSB), 270 MOV (asm), 388–89 MOVD (asm), 389 MOVI (asm), 390 MOVS (asm), 390–91 MSB, 270 Multi-line code comment, , 101, 319 Multi-line doc comment, , 101, 319 Multiple line indenting, 73 Multiply, Return High‘**’, ‘**=’, 264 Multiply, Return Low ‘*’, ‘*=’, 264 MUXC (asm), 391 MUXNC (asm), 392 MUXNZ (asm), 392–93 MUXZ (asm), 393

Page 437: Propeller Manual - Parallax Home

附录 B: 访问数学函数表

Propeller Manual v1.0 · Page 437

N NEG (asm), 394 Negate ‘-’, 262 NEGC (asm), 394–95 NEGNC (asm), 395 NEGNZ (asm), 396 NEGX, 207, 208 NEGZ (asm), 397 New (menu), 47 NEXT (spin), 252 NOP (asm), 397 NOT, Bitwise ‘!’, 277 NOT, Boolean ‘NOT’, 279 NR (asm), 378–79 Numerical bases, 163

O OBJ (spin), 253–54 Object Address Plus Symbol ‘@@’, 284 Object assignment, :, 319 Object block, 100, 126, 253 Object Files (figure), 89 Object Hierarchy (figure), 90 Object Info, 129 Object Info (figure), 57, 59, 130 Object interface, 112 Object lifetime, 131 Object reference, 253 Object View, 113 Object View (figure), 54 Object, structure of, 154 Object-Constant Reference, #, 318 Object-Method Reference, ., 112, 318 Objects, 88 Objects and applications, 89 Objects vs. cogs, 118 Open File button, 59 Open From… (menu), 47 Open... (menu), 47 Operator attributes, 255 Operator Precedence Levels (table), 257 Operators

- - (Decrement, pre- or post-), 262 - (Negate), 262 ! (Bitwise NOT), 277

#>, #>= (Limit Minimum), 265 &, &= (Bitwise AND), 274 **, **= (Multiply, Return High), 264 *, *= (Multiply, Return Low), 264 -, -= (Subtract), 261 /, /= (Divide), 265 //, //= (Modulus), 265 := (Variable Assignment), 260 ? (Random), 269 @ (Symbol Address), 283 @@ (Object Address Plus Symbol), 284 ^, ^= (Bitwise XOR), 276 ^^ (Square Root), 266 |, |= (Bitwise OR), 275 || (Absolute Value), 267 |< (Bitwise Decode), 270 ~ (Sign-Extend 7 or Post-Clear), 267 ~~ (Sign-Extend 15 or Post-Set), 268 ~>, ~>= (Shift Arithmetic Right), 269 + (Positive), 261 + + (Increment, pre- or post-), 263 +, += (Add), 261 <#, <#= (Limit Maximum), 266 <-, <-= (Bitwise Rotate Left), 272 <, <= (Boolean Is Less Than), 281 <<, <<= (Bitwise Shift Left), 271 <>, <>= (Boolean Is Not Equal), 280 = (Constant Assignment), 259 =<, =<= (Boolean Is Equal or Less), 282 ==, === (Boolean Is Equal), 279 =>, =>= (Boolean Is Equal or Greater), 283 ->, ->= (Bitwise Rotate Right), 273 >, >= (Boolean Is Greater Than), 281 >| (Bitwise Encode), 271 ><, ><= (Bitwise Reverse), 274 >>, >>= (Bitwise Shift Right), 272 AND, AND= (Boolean AND), 277 NOT (Boolean), 279 OR, OR= (Boolean OR), 278

Operators (asm), 398–99 Operators (spin), 255–70 OR (asm), 400 OR (spin), 226 OR, Bitwise ‘|’, ‘|=’, 275 OR, Boolean ‘OR’, ‘OR=’, 278 ORG (asm), 400–401 Origin (find), 52 OSCENA (table), 30

Page 438: Propeller Manual - Parallax Home

Index

Page 438 · Propeller Manual v1.0

OSCMx (table), 31 OTHER (spin), 177 OUTA, OUTB, 25, 311 OUTA, OUTB (asm), 405 OUTA, OUTB (spin), 286–88

P PAR, 25, 311 PAR (asm), 405 PAR (spin), 289–90, 289–90 Parallel processing, 107 Parameter list designators, ( ), 319 Parameters, 295 Parentheses Matching (figure), 121 Paste (menu), 48 Phase-Locked Loop (PLL) register, 291 PHSA, PHSB, 25, 311 PHSA, PHSB (asm), 405 PHSA, PHSB (spin), 291 PI, 207, 208 Pin descriptions, 17 PLL, 291 PLL16X, 185, 207, 208 PLL1X, 185, 207, 208 PLL2X, 185, 207, 208 PLL4X, 185, 207, 208 PLL8X, 185, 207, 208 PLLDIV Field (table), 210 PLLENA (table), 30 Positive ‘+’, 261 Post-Clear ‘~’, 267 Post-Decrement ‘- -’, 262 Post-Increment ‘+ +’, 263 Post-Set ‘~~’, 268 POSX, 207, 208 Power up, 20 Precedence level, 255, 258 Pre-Decrement ‘- -’, 122, 262 Preferences… (menu), 49 Pre-Increment ‘+ +’, 263 PRI (spin), 292 Print Preview… (menu), 48 Print… (menu), 48 Private method block, 100 Process Control (asm), 349 Process control (spin), 157

Processors (cogs), 24, 98 Programming connections, 19 Propeller Assembly. See Assembly Language Propeller Assembly Instructions (table), 359–60 Propeller Assembly language, categorical, 349 Propeller chip

Architecture, 15–36 Block Diagram (figure), 22 Boot up procedure, 20 Cogs (processors), 24 Hardware connections, 19 Pin descriptions, 17 Power up, 20 Run-time procedure, 20 Shared resources, 24 Shutdown procedure, 21 Specifications, 18 Warranty, 2

Propeller Clip, 19 Propeller Font Characters (figure), 34 Propeller Library Browsing (figure), 140 Propeller Object (figure), 89 Propeller objects, 88 Propeller Spin. See Spin Language Propeller Tool

Menu items, 47–50 View modes, 43

Propeller Tutorial Schematic (figure), 92 Pseudo-real numbers, 146 PUB (spin), 293 Public method block, 100 Pulse counting, 209 Pulse measurement, 209 Pulse-width modulation (PWM), 209

Q Quaternary indicator, %%, 318 QUIT (spin), 297

R RAM

Main, 32 Random ‘?’, 269 Range indicator, .., 318 RCFAST, 31, 185, 207, 208

Page 439: Propeller Manual - Parallax Home

附录 B: 访问数学函数表

Propeller Manual v1.0 · Page 439

RCL (asm), 401 RCR (asm), 402 RCSLOW, 31, 185, 207, 208 RDBYTE (asm), 402–3 RDLONG (asm), 403 RDWORD (asm), 404 Reading/writing

Bytes of main memory, 171, 402, 422 Longs of main memory, 244, 403, 423 Words of main memory, 340, 404, 424

Real numbers, 146 REBOOT (spin), 298 Redo (menu), 48 Registers, 405 Registers (spin), 159 Registers, Cog (table), 405 REPEAT (spin), 299–304 Replace, 51 Replace (menu), 49 Replace All button, 53 Replace button, 53 RES (asm), 406 Reserving memory, 223, 406 Reset, 20 Reset (pin), 17 Reset (table), 30 Reset, software, 30 RESn (pin), 17 Resources

Shared, 24 RESULT (spin), 305–6 RET (asm), 407 RETURN (spin), 307–8 Return value, 294 Return value separator, :, 319 REV (asm), 407 Reverse, Bitwise ‘><’, ‘><=’, 274 ROL (asm), 408 ROM

Bitmap character view, 60, 61 ROR (asm), 408–9 Rotate Left, Bitwise ‘<-’, ‘<-=’, 272 Rotate Right, Bitwise ‘->’, ‘->=’, 273 ROUND (spin), 309–10 Run-time procedure, 20

S SAR (asm), 409 Save (menu), 47 Save All (menu), 47 Save As... (menu), 47 Save Binary File button, 59 Save EEPROM File button, 59 Save To… (menu), 47 Scope (find), 52 Scope of constants, 204 Scope of object symbols, 254 Scope of variables, 322 Screen Organization, Propeller Tool (figure), 39 Select All (menu), 48 Select Top Object File… (menu), 47 Semaphore, 31, 383, 384, 385 Semaphore, rules, 237 Set, Post ‘~~’, 268 Shared resources, 24 Shift Arithmetic Right ‘~>’, ‘~>=’, 269 Shift Left, Bitwise ‘<<’, ‘<<=’, 271 Shift Right, Bitwise ‘>>’, ‘>>=’, 272 SHL (asm), 410 Shortcut keys, 77–86

By key, 82–86 Categorical, 77–81

SHR (asm), 410–11 Shutdown procedure, 21 Sign-Extend 15 ‘~~’, 268 Sign-Extend 7 ‘~’, 267 Simple finite loops, 300 Simultaneous processing, 107 Sine table, 36, 430 Single Cog, Running (figure), 98 Single line indenting, 72 Single-line code comment, ', 319 Single-line doc comment, ' ', 101, 319 Software reset, 30 Special purpose registers, 25 Special Purpose Registers (table), 311 Specifications, 18 Spin

Operators, 255–70 Spin Interpreter, 36 Spin language, 153

_CLKFREQ, 182

Page 440: Propeller Manual - Parallax Home

Index

Page 440 · Propeller Manual v1.0

_CLKMODE, 185–87 _FREE, 223 _STACK, 313 _XINFREQ, 344–45 ABORT, 165–68 AND, 226 Binary operators, 161 Block designators, 156 BYTE, 169–73 BYTEFILL, 174 BYTEMOVE, 175 CASE, 176–78 CHIPVER, 179 CLKFREQ, 180–81 CLKMODE, 184 CLKSET, 188 CNT, 189–90 Cog control, 157 COGID, 191 COGINIT, 192 COGNEW, 194–97 CON, 199–204 Configuration, 156 CONSTANT, 205–6 Constants (pre-defined), 207–8 CTRA, CTRB, 209–12 DAT, 213–16 DIRB, DIRB, 217–19 Directives, 159 ELSE, 227 ELSEIF, 227 ELSEIFNOT, 229 FLOAT, 221 Flow control, 157 FROM, 299, 301 FRQA, FRQB, 224 IF, 225–29 IFNOT, 231 INA, INB, 231–33 LOCKCLR, 234 LOCKNEW, 236–37 LOCKRET, 239 LOCKSET, 240 LONG, 242–43 LONGFILL, 246 LONGMOVE, 247 LOOKDOWN, LOOKDOWNZ, 248–49 LOOKUP, LOOKUPZ, 250

Memory, 158 NEXT, 252 OBJ, 253–54 OR, 226 OUTA, OUTB, 286–88 PHSA, PHSB, 291 PRI, 292 Process control, 157 PUB, 293 QUIT, 297 REBOOT, 298 Registers, 159 REPEAT, 299–304 RESULT, 305–6 RETURN, 307–8 ROUND, 309–10 SPR, 311–12 STEP, 302 STRCOMP, 314–15 STRING, 316 STRSIZE, 317 Symbols, 318–19 Syntax definitions, 164 TO, 299, 301 TRUNC, 320 Unary operators, 160 UNTIL, 299, 303 VAR, 321 VSCL, 327–28 WAITCNT, 329–32 WAITPEQ, 333–34 WAITPNE, 335 WAITVID, 336–37 WHILE, 299, 303 WORD, 338–40 WORDFILL, 342 WORDMOVE, 343

Spin language, categorical listing, 154, 156 SPR (spin), 311–12 Square Root ‘^^’, 266 Start method, the, 118 Starting a new cog, 192, 194, 374 Status Bar (figure), 46 STEP (spin), 302 Stop method, the, 118 Stopping a cog, 198, 375 STRCOMP (spin), 314–15 STRING (spin), 143, 316

Page 441: Propeller Manual - Parallax Home

附录 B: 访问数学函数表

Propeller Manual v1.0 · Page 441

String comparison, 314 String size, 317 Striped folders, 55 STRSIZE (spin), 317 Structure of Propeller Assembly, 347 Structure of Propeller object, 154 SUB (asm), 411 SUBABS (asm), 412 SUBS (asm), 412–13 SUBSX (asm), 413 Subtract ‘-’, ‘-=’, 261 SUBX (asm), 414 SUMC (asm), 414–15 Summary view mode, 43 SUMNC (asm), 415–16 SUMNZ (asm), 416 SUMZ (asm), 416–17 Symbol Address ‘@’, 283 Symbol rules, 163 Symbolic Order character view, 60 Symbols

- - (Decrement, pre- or post-), 262 ' ' (single-line document comment), 319 - (Negate), 262 ' (single-line code comment), 319 ! (Bitwise NOT), 277 # (multipurpose), 318 #>, #>= (Limit Minimum), 265 $ (Hexadecimal indicator), 318 % (Binary indicator), 318 %% (Quaternary indicator), 318 &, &= (Bitwise AND), 274 ( ) (parameter list designators), 319 \ (abort trap), 319 **, **= (Multiply, Return High), 264 *, *= (Multiply, Return Low), 264 , (list delimiter), 319 -, -= (Subtract), 261 . (multipurpose), 318 .. (Range indicator), 318 /, /= (Divide), 265 //, //= (Modulus), 265 : (multipurpose), 319 := (Variable Assignment), 260 ? (Random), 269 @ (Symbol Address), 283 @@ (Object Address Plus Symbol), 284 [ ] (array-index designators), 319

^, ^= (Bitwise XOR), 276 ^^ (Square Root), 266 _ (multipurpose), 318 (In-line, multi-line code comments), 319 (In-line, multi-line doc comments), 319 | (local variable separator), 319 |, |= (Bitwise OR), 275 || (Absolute Value), 267 |< (Bitwise Decode), 270 ~ (Sign-Extend 7 or Post-Clear), 267 ~~ (Sign-Extend 15 or Post-Set), 268 ~>, ~>= (Shift Arithmetic Right), 269 + (Positive), 261 + + (Increment, pre- or post-), 263 +, += (Add), 261 <#, <#= (Limit Maximum), 266 <-, <-= (Bitwise Rotate Left), 272 <, <= (Boolean Is Less Than), 281 <<, <<= (Bitwise Shift Left), 271 <>, <>= (Boolean Is Not Equal), 280 = (Constant Assignment), 259 =<, =<= (Boolean Is Equal or Less), 282 ==, === (Boolean Is Equal), 279 =>, =>= (Boolean Is Equal or Greater), 283 ->, ->= (Bitwise Rotate Right), 273 >, >= (Boolean Is Greater Than), 281 >| (Bitwise Encode), 271 ><, ><= (Bitwise Reverse), 274 >>, >>= (Bitwise Shift Right), 272 AND, AND= (Boolean AND), 277 NOT (Boolean), 279 OR, OR= (Boolean OR), 278

Symbols (spin), 318–19 Symbols (table), 318–19 Symbols:, 213, 220, 253, 318 Synchronized delay, 330 Synchronized Delay Timing (figure), 331 Syntax definitions (asm), 357 Syntax definitions (spin), 164 System Clock, 24 System Clock Tick vs. Time (table), 180 System Counter, 25, 189

T Tables

Bitwise AND Truth Table, 274

Page 442: Propeller Manual - Parallax Home

Index

Page 442 · Propeller Manual v1.0

Bitwise NOT Truth Table, 277 Bitwise OR Truth Table, 275 Bitwise XOR Truth Table, 276 CLK Register Structure, 29 Clock Mode Setting Constants, 185, 186 Conditions, Assembly, 377 Counter Modes, 212 CTRA and CTRB Registers, 210 Effects, Assembly, 379 Example Data in Memory, 214 Math/Logic Operators, 256 Operator Precedence Levels, 257 Pin Descriptions, 17 PLLDIV Field, 210 Propeller Assembly Instructions, 359–60 Registers, Cog, 405 Shortcut Keys – By Key, 82–86 Shortcut Keys – Categorical, 77–81 Special Purpose Registers, 25, 311 Specifications, 18 Symbols, 318–19 System Clock Ticks vs. Time, 180 VCFG Register, 324 VSCL Register, 327

TEST (asm), 417 Text Bigger (menu), 49 Text Smaller (menu), 49 Time, calculating, 332 TJNZ (asm), 418 TJZ (asm), 418–19 TO (spin), 299, 301 Top Object File, 114 Top Object, Setting (figure), 116 TRUE, 207 TRUNC, 149 TRUNC (spin), 320 Truth tables

Bitwise AND, 274 Bitwise NOT, 277 Bitwise OR, 275 Bitwise XOR, 276

Two Cogs, Running (figure), 109

U Unary / binary, 257 Unary operators (asm), 354

Unary operators (spin), 160 Underscore, _, 318 Undo (menu), 48 UNTIL (spin), 299, 303 Update Status (menu), 49

V Value representations, 163 VAR (spin), 321 Variable Assignment ‘:=’, 260 Variable block, 100 Variable declarations, 170, 243, 321, 339 Variable scope, 322 Variable type

Byte, 169 Word, 338

VCFG, 25, 311 VCFG (asm), 405 VCFG (spin), 324–26 VCFG Register (table), 324 Video Configuration register, 25, 324 Video Scale register, 25, 327 View Character Chart… (menu), 50 View Info… (menu), 49 View modes, 63 View Modes (figure), 64 Viewing Multiple Objects (figure), 44, 45 VSCL, 25, 311 VSCL (asm), 405 VSCL (spin), 327–28 VSCL Register (table), 327

W WAITCNT (asm), 419 WAITCNT (spin), 329–32 Waiting for transitions, 334 WAITPEQ (asm), 420 WAITPEQ (spin), 333–34 WAITPNE (asm), 421 WAITPNE (spin), 335 WAITVID (asm), 422 WAITVID (spin), 336–37 Warranty, 2 WC (asm), 378–79 WHILE (spin), 299, 303

Page 443: Propeller Manual - Parallax Home

附录 B: 访问数学函数表

Propeller Manual v1.0 · Page 443

Word Memory type, 338 Reading/writing, 340, 404, 424 Variable declaration, 338

WORD (spin), 338–40 WORDFILL (spin), 342 WORDMOVE (spin), 343 Work and library folders, 144 Work and Library Folders (figure), 144 Work folder, 55, 144 WR (asm), 378–79 WRBYTE (asm), 422–23 WRLONG (asm), 423 WRWORD (asm), 424 WZ (asm), 378–79

X XI (pin), 17 XI capacitance, 31 XINPUT, 31, 185, 207, 208 XO (pin), 17 XOR (asm), 425 XOR, Bitwise ‘^’, ‘^=’, 276 XOUT resistance, 31 XTAL1, 31, 185, 207, 208 XTAL2, 31, 185, 207, 208 XTAL3, 31, 185, 207, 208

Z Zero-terminated strings, 315