Arduino Basic

From Hamsterworks Wiki!

Jump to: navigation, search

This is my port of TinyBasic from 68K assembler to the Arduino platform.

Tinybasic screenshot.png

Contents

News flash!

Somebody has taken this project and run with it...

https://github.com/BleuLlama/TinyBasicPlus

Plenty of enhancements and fixes - thanks Scott!

The project sketch / source file

Here is the arduino project File:Tinybasic.pde. Just rename it to .cpp for use in other environments.

What I've been running it on

I'm running it on an Arduino Mini Pro and my Pololu 3pi robot, both AVRmega parts. But it is in generic C, and can be compiled under Visual Studio or GCC for testing/development purposes, and should move to any of the larger microcontrollers with ease.

As is it currently configured for the Arduino environment, but should you wish to move it to a different platform it should be relatively easy. It compiles fine in AVR studio...

If you really want to get it up and running fast, get a Seeeduino or Arduino Uno and be running in seconds with no special hardware.

The original source

This project is based on the TinyBasic source from http://members.shaw.ca/gbrandly/68ktinyb.html.

Moving to a different environment

The required customisation is as follows - An "unsigned char inchar()" function is needed to read a character from the input device. - A "void outchar()" function is needed to write to the output device - Adjust the size of "program[]" to use up as much memory as you dare (you need to leave some for the CPU stack though) - Just call "loop()" when you have initialised your hardware.

Ardinuo appends the equivalent of

 int main(void)
 {
   setup();
   while(1)
     loop();
 }

which you may need to add depending on your target environment.

A quick note on tiny basic

TinyBASIC is a little odd. It has no 'THEN' in the IF statement, and its syntax doesn't allow unary for minus anywhere other than the start of an expression. (i.e. A = 1*-2 is bad, but A=-1*2 is OK).

Adding new keywords or functions

As provided, the interpreter is good for nothing - you will need to add your own statements or functions to do useful stuff. For my 3pi I've added "MOTORS x,y", "DELAY <ms>" and "SENSORS()". Because these are platform dependant I haven't included them.

Adding a statement

  • Add your word into keywords[] before the trailing 0, adding the 0x80 to the final character.
  • define a new unique KW_<keyword> #define following the table.
  • Add your keyword specific code to the switch() construct following "interperateAtTxtpos:"
  • "POKE" and "GOTO" make a good template of how to do things.

Adding a function

  • Add your function name into func_tab[] before the trailing 0, adding the 0x80 to the final character.
  • define a new unique FUNC_<name> #define following the table
  • Add your function dependant code into the "switch(f)" in the expr4() function.

Memory layout issue

The original TinyBASIC memory layout is wrong.

  • Basic code (Dynamic, grows up)
  • Free space
  • Variables (Fixed size)
  • Program maintained call stack. (Fixed size, grows down)

I've shuffled this around...

  • Variables (Fixed size)
  • Basic code (Dynamic, grows up)
  • Free space
  • Program maintained call stack. (Dynamic, grows down)

This allows for a deeper FOR/GOSUB call stack - a small programs will leave a deep stack.

My Arduino TinyBasic to-do list

None of this stuff will get done, but if others are interested in doing something...

  • The program memory space is set at compile time (see "static unsigned char program[412];). I have this at more than than 1412 on an AVR with 2k RAM.
  • There are still a lot of tidy-ups to do to reduce code size.
  • GetLn might not handle most special characters correctly (NL & CR, DEL vs CTRL+H, CTRL+C and others).
  • I'm not sure that the static constants such as tables end up in program memory. AVR studio reports it better during the build.
  • The expression evaluator is recursive, and doesn't check how much stack is available. As I don't know how big the CPU stack is a really deep expression (eg "A=((((((((((B)))))))))") may crash it.
  • Still tossing a coin on what to do for LOAD and SAVE... perhaps store program in EEPROM, but EEPROM is only half the size of RAM. Perhaps by using tokens it will take more...
  • No keywords to access the standard Arduino hardware have been added - I'm thinking of "DELAY <ms>", "DOUT <pin>,<value>" and "AOUT <pin>,<value> " statements and a "DIN(<PIN>)" and "AIN(<PIN>)" function at least! Any suggestions / contributions would be great
  • POKE() is poked :-). But it is a template for future expansion.
  • Might be some weirdness, like IF A=B GOTO 99: PRINT "Hi" might fail oddly.
  • I bet I sometimes call the wrong error routines (e.g. "qhow" and "qwhat") , but I plan on making these more explicit (e.g. "Syntax error", "Divide by zero", "Out of memory"...)
  • Testing, testing, testing...

Please let me know if you have any success and of any bugs you fix! :-)

The source code

It is here at tinybasic_source

Updated version

Here's a version provided by Scott Lawrence: File:Tinybasicplus.zip

Attached is an updated version of your BASIC that adds a few things:

Support for the SD Library.  I've tested it with a Seeeduino SD Shield
(Which i snagged at Radio Shack for $13).
New additions:
FILES   - displays a list of files in the root of the SD card (seems
to misbehave after a lot of IO for some reason)
LOAD - load a file in as a program
SAVE - save a file out
MEM - display the amount of free memory currently available.
? - synonymous with PRINT.  Save a few bytes in your program by using
this standard shortener!

I was noticing some quirks with it;
- INPUT seems broken.  not sure about this, i might just have the syntax wrong
- LET A = A + B does not work, however LET A = A+B does work.

I implemented LOAD and SAVE by having a global file pointer.  When you
go to save a file, it opens the output file, and sets a flag that all
output goes to the file instead of to the serial port.  Then it just
does a standard file listing.  Similarly, when you load, it sets the
input as from the file, then the getchar routine just sucks from the
file instead of the serial line until there's nothing left.  It seems
a bit quirky, I have yet to figure out exactly what the quirks are and
fix them.

For what it's worth, including the SD library eats 9k of program
space, so I made it optional.
#define ENABLE_FILEIO 1
to turn it on.  Also, since some SD card shields have a different chip
select line, I made that a #define at the top as well.

Personal tools