×

编译BASIC解释器方案

消耗积分:0 | 格式:zip | 大小:0.46 MB | 2022-10-19

分享资料个

描述

最初的想法

Steve Wozniak 曾说过,创建 Apple 1 整数基本解释器是他一生中最大的职业挑战。我试着做史蒂夫所做的事情,从头开始编写一个 BASIC 解释器,而不使用任何其他人的任何代码。我想要在一台非常小的计算机上有用的东西。事实证明,它可能是 Arduino 的一个不错的工具。对 I/O 功能的交互式访问使测试电子设备变得容易。可以使用 BASIC 命令控制所有引脚。程序和数据可以存储在 EEPROM 中。我实现了大部分标准 BASIC 语言,包括字符串、浮点数和大部分 Dartmouth 语言集。

查看我的 github 页面以找到代码https://github.com/slviajero/tinybasic

下载并编译 BASIC 解释器

下载 TinybasicArduino 中的代码并将其与 hardware-arduino.h 和 basic.h 一起导入您的 Arduino IDE。打开代码并查看代码最开头的设置部分。对于像上面提到的那些标准的 8 位 AVR 系统,初始部分需要看起来像这样

#undef MINGW
#undef MSDOS
#undef

除非您想为 MSDOS 或 Windows 编译,否则不要更改此设置。作为下面的语言功能部分,这些设置可以是

#undef	BASICFULL
#undef	BASICINTEGER
#define	BASICSIMPLE
#undef	BASICMINIMAL
#undef	BASICTINYWITHFLOAT

如果您使用 Arduino UNO 为 am Integer BASIC 定义 BASICSIMPLE 宏,并使用包含字符串、数组和全套 BASIC 控制结构的合理语言集。

对于闪存较大的 Arduino,可以使用 BASICFULL。这将在 MEGA 或 NANO Every 等 8 位平台上生成 36 kB 的可执行文件。

打开硬件-arduino.h。在硬件定义部分,除了

#define ARDUINOEEPROM

使用这些设置编译代码并查看内存消耗。对于 UNO,这应该是一个 24 kB 的可执行文件,并且在编译后应该有 1.4 kB 的可用 RAM 报告。上传代码。

试试看!

使用具有以下设置的 Arduino IDE 的串行监视器 * 波特率 9600 * 换行

poYBAGNOSJiARYQ2AAA1tTI50Ys736.png
 

解释器应该显示一条启动行,如

Stefan的基础1.2内存1024 1024

然后提示输入。

第一个数字是 BASIC 可用的 RAM,第二个数字是可用的 EEPROM。可用 RAM 可能因语言功能而异。1KB 大约是一个人得到的数量,因为 BASIC 的内部变量需要其余的。

输入您的第一个 BASIC 程序

10 打印“你好世界”

并运行它。

RUN 应显示“HELLO WORLD”并返回输入提示。

键入 SAVE 会将程序存储到 EEPROM 中。您可以通过重置您的 Arduino 来尝试这一点,然后使用 LOAD 重新加载程序。键入 LIST 进行检查。

眨眼程序

与 Arduinos 上的“Hello World”等价的是 blink 程序。

在 BASIC 中它看起来像这样

10 PINM 13,1
20 DELAY 1000
30 DWRITE 13,1
40 DELAY 1000
50 DWRITE 13,0
60 GOTO 20 

输入它并使用 RUN 命令启动它。Arduino 上的小 LED 现在应该每隔 1 秒闪烁一次。发送字符 '#' 将中断程序并使解释器返回到命令提示符。

你可以在这里下载blink程序blink.bas

'#' 中断程序。所有其他输入都被忽略。键入除“#”之外的任何其他字符都将淹没串行缓冲区,并且将不再识别中断字符。

Arduino 函数的工作原理与 C++ 中的差不多。有关移植的命令,请参见此处您可以在交互模式下尝试它们。这是在 Arduino 上运行 BASIC 的优势之一。同样,您可以通过键入 SAVE 将您的工作保存到 EEPROM,并在以后使用 LOAD 重新加载程序。

从 EEPROM 自动运行

如果您已将程序保存到 EEPROM,您可以通过键入 SET 1, 1 来激活自动运行标志

如果您现在使用重置按钮或断开并连接电源来重置 Arduino,程序将自动启动。不会出现命令提示符。

从串行控制台发送“#”会中断程序。

如果您现在键入 LIST,则不会显示任何程序。自动运行程序不加载到 RAM 中,而是直接从 EEPROM 中执行。这样,整个 RAM 在自动运行模式下可用。可以通过命令 SET 1, 0 删除自动运行标志。

