当你下载PBASIC程序到BASIC Stamp时,BASIC Stamp编辑器会将程序转换为称为标记的数字 值。这些标记是BASIC Stamp用来作为执行程序的指令。它们存储在BASIC Stamp上面两个黑色芯 片中一个标有“24LC16B”的芯片里面。这个芯片是一种特殊的计算机存储器叫EEPROM,意思是 电可擦除可编程只读存储器。BASIC Stamp的EEPROM能够容纳2048字节(即2kB)的信息。没有 存储程序(从地址2047 到 0)的存储空间可以用来存储数据(从地址 0 到2047),即程序从地址 2047开始往下存储,而数据则从地址0开始往上存储。如果存储的数据和程序发生了交叉重叠,程 序就不能正常工作了,这一点要切记。
基础机器人制作与编程 EEPROM存储器与RAM(随机存取存储器)变量存储器有几个方面的不同。
z EEPROM存储一个值要花费更多时间,有时需要几毫秒。
z EEPROM可以接受写操作的次数是有限的,大约1千万次,而RAM能无限次的读写。
z EEPROM 的主要功能是存储程序,数据可以存在剩余的部分。
你可以单击BASIC Stamp 编辑器的Run菜单,选择“Memory Map”来浏览BASIC Stamp的 EEPROM的内容。图4-6显示了程序MovementsWithSubroutines.bs2的存储映射图。注意左边的 EEPROM压缩图。底部小框图阴影部分显示了程序MovementsWithSubroutines.bs2占用的内存数量。
图4-6 BASIC Stamp存储器映射图
注意:该内存映射图是从BASIC Stamp编辑器v2.1版本上截取下来的,对于不同版本的编辑器,其返回的内存 映射都回包含相同的信息,只不过采用了不同的格式。
在这儿,你也注意到声明成字变量的“counter”变量在RAM映射图的寄存器0中。
这个程序在输入的时候似乎比较大,但是它只占用了可用2048字节程序存储区的136个字节。
现在那里有足够的空间来存放一串相当长的指令。因为在内存中一个字符占用一个字节,因此还有 可以存放1912个单字符指令的空间。
EEPROM指南
到目前为止你已经试过三种不同的编程方法来使机器人向前走,左转,右转和向后走。每种方 法都有它的优点,但是如果你要让机器人执行一个更长、更复杂的巡航动作时,用这些方法都很麻 烦。下面要介绍的一个例子将在子程序中使用现在已经熟悉的代码段来实现每个基本巡航动作,每 个基本动作都用一个单字母代码来引用。一长串代码字母就表示一长串的巡航动作,它们存储在 EEPROM中,在程序执行过程中读出并解码。这样避免了重复执行一长串子程序或者在每个 GOSUB指令执行前更改变量。
这种编程方法需要用到一些新的PBASIC指令:DATA指令,READ和SELECT ... CASE ...
ENDSELECT指令,在试验新的例程之前,你先学习一下如何使用这些新的指令。
每个基本动作都由一个与子程序相对应的单字母代码来引用:F代表Forward,B代表
Backward,L代表Left_Turn,R代表Right_Turn。复杂的机器人运动可以很快的用这样一串代码 字母设计出来。字母串的最后一个字母是Q,意思是动作完成后退出(Quit)。下载程序时用DATA 指令把这个字母串存在EEPROM中。如下所示:
DATA "FLFFRBLBBQ"
每个字母被存在EEPROM中的一个字节里,由地址0开始(除非你告诉它存在那里),READ
基础机器人制作与编程 指令能够在程序运行的时候从EEPROM中读出这个字母串。这些值可以这样从DO…LOOP循环中 读出:
DO UNTIL (instruction = "Q") READ address, instruction address = address + 1
' PBASIC code block omitted here.
LOOP
address变量是存放每个代码字母的EEPROM字节的地址。Instruction变量拥有存储在该地址 的实际值,即代码字符。注意每执行一次循环,address 变量的值增加1。这就使每个字母从地址 0开始从EEPROM字节中连续的被读出。
DO…LOOP指令有可选的条件,这对于不同的情况非常便利。DO UNTIL (condition)...LOOP 允许循环重复执行直到确定的情况发生。DO WHILE (condition)...LOOP允许当某一个条件存在时 循环重复执行。你的例子将使用DO…LOOP UNTIL。在这种情况下,DO…LOOP 循环重复执行 直到从EEPROM中读到Q字符。
SELECT...CASE...ENDSELECT语句用来选择一个变量并一个一个对照执行CASE列中对应 的代码块。下面的代码块将根据instruction变量中的字母值调用合适的子程序
这些概念都在下面例程中体现。
例程: EepromNavigation.bs2
z 仔细阅读程序EepromNavigation.bs2的代码指令和注释来理解程序的每一部分是如何工 作。
z 输入、保存并运行程序 EepromNavigation.bs2.
' EepromNavigation.bs2
' Navigate using characters stored in EEPROM.
' {$STAMP BS2} ' Stamp directive.
' {$PBASIC 2.5} ' PBASIC directive.
DEBUG "Program Running!"
'-[ Variables ]--- pulseCount VAR Word ' Stores number of pulses.
address VAR Byte ' Stores EEPROM address.
instruction VAR Byte ' Stores EEPROM instruction.
'---[ EEPROMData ]--- ' Address: 0123456789 ' These two commented lines show
' |||||||||| ' EEPROM address of each datum.
DATA "FLFFRBLBBQ" ' Navigation instructions.
'---[ Initialization ]--- SELECT instruction
CASE "F": GOSUB Forward CASE "B": GOSUB Backward CASE "R": GOSUB Right_Turn CASE "L": GOSUB Left_Turn ENDSELECT
基础机器人制作与编程 FREQOUT 4, 2000, 3000 ' Signal program start/reset.
'---[ MainRoutine ]--- DO UNTIL (instruction = "Q")
READ address, instruction ' Data at address in instruction.
address = address + 1 ' Add 1 to address for next read.
SELECT instruction ' Call a different subroutine
CASE "F": GOSUB Forward ' for each possible character CASE "B": GOSUB Backward ' that can be fetched from CASE "L": GOSUB Left_Turn ' EEPROM.
CASE "R": GOSUB Right_Turn ENDSELECT
LOOP
END ' Stop executing until reset.
' --[ Subroutine Forward ]--- Forward: ' Forward subroutine.
FOR pulseCount = 1 TO 64 ' Send 64 forward pulses.
PULSOUT 13, 850 ' 1.7 ms pulse to left servo.
PULSOUT 12, 650 ' 1.3 ms pulse to right servo.
PAUSE 20 ' Pause for 20 ms.
NEXT
RETURN ' Return to Main Routine loop.
' ---[ Subroutine -Backward ]--- Backward: ' Backward subroutine.
FOR pulseCount = 1 TO 64 ' Send 64 backward pulses.
PULSOUT 13, 650 ' 1.3 ms pulse to left servo.
PULSOUT 12, 850 ' 1.7 ms pulse to right servo.
PAUSE 20 ' Pause for 20 ms.
NEXT
RETURN ' Return to Main Routine loop.
' ---[ Subroutine - Left_Turn ]--- Left_Turn: ' Left turn subroutine.
FOR pulseCount = 1 TO 24 ' Send 24 left rotate pulses.
PULSOUT 13, 650 ' 1.3 ms pulse to left servo.
PULSOUT 12, 650 ' 1.3 ms pulse to right servo.
PAUSE 20 ' Pause for 20 ms.
NEXT
RETURN ' Return to Main Routine loop.
' ---[ Subroutine – Right_Turn ]---
基础机器人制作与编程 Right_Turn: ' right turn subroutine.
FOR pulseCount = 1 TO 24 ' Send 24 right rotate pulses.
PULSOUT 13, 850 ' 1.7 ms pulse to left servo.
PULSOUT 12, 850 ' 1.7 ms pulse to right servo.
PAUSE 20 ' Pause for 20 ms.
NEXT
RETURN ' Return to Main Routine section.
你的机器人是否走了一个矩形,向前走两个边,向后走两个边?如果它走得更像一个梯形,你 可能需要调节转动程序中FOR...NEXT 的EndValue值,使其旋转精确的90度。
该你了
z 让BASIC Stamp 编辑器中程序 EepromNavigation.bs2处于激活状态时,单击 Run菜单并 选择 Memory Map。
如图4-7,在EEPROM 详细映射图的开始部分,你存储的数据代码指令将以蓝色高亮显示。显 示的数据是十六进制的ASCII码,与你在DATA指令中输入的字符相对应。
图4-7 EEPROM中存储的数据代码指令 z 单击图中左下角的Display ASCII复选框。
现在这些数据代码指令将以一种更熟悉的形式显示在图4-8中。它显示的是你使用DATA指令 记录的实际字符,不是ASCII码。
基础机器人制作与编程
z 试着更改,增加或删除DATA指令中的动作字符,重新运行程序,记住:DATA指令中的 最后字符应该是“Q”。
z 更改DATA指令使机器人进行你熟悉的向前,左转,右转和后退等系列基本动作。
z 试着增加第二个DATA指令,记着将“Q”字符从第一个DATA指令的最后移到第二个指令 的最后,否则程序只执行第一个DATA指令。
READ Pulses_Count + addressOffset, Word pulseCount READ Pulses_Left + addressOffset, Word pulseLeft READ Pulses_Right + addressOffset, Word pulseRight addressOffset = addressOffset + 2
' PBASIC code block omitted here.
LOOP UNTIL (pulseCount = 0)
第一次执行完循环后,addressOffset = 0。第一个READ指令将从Pulses_Count标签的第一 个地址中得到一个值64,并把它放在pulseCount变量中。第二个READ指令从Pulses_Left标签指 定的第一个地址中得到值850,并把它放在pulseLeft变量中。第三个READ指令从Pulses_ Right 标签指定的第一个地址得到值650,并把它放在pulseRight变量中。注意,这些数值都是上面代码 片段第“0”列的三个值,当将这些数值替换下面的代码块中的变量时,
FOR counter = 1 TO pulseCount
基础机器人制作与编程 PULSOUT 13, pulseLeft
PULSOUT 12, pulseRight PAUSE 20
NEXT 程序变成:
FOR counter = 1 TO 64 PULSOUT 13, 850 PULSOUT 12, 650 PAUSE 20
NEXT
你还记得该代码块产生的基本操作吗?
z 看上面代码段的其它列,猜想一下,FOR…NEXT代码块执行第二,第三和第四个循 环会是怎样的?
z 看下面程序的LOOP UNTIL (pulseCount = 0),<>代表“不等于”,执行第五次循 环会是怎样的呢?
z 输入、保存并运行程序EepromNavigationWithWordValues.bs2.
' EepromNavigationWithWordValues.bs2
' Store lists of word values that dictate.
' {$STAMP BS2} ' Stamp directive.
' {$PBASIC 2.5} ' PBASIC directive.
DEBUG "Program Running!"
'--[ Variables ]--- counter VAR Word
pulseCount VAR Word ' Stores number of pulses.
addressOffset VAR Byte ' Stores offset from label.
instruction VAR Byte ' Stores EEPROM instruction.
pulseRight VAR Word ' Stores servo pulse widths.
pulseLeft VAR Word
' --[ EEPROM Data ]--- --- ' addressOffset 0 2 4 6 8
Pulses_Count DATA Word 64, Word 24, Word 24, Word 64, Word 0 Pulses_Left DATA Word 850, Word 650, Word 850, Word 650 Pulses_Right DATA Word 650, Word 650, Word 850, Word 850
' -[ Initialization ]--- --- FREQOUT 4, 2000, 3000 ' Signal program start/reset.
' --[ Main Routine ]---- --- DO
READ Pulses_Count + addressOffset, Word pulseCount READ Pulses_Left + addressOffset, Word pulseLeft READ Pulses_Right + addressOffset, Word pulseRight
基础机器人制作与编程 addressOffset = addressOffset + 2
FOR counter = 1 TO pulseCount PULSOUT 13, pulseLeft
PULSOUT 12, pulseRight PAUSE 20
NEXT
LOOP UNTIL (pulseCount = 0)
END ' Stop executing until reset.
你的机器人是否已经执行了你所熟悉的向前—向左—向右—向后的顺序动作呢?现在是不是 有点厌烦了?是不是还想让机器人做点其它的动作或者创建你自己的程序?
该你了―设计你自己的程序
z 以一个新的文件名保存程序EepromNavigationWithWordValues.bs2.
z 用下面的代码代替DATA 语句
z 运行更改后的程序,观察Boe-Bot会做些什么。
Pulses_Count DATA Word 60, Word 80, Word 100, Word 110,
Word 110, Word 100, Word 80, Word 60, Word 0 Pulses_Left DATA Word 850, Word 800, Word 785, Word 760, Word 750,
Word 740, Word 715, Word 700, Word 650, Word 750 Pulses_Right DATA Word 650, Word 700, Word 715, Word 740, Word 750,
Word 760, Word 785, Word 800, Word 850, Word 750 z 做一个三行的表格,一行对应一条DATA指令。一列是每个你想让机器人做的动作,在
Pulses_Count行中增加Word 0项。
z 用这个表列出机器人运行方案,填充每个动作的代码块所需的FOR...NEXT循环的 EndValue 和PULSOUT Duration参数。
z 用新的数据代替DATA指令。
z 输入、保存并运行程序,看机器人是不是按你的想法运动呢?继续做直到你满意为止。
工程素质和技能归纳
z 机器人基本动作的归纳、定义和程序编制;
z 机器人基本动作的精确调整和叠代调试方法;
z 机器人运动速度的测量;
z 测量出机器人的运动速度后,根据需要运行的距离计算程序所需的循环次数;
z 机器人的加速和减速运动编程;
z 子程序的概念和使用,用子程序简化机器人巡航程序;
z 微控制器的内存映射的概念和数据的存储,DATA指令的使用等
z SELECT…CASE…ENDSELECT语句的使用和DO…LOOP循环条件的使用;
z 用这些新的功能语句进一步简化巡航程序的编写等。
基础机器人制作与编程
© 2008 Open-Tech. All rights reserved. 62