This project is about building a small IoT computer running with BASIC with low cost components. There is a lot of powerful hardware on the market that can be used for it. Integrating them properly can get a lot of compute power for almost no money.
The computer presented here serves in my home as an MQTT display station. It is connected to Wifi, reads messages from an MQTT broker, displays and records them. It has an PS2 keyboard interface and can be used as a standalone system. Alternatively the programs on it can be changes via the serial or USB interface.
I use some really funny components to build it. The key ingredients to the recipe, the Wemos D1 R1 board and the SD/DS1307 datalogger shield are incompatible without hardware modifications.
The fun in this project is to make two things work together that weren't properly designed for it.
The Wemos D1 R1 boards are based on a ESP8266 and look like an Arduino UNO. The pinout is somehow identical to the UNO which can be misleading. Some of the ESP8266 pins have different functions which makes it difficult to use UNO shields on the Wemos D1. Wemos tried to position them as an Arduino UNO competitor. After a while they discontinued the Website and the manufacturing. The boards are still on the market from third party vendors at 6 Euros a piece. They offer a lot of processing power and memory.
The second ingredient to the recipe is a data logger shield. These shield where designed and manufactured for UNOs and contain a DS1307 real time clock, a SD card holder and a small prototype area. Many Chinese manufactures make them now following and original design from around 2010. They come at 4 Euros a piece.
Typical prices for the two components together would be 10 Euros.
Now, if you simply plug the shield to to board and try to get it running, you will be disappointed. The ESP8266 CPU will not even boot. The reason for this is that the designers of the data logging shield interpreted Arduino specs very narrowly and the designers of the Wemos board interpreted them very generously.
All this can be overcome with a bit of shield modding. This makes the project a little more advanced. This tutorial is about the inner workings of some of these components and technologies used.
Fix the SPI on the ShieldThe shield uses pins 10, 11, 12, and 13 for SPI which is Arduino UNO standard. Pin 10 is the slave select pin SS. To avoid SPI slaves from activating during boot, the shield pulls pin 10 on HIGH with a small resistor. This is not uncommon and good practice when using SPI peripherals.
The designers of the Wemos board have attached one digital output of the ESP12 to this pin. They named it D10 and even labeled it SS on the board.
Unfortunately they have used GPIO15 pin of the ESP12 for this.
Now, ESP8266 board don't boot if this pin is pulled to high during boot. This means that practically no shield using SPI and (correctly) pulling up SS to HIGH will run on the Wemos D1 board. The board designers could have used any other ESP12 GIO for it but that would have made their life just a little more complicated because it would have made the board layout more complex.
A simple solution for this is simply to bend the D10 pin upward or remove it altogether like it is shown in the first image.
With this modification the microcontroller will boot correctly.
To use the SD card on the shield, another pin of the Arduino has to be connected to the pin of the board. The best choice is to use D8. It is close to pin 10 and it has no special function on the ESP8266. It is a no interrupt pin and can only be used as digital I/O.
To make the shield work solder a little link from pin 8 to pin 10 on the board. Now, the SD card can be used
Fix the I2C WiringThe Wemos board uses the pins in the upper left corner next to the reset button for the two I2C signals SDA and SCL. These pins are connected with GPIO 4 for SDA and GPIO 5 for SCL. These are the standard ESP8266 I2C GPIOs. These two pins are also connected to D3 and D4.
An Arduino UNO also would also have the SDA and SCL pins on the upper left. They also use the A4 and A5 pins diagonally on the other side of the board. The two sets of pins are connected.
The Wemos D1 board designers did not do that. The pins A2-A5 on the bottom right corner of the board are unconnected. They could have connected A4 and A5 to the standard ESP8266 I2C pins as well, but they left this away.
Unfortunately, the shield expects SDA and SCL on pins A4 and A4. There are no extra SDA and SCL pins.
This can be fixed on the shield adding two wires to connect the right pins a shown in the schematics.
With these two modifications can use the shield on the Wemos. There is a real time clock, an SD card and a working I2C bus for all kind of sensors.
To build a standalone computer a keyboard is needed. PS2 keyboards can be connected easily. The PS2 socket can also be used to connect other peripherals.
PS2 needs two pins, one of them for the clock signal and the other for data input. The clock pin has to be interrupt ready. The only free interrupt ready pin of the Wemos with the shield is pin 9. Pin 8 cannot be used for interrupts on the ESP8266. This is the reason why pin 8 is used for the slave select and pin 9 is left free in the shield modding. Pin 2 is available for the data connection of the PS2 socket. Connect the pins to the PS2 connector like it is shown in the drawing. Clock goes to pin 9 and 8 to data.
The complete shield now has quite a few wires on the top and can be mounted on the Wemos D1 R1 board. I usually put them on a small piece of plywood and add a breadboard if I use the parts in the lab.
You will need an Arduino IDE on your computer that has the ESP8266 board definitions. http://arduino.esp8266.com/stable/package_esp8266com_index.json. There are a lot of tutorials on how to use the IDE with ESP so I won't write anything about it here.
I use my IoT BASIC interpreter on this hardware configuration. If you want to do this, download the software from my repo https://github.com/slviajero/tinybasic/tree/main/IoTBasic.
First you need to set the language set in IoTBasic.ino.
#define BASICFULL
Set the definition BASICFULL. This will compile a full featured BASIC interpreter.
The interpreter is a completely new implementation. No part of the Arduino Tiny BASIC has been used despite the name the folder. It implements most features of the powerful BASIC interpreters of the 80s and some more things.
You will need to edit the file hardware-arduino.h and set the definition
#define WEMOSSHIELD
All other hardware definitions at the beginning of the code should be #undef.
This will set all necessary hardware parameters for this configuration. If you want to use the PS2 keyboard, please download my patched PS2 library from https://github.com/slviajero/PS2Keyboard. The unmodified Arduino library doesn't work with ESP8266.
Edit the file wifisettings.h and enter your WLAN settings.
Compile the sketch with the board setting Wemos D1 R1 in the ESP8266 board menu of the Arduino IDE. Finally insert a formatted SD card. After uploading the software you should see the BASIC input prompt when connecting with the Arduino serial monitor.
Stefan's Basic 1.4a Memory 41000 1014
The first number after memory is the RAM, the second is the EEPROM size.
Entering the netstat command here will show you the Wifi and MQTT server status. The system will answer.
> netstat
if Wifi is connected successfully.
Add a DisplayFor this extension you will need a 20x4 LCD display with an I2C interface. Smaller displays also work but the display dimension have to be changed in the BASIC code.
Power the system down, then connect the display to the 5V and GND power pins and to the SCL and SDA pins of the microcontroller. Restart the system.
PRINT &2, "hello world"
should show the text on the screen.
PUT &2, 12
clears the screen. 12 is the ASCII value for form feed. &2 is the display output stream. The display can scroll and has a subset of the VT52 control characters for cursor control.
If you don't see anything, check the brightness control at the back of the display.
Write MQTT messages from BASICAn overview of the BASIC commands and how to use IoT BASIC can be found on my my wiki. The language is mostly standard BASIC with a few differences like Apple 1 style string handling and IoT helper functions.
This tutorial will focus mainly on the MQTT features of the BASIC interpreter. MQTT is build in as a proof of concept code with unencrypted an unauthenticated communication. The MQTT broker address is compiled into the code:
const char* mqtt_server = "test.mosquitto.org";
This is the mosquitto test server. Any other open MQTT broker can be used.
Writing to an MQTT topic is initiated by first opening the MQTT I/O stream with a topic name.
OPEN &9, "iotbasic/data" ,1
&9 is the MQTT I/O stream in BASIC, the string is the topic name and 1 is the flag to open a stream for writing. The netstat command should now show an output like this
> netstat
The output topic is set to the specified value. Sending a message to this topics is done with the PRINT command
PRINT &9, "hello world"
The network status should now be
> netstat
An MQTT state 0 indicates and active connection. The MQTT name is set randomly to make it unique. If you listen to the topic on a client program you can see the message. I recommend EasyMQTT app from https://www.easymqtt.app for this.
Read MQTT messages from BASICA stream can be open for reading with the command
OPEN &9, "iotbasic/commands", 0
The flag 0 opens the stream for reading. Sending a message to the topic from an MQTT client like EasyMQTT will cause the message to be buffered for reading in BASIC with a background task. The BASIC function AVAIL(9) checks if there is data to read. If
PRINT AVAIL(9)
delivers a value greater 0 you can input and display the message with
INPUT &9, A$
BASIC will keep the read stream open and active with keep alive mechanisms indefinitely. If the connection to the MQTT server fails it is automatically reconnected. If no read topic is specified, the MQTT connection is closed after a while but rebuild after the next PRINT to the channel &9. All the background tasks and ESP8266 specific yield() mechanisms are handled by the BASIC interpreter as well.
Measuring Data and Sending Them Via MQTTA typical device to connect to a board like this could be a soil humidity sensor. Every Arduino hobbyist has one laying around somewhere. Alternatively, an analog light sensor could also be used.
Connect the sensor to the power and the analog input A0 of the shield.
In BASIC, analog data is read with the AREAD() function. Check the sensor by typing
PRINT AREAD(AZERO)
The output should be a value between 0 and 1023 according to the conventions of Arduino analog data.
A small BASIC program to measure the soil humidity periodically and transfer the data to the MQTT broker could look like this:
10 OPEN &9,"iotbasic/data",1
After typing this into the console, save the program with
SAVE "hum.bas"
to the SD card. Then start the program with RUN. You should see MQTT messages coming in in your EasyMQTT app every second. The program can be interrupted by sending the # character via the serial console and you return to the command prompt.
If a program is saved with the name
SAVE "autoexec.bas"
it will be started automatically after reboot of the system. This way you can disconnect the microcontroller from the computer, connect it to a power supply or battery and start to run it as a standalone sensor system.
Like in interactive mode, sending # from the console will stop the program and give you access to the command prompt.
Activate the Real Time ClockThe real time clock has to be set once to run. Setting the time is done using the special array @t() in BASIC. Setting the clock to Sunday, March, 6th 2022, 14:10:00 can be done by entering
@t(0)=0 : @t(1)=10 : @t(2)=14 : @t(3)=6 : @t(4)=3 : @t(5)=22 : @t(6)=0
after the BASIC command prompt. The elements of the time can either be displayed individually or together using the special string @t$.
PRINT @T$
will show
14:10:02-6/3/22
Saving Data to the SD CardModify the program above by typing in a few more lines
50 OPEN &16,"hum.dat",2
Save the program, then run it. You should see data in the MQTT channel.
After a while, disconnect the microcontroller from the computer, remove the SD card and look at the file hum.dat on it.
It will contain the data line by line with timestamp and measured value. The OPEN statement opens the file channel &16 with the filename "hum.dat" with the flag 2 which means append. The file is closed after every write to make sure it is flushed correctly to the disk. The SD card can be removed and reinserted.
Receive and Display MQTT MessagesType in NEW to clear the program storage, then enter a small MQTT reader program.
10 OPEN &9,"iotbasic/commands",0
Save the program by typing in
SAVE "display.bas"
and run it with RUN.
When the program is running, send MQTT message to the topic iotbasic/commands using EasyMQTT and see them displayed on the LCD screen with the respective time stamp.
Line 20 in the BASIC program checks for incoming messages every second and loops until a message is reached. Please note that MQTT messages are received asynchronously by the system. The real MQTT client loop is hidden in the BASIC interpreter. It runs at a 32 ms pace.
Connect a KeyboardWe are now ready to connect a keyboard and make the computer standalone.
PS2 is not hot pluggable. Please disconnect the microcontroller from your computer, plug in the keyboard and then reconnect it. Some PS2 keyboard don't initialize properly at power up. They need a lot of power and charging their internal capacitors takes a bit too long. Disconnect the system briefly from power and reconnect it, if this happens. Observe the keyboard status lines.
Keyboard IO is done through the input channel &2 in BASIC. Code like
INPUT &2, A$
lets you input data from the keyboard.
If this works you can recompile the interpreter with the flag
#define STANDALONE
which makes it a standalone system with keyboard and display I/O as the default. Read more about this im my wiki https://github.com/slviajero/tinybasic/wiki or in the chapter https://github.com/slviajero/tinybasic/wiki/Projects:-3.-Rockwell-AIM-65-lookalike-computer
Closing Words on This and ThatEvil electronicsSome of you may have noticed the evil part in some of the things we are doing. The ESP8266 is a 3.3V machine. The chip is not specified for 5V operations. Yet we connect a PS2 keyboard to it. It needs 5V and will put that higher voltage on the input pins of the Wemos D1 R1. Actually, our peripherals should fry the chip.
There was a lot of discussion if the board is 5V tolerant when it appeared on the market. Officially and by specification it never was. In practice it is and someone from Wemos has also stated it in a user forum.
I have tried all kinds of 5V components on its I2C bus and they all work fine. This is why I like the board so much despite its design flaws. It is not a beginner board but it has a lot of potential.
Why BASIC?Why use BASIC, the most outdated of the outdated programming languages to do IoT? Lua and Python are much better for it. C++ is the implementation language of most microcontroller software. And why a BASIC dialect which is based on language concepts from 1977 instead the newer one?
First of all, because it is fun to create a programming language from scratch, to own the code and to modify it according to your own needs.
Secondly, I observed that most of my IoT programs have a very simple logic. They are of the type "Read a sensor and broadcast the value every 10 seconds." What makes them complex is the hardware integration, sensor code, I2C and SPI protocols and MQTT connection stuff. All this complexity is encapsulated in the BASIC interpreter code which currently is approximately 200 kB. The easy part can be done in BASIC very quickly.
Thirdly, the BASIC interpreter scales from very small Arduino UNO systems up to ESP32 and Raspberry PI. It is the some language with the same features. The small BASIC programs are fully portable between these different systems. I still compile the interpreter in its smallest version for a AVR 168 CPU to make sure that it stays compact. It is stable and fast as it avoids some of the slow things of the old BASIC. It tokenizes fully and handles memory very economically. It is deterministic and real time capable.
More stuff to comeThe Wifi and MQTT code is only a proof of concept. Encrypted and authenticated MQTT is needed. LoraWAN is in preparation. For Lora I worked with the Heltech Lora system which have many interesting features.
Libraries usedBoard linksMore on BASIC computersThere are a few more computers based on this software.
If you need a 80s style home computers, you might want to look at this instructable https://www.instructables.com/Build-a-80s-Style-Home-Computer-From-Scratch-From-/
A smaller system with graphics would be https://www.instructables.com/A-Arduino-RP2040-Standalone-IoT-Computer-Running-B/
They are software compatible to the Wemos / datalogger system.
The basics of the BASIC interpreter are explained in the tutorials on built-in examples.
Comments