重置后会出现命令提示符。

这里有更多关于这整组命令的内容“ SD 卡、文件命令、EEPROM 和相关内容”。

读取数据

此项目需要任何模拟传感器和电缆。一个很好的例子是图片中显示的光电传感器。它在绝对黑暗时返回模拟值 1023,在最大亮度时返回 0。

pYYBAGNOSJqAD0pLAACblcuvdrU235.png
 

将传感器的模拟输出引脚连接到模拟端口 A0,将数字输出连接到 Arduino 的数字端口 D2。然后输入 BASIC 程序

10 PINM AZERO ,0
20 M0=1024:M1=0
30 FOR I=1 TO 10
40 L=AREAD (AZERO )
50 IF M0>L THEN M0=L
60 IF M1THEN M1=L
70 DELAY 1000
80 NEXT I
90 PRINT "Minimum ",M0
100 PRINT "Maximum ",M1

并使用 SAVE 将其保存到 EEPROM。运行程序将记录传感器每秒读取的值 10 次,并计算最小值和最大值。AZERO 是一个常数,包含最低的模拟引脚 A0。A1 将是 AZERO+1。

存储数据

Arduino 的 EEPROM 可用于存储测量数据。接下来测量一分钟的平均光强度并将结果存储在 EEPROM 中:

10 PRINT "Previous measurement ",@E(1)
20 PRINT "Starting new measurement"
30 L=0
40 FOR I=1 TO 60
50 L=L+AREAD(AZERO)/10
60 DELAY 1000
70 NEXT 
80 @E(1)=L/60
90 PRINT "Average = ",@E(1)

使用 SET 1, 1 激活自动运行功能后,无需计算机即可使用 Arduino 测量数据。下次 Arduino 连接到计算机时可以读取该值。

终端程序

Arduino IDE 有一个简单的串行监视器,但不能下载和上传数据。存在许多解决方案。我推荐并使用 Roger Meier 的CoolTerm

存在适用于 Windows、Linux 和 Mac 的二进制文件。该程序是一个功能齐全的串行终端。我从MacUpdate下载了我的 Mac 二进制文件

在连接到 Arduino 之前,必须在选项菜单中配置终端程序:

pYYBAGNOSJ-AIhU6AABfKL2ZkfM588.png
 

将端口设置为您的串行端口(与使用的 Arduino IDE 相同),波特率设置为 9600,数据设置为 8,奇偶校验设置为无,停止设置为 1。这些是 Arduino 串行和 Stefan 的 BASIC 的默认设置。在终端配置页面中选择了这些选项:

poYBAGNOSKGAXngYAAB3CsfdPiI261.png
 

原始模式传输每个按键,按键模拟必须是 Unix 风格的 LF。除此之外,“Handle DEL and BS”需要删除一行中的数据,“Handle FF”可以从 BASIC 清除屏幕。这些是标准 BASIC 语言集中的最小终端功能。

在 Arduino 上使用 Stefan 的 BASIC 的终端设置可以在这里下载:CoolTerm 设置该程序不是一个功能齐全的 vt52/100 兼容终端程序。

上传或下载程序

对于文件上传,转到 CoolTerm 中的连接菜单,然后选择发送文本/二进制文件。

一个很好的例子是 101 BASIC 游戏中的字母猜谜游戏它适合 1k Arduino BASIC 内存。上传程序,享受 1975 年的游戏乐趣。

CoolTerm 的当前设置没有流量控制。时序问题可能导致上传失败,因为 Arduino 上的 BASIC 接收字符的速度不够快。一个简单的解决方法是在 CoolTerm 的配置菜单的 Transmit 页面中添加小的延迟。3ms 的线路延迟就可以完成这项工作。

pYYBAGNOSKSAEBg2AAB5wd3MQu8850.png
 

可以使用捕获文本/二进制文件功能从 Arduino 下载程序。启动捕获类型 LIST 后,再停止捕获。编辑计算机上的文件以删除最后一行和第一行。或者,您可以使用非常基本的 python 串行监视器连接到 Arduino。串行端口必须在程序的第一行中进行编辑。Control L 和 Control S 用于上传和下载。

基于 LCD 屏蔽的 BASIC 系统

pYYBAGNOSKaAHcLVAABSRHVhUII979.png
 

Arduino 最好的小型硬件扩展之一是带有 4 个按钮的 16x2 LCD 扩展板。它们可以很容易地从 BASIC 程序中使用。像以前一样编译解释器,但使用附加设置

#define LCDSHIELD
#define DISPLAYCANSCROLL

在硬件 arduino.h 中。

这将激活 LCD 屏的显示驱动程序和硬件代码。编译并上传脚本。使用串行监视器或 CoolTerm 连接到 Arduino。进入

打印 &2, "你好世界"

并查看显示屏。它应该在显示屏的左上角显示字符串。

poYBAGNOSKiAJ5QNAAC5q7fgjcU984.png
 

修饰符 &2 将打印命令的输出重定向到显示器。通过上面的设置,可以作为一个迷你终端访问,能够滚动和一些终端命令。键入 PUT &2, 12 以清除显示屏幕。12 是 Form Feed 的 ASCII 码,用于清屏。

液晶屏的键盘功能

输入代码

10 PUT &2, 12
20 PRINT &2,"LCD shield test"
30 PRINT &2,"Key code: ";
40 @X=8:@Y=1
50 GET &2,A
60 IF A<>0 THEN PRINT &2,A;
70 DELAY 10
80 GOTO 30

或使用shield.bas将其上传到带有 CoolTerm 的 Arduino 键入 RUN 启动程序,然后按其中一个屏蔽键。密钥代码显示在第二行。

poYBAGNOSKyASf1jAABB5-ZCKQs766.png
 

键映射到单个字符的 ASCII 值 - 选择 = LF、右 = 2、左 = 1、上 = 3 和下 = 4。

GET &2, A 将这些值返回到变量 A 中,无论何时按下键,如果没有按下键,则返回 0。此代码使用特殊变量@X 和@Y 来定位光标。它们包含从 0 开始的光标的水平和垂直位置,可以由程序读取或分配。

显示缓冲区数组

键入以下代码,然后键入 RUN。

10 PUT &2, 12
20 X=0: Y=0
30 P=X+16*Y+1
40 @D(P)="X"
50 GET &2, A : IF A=0 THEN 50
60 A$=A
70 @D(P)=" "
80 IF A$="3" AND Y>0 THEN Y=Y-1
90 IF A$="4" AND Y<1 THEN Y=Y+1
100 IF A$="1" AND X>0 THEN X=X-1
110 IF A$="2" AND X<15 THEN X=X+1
120 IF A=10 GOSUB 200
130 DELAY 300
140 GOTO 30
200 PRINT "Selected", X, Y
210 DELAY 500
220 RETURN

您可以使用按键在“X”符号周围移动。按选择输出屏幕上符号的位置。

pYYBAGNOSK6ASgn2AAAyk6loMek701.png
 

该代码使用显示缓冲区数组@D()。写入它会直接在屏幕上显示一个字符。@D() 从数组下标 1 开始,从左到右、从上到下计算单元格。请注意程序如何在第 40 行和第 60 行将字符串转换为整数。在赋值中,字符串将第一个字符的 ASCII 码作为其整数值。这仅适用于赋值或整数表达式的右侧。该程序具有 Arduino 草图的典型结构——第 10 行和第 20 行是 setup(),第 30 到 140 行是循环,第 200 到 220 行是函数。

秒表

pYYBAGNOSLCAbnuUAABLcwTxZoo188.png
 

一个独立程序的例子是秒表。

100 REM "A little stopwatch using the 16*2 shield"
200 REM "The setup()"
210 D=0:T=0:U=0:S=0:C=0
220 PUT &2,12 : PRINT &2;"Time = ";
230 GOSUB 600
300 REM "The loop()"
320 GET &2,A
330 IF A=10
340 IF C=10
350 IF A="l" THEN 500
360 DELAY 10
370 IF S=1 THEN T=MILLIS (10)-D
380 IF T<>U THEN U=T:GOSUB 600
390 GOTO 300
400 S=(S+1)%2:IF S=1 THEN D=MILLIS (10)
499 GOTO 300
500 END
600 @Y=0:@X=8:PRINT &2;"       ";
605 @Y=0:@X=8:PRINT &2;T;
610 RETURN

输入程序或使用 Coolterm 上传程序。然后键入 SAVE : SET 1, 1 从 EEPROM 激活自动运行。从外部电源(如小电源条)为 Arduino 供电,使其成为独立的秒表。

下一步是什么?

BASIC 的发展远远超出了本项目中描述的功能。与此同时,它拥有 Wire、许多不同的显示器、网络,并且可以为更大的计算机供电。我还为它移植了大部分 Arduino 示例库。

如果您对此感兴趣,请点击这些链接中的任何一个

Arduino 库中的所有标准示例都在我的仓库中。


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

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.obk20.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'编译BASIC解释器方案',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.obk20.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);