User Manual

Version 1.44.2

© ciccioCB 2022





The Annex firmware including the AnnexToolKit and this manual are Copyright 2017-2020 by Francesco Ceccarella (ciccioCB).


The compiled object code (the .bin file) for the Annex firmware is free software: you can use or redistribute it as you please except for commercial purposes. It is not allowed to distribute or embed it into products that are sold or for any other activity making or intended to make a profit.


The compiled object code (the .exe file) for the AnnexToolKit utility is free software: you can use or redistribute it as you please except for commercial purposes. It is not allowed to distribute or embed it into products that are sold or for any other activity making or intended to make a profit.


This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even



This manual is distributed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 France license (CC BY-NC-SA 3.0)


The above copyright notice and this permission notice shall be included in all copies or redistributions of the Software in any form.


License and credits

Adafruit BNO055 Orientation Sensor library is written by KTOWN is Copyright (c) Adafruit Industries. It is released under MIT license.

TFT_eSPI display Library is Copyright ©  2017 Bodmer. It is released under FreeBSD license.

Adafruit NeoPixel library is Copyright (c) Adafruit. It is released under MIT license.

Makuna/NeoPixelBus library is Copyright © by Michael C. Miller. It is released under LGPL license.

Adafruit PWM Servo Driver Library is Copyright (c) Adafruit. It is released under MIT license.

Arduino Library for Dallas Temperature ICs is Copyright (c) Miles Burton <>. It is released under LGPL license.

OneWire Library is Copyright 1999-2006 Dallas Semiconductor Corporation and Copyright (c) 2007, Jim Studt.

Adafruit DHT Humidity & Temperature Sensor Library is Copyright (c) Adafruit. It is released under MIT license.

ESP8266 and ESP32 Oled Driver library is Copyright (c) 2016 by Daniel Eichhorn and Copyright (c) 2016 by Fabrice Weinberg. It is released under MIT license.

ESP8266Ping is Copyright (c) Daniele Colanardi. It is released under LGPL license.

ESP AsyncTCP library is Copyright (c) 2016 Hristo Gochkov. It is released under LGPL license.

ESP AsyncWebServer library is Copyright (c) 2016 Hristo Gochkov. It is released under LGPL license.

IRremoteESP8266 library is Copyright (c) Sebastien Warin, Mark Szabo, Ken Shirriff, David Conran. It is released under LGPL license.

uRTCLib is Copyright (c) 2015 Naguissa ( It is released under LGPL license.

BME280 library is written by Limor Fried/Ladyada for Adafruit Industries. It is released under BSD license,

APDS9960 library is written by Shawn Hymel for Sparkfun Electronics. It is released under Beerware license.

PID Library is written by Brett Beauregard ( It  is released under MIT license.

MQTT library pubsubclient is Copyright (c) 2008-2015 Nicholas O'Leary. It is released under MIT license

MFRC522 library is written by Miguel Balboa.

The Javascript Editor  EditArea is  Copyright © 2008 Christophe Dolivet. It is released under LGPL license.

The base of the interpreter comes from the original project "MiniBasic" by Malcom Mclean.

The MFRD522 library is written by Miguel Balboa and is released as free and unencumbered software released into the public domain.



A very big thank you to Robin Baker (Electroguard) for his great involvement in the project by supporting all the tests on the real hardware (bought with his money), and all the advices that allowed me to add a lot of functionality, not to mention the Huge work he did while documenting the project on the website.



Content :

Introduction:                                                                                                                                                         15

Interpreter:                                                                                                                                                            17

Branch labels                                                                                                                                                        17

Variables:                                                                                                                                                              17

Arrays:                                                                                                                                                                   19

Scope of the variables:                                                                                                                                        19

Bases of the language                                                                                                                                         20

OPERATORS AND PRECEDENCE                                                                                                                   20

Basic internal keywords:                                                                                                                                    22

IF command :                                                                                                                                                   22

FOR loop                                                                                                                                                          23

WHILE WEND loop                                                                                                                                          23

DO LOOP loop                                                                                                                                                 24

SELECT CASE                                                                                                                                                25

GOTO                                                                                                                                                              25

GOSUB                                                                                                                                                            26

DATA                                                                                                                                                                26

END                                                                                                                                                                  27

EXIT                                                                                                                                                                 27

SUB                                                                                                                                                                  27

Logical / boolean Operations                                                                                                                             29

ERRORS HANDLING                                                                                                                                          30

ONERROR ABORT                                                                                                                                  30

ONERROR IGNORE                                                                                                                                30

ONERROR SKIP [nn]                                                                                                                                30

ONERROR CLEAR                                                                                                                                   30

ONERROR GOTO [label | OFF]                                                                                                               30

BAS.ERRLINE                                                                                                                                           31

BAS.ERRNUM                                                                                                                                          31

BAS.ERRMSG$                                                                                                                                        31

HOW the interpreter works with the HTML code and Objects :                                                                    31

HTML Objects                                                                                                                                                  35

TIMERS                                                                                                                                                                 40

EVENTS                                                                                                                                                                40

Button Event                                                                                                                                                     40

OnHtmlChange Event                                                                                                                                      41

OnHtmlReloadEvent                                                                                                                                        41

OnInfrared Event                                                                                                                                             42

OnSerial Event                                                                                                                                                 42

OnSerial2 Event                                                                                                                                               42

OnTouch Event                                                                                                                                                42

OnUDP Event                                                                                                                                                  42

OnWgetAsync Event                                                                                                                                       43

OnUrlMessage Event                                                                                                                                       43

OnEspNowMsg Event                                                                                                                                     46

OnEspNowError Event                                                                                                                                    47

OnMQTT Event                                                                                                                                               47

WiFI CONNECTIONS                                                                                                                                           47

PROGRAM AUTORUN                                                                                                                                       49

RECOVERY MODE                                                                                                                                              50

WATCHDOG TIMER                                                                                                                                            50

DATE - TIME timekeeper                                                                                                                                    51

Unix Time functions                                                                                                                                            52

SPIFFS File System                                                                                                                                             52

Ret = FILE.COPY(filename$, newfile$)                                                                                                    53

Ret = FILE.DELETE(filename$)                                                                                                                53

Ret = FILE.EXISTS(filename$)                                                                                                                 53

Ret = FILE.RENAME(oldname$, newname$)                                                                                          53

Ret = FILE.SIZE(filename$)                                                                                                                      53

Ret$ = FILE.DIR$(path$)                                                                                                                           53

Ret$ = FILE.READ$(filename$, [line_num] | [start, length])                                                                     53

FILE.APPEND filename$, content$                                                                                                          53

FILE.SAVE filename$, content$                                                                                                                53

I/O BUFFERS                                                                                                                                                        54

Read Operations                                                                                                                                              56

Write Operations                                                                                                                                              56

Special operations                                                                                                                                            57

Advanced operations                                                                                                                                       57

Bit operations                                                                                                                                                    58

Buffer copy                                                                                                                                                      58

Code examples :                                                                                                                                              58

DIGITAL I/O                                                                                                                                                          60

PIN INTERRUPTS                                                                                                                                          62

Analog input                                                                                                                                                         62

Hardware interfaces:                                                                                                                                           63

PWM                                                                                                                                                                63

SERVO                                                                                                                                                            63

COUNTERS                                                                                                                                                    64

PID controllers                                                                                                                                                  65

I2C BUS                                                                                                                                                           67

PCF8574 Module                                                                                                                                       68

ADS1115 Module                                                                                                                                       69

MCP23017 Module                                                                                                                                    72

SPI BUS                                                                                                                                                           73

74HC595 Module                                                                                                                                       74

MCP23S17 Module                                                                                                                                    75

LCD DISPLAY USING I2C                                                                                                                                   77

OLED DISPLAY                                                                                                                                                    81

ST7920 LCD DISPLAY                                                                                                                                         83

RTC module                                                                                                                                                          85

PCA9685 (PWM / Servo) Module                                                                                                                        86

TM1637 display module                                                                                                                                      88

TM1638 display module                                                                                                                                      90

MAX7219 8-Digits 7-segment display                                                                                                                91

MAX7219 Dot Matrix Display                                                                                                                              92

NeoPixel WS2812B led strips                                                                                                                             95

NeoPixel based WS2812b Dot Matrix DIsplay                                                                                                  96

TFT DISPLAY ILI9341                                                                                                                                        100

TouchScreen                                                                                                                                                  104

TFT DISPLAY ST7735                                                                                                                                       104

INFRARED INTERFACE                                                                                                                                   109

ULTRASONIC DISTANCE SENSOR HC-SR04                                                                                              112

DHT xx Temperature / Humidity Sensors                                                                                                       113

DS18B20 Temperature Sensors                                                                                                                       115

BNO055 Absolute Orientation Sensor                                                                                                            116

BME280 Combined humidity and pressure sensor                                                                                       118

APDS9960 Digital Proximity, Ambient Light, RGB and Gesture Sensor                                                    120

RFID MFRC522 RFID cards reader                                                                                                                  122

Writing NUID for UID changeable card (4 byte UID version)                                                                       126

AC LIGHT DIMMER                                                                                                                                           126

DIMMER.SETUP pin_in, pin_out, [,invert [,swap]]                                                                                  127

DIMMER.DELAY uSec                                                                                                                           127

DIMMER.LIMITS min, max                                                                                                                     127

DIMMER.BRIGHTNESS val                                                                                                                   127

DIMMER.STOP                                                                                                                                       127

SONOFF B1 LAMP                                                                                                                                            128

SONOFFB1.INIT                                                                                                                                     128

SONOFFB1.RGB r, g, b                                                                                                                          128

SONOFFB1.RGB color                                                                                                                           128

SONOFFB1.WHITE cold, warm                                                                                                             129

TUYA RGBCW LAMP                                                                                                                                        129

TUYALAMP.INIT [max_current_RGB, max_current_WHITE]                                                               129

TUYALAMP.RGB r, g, b                                                                                                                          130

TUYALAMP.RGB color                                                                                                                           130

TUYALAMP.WHITE cold, warm                                                                                                             130

FTP                                                                                                                                                                      131

BAS.FTP$                                                                                                                                                      131

Server data requests (GET and POST)                                                                                                           132

WGET$(server$, port, [,header])                                                                                                                   133

WGET$(url$ [,header])                                                                                                                                   133

WPOST$(server$, body$, port [,header])                                                                                                      133

WPOST$(url$, body$ [,header])                                                                                                                    133

WGETASYNC[(] server$, port, [,header [,ping]] [)]                                                                                       133

WGETASYNC[(] url$, [,header [,ping]] [)]                                                                                                      133

MQTT                                                                                                                                                                  134

Ret = MQTT.Setup(server$)                                                                                                                    136

Ret = MQTT.Fingerprint(fingerprint$)                                                                                                      136

Ret = MQTT.Connect(login$, pass$ [id$])                                                                                               136

Ret = MQTT.Connect("", "", [id$])                                                                                                            136

Ret = MQTT.Disconnect[()]                                                                                                                     136

Ret = MQTT.Publish(topic$, message$)                                                                                                 136

Ret = MQTT.Subscribe(topic$ [,Qos])                                                                                                     136

Ret = MQTT.UnSubscribe(topic$)                                                                                                           136

Ret = MQTT.Connected[()]                                                                                                                      136

Ret = MQTT.Status[()]                                                                                                                             136

ESP-NOW                                                                                                                                                            138

TELEGRAM (messenger) support                                                                                                                   148

CONVERSION FUNCTIONS                                                                                                                             150

CONVERT.DEGC_TO_F(degC)                                                                                                            150

CONVERT.F_TO_DEGC(degF)                                                                                                             150

CONVERT.TO_IEEE754(num)                                                                                                               150

CONVERT.FROM_IEEE754(iee754_bin)                                                                                              150

CONVERT.MAP(number, fromLow, fromHigh, toLow, toHigh)                                                             150

BAS CONSTANTS                                                                                                                                             150

BAS.VER                                                                                                                                                 152

BAS.VER$                                                                                                                                               152

BAS.ERRLINE                                                                                                                                         152

BAS.ERRNUM                                                                                                                                        152

BAS.ERRMSG$                                                                                                                                      152

BAS.FILENAME$                                                                                                                                    152

BAS.RTCMEM$                                                                                                                                      152

BAS.SSID$                                                                                                                                              152

BAS.PASSWORD$                                                                                                                                 152

BAS.LOAD                                                                                                                                               152

BAS.RESETREASON                                                                                                                             152

OPTION COMMANDS                                                                                                                                       153

OPTION.CPUFREQ 80|160                                                                                                                    153

OPTION.MAC mac$                                                                                                                               153

OPTION.LOWRAM memory                                                                                                                  153

OPTION.PWMFREQ freq                                                                                                                       153

OPTION.NTPSYNC                                                                                                                                153

OPTION.WDT timeout_msec                                                                                                                  153

OPTION.WDTRESET                                                                                                                             153

FUNCTIONS:                                                                                                                                                      154

NUMERICAL FUNCTIONS                                                                                                                          154

ABS(number)                                                                                                                                           168

ACOS(number)                                                                                                                                        168

ADC                                                                                                                                                          168

APDS9960.SETUP (mode)                                                                                                                     168

APDS9960.READGESTURE                                                                                                                  168

APDS9960.AMBIENT                                                                                                                              168

APDS9960.RED                                                                                                                                      168

APDS9960.GREEN                                                                                                                                 168

APDS9960.BLUE                                                                                                                                     168

APDS9960.PROXIMITY                                                                                                                          168

APDS9960.GESTUREGAIN (gain)                                                                                                         168

APDS9960.GESTURELED (intensity)                                                                                                    168

ASC(string$)                                                                                                                                             168

ASIN(number)                                                                                                                                          168

ATAN(number)                                                                                                                                         168

ATAN2(x, y)                                                                                                                                             168

BAS.VER                                                                                                                                                 168

BAS.ERRLINE                                                                                                                                         157

BAS.ERRNUM                                                                                                                                        157

BME280.SETUP(address)                                                                                                                       168

BME280.ALT(qnh)                                                                                                                                   168

BME280.HUM                                                                                                                                          168

BME280.QFE                                                                                                                                           168

BME280.QNH(altitude)                                                                                                                            168

BME280.TEMP                                                                                                                                        168

BNO055.SETUP( address)                                                                                                                      168

BNO055.HEADING                                                                                                                                 168

BNO055.PITCH                                                                                                                                       168

BNO055.ROLL                                                                                                                                         168

BNO055.VECTOR ( param, axis)                                                                                                           168

BNO055.CALIB [(param)]                                                                                                                        168

CINT(number)                                                                                                                                          168

CONVERT.DEGC_TO_F(degC)                                                                                                            168

CONVERT.F_TO_DEGC(degF)                                                                                                             168

CONVERT.TO_IEEE754(num)                                                                                                               168

CONVERT.FROM_IEEE754(ieee754_bin)                                                                                            168

CONVERT.MAP(number, fromLow, fromHigh, toLow, toHigh)                                                             160

COS(number)                                                                                                                                          160

COUNTER.COUNT (cnt)                                                                                                                        168

COUNTER.FREQ (cnt)                                                                                                                           168

COUNTER.PERIOD (cnt)                                                                                                                       168

DATEUNIX(date$)                                                                                                                                   168

DHT.TEMP                                                                                                                                              168

DHT.HUM                                                                                                                                                168

DHT.HEATINDEX                                                                                                                                   168

DISTANCE(pin_trig, pin_echo)                                                                                                                168

EMAIL from$, to$, subject$, message$                                                                                                  168

ESPNOW.ADD_PEER(MAC_add$)                                                                                                       168

ESPNOW.BEGIN                                                                                                                                    168

ESPNOW.DEL_PEER(MAC_add$)                                                                                                       168

ESPNOW.STOP                                                                                                                                      168

ESPNOW.WRITE( msg$)                                                                                                                       168

ESPNOW.WRITE( msg$,MAC_add$)                                                                                                    168

EXP(number)                                                                                                                                           168

FIX(number)                                                                                                                                             168

FILE.COPY(filename$, newfile$)                                                                                                            168

FILE.DELETE(filename$)                                                                                                                        162

FILE.EXISTS(filename$)                                                                                                                         168

FILE.RENAME(oldname$, newname$)                                                                                                  168

FILE.SIZE(filename$)                                                                                                                              162

FLASHFREE                                                                                                                                            168

FUSION.ANGLE(axis)                                                                                                                             168

INSTR([start], string$, pattern$)                                                                                                               168

I2C.LEN                                                                                                                                                    168

I2C.READ                                                                                                                                                168

I2C.READREGBYTE (i2c_address, register)                                                                                         168

I2C.END                                                                                                                                                   168

INT(number)                                                                                                                                             168

LEN(string$)                                                                                                                                             168

LOG(number)                                                                                                                                           168

MILLIS                                                                                                                                                      168

MQTT.Setup(server$ )                                                                                                                             164

MQTT.Fingerprint(fingerprint$)                                                                                                                165

MQTT.Connect(login$, pass$, [id$])                                                                                                        165

MQTT.Connect("", "", [id$])                                                                                                                      168

MQTT.Disconnect[()]                                                                                                                               168

MQTT.Publish(topic$, message$)                                                                                                           168

MQTT.Subscribe(topic$ [,Qos])                                                                                                               168

MQTT.UnSubscribe(topic$)                                                                                                                     168

MQTT.Connected[()]                                                                                                                                168

MQTT.Status[()]                                                                                                                                       168

NEO.GETPIXEL(pos)                                                                                                                              167

NEO.RGB(R, G, B)                                                                                                                                 168

PI                                                                                                                                                              168

PID1.COMPUTE( current_value, target_value)                                                                                      168

PIN(pin_number)                                                                                                                                      168

PING(host$)                                                                                                                                             168

POW(x, y)                                                                                                                                                168

RAMFREE                                                                                                                                               168

RND(number)                                                                                                                                          168

SERIAL.LEN                                                                                                                                            168

SERIAL2.LEN                                                                                                                                          168

SGN(number)                                                                                                                                          168

SIN(number)                                                                                                                                            168

SPI.BYTE(byte)                                                                                                                                       168

SQR(number)                                                                                                                                          168

TAN(number)                                                                                                                                           168

TFT.RGB(r,g,b)                                                                                                                                        168

TIMEUNIX(time$)                                                                                                                                    168

TM1638.BUTTONS                                                                                                                                 168

TOUCH.X                                                                                                                                                 168

TOUCH.Y                                                                                                                                                 168

VAL(string$)                                                                                                                                             168

WIFI.CHANNEL                                                                                                                                       168

WIFI.MODE                                                                                                                                             168

WIFI.NETWORKS  ( network$ )                                                                                                              168

WIFI.RSSI                                                                                                                                                169

WIFI.STATUS                                                                                                                                          169

WORD.COUNT( string$ [,delimiter$])                                                                                                     169

WORD.FIND( string$, find$ [,delimiter$])                                                                                                169

STRING FUNCTIONS                                                                                                                                  170

BAS.ERRMSG$                                                                                                                                      181

BAS.FILENAME$                                                                                                                                    181

BAS.FTP$( host$, login$, password$, file$, folder$)                                                                               181

BAS.PASSWORD$                                                                                                                                 181

BAS.RTCMEM$                                                                                                                                      181

BAS.SSID$                                                                                                                                              181

BAS.VER$                                                                                                                                               181

BIN$(number)                                                                                                                                          181

BUTTON$(name$, label [, id] )                                                                                                                181

CHECKBOX$( variable [,id])                                                                                                                   181

CHR$(number)                                                                                                                                        181

CSSID$(object_id, object_style)                                                                                                              181

DATE$[(format)]                                                                                                                                      181

ESPNOW.ERROR$                                                                                                                                181

ESPNOW.READ$                                                                                                                                   181

ESPNOW.REMOTE$                                                                                                                              181

FILE.DIR$[(path$)]                                                                                                                                   181

FILE.READ$(filename$,[line_num] | [start, length])                                                                                181

HEX$(number)                                                                                                                                         181

HtmlEventButton$                                                                                                                                    181

HtmlEventVar$                                                                                                                                         181

IMAGE$(path [,id])                                                                                                                                   181

IMAGEBUTTON$(path, label [,id])                                                                                                          181

IP$                                                                                                                                                            181

IR.GET$[ (param) ]                                                                                                                                  181

JSON$(string$, field$)                                                                                                                             181

LCASE$(string$)                                                                                                                                      181

LED$(variable[$] [,id])                                                                                                                              181

LEFT$(string$, num)                                                                                                                                181

LISTBOX$(variable$, "option1, option2, option3, ..." [, height]  [,id])                                                       181

METER$(variable, min, max [,id])                                                                                                           181

MID$(string$, start [,num])                                                                                                                       181

MAC$[ (id) ]                                                                                                                                              181

MQTT.Message$                                                                                                                                     181

MQTT.Topic$                                                                                                                                           181

OCT$(number)                                                                                                                                         181

PASSWORD$(variable [, id] )                                                                                                                  181

REPLACE$(expression$, find$, replacewith$)                                                                                        181

RIGHT$(string$, num)                                                                                                                             181

RTC.DATE$[(format)]                                                                                                                              181

RTC.TIME$                                                                                                                                              181

SERIAL.CHR$                                                                                                                                         181

SERIAL.INPUT$                                                                                                                                      181

SERIAL2.CHR$                                                                                                                                       181

SERIAL2.INPUT$                                                                                                                                    181

SLIDER$(variable, min, max [,step] [,id])                                                                                                181

SPACE$(number)                                                                                                                                    181

SPI.STRING$(data$, len)                                                                                                                        181

SPI.HEX$(datahex$, len)                                                                                                                         181

STR$ (number [,format$ [,toint]])                                                                                                             181

STRING$(num, char$)                                                                                                                            181

TEMPR$(pin_number [,ID])                                                                                                                     181

TEXTAREA$(variable [, id] )                                                                                                                    181

TEXTBOX$(variable [, id] )                                                                                                                      181

TRIM$(string$)                                                                                                                                         181

TIME$                                                                                                                                                       181

UCASE$(string$)                                                                                                                                     181

UDP.READ$                                                                                                                                            181

UDP.REMOTE$                                                                                                                                      181

UNIXDATE$(value [,format])                                                                                                                   181

UNIXTIME$(value)                                                                                                                                  181

URLMSGGET$ ([arg$])                                                                                                                           181

WGET$( http_server$, port [,header] )                                                                                                    181

WGET$( url$, [,header] )                                                                                                                          180

WGETRESULT$                                                                                                                                      180

WPOST$(server$, body$, port [,header])                                                                                                181

WPOST$(url$, body$,  [,header])                                                                                                            180

WORD$(string$, position [,delimiter$])                                                                                                    181

WORD.DELETE$(string$, position [delimiter$])                                                                                      181

WORD.EXTRACT$(string$, lead$, trail$)                                                                                               181

WORD.GETPARAM$( setting$, parameter$  [,separator$])                                                                  181

COMMANDS:                                                                                                                                                     181

AUTOREFRESH interval                                                                                                                        212

BAS.LOAD filename$                                                                                                                              212

BAS.RTCMEM$ = val$                                                                                                                           212

CLS                                                                                                                                                          212

CSS style_code$                                                                                                                                     212

COMMAND cmd$                                                                                                                                   212

COUNTER.RESET cnt                                                                                                                           212

COUNTER.SETUP cnt, pin [,mode]                                                                                                       212

CSSEXTERNAL file$                                                                                                                              212

DATA const1 [,const2] ...                                                                                                                         212

DHT.SETUP pin, model                                                                                                                           212

EMAIL.SETUP server$, port, user_name$, password$ [, debug]                                                           212

EMAILASYNC from$, to$, subject$, message$                                                                                     212

FILE.APPEND filename$, content$                                                                                                        212

FILE.SAVE filename$, content$                                                                                                              212

FUSION.INIT                                                                                                                                           212

FUSION.MADGWICK ax, ay, az, gx, gy, gz                                                                                           212

FUSION.MADGWICK ax, ay, az, gx, gy, gz, mx, my, mz                                                                     212

FUSION.MAHONY ax, ay, az, gx, gy, gz, mx, my, mz                                                                          212

FUSION.BETA =                                                                                                                                     212

FUSION.ZETA =                                                                                                                                      212

FUSION.KI =                                                                                                                                            212

FUSION.KP =                                                                                                                                          212

HTML code$                                                                                                                                            212

I2C.SETUP sda_pin, scl_pin [,freq [,stretch]]                                                                                          212

I2C.BEGIN address                                                                                                                                 212

I2C.END                                                                                                                                                   212

I2C.REQFROM address, length                                                                                                              212

I2C.READREGARRAY i2c_address, register, nb_of_bytes, Array()                                                     212

I2C.WRITE value                                                                                                                                     212

I2C.WRITEREGBYTE i2c_address,register, value                                                                                 212

I2C.WRITEREGARRAY i2c_address, register, nb_of_bytes, Array()                                                    212

INPUT.TIMEOUT timeout                                                                                                                       212

INPUT["prompt$";] variable                                                                                                                      212

INTERRUPT pin_no, {OFF | label}                                                                                                          212

IR.INIT pin_rx | OFF [, pin_tx]                                                                                                                  212

IR.SEND type, code$, bits                                                                                                                       212

JSCALL javaCode$                                                                                                                                 212

JSCRIPT script$                                                                                                                                      212

JSEXTERNAL file$                                                                                                                                  212

LCD.INIT address, cols, rows                                                                                                                  212

LCD.CLS                                                                                                                                                  212

LCD.CUSTOM char, array()                                                                                                                   212

LCD.PRINT x, y, text$                                                                                                                             212

LCD.WRITE char                                                                                                                                     212

LOCAL var1 [,var2], ...                                                                                                                             212

MAXDISPLAY.SETUP CS_pin                                                                                                               212

MAXDISPLAY.PRINT msg$ [,‘brightness]                                                                                              212

MAXSCROLL.SETUP nb_devices, CS_pin [,reverse]                                                                           212

MAXSCROLL.PRINT msg$                                                                                                                    212

MAXSCROLL.NEXT msg$                                                                                                                     212

MAXSCROLL.SHOW pos [, brightness]                                                                                                 212

MAXSCROLL.SCROLL [brightness]                                                                                                       212

MAXSCROLL.OSCILLATE [brightness]                                                                                                 212

NEO.PIXEL led_pos, R, G, B [, disable]                                                                                                  212

NEO.PIXEL led_pos, COLOR [, disable]                                                                                                 212

NEO.SETUP [nb_led]                                                                                                                              212

NEO.STRIP led_start_pos, led_end_pos, R, G, B [, disable]                                                                  212

NEO.STRIP led_start_pos, led_end_pos, COLOR [, disable]                                                                 212

NEOSCROLL.SETUP nb_devices, pin [,serpentine]                                                                              212

NEOSCROLL.PRINT msg$                                                                                                                    212

NEOSCROLL.NEXT msg$                                                                                                                     212

NEOSCROLL.COLORS col$                                                                                                                  212

NEOSCROLL. NEXTCOLORS col$                                                                                                       212

NEOSCROLL.SHOW pos [, brightness]                                                                                                 212

NEOSCROLL.TEXT msg$                                                                                                                      212

NEOSCROLL.SCROLL [‘brightness]                                                                                                      212

NEOSCROLL.OSCILLATE [‘brightness]                                                                                                 212

OLED.CLS                                                                                                                                               212

OLED.INIT orientation [,model]                                                                                                                212

OLED.REFRESH fmt                                                                                                                              212

OLED.COLOR color                                                                                                                                212

OLED.PIXEL x, y                                                                                                                                     212

OLED.LINE x1, y1, x2, y2                                                                                                                       212

OLED.RECT x,y, width, height [,fill]                                                                                                        212

OLED.CIRCLE x, y, radius [, fill]                                                                                                             212

OLED.FONT font_num                                                                                                                            212

OLED.PRINT x, y, text$ [background]                                                                                                    212

OLED.IMAGE x, y, image$                                                                                                                     212

ONERROR ABORT or ONERROR IGNORE or ONERROR SKIP [nn] or ONERROR CLEAR or ONERROR GOTO label                                                                                                                         212

ONESPNOWERROR [label | OFF]                                                                                                        212

ONESPNOWMSG [label | OFF]                                                                                                             212

ONGESTURE [label | OFF]                                                                                                                     212

ONHTMLCHANGE [label | OFF]                                                                                                            212

ONHTMLRELOAD [label | OFF]                                                                                                             212

ONINFRARED label                                                                                                                                212

OnMQTT label                                                                                                                                         212

ONSERIAL [label | OFF]                                                                                                                          212

ONSERIAL2 [label | OFF]                                                                                                                        212

ONTOUCH [label | OFF]                                                                                                                         212

ONUDP [label | OFF]                                                                                                                               212

ONURLMESSAGE [label | OFF]                                                                                                             212

ONWGETASYNC [label | OFF]                                                                                                               212

OPTION.CPUFREQ 80|160                                                                                                                    212

OPTION.MAC mac$                                                                                                                               212

OPTION.LOWRAM value                                                                                                                       212

OPTION.PWMFREQ value                                                                                                                     212

OPTION.NTPSYNC                                                                                                                                212

OPTION.WDT timeout_msec                                                                                                                  212

OPTION.WDTRESET                                                                                                                             212

PAUSE delay                                                                                                                                           212

PCA9685.SETUP addr [,freq]                                                                                                                  212

PCA9685.SETFREQ freq                                                                                                                        212

PCA9685.PWM pin, value                                                                                                                       212

PID1.INIT Kp, Ki, Kd                                                                                                                                212

PID1.LIMITS min, max                                                                                                                            212

PID1.PERIOD msec                                                                                                                                212

PID1.PARAMS Kp, Ki, Kd                                                                                                                       212

PID1.SETMODE mode                                                                                                                           212

PIN(pin_number) = val                                                                                                                             212

PIN.MODE pin_number, mode [,PULLUP]                                                                                             212

PIN.TONE pin, freq [,duration]                                                                                                                 212

PRINT expression[[,; ]expression] ...                                                                                                       212

PRINT2 expression [[,; ]expression] ...                                                                                                    212

PWM(pin_number) = value                                                                                                                      212

READ var1 [,var2] ...                                                                                                                                212

REBOOT                                                                                                                                                  212

REFRESH                                                                                                                                                212

RESTORE                                                                                                                                               212

RTC.SETTIME Year, Month, Day, Hours, Minutes, Seconds                                                                212

SERIAL.BYTE ch1 [,ch2] . . .                                                                                                                   212

SERIAL2.BYTE ch1 [,ch2] . . .                                                                                                                 212

SERIAL.MODE baudrate [, bits, parity, stop]                                                                                          212

SERIAL2.MODE baudrate, pin_tx, pin rx  [, bits, parity, stop]                                                                 212

SERVO id, value                                                                                                                                      212

SERVO.SETUP id, pin_number | OFF                                                                                                   212

SETTIME Year, Month, Day, Hours, Minutes, Seconds                                                                         212

SLEEP value                                                                                                                                            212

SPI.SETUP speed [,data_mode [, bit_order]]                                                                                          212

SPI.SETMODE data_mode                                                                                                                     212

SPI.SETFREQ speed                                                                                                                              212

ST7920.INIT CS_pin                                                                                                                                212

ST7920.CLS                                                                                                                                             212

ST7920.REFRESH fmt                                                                                                                           212

ST7920.COLOR color                                                                                                                             212

ST7920.PIXEL x, y                                                                                                                                  212

ST7920.LINE x1, y1, x2, y2                                                                                                                     212

ST7920.RECT x,y, width, height [,fill]                                                                                                      212

ST7920.CIRCLE x, y, radius [, fill]                                                                                                           212

ST7920.FONT font_num                                                                                                                         212

ST7920.PRINT x, y, text$ [background]                                                                                                 212

ST7920.IMAGE x, y, image$                                                                                                                   212

TM1637.PRINT msg$ [, brightness]                                                                                                        212

TM1637.SETUP data_pin, clock_pin [, bit_delay] [, display_type]]                                                         212

TM1638.PRINT msg$ [, brightness ]                                                                                                       212

TM1638.SETUP data_pin, clock_pin, strobe_pin                                                                                    212

TM1638.LEDS val                                                                                                                                    212

TFT.BMP filename$, [x, y [, back_color] ]                                                                                               212

TFT.CIRCLE x, y, radius [, fill]                                                                                                                 212

TFT.FILL color                                                                                                                                          212

TFT.INIT CS_pin, DC_pin, orientation [Display_width, Display_height, Variant]                                    212

TFT.LINE x1, y1, x2, y2, col                                                                                                                    212

TFT.PRINT expression [[,; ]expression] ...                                                                                               212

TFT.RECT x, y, width, height, color [ [,fill] ,[round_radius] ]                                                                    212

TFT.TEXT.COL color [,backcolor]                                                                                                           212

TFT.TEXT.POS x, y                                                                                                                                212

TFT.TEXT.SIZE size                                                                                                                                212

TIMER0 interval, label                                                                                                                              212

TIMER1 interval, label                                                                                                                              212

TOUCH.SETUP T_CS_pin                                                                                                                     212

TRACE message                                                                                                                                     212

UDP.BEGIN(port)                                                                                                                                    212

UDP.REPLY msg$                                                                                                                                  212

UDP.STOP                                                                                                                                              212

UDP.WRITE ip, port, msg$                                                                                                                      212

URLMSGRETURN msg$ [,content_type$]                                                                                             212

WAIT                                                                                                                                                        212

WGETASYNC [(] server$, port, [,header [,ping]] [)]                                                                                212

WGETASYNC [(] url$, [,header [,ping]] [)]                                                                                               211

WIFI.APMODE SSID$, password$ [, channel] [, IP$ , MASK$]                                                             211

WIFI.AWAKE                                                                                                                                           211

WIFI.CONNECT SSID$, password$ [, BSSID$] [, IP$ , MASK$ [, GATEWAY$]]                                 211

WIFI.POWER pow                                                                                                                                   212

WIFI.SCAN                                                                                                                                              212

WIFI.SLEEP                                                                                                                                             212

WLOG expression[[,; ]expression] ...                                                                                                       212

WORD.DELPARAM setting$, parameter$, [,separator$]                                                                       212

WORD.SETPARAM  setting$, parameter$, value$ [,separator$]                                                           212

BASIC KEYWORDS                                                                                                                                           213

CASE                                                                                                                                                       215

DIM array(size) [, …] [= init1, init2, …]                                                                                                     215

DO                                                                                                                                                            215

ELSE                                                                                                                                                        215

END [IF | SELECT | SUB]                                                                                                                       215

ENDIF                                                                                                                                                      215

EXIT {DO | FOR | SUB}                                                                                                                          215

FOR                                                                                                                                                          215

GOSUB [label | lab$]                                                                                                                                215

GOTO [label | lab$]                                                                                                                                  215

IF                                                                                                                                                              215

LET var = expression                                                                                                                               215

LOOP                                                                                                                                                       215

NEXT                                                                                                                                                        215

OFF                                                                                                                                                          215

OUTPUT                                                                                                                                                  215

PULLUP                                                                                                                                                   215

REM                                                                                                                                                         215

RETURN                                                                                                                                                  215

SELECT                                                                                                                                                   215

SPECIAL                                                                                                                                                  215

STEP                                                                                                                                                        215

SUB                                                                                                                                                          215

THEN                                                                                                                                                       215

TO                                                                                                                                                            215

UNTIL                                                                                                                                                       215

WEND                                                                                                                                                      215

WHILE                                                                                                                                                      215



Annex WI-Fi RDS (Rapid Development Suite) is a version of the "basic" language developed to run on low cost ESP8266 WIFI devices.

It takes from the original concept of ESPbasic - which I cooperated on and contributed to in the past - but is a completely re-designed breakaway project designed to offer improved functionality and reliability.

The intention was to create a  Basic language for the ESP which complies as much as possible with the original GWbasic / Visual Basic - from which it shares many concepts / ideas / syntax - and also from the excellent project "Micromite" of  Geoff Graham.

The base of the interpreter comes from the original project "MiniBasic" by Malcom Mclean.

The text editor comes from the original project "EditArea" by Christophe Dolivet.


-       Includes an internal IDE so can be programmed directly using your web browser without any additional utility (even with your phone/tablet).

-       Syntax  highlighting with context sensitive Help

-       A programmable web server including file server

-       Supports OTA (over the air) update.

-       Support async events (interrupts, timers, web access, UDP, ….)

-       Breakpoints, immediate execution of commands, display of variables, single step.

-       A basic interpreter with floating point variables (double precision) and string variables, multidimensional arrays (float and string), user defined subroutines.

-       Access to any available I/O pin for input/output, PWM and Servo.

-       Errors Handling .

-       Support TCP (HTTP) GET and POST for communications

-       Support for UDP for communications.

-       Support for sending Emails using SMTP SSL servers

-       Support for AJAX communications

-       Support for ESP-NOW communications

-       Support for MQTT communications

-       Support for FTP communications

-       Accompanying utility suite includes Flasher, File Manager, HTML Converter, Backup/Restore to bin or zip, integrated Serial Port Monitor, OTA (over the air) update server and UDP Console.

-       IMU / AHRS Fusion algorithms 6 DOF and 9 DOF (Madgwick and Mahony)

-       4 Channels PID controller


The following devices are supported directly with dedicated commands / functions :

-       DHT11, DHT21 or DHT22 Temperature / Humidity Sensors

-       DS18B20 Temperature sensor

-       LCD HD44780 with I2C interface module (1, 2 or 4 lines with 16 or 20 chars per line)

-       LCD Display based on chipset ST7920 with 128x64 pixels monochrome

-       OLED Display based on chipset SSD1306 or SH1106 with 128x64 pixels monochrome

-       TFT Display based on Chipset ILI9341 with 320x240 pixels and 16 bits colors

-       TM1637 4 digits 7-segments display

-       TM1638 8 digits 7-segments display including 8 leds and 8 buttons

-       MAX7219 8 digits 7-segments display

-       MAX7219 8x8 dot matrix display modules

-       Neopixel WS2812 led strips

-       Neopixel WS2812 8x8 dot matrix display

-       PCA9685 PWM/SERVO module

-       Infrared interface with many RC protocols (transmission and reception)

-       RTC module (DS1307 or DS3231)

-       HC-SR04 ultrasonic sensor for distance measurement

-       BNO055 Absolute Orientation Sensor

-       BME280 Combined humidity and pressure sensor

-       APDS9960 Digital Proximity, Ambient Light, RGB and Gesture Sensor

-       RFID MFRC522 cards reader


The basic interpreter works by reading a script file saved to the esp local disk filing system (SPIFFS).

In order to use less RAM, the user script is copied from the disk into a dedicated area in the flash memory where it is executed, so only the list of the program lines, the branch labels and the list of the user defined subroutines get loaded into memory.

This is slower compared to other approaches, but permits maximum memory to be available for user variables and program use.

Another performance consideration is that the ESP8266 must be capable of executing several activities in the background (web server, file server, ..) so needs sufficient free memory for running such tasks, and those parallel tasks must obviously have an impact on script performance..

So performance-wise, the interpreter is not particularly fast, but it should be fast enough for most tasks you may require. I tried to run some "1980s BASIC benchmark" taken from "the back shed" forum and I can say that the performance is around 2 to 4 times slower than a micromite @48 Mhz; but (IMHO) that’s not bad considering all the additional connectivity and web functionalities provided by the esp module.


Basic program lines :

A typical script line should comply with the following syntax :

[label:] command [argument1 [,argument2 …..]]


Script lines may contain several commands on the same line if separated by the colon character ":".

[label:] command1 [argument1 [,argument2 …..]]: command2 [argument1 [,argument2 …..]]

It must be noted that use of several commands on the same line is not recommended and will cause program errors if the line contains GOSUB or user defined subroutine calls.


All program jumps (eg: GOTO, GOSUB) are referenced by their branch label names - line numbers are not referenced in scripts, they are merely available in the editor as a programming convenience if wished.


NOTE : The gosub and the call to user defined subroutines must be used alone on the script line.


Branch labels

Branch labels should not be named the same as a command name, and must follow the same format as variables (see below).

A branch label definition must begin the line, and a colon (":") must terminate the label definition.

Any references to the defined label (GOTOs and GOSUBs etc) do not use a colon.

Example :


b = 10

a = 20 : c = 30



LABEL1:  print "Label1"




The interpreter has 2 types of variables:

-          Floating Point (double precision)

-          String

Floating point variables can store numbers with decimal point; they can also store integer numbers with a precision equivalent to 32bits.

Strings contain sequences of characters (example "my program") and must be terminated by "$".

The strings are not limited in size, they are only limited by the amount of memory available.

NOTE: The string variables cannot contain the character with ASCII code 0 (zero) because it is used internally as an end of string delimiter.


The variables are defined as any name starting with an alpha character (a, b, ..z) followed by any alphanumeric character (a..z, 0..9); it can also include the "_" (underscore).

The case is don’t care, so  ‘’Num"  is equivalent to "nuM".

The name length is limited to 31 characters maximum, including the "$" for the strings.

There are no limits in terms of number of variables; the only limit is the RAM memory available.



NUM = 10.56

myString$ = "this is My String"

this_is_my_value$  = "ESP8266"

number = 8826621


Numeric variables and string variables are managed separately so the same name can be used; this means that A and A$ are different variables that can coexist at the same time (even if this could lead to confusion).



The numeric constants can have the following format :

A = 5 : Z = 1.5

B = 1.23456E5   -> same as 123456

C = 1.23456E+5  -> same as 123456

D = 1.23456E-3  -> same as 0.00123456


The string constants are simply defined as a text between quotes:

A$ = "This is my string" : B$ = "another string"


The strings can include the character " (quote) simply typing it two times :

A$ = "this is ""MY"" string"


The | (vertical bar) can also be used as a string literal.

This permit to include the " (quote) easily inside a string constant :

A$ = |this is a "string" constant|


The hexadecimal constants can be defined simply prefixing it with &H :

E = &HABCD -> equivalent of decimal 43981  (hexadecimal constant)

F = &HA0   -> equivalent of decimal 160


The binary constants can be defined simply prefixing it with &B :

E = &B00000101  -> equivalent of decimal 5  (binary constant)

F = &B10000001   -> equivalent of decimal 129


The octal constants can be defined simply prefixing it with &O :

E = &O377  -> equivalent of decimal 255 (octal constant)

F = &O17   -> equivalent of decimal 15


Arrays are defined using the DIM command.

Their names follow the same rules as the regular variables and are followed by parenthesis (brackets) containing the index. The subscript always starts from 0.

The scope of the Arrays is always global (see next paragraph).


DIM A(100)              define a floating point array with 101 elements (index from 0 to 100)

DIM ABC$(50)          define a string array with 51 elements (index from 0 to 50)

A(15) = 1234.5678

ABC$(49) = "Hi friend!"


The arrays can have up to 5 subscripts (dimensions), examples:

DIM A(50,50)  -> create a floating point array with 51*51 elements (2601)

DIM J$(4, 4, 4)  -> create a string array with 5 * 5 * 5 elements (125)




The numerical Arrays are always initialised at 0 with the command DIM.

The string Arrays are always initialised as null string with the command DIM.

There are no limits to the number of arrays or their size, the only restriction is the RAM memory available.


The arrays can be re-dimensioned using the same command DIM.

In this case all the existing elements will maintain the previous value except the new elements that will be initialised at 0 or null string.


Example :

DIM A(5)      ' all the elements are initialised at 0

A(0) = 123

Print A(0)   ' print 123

Dim A(10)

Print A(0)  ' print the same value 123

Print A(10) ' print 0


In addition the elements of the arrays can be initialised with a given value during the command DIM.

Example :

DIM A(5) = 0, 1, 2, 3, 4, 5   ' set A(0)= 0, A(1)= 1, A(2)=2, ….


The same can be done with string arrays.

Example :

DIM A$(5) = "zero", "one", "two", "three", "four", "five"

Scope of the variables:

Variables and arrays defined in the main code are global, therefore any variable is accessible from any part of the code after it has been previously defined there.

Variables and arrays defined  inside “user defined” subroutine (SUB) are visible only inside that sub and inside all the code called by that subroutine; their content (and their memory space) is removed at the end of the SUB

The LOCAL command permits defining local variables inside of "user defined" subroutines; this permits to use the same name of an “already existing” variable locally without modifying the original.

As for all the variables defined inside SUB, they will disappear at the end of the subroutine.



A = 10

B = 20

C = 30

mysub "Hello"




SUB mysub(a$)


  A = 123

  B = 456

  C = 789

  D = 8888




In this example, calling the user-defined subroutine "mysub" will not modify the content of the global variables A and B (defined locally) but will modify the content of the variable C (not defined locally) and the variable D will disappear at the end of the SUB.


Bases of the language

The keywords recognized by the interpreter can be defined into 3 classes:





The Operators are symbols that tells the compiler to perform specific mathematical or logical manipulations.

Commands and Functions both execute an action, but functions also return a data value.

For example PRINTis a command and SIN() is a function whereas the ‘+’ in a = b + 5 is an operator.

The string functions are always followed by the "$" symbol if they return a string value.

In addition to commands and functions there are all the internal interpreter internal commands that are part of the language itself.



The following operators are available. These are listed in the following tables by order of precedence. Operators on the same line are processed with a left to right precedence.


Arithmetic operators:



* /  \  MOD

Multiplication, division, integer division and modulo (remainder of the division)

+ -

Addition and subtraction


Shift operators:

x << y    

x >> y

These operate in a special way. << means that the value returned will be the value of x shifted by y bits to the left while >> means the same only right shifted. They are integer functions and any bits shifted off are discarded and any bits introduced are set to zero.

For more information about the kinds of bitwise shifts, see Bitwise shifts.


Logical operators:

<>    <   >   <=

  =>    =

Not Equal, less than, greater than, less than or equal to,

greater than or equal to, equal


Conjunction, disjunction, negation, Exclusive OR


String operators:

<>    <   >   <=

  >=    =

Not Equal, less than, greater than, less than or equal to,

greater than or equal to, equal

+   &

Add strings together


Bitwise operators:


Binary AND, binary OR, binary exclusive OR, binary negation

For more information about the bitwise operators, see Bitwise Operators



The operators AND, OR and XOR are integer bitwise operators. For example PRINT (3 AND 6) will output 2.


Expressions beginning with open parenthesis ‘(‘ are always considered numerical but the parser is able to determine if an expression is true or false even if the expression represents a string.

Each expression representing a comparison, returns a numerical value of 1 if the expression is true or 0 if false.

For example 10 = 10 represents a value of 1 whereas 10 = 5 represents a value of 0.


The same logic is applied for string expressions where "abc" = "abc" represents a value of 1 and "abc" = "def" represents a value of 0.

This is very useful in the IF command and also in other expressions.

For example the following code :



A$ = "on"

If A$ = "on" then

   pin(4) = 1


  pin(4) = 0

End if



Can be replaced by

pin(4) = (a$ = "on")


Basic internal keywords:


IF command :

The IF can have the following syntax :

1)    IF expression THEN statement

2)    IF expression THEN statement1 ELSE statement 2

3)    IF expression THEN




            END IF



IF a > 100 THEN print "a"


IF b <a THEN print "b" ELSE print "a"


IF c > d THEN

   print "C"

   print "is greater"


   print "D"

   print "is greater"

END IF  ' (can also be ENDIF without space between END and IF)


The AND , OR  keywords can be used between the expressions as long as they are in parenthesis.


IF (a=1) AND (b=2) THEN PRINT "ok"




IF ((a=2) AND (b=3) AND (c = 3)) OR (d=4) THEN PRINT "ok"



The IF can be nested




  IF b = 2 THEN

    IF c = 3 THEN

      PRINT "ok"

    END IF




The “THEN” keyword can eventually be removed, even if this is not recommended.



IF a > 100 print "a" else print "b"


FOR loop

The FOR loop can have the following syntax :


FOR variable=init_value to end_value [step value]


NEXT variable


The ‘step’ value can be positive or negative



FOR i=1 to 5

  Print i



Will print 1, 2, 3, 4, 5


FOR i=1 to 3 step 0.5

  Print i



Will print 1, 1.5, 2, 2.5, 3


FOR i=3 to 1 step -0.5

  Print i



Will print 3, 2.5, 2, 1.5, 1


The command EXIT FOR can be used to exit from the loop at any time:


FOR i=1 to 50


  Print i


Print "end of loop"


New feature : the variable in the NEXT statement can be omitted.

This means that this program is valid :


FOR i=1 to 5

  Print i



The WHILE WEND loop can have the following syntax :

WHILE expression



The loop is iterated as long as the expression is true



i = 0

WHILE i < 3

   Print i

   i = i + 1



Will print 0, 1, 2


DO LOOP loop

The DOLOOP can have one of the following 4 syntax :


DO WHILE expression




DO UNTIL expression






LOOP WHILE expression




LOOP UNTIL expression


The command EXIT DO can be used to exit from the loop at any time



i = 0


Print i

i = i + 0.5


Will print 0, 0.5, 1, 1.5, 2, 2.5, 3


i = 0


Print i

i = i + 0.5



Will print 0, 0.5, 1, 1.5, 2



The SELECTcan have the following syntax:


SELECT CASE expression

   CASE exp1 [,exp2], ... [: Statements]


   CASE exp3 [,exp4], ... [: Statements]

   CASEfrom TO to  [: Statements]








a = 4


   CASE 1

     PRINT "case 1"

   CASE 2 : PRINT "case 2"

   CASE 3 : PRINT "case 3" : PRINT "can continue on same line"

   CASE 4 : PRINT "case 4"

     PRINT "can continue also on next line"

   CASE 5, 6 : PRINT "case 5 or 6"

   CASE 7 TO 10 : PRINT "case 7 to 10"


     PRINT "case else"




The GOTOcan have the following syntax :




a = 5






PRINT "This is label1"



The goto must be considered as an obsolete command and is provided just for backward compatibility with old style Basic programs.



The GOSUBcan have the following syntax :


The called function must terminate with the command RETURN



a = 5






PRINT "This is label1"




The command DATA is used to store constant information in the program code, and is associated with the command READ. Each DATA-line can contain one or more constants separated by commas. Expressions containing variables  will be also evaluated here.

The goal of the DATA is to avoid repetitive variable assignation lines, in particular for arrays.

The DATA values will be read from left to right, beginning with the first line containing a DATA statement. Each time a READ instruction is executed the saved DATA position of the last READ is advanced to the next value. Strings must be written in quotes like string constants. The command RESTORE resets the pointer of the current DATA position, so the next READ will read from the first DATA found from the beginning of the program.

In case READ uses the wrong variable type the error message "Type mismatch" appears while referring to the line number containing the READ statement that triggered the condition.

DATA lines may be scattered throughout the whole program code, but for the sake of clarity they would be better kept together at the beginning of the program.


The DATA can have the following syntax :

DATA const1 [,const2] …..

The constants can be Numerical or String.


Example :

DATA 1, 55.88, "constant", 99

READ A, B, C$, D



Example without DATA:

dim colors$(5)

colors$(1) = "Red"

colors$(2) = "Green"

colors$(3) = "Blue"

colors$(4) = "Yellow"

colors$(5) = "Magenta"


Same example but using  DATA:

DATA "Red", "Green", "Blue", "Yellow", "Magenta"

dim colors$(5)

For i=1 to 5

  Read colors$(i)

Next i





Define the end of the program. With this command the program stops.

It can also be :

END IF -> close the IF command

END SELECT -> closes the SELECT CASE command

END SUB -> closes the user defined SUB



Permit to exit from a loop or a user defined SUB.

The syntax is :

EXIT DO  -> exit from a DO loop

EXIT FOR -> exit from a FOR loop

EXIT SUB -> exit from a user defined SUB.


Define a user-defined subroutine, which the script can use like a command or function.

User-defined subroutines are effectively additional commands, so cannot be used as branch labels.

Permit to create a user defined command with optional parameters.

The syntax is SUB subname[(arg1 [,arg2] …)]

The variables are passed by reference; this means that the arguments, if modified inside the subroutine, will modify the original variable. This can be useful to return values from the subroutine (acting like a function).

It is possible to pass arrays using the syntax array_name().

Using the LOCAL command will permit to define local variables (useful to avoid to modify existing global variables).


Example 1 : routine cube


SUB cube(x)

  PRINT X ^3



cube 3 ' will print 27



Example 2: routine cube with returning argument


SUB cube(x,y)

  y = x ^3    ' the value is returned using the 2nd argument



ret = 0

cube 5, ret

PRINT ret ' will print 125



Example 3: routine with local variables and returning argument


SUB left_trim(s$, ret$)


  i = 1

  DO UNTIL i = len(s$)

    IF mid$(s$, i, 1) <> " " THEN EXIT DO

    i = i + 1


  ret$ = mid$(s$, i)



z$ = ""

FOR i = 1 to 3

  left_trim "  remove space from left ", z$

  PRINT  z$ + "--"



Will print

remove space from left          --

remove space from left          --

remove space from left          --

As you can see in this example, the variable i in the FOR loop is not modified by the LOCAL variable i in the subroutine.


Example 4: pass arrays


SUB pass_array(f(), c$())

  Dim myArray(10)

  myArray(0) = 456 

  Print f(0), c$(0), myArray(0)

  f(1) = 123

  c$(1) = "myText"



Dim alpha(10)

Dim beta$(10)

alpha(0) = 456

beta$(0) = "testme"

Pass_array alpha(), beta$()

Print alpha(1), beta$(1)


In this example, the array alfa() is passed locally to the array f() and the array beta$() is passed locally to the array c$().

Modifying locally these arrays change the value of the original one as their content is passed by reference.

The array “myArray” will disappear at the end of the SUB




Logical / boolean Operations

As the numerical variables are stored internally as double precision floating number, it is possible to store numbers with a precision equivalent to 32 bits.

Several boolean operators are available to manipulate these numbers..


The first operator is the bit shift; it can be shift left << or shift right >>

This operator permit to shift the number of a specified number of positions to left or right.



A = 1

Print A << 3 ' will print 8


A = 16

Print A >> 2 ' will print 4


The operators AND , OR , XOR are also available :


A = 24

A = 15

Print A AND B ' will print 8


A = 24

A = 15

Print A OR B ' will print 31


A = 24

A = 15

Print A XOR B ' will print 23


The unary operator NOT is also available. It inverts all the bits from 0 to 1:

A = 0

Print Hex$(NOT A) ' will print FFFFFFFF


For a 32 bits number, assuming 4 bytes ABCD where A is the MSB and D the LSB, the bytes can be extracted as follows :


VAR = &h12345678 ' this is a 32 bits variable



C = (VAR >>  8) AND &hFF

B = (VAR >> 16) AND &hFF

A = (VAR >> 24) AND &hFF


For more information, see Bitwise Operators


Annex allows to control and manage errors happened during the execution of the code.

This is managed with the command ONERROR.

This command defines the action done when an error occurs and applies to all errors including syntax errors.

It can be used in different ways, as specified in the table below:





Displays the error message and abort the program.

This is the normal behaviour and is the default when a program starts running.


Any error will be simply ignored.

As this can make very difficult to debug a program it should be used wisely.


Ignore an error in a number of commands (specified by the number 'nn') executed following this command.

'nn' is optional, the default if not specified is one.

After the number of commands has completed (with an error or not) the behaviour will revert to ONERROR ABORT.


Reset the eventual pending error


Jumps to the error handling routine defined by the label.

It can be removed (hence reverting to ONERROR ABORT) replacing the label with OFF.

Using RETURN inside the error handling routine will continue the execution on the line following the error.


When an error occurs, the following constants are available :





Returns the line number where the error happened. Value of 0 means no error.

It is reset to 0 with the command ONERROR CLEAR or  running the program or with the command ONERROR IGNORE or ONERROR SKIP.


Returns a number where non zero means that there was an error.

It is reset to 0 with the command ONERROR CLEAR or  running the program or with the command ONERROR IGNORE or ONERROR SKIP.


Return a string representing the error message that would have normally been displayed on the console. It is reset to “No Error” running the program or with the command ONERROR CLEAR or ONERROR IGNORE or ONERROR SKIP.


Example of error handling using the command ONERROR GOTO :


ONERROR GOTO Error_Handler

Print "start"

Print 3/0  ' this generates a divide by zero error

Print space$(60000) ' this generates an out of memory error




Print "Error text "; BAS.ErrMsg$

Print "Error num  "; BAS.ErrNum

Print "Error line "; BAS.ErrLine

Return ' returns to the line following the error



HOW the interpreter works with the HTML code and Objects :

When a client connects to the module using its IP address, the module will redirect automatically to the url ‘/output?menu’, which sends an empty html page present on the module.

That page contains a bunch of javascript code permitting to interface the page with the module using javascript.



This page will automatically open a websocket connection with the module; the "squared led" indicates if the connection was successful (green) or not (red).

A mechanism of ping - pong has been implemented into the javascript in order to hold the connection alive all the time. If the connection is lost, the page will try to reconnect automatically without any manual action.

The button "reconnect" permit to force the reconnection if the automatic reconnection fails.


As soon as the connection is done with the module, the html page is ready to send and receive messages to / from the module.

Initially the page is empty but its content can be easily filled.


To send HTML code to the page, the command HTML is used.

The syntax is : HTML  HTML code.

For example the line

HTML "Hello, world <br>This is my first html content<br>"


Will give this result :


Continuing with the HTML command, the content can be improved :

HTML "Textbox: <input type='text'><br>"




Continuing again:

HTML "Button:  <button type='button'>Click Here</button>"



All the html code can be combined and sent with just one HTML command; this is much faster:


a$ = "Hello, world <br>This is my first html content<br>"

a$ = a$ + "Textbox: <input type='text'><br>"

a$ = a$ +  "Button:  <button type='button'>Click Here</button>"




To clear the content of the page, the command is:




Now we can try another example


a$ = "Now style me, please<br>"

a$ = a$ + "Button1:  <button id='but1' type='button'>ON</button> "

a$ = a$ + "Button2:  <button id='but2' type='button'>OFF</button>"




Now we will try to style the buttons using css.

This can be done using  command CSS CSSID$()

For example the line

CSS CSSID$("but1", "background-color: red;")

Will give this result :



Combining with the style for the other button:


a$ = a$ + cssid$("but1", "background-color: red;")

a$ = a$ + cssid$("but2", "background-color: green;")

CSS a$




A set of functions is included to simplify the creation of HTML pages as we will see later, so no need to worry if you are not familiar with writing HTML code.


Now we will mention an important ‘event’ that can be used to automatically fill the content of the page each time a client connects to the module : OnHtmlReload.

This ‘event’ defines a place where the program will jump to as soon as Websocket connection request is accepted.

Let’s clarify with an example :

OnHtmlReload Fill_Page    ‘will jump to Fill_Page when the page is reloaded

gosub Fill_Page  'load the page for the first time

Wait         ‘pause waiting for the event

Fill_Page:   ‘place where the page begins to be created


a$ = "Now style me, please<br>"

a$ = a$ + "Button1:  <button id='but1' type='button'>ON</button> "

a$ = a$ + "Button2:  <button id='but2' type='button'>OFF</button>"


a$ = cssid$("but1", "background-color: red;")

a$ = a$ + cssid$("but2", "background-color: green;")




The result will be:


Now try to play with the button "Reconnect"; you’ll see that, at each time the page reconnects to the module, the HTML content is built and sent again. This ensures that each time a client connects to the module it will receive the correct content. At the same time, if other clients are already connected, the content of all the pages will be refreshed simultaneously. This insures a synchronized content between all the clients.


HTML Objects

As said previously, in order to simplify the creation of HTML pages, there are several functions permitting to generate the html code automatically.

Let’s start with the button.

A button is an object that is used to generate an action each time it is pressed on the web page.

The function is BUTTON$.

Let’s explain with an example:



HTML BUTTON$("Button1", jump1)


Wait         'pause waiting for the event



PRINT "Clicked on Button1"





The result will be:



Try clicking on the button then checking the result in the terminal console; the message "Clicked on Button1" will be shown at each click.



To style the button, we need to modify the syntax of the BUTTON$ command slightly; in fact we need to add another parameter to give the button an ID:



HTML BUTTON$("Button1", jump1, "but1")   ' "but1" is the ID


Wait         'pause waiting for the event



PRINT "Clicked on Button1"

CSS cssid$("but1", "background-color: red;") 'the same ID is used here



Clicking on the button now will change its color to red



Now we can now introduce the LED object. The LED object is a circle that can be filled in red or green depending on the content of a variable. The function is LED$

As usual, let’s start with an example:




led ='this is the variable associated with the LED. With 0 the led is red, with 1 the led is green

HTML LED$(led)


The result will be:



Let’s also add a button :



led = 0

a$ = BUTTON$("Button1", jump1, "but1")   ' "but1" is the ID

a$ = a$ + LED$(led)



Wait         'pause waiting for the event



PRINT "Clicked on Button1"

led = 1 - led ' invert the variable

REFRESH ' refresh (update) the variables between the code and the html




The result will be:



Clicking on the button will toggle the led between red and green colors.


The command REFRESH permits to update (synchronize) the variables in the code with the corresponding objects variables on the web page. It should be run each time a variable is modified.

The refresh interval should not be less than 300 milliseconds (otherwise the module will be too busy).

As a simpler alternative, the command AUTOREFRESH will regularly sync the variables.

The command must be run with the desired refresh timing.


AUTOREFRESH 500   will refresh the variables each 500 milliseconds.

This command does not have the same timing limitation of REFRESH so the timing can be faster.


The example :



led = 0

a$ = BUTTON$("Button1", jump1, "but1")   ' "but1" is the ID

a$ = a$ + LED$(led)


AutoRefresh 100   'sync each 100 milliseconds

Wait         'pause waiting for the event



PRINT "Clicked on Button1"

led = 1 - led ' invert the variable




The result will be the same as the previous example.


Now it’s time to introduce another object; the TEXTBOX with the corresponding function TEXTBOX$.

The TEXTBOX will display a ‘text box’ on the web page which is linked with a variable. When the variable is modified in the code, the TEXTBOX content will be updated on the web page and vice-versa.

This will lets us introduce another ‘event’ : the OnHtmlChange command.

This ‘event’ defines a branch for the program to jump to whenever a variable is modified inside the web page.

As usual, let’s start with an example:




text$ = "Change me, please"


OnHtmlChange Jump1  'will jump to Jump1 when a variable changes on the web page

Wait         'pause waiting for the event



Print text$ 'print the content of the variable inside the terminal console






Try now to change the content of the textbox and press "Enter" on the keyboard.

Let’s see the result in the terminal console:




With the concepts already learned you’ll be able to use the other objects using the similar logic.

Refer to the pages below to understand the syntax of each object.



A timer is an "object" that permits the execution of a particular action at regular intervals.

When the given time expires, the normal execution of the program is interrupted and control is passed to the "timer interrupt routine" until the execution of the return command.

Then the program continues from the point where it has been interrupted.

Let’s explain with an example :


timer0 1000, mytimer




  wlog "mytimer " + time$



Annex WI-Fi Basic implements 2 timers, Timer0 and Timer1.

The Timer0 has a higher priority against Timer1.


Many of the actions are not executed directly by basic commands but can be executed as asynchronous events.

An  "event" is simply an action that can be executed when something happens.

For example, the pin change interrupts is an asynchronous event as it can happen at any time without user control.

In order to manage the events, a list of commands "ONxxxx" is provided. These commands define the place where the normal execution of the program will branch to when the event occurs.

So, when the "event" happens, the interpreter interrupts the normal execution of the code and "jumps" to the location defined by the corresponding command "ONxxx". As soon as the code associated with the "event" is terminated with the command "return", the execution continues from the previous interrupted location.


Button Event

This is a special event that happens every time aBUTTON$ object is clicked in the HTML pages.

When this happens, a special variable HtmlEventButton$ is created containing the name of the button that was clicked.

This is useful to determine the button within a group of buttons.

Let’s see an example:



HTML Button$("ON", buttonEvent) + " " + Button$("OFF", buttonEvent)




print "You clicked on "; HtmlEventButton$



OnHtmlChange Event

This event is triggered when an object present in the HTML output page changes its value.

It is useful to make actions when something changes in the HTML Pages.

When this event happens, a special variable HtmlEventVar$ is created containing the name of the variable that changed its value.

This is useful to determine the object that generated the event.

Let’s see an example :



text$ = "Change me, please"


OnHtmlChange Jump1  'will jump to Jump1 when a variable changes on the web page

Wait         'pause waiting for the event



Print text$ 'print the content of the variable inside the terminal console




This event is triggered when a Websocket connection request is accepted.

This can be used to automatically fill the content of the WEB page each time a client connects to the module.

Let’s see an example :



OnHtmlReload Fill_Page   'will jump to Fill_Page when the page is reloaded

gosub Fill_Page  'load the page for the first time

Wait         'pause waiting for the event

Fill_Page:   'place where the page begins to be created


a$ = "Now style me, please<br>"

a$ = a$ + "Button1:  <button id='but1' type='button'>ON</button> "

a$ = a$ + "Button2:  <button id='but2' type='button'>OFF</button>"


a$ = cssid$("but1", "background-color: red;")

a$ = a$ + cssid$("but2", "background-color: green;")




OnInfrared Event

This event is triggered when a code is received by the infrared receiver.

Refer to chapter INFRARED INTERFACE for more details.


OnSerial Event

This event is triggered when a message is received on the serial port.



print "Ram Available "; ramfree
onserial rec1

'print serial.input$
print serial.chr$;




OnSerial2 Event

This event is triggered when a message is received on the serial port #2.



serial2.mode 9600, 2, 5 ' set serial port #2 to 9600 pin 2 TX, pin 5 RX
print2 "Ram Available "; ramfree
onserial2 rec2

print serial2.input$



OnTouch Event

This event is triggered when the TFT screen is touched.

Refer to the chapter TouchScreen for more details.


OnUDP Event

This event is triggered when a UDP message is received.



udp.begin 5001  'set the UDP commmunication using port 5001
onudp goudp
'Write several messages to the port
for i
= 0 to 100
udp.write "", 5001, "Hello " + str$(i)
next i

=$ 'receive the UDP data

print v$



OnWgetAsync Event

This event is triggered when a WgetAsync message is received.

This is associated with the command WGETASYNC.

The goal of the WGETASYNC command is to start a html get request without the module having to wait for the answer.

As the answer is async, this command will define the place where the program execution will continue when the message will be received.



ONWGETASYNC answer_done


For i = 0 to 10000

  ' a kind of sleep just to demonstrate that the code continue to run

  Print i

Next i






OnUrlMessage Event

This event is triggered as soon as a web client requests for a web page with the url composed with http://local_ip/msg?param=value.This kind of request is typically called an AJAX request as it permit to exchange in both directions between the client (the web browser) and the server (the ESP module).

In fact, in the url request, the client can send parameters in the form of couples of "param=value" separated by the character "&". For example, if the client want sent 2 parameters, it can send the following request :


As soon as this message is received by the ESP module, the event OnUrlMessage is triggered; this means that the program will continue from the location defined by the command OnUrlMessage.

As soon as the message is received, the parameters sent by the client can be get with the function UrlMsgGet$ and a message can be sent back to the client with the command UrlMsgReturn.

Let’s see an example :


onUrlMessage urlAjax




wlog "message received " + UrlMsgGet$("a") + " " + UrlMsgGet$("b")

UrlMsgReturn "Message sent back " + time$

print UrlMsgGet$("b"), ramfree



Now using another web browser window, let’s type the following url :


As you can see in the following picture, the message is received by the ESP module





At the same time, the client receive the message sent back from the ESP module



If the program is stopped, the module will answer with the message "STOPPED"


Now, let’s see a more complete example :


' this is the default value for pwm out

R = 512

G = 512

B = 512

pwm(12) = R

pwm(15) = G

pwm(13) = B

' these are the sliders

a$ = ""

a$ = a$ + |R <input type="range" id="dimmer_R" oninput="setPWM()" onclick="setPWM()" min="0" max="1023" value="| & str$(R) & |"/><br>|

a$ = a$ + |G <input type="range" id="dimmer_G" oninput="setPWM()" onclick="setPWM()" min="0" max="1023" value="| & str$(G) & |"/><br>|

a$ = a$ + |B <input type="range" id="dimmer_B" oninput="setPWM()" onclick="setPWM()" min="0" max="1023" value="| & str$(B) & |"/><br>|

a$ = a$ + |<input type='text' id="txbox" value='---'>|

html a$

'this is the javascript "AJAX" code

fun$ =    |function setPWM() {|

fun$ = fun$ & |r=_$("dimmer_R").value;|

fun$ = fun$ & |g=_$("dimmer_G").value;|

fun$ = fun$ & |b=_$("dimmer_B").value;|

fun$ = fun$ & |var xmlHttp = new XMLHttpRequest();|

fun$ = fun$ & |"GET", "msg?r=" + r +"&g=" + g +"&b=" + b, false);|

fun$ = fun$ & |xmlHttp.send(null);|

fun$ = fun$ & |r = xmlHttp.responseText;|

fun$ = fun$ & |_$("txbox").value = r;|

fun$ = fun$ & |return r;}|


' this is where the javascript code is inserted into the html

jscript fun$


'this is where the prog will jump on slider change

onUrlMessage message




print UrlMsgGet$()


pwm(12) = val(UrlMsgGet$("r"))

pwm(15) = val(UrlMsgGet$("g"))

pwm(13) = val(UrlMsgGet$("b"))

UrlMsgReturn UrlMsgGet$()



Open the input page into another window and run the program



If you have a ESP-202, you’ll be able to control the color of the RGB led present on the card.

You’ll see how the exchanges can be fast using AJAX exchanges. This program uses javascript embedded into the code. The javascript works with the function XMLHttpRequest.

A good reference for this function is here AJAX - Send a Request To a Server


OnEspNowMsg Event

This event is triggered when a ESP-NOW message is received.



espnow.begin  ' init the ESP-NOW

onEspNowMsg message ' set the place where jump in case of message reception




print "Message Received!"



OnEspNowError Event

This event is triggered when a ESP-NOW a transmission error occurs.

This happens, in particular, when the receiver device has not received the message.


espnow.begin  ' init the ESP-NOW

espnow.add_peer "60:01:94:51:D0:7D" ' set the MAC address of the receiver

onEspNowError status ' set the place where jump in case of TX error

espnow.write "TX message" ' send the message




print "TX error on "; espnow.error$  ' print the error



OnMQTT Event

This event is generated when a MQTT message is received




onmqtt mqtt_msg



' receive messages from the server


print "TOPIC  : "; mqtt.topic$

print "MESSAGE: "; mqtt.message$




At startup, the module tries to connect to the router with the parameters provided in the page “Config”.

If the connection is unsuccessful, it will default to AP (Access Point) mode .

By default, if no parameters are specified into the “Config” page, the module will default to the IP address in AP mode with the SSID composed of ESP(+ mac address).

If the connection is successful, the module will use the IP address defined in the “Config” page or, if not specified, the IP will be given automatically by the Router DHCP server.

As soon as the module is connected to the router, it will reconnect automatically if the connection is lost.


There are several commands / functions available to manage the WIFI.


The first function is WIFI.STATUS that permits to get the status of the connection.

print WIFI.STATUS ’ print 3 if connected, 6 if disconnected


The first useful command is WIFI.CONNECT SSID$, password$ [, BSSID$] [, IP$ , MASK$ [, GATEWAY$]]


This command allows you to connect to any WIFI network (STA mode) overriding the parameters defined into the’ “Config” page. This function is async so the connection is done in background, while the program continues to run.

Is then possible to check the status of the connection using the function WIFI.STATUS

Example :


print "connecting"
While WIFI.STATUS <> 3
Print "."
pause 500


Using the optional parameter BSSID$, will enable the connection to a specific WiFi access point.

The BSSID represents the MAC address of the WiFi access point (the router) and it is defined as 6 bytes in hex format separated by colon, i.e. AA:BB:CC:12:34:56.


For stand alone configuration or for ESP-NOW applications, there is another command that puts the module in AP mode.

This command is WIFI.APMODE SSID$, password$ [, channel] [, IP$ , MASK$]

The result is immediate and the status can be checked using the function WIFI.MODE (see below).

The channel is optional and is 1 by default.


It is eventually possible to control the output power of the module with the command WIFI.POWER pow

WIFI.POWER 5 ’ set the output power at 5 dBm.


The module can also be put in WiFi sleep mode. This mode permits to turn off the WiFi reducing the power requirements of the module; this is very useful for battery oriented applications or for applications where the WiFi is not required.

To put the module in “modem-sleep”, the command to execute is WIFI.SLEEP.

The module will stay in that mode until the execution of the command WIFI.AWAKE.

After this command, the module will reconnect automatically to the router (the command WIFI.CONNECT is not required).


Another function available is WIFI.CHANNEL that shows the current Radio Channel used by the WIFI.


Using the function WIFI.RSSI is it possible to get the intensity of the signal received (RSSI)  


It is also possible to scan for the WiFi networks accessible around the module.

This can be done using the command WIFI.SCAN and the function WIFI.NETWORKS(network$).

Example :
While WIFI.NETWORKS(A$) = -1
Print a$

The result will be :

Vodaphone, 00:50:56:C0:00:08, -50, 5

Orange, 00:50:56:C0:32:07, -70, 5

Xxxx,  00:50:56:C0:86:CA,-78, 12


These information represent, in the order :

SSID, BSSID(mac address), RSSI(signal intensity), Channel Radio


The function WIFI.MODE returns the current mode of the WIFI connection as below:





The WIFI is in sleep mode


The WIFI is in STATION mode


The WIFI is in AP mode


The WIFI in AP+STA mode


The WIFI in AP+STA mode can be obtained by configuring the module in AP mode and then using the command WIFI.CONNECT in the program.


Using a “fake” SSID / password (example WIFI.CONNECT "A", "" ) can be used to switch the WIFI into the AP+STA mode. This can be useful for mixed ESP32 / ESP8266 ESP-NOW operations.


Another Wifi related command is OPTION.MAC mac$ that permits to modify the MAC address of the module.

This is very important for the ESP Now functionality.

Example :



In addition, the functions BAS.SSID$ and BAS.PASSWORD$ returns respectively the login and the password used for the STATION wifi connection.



If a program is defined to run automatically (“Autorun File” in the config page), the WiFi connection process is slightly different.

If the option “Fast boot” in the config page is selected, the program will be executed immediately and the WiFi will be powered ON after a little delay ( 0.1 sec ).

If the command WIFI.SLEEP is executed during the very beginning of the program ( for example as the first line of the program) the WiFi will be simply disabled without using any power.

This enhances the use of the module in low power applications (i.e. on battery).

The WiFi connection can then be restored later using the commands WIFI.CONNECT or WIFI.APMODE.


If the command WIFI.SLEEP is not executed at the beginning of the program, the WiFi connection will be established by default as described in the previous chapter (WiFI CONNECTIONS).


The function BAS.RESETREASON can be used at the beginning of the program to understand the reasons for the restart of the module enabling it to take the appropriate actions.


In case of any IP or Autorun problem preventing the module from being accessed, it is possible to temporarily bypass the IP settings of the module and disable the Autorun file by connecting the serial TX and RX pins together (GPIO1 to GPIO3) during the startup phase (power up).

This could happen if, for example, a wrong IP address has been set.

Doing this action when restarting the module will put it in AP mode with the IP address at, just like a module that has not been configured.

A message “Recovery Mode” will be printed on the console, but none of the existing files on the module will be modified, including config.ini.

In this mode it will be possible to gain access to the module for changing such correct wrong IP parameters using the configuration page.

When the TX/RX link is removed, the module can be rebooted to the configured settings at next restart.



A watchdog timer (or simply a WDT) is an electronic timer that is used to detect and recover from computer malfunctions. During normal operation, the computer regularly resets the watchdog timer to prevent it from elapsing, or "timing out".

If, due to a hardware fault or program error, the computer fails to reset the watchdog, the timer will elapse and generate a timeout signal. The timeout signal is used to initiate corrective action or actions. The corrective actions typically include placing the computer system in a safe state and restoring normal system operation.

Annex implements a watchdog timer with the command  OPTION.WDT timeout_msec.

As soon as the watchdog has been defined, the command OPTION.WDTRESET must be executed regularly within the defined timeout otherwise the module will reset automatically.

At the beginning of the program, It is possible to know if the module has been reset by the WDT using the functionBAS.RESETREASON.




' WDT example
print "reset reason: ";

select case bas.ResetReason

  case 0: print "normal startup"

  case 1: print "hardware WDT"

  case 2: print "exception reset"

  case 3: print "software WDT"

  case 4: print "software restart"

  case 5: print "wake up from deep sleep"

  case 6: print "external reset"

end select


option.WDT 1000 ' set the WDT at 1 second


print "WDT reset regularly"

for z = 1 to 50

  print z,

  pause 100


next z


print "WDT not reset regularly, so should crash after 1 sec"

for z = 1 to 50

  print z,

  pause 100

next z


DATE - TIME timekeeper

The ESP module normally synchronises its date and time from either of two NTP time servers ("" and ""). Optionally an alternative (eg: intranet) time server can be defined using the [CONFIG] page.

Using these servers the ESP doesn’t require any date/time setting as soon as the timezone is correctly defined into the [CONFIG] page.


The timezone is defined as a string likeCET-1CEST,M3.5.0,M10.5.0/3 that describe how the local time must be managed in terms of time shift and DST (summer / winter time).


A complete list of timezone strings can be found here :


An internal timekeeper has been included if no time server is available, eg no available internet access.

This timekeeper starts from 01/01/1970 00:00:00 and counts the seconds since the power on of the module.

If internet connection becomes available later, the internal timekeeper will sync its time with the NTP servers.


The time can be sync with the NTP time server at any moment using the command OPTION.NTPSYNC.


This time and date can be manually set using the command SETTIME.

The Syntax is :

SETTIME year, month, day, hours, minutes, seconds



Set the date to 02 September 2017 at 13:58:12


SETTIME 17, 9, 2, 13, 58, 12


The time and date can also be manually synchronised to the computer using the "Time Sync" button in the File Manager window of the computer utility ‘tool’ if it has a websocket connection.



In both cases of manual setting, the time and date will be reset back to 1970 default at next restart of the module, so will require setting again.


For more information about the Time Zones and DST, please consult the following page :

Time Zone and DST


It is also possible to connect an RTC (DS1307 or DS3231) to the module.

See the chapter “RTC Module” for more details.

Unix Time functions

The following functions utilises the time following the “Unix Time Stamp” format :

DATEUNIX(date$), TIMEUNIX(time$), UNIXDATE$(value [,format]), UNIXTIME$(value)


The “Unix Time Stamp” is a way to track time as a running total of seconds.

This count starts at the Unix Epoch on January 1st, 1970 at UTC.

Therefore, the unix time is merely the number of seconds between a particular date and the Unix Epoch.

In synthesys :

-       DATEUNIX("01/01/18") returns the number of seconds between the 01/01/1970 and the 01/01/2018  (1514764800)

-       TIMEUNIX("12:30:55") returns the number of second since midnight (45055)

-       UNIXDATE$("1532773308") returns 28/07/18

-       UNIXTIME$(1532773308) returns 10:21:48

SPIFFS File System

 Annex includes a SPIFFS file system hosted on the flash memory chip.

It “emulates” a disk file system enabling to save and load files in a transparent way.

Depending on the size of the flash chip, the following free space is available :


Flash Chip size

Free space available


256 Kb










As the SPIFFS has been designed to be very light in terms of resources, it comes with some limitations :


-       First the SPIFFS does not support directories, it just stores a “flat” list of files. But contrary to traditional filesystems, the slash character '/' is allowed in filenames, so the functions that deal with directory listing (e.g. FILE.DIR$("/website")) basically just filter the filenames and keep the ones that start with the requested prefix (/website/). Practically speaking, that makes little difference though.

-       Second, there is a limit of 31 chars in total for filenames.

-       Combined, that means it is advised to keep file names short and not use deeply nested directories, as the full path of each file (including directories, '/' characters, base name, dot and extension) has to be 31 chars at a maximum. For example, the filename /website/images/bird_thumbnail.jpg is 34 chars and will cause some problems if used, for example in FILE.EXISTS() or in case another file starts with the same first 31 characters.

Warning: That limit is easily reached and if ignored, problems might go unnoticed because no error message will appear at runtime.

All the file related functions share the same prefix FILE. followed by the specific function.




Ret = FILE.COPY(filename$, newfile$)

Copy the file filename$ into the file newfile$

Returns 1 in case of success or 0 if error

Ret = FILE.DELETE(filename$)

Delete the file specified by filename$

Returns 1 in case of success or 0 if error

Ret = FILE.EXISTS(filename$)

Returns 1 if filename$ exists, otherwise returns 0

Ret = FILE.RENAME(oldname$, newname$)

Rename the file oldname$ to  newname$

Returns 1 in case of success or 0 if error

Ret = FILE.SIZE(filename$)

Returns the size of the file (in bytes) if the file exist, otherwise returns -1

Ret$ = FILE.DIR$(path$)

Will search for files and return the names of entries found.

path$ represents the directory name.

The function will return the first entry found.

To retrieve subsequent entries use the function with no arguments. ie, FILE.DIR$.

The return of an empty string indicates that there are no more entries to retrieve.

Ret$ = FILE.READ$(filename$, [line_num] | [start, length])

Returns the content of the file filename$.

Specifying line_num, only the corresponding line is read from the file.

If start and length options are specified, the file is read from the start position for length characters, otherwise the complete file is read in one go

The line number starts from 1.

FILE.APPEND filename$, content$

Append the content of content$ to the file filename$.

If the file does not exist, it will be created.

The file can be read back using the function FILE.READ$(filename$)

File size is only limited by available SPIFFS memory, but the length of filename$ is limited to 31 characters including folder and "/" separators

FILE.SAVE filename$, content$

Save the content of content$ to the file filename$.

The file can be read back using the function FILE.READ$(filename$)

File size is only limited by available SPIFFS memory, but the length of filename$ is limited to 31 characters including folder and "/" separators




List all the files in the directory /html

d$ = FILE.DIR$("/html")

While D$ <> ""

  wlog d$

  d$ = FILE.DIR$



File operations "/test.bas", "The quick brown fox "

wlog "exists", file.exists("/test.bas")

wlog "size", file.size("/test.bas")

file.append "/test.bas", "jumps over the lazy dog"

wlog "size", file.size("/test.bas")

wlog "copy", file.copy("/test.bas", "/AAA.bas")

wlog "size", file.size("/AAA.bas")

wlog "rename", file.rename("/AAA.bas", "/BBB.bas")

wlog "size", file.size("/BBB.bas")

wlog "size", file.size("/AAA.bas")

wlog "read",$("/test.bas")

wlog "delete", file.delete("/BBB.bas")



The I/O BUFFER is a functionality that gives the capability to hold and manage binary data.

In short the I/O buffer is a block of RAM memory that can be exchanged as a block or read and written byte per byte.  It surpasses the limit of the Strings that cannot hold the character ASCII 0 (NUL).

It has a defined length and can be freely dimensioned and cleared.

It can be used in the code using the IOBUFF keyword and Annex exposes 5 I/O buffers numbered from 0 to 4.

The I/O buffers can have any size within the limits of the free RAM memory available.

The main goal of this functionality is to interface with all the functions that require exchanges using binary data.

In the current implementation it can be used with :

-       Files

-       Serial Ports

-       SPI

-       I2C

-       UDP


As it is essentially a block  of memory, the first command is IOBUFF.DIM(buff_num, size) that defines its size.

buff_num can span from 0 (first buffer) to 4 (last buffer)

size can span from 0 to the maximum RAM memory available


IOBUFF.DIM(0, 1000) 'dimension the I/O buffer 0 with 1000 bytes


The I/O buffer can be filled with a given set of data directly using the function IOBUFF.DIM


IOBUFF.DIM(0, 10) = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

IOBUFF.DIM(1, 5) = &h12, &hAA, &h50, &O377, &B10101010


As soon as the buffer is dimensioned, the given amount of RAM is reserved for the buffer.

When not required anymore, it can be removed with the command IOBUFF.DESTROY(buff_num)


IOBUFF.DESTROY(0) 'remove the buffer releasing the memory reserved


Note : The I/O buffers are automatically destroyed each time the program is run.


It is possible to know the size of the buffer using the function IOBUFF.LEN(buff_num)


Print IOBUFF.LEN(buff_num) 'print the length of the buffer


The I/O buffer can be read byte per byte using the function IOBUFF.READ(buff_num, position)

position can span from 0 (first byte) and the buffer length - 1 (last byte)



Print IOBUFF.READ(0, 4) 'print the byte 4 from the I/O buffer 0

A = IOBUFF.READ(0, 7) ' read in the variable A the byte 7 from the I/O buffer 0

The I/O buffer can be written byte per byte using the command IOBUFF.WRITE(buff_num, position, value)

position can span from 0 (first byte) and the length - 1 (last byte)

value can span from 0 to 255 (byte)


The I/O buffers communicate with the other modules using the following syntax:

-   xxxx.READ_IOBUFF(buff_num)

Receive data in the buffer buff_num


-   xxxx.WRITE_IOBUFF(buff_num, start, size)

Transmit (send) data from the buffer buff_num starting from the position ‘start’ for ‘size’ bytes


-   xxxx.REPLY_IOBUFF(buff_num, start, size)

Reply to the sender data from the buffer buff_num starting from the position ‘start’ for ‘size’ bytes


Where xxxx can be :








Detailed syntax :




FILE.READ_IOBUFF(buff_num), filename$ [, position, nb_of_bytes_to_read]

I2C.READ_IOBUFF(buff_num), address, register, nb_of_bytes_to_read

SPI.READ_IOBUFF(buff_num), nb_of_bytes_to_read


UDP.WRITE_IOBUFF(buff_num [, start [, size]]), IP$, port

SERIAL.WRITE_IOBUFF(buff_num [, start [, size]])

SERIAL2.WRITE_IOBUFF(buff_num [, start [, size]])


FILE.SAVE_IOBUFF(buff_num [, start [, size]]), filename$

FILE.WRITE_IOBUFF(buff_num [, start [, size]]), filename$

FILE.APPEND_IOBUFF(buff_num [, start [, size]]), filename$


I2C.WRITE_IOBUFF(buff_num [, start [, size]]), address, register

SPI.WRITE_IOBUFF(buff_num [, start [, size]])


UDP.REPLY_IOBUFF(buff_num [, start [, size]]) [,port]

SPI.REPLY_IOBUFF(buff_num [, start [, size]]), (buff_num_reception)


Read Operations

The IOBUFFER can be used for sending or receiving data.

When used for receiving data, the syntax is always .READ_IOBUFF(buff_num).


When receiving data, it is not necessary to dimension the buffer before as it will be automatically dimensioned depending on the size of the data received. If the buffer was already containing some data, these will be flushed and replaced by the new data.


For example, the following command receive all the data available from the serial port 2 in the buffer 3 :



This command receive the data coming from an UDP connection in the buffer 1:



Additionally some other arguments may be required.

This command read 512 bytes from the file data.bin starting from the file position 123 in the buffer 0:

FILE.READ_IOBUFF(0), “/data.bin”, 123, 512


This command read 8 bytes from an I2C device with address 63 from the register 19 in the buffer 4 :

I2C.READ_IOBUFF(4), 63, 19, 8


This command read 32 bytes from the SPI bus in the buffer 2 :



Write Operations

When used for sending data, the syntax is always .WRITE_IOBUFF(buff_num [, start [, size]])


When sending data, it is possible to send the entire buffer or only a part of it.

Specifying the optional arguments start and size it is possible to define the part of the buffer to be sent otherwise, if omitted, the entire buffer will be transferred.


For example, the following command send 10 bytes from the buffer 1 starting from the position 45 to the serial port :



This command send the complete buffer 1 to the serial port 2



This command send 8 bytes from the buffer 2 starting from the position 128 to the SPI bus



Additionally some other arguments may be required.


This command send 12 bytes from the buffer 1 starting from the position 64 to the UDP on the address and port 8080 :

UDP.WRITE_IOBUFF(1, 64, 12), “”, 8080


This command send the entire buffer 2 on the same UDP device :

UDP.WRITE_IOBUFF(2), “”, 8080


This command write the buffer 1 to the file data.bin

FILE.WRITE_IOBUFF(1), “data.bin”


This command has the same result and is provided for compatibility with the existing syntax

FILE.SAVE_IOBUFF(1), “data.bin”


This command appends 36 bytes from the buffer 0 starting from the position 25 to data.bin

FILE.APPEND_IOBUFF(0, 25, 36), “data.bin”


This command send the buffer 2 to the I2C device with address 63 and register 19 :

I2C.WRITE_IOBUFF(2), 63, 19


The same operation but sending only 4 bytes starting from position 0:

I2C.WRITE_IOBUFF(2, 0, 4), 63, 19


Special operations

The syntax .REPLY_IOBUFF(buff_num [, start [, size]]) defines some kind of special operations.


For example, this command send the buffer 0 back to the UDP message original transmitter :


This is the equivalent of UDP.REPLY message$


Optionally it is also possible specify part of the buffer and the destination port 5001 as below:

UDP.REPLY_IOBUFF(0, 2, 6), 5001


When used with the SPI bus, it enables it to transmit and receive at the same time.

As this operation requires 2 buffers, both must be specified.

For example, this command send the buffer 0 and receive into the buffer 2:


This command send 4 bytes from the buffer 0 starting from the position 89 and receive 4 bytes in the buffer 3:

SPI.REPLY_IOBUFF(0, 89, 4), (3)


Advanced operations

Several other functions / commands are available for advanced users.

These enable bit, string and hex operations


conversion from hex string :

IObuff.FromHex(buff_num, var$ [, pos])

var$ must contain a hex string in the form of "aabbcc1235"

pos is the position where the HEX must be included in the buffer  (0 by default)

A part of the string can be converted in combination with mid$


conversion from string:

IObuff.FromString(buff_num, var$ [, pos])

var$ must contain a text string in the form of "This is a text string"

pos is the position where the HEX must be included in the buffer  (0 by default)

A part of the string can be converted in combination with mid$


conversion to hex string:

A$ = IObuff.ToHex$(buff_num, [, start [, size]])

returns an hex string in the form of "aabbcc1235"

start and size are optional and define the start and length (like MID$ but the 1st byte is 0)


conversion to string:

A$ = IObuff.ToString$(buff_num, [, start [, size]])

returns an hex string in the form of "This is a string"

start and size are optional and define the start and length (like MID$ but the 1st byte is 0)

Bit operations

a = IObuff.bit(buff_num, position, bit)

returns the value of the bit of the byte at the position of the buff_num

returns 0 or 1


IObuff.setbit(buff_num, position, bit)

set the bit of the byte at the position of the buff_num


IObuff.clearbit(buff_num, position, bit)

clear the bit of the byte at the position of the buff_num


IObuff.togglebit(buff_num, position, bit)

toggle the bit of the byte at the position of the buff_num


Buffer copy

IObuff.copy(dest_buff_num [,pos]) , (source_buff_num, [, start [, size]])

Copy the from source_buff to dest_buff

pos is the position where the source must be copied in the source (0 by default)

start and size define what must be copied (have the same meaning as in .WRITE_IOBUFF)

Code examples :


UDP - use the remote controller APP for IOS devices (iphone and Ipad)





' I/O buffers example using the RCWController

' available in the IOS app store.

' It uses by default the port 10000

' The APP sends a block of 10 bytes that

' will be printed in the console on the same line

udp.begin 10000


' define the place where jump on message reception

onudp received




' read the incoming data in the buffer 0


size = iobuff.len(0)

print "received "; size; " bytes"

for z = 0 to 9

  ' read and print 1 byte at the time on the same line

  print, z),

next z

Print ' print an empty line




File read and transfer to the serial port by blocks


' I/O BUFFERS example using files

' read a file in blocks of 512 characters

' and send them to the serial port (print)

fileName$ = "/data8.txt"

block_size = 512 ' size of the block to be read

file_size = file.size(fileName$)

print "File size "; file_size

print file_size

for z = 0 to file_size - 1 step block_size

  file.read_iobuff(0), fileName$, z, block_size

  ' send the block on the serial port (print)




Serial port data logger


' I/O BUFFERS example to create a serial data logger

' receive bytes from the serial port and

' write them into the file /mylog.txt

' all the characters will be recorded

' including the ASCII 0 (NUL)

filename$ = "/mylog.txt"


' define the place where jump on message reception

onserial received




' waits for 10 millisec giving time to receive all the data

pause 10

' read the incoming data in the buffer 0


size = iobuff.len(0)

print "received "; size; " bytes"

' appends the received data to the file

file.append_iobuff(0), filename$






Pin numbers correspond directly to the ESP8266 GPIO pin numbering.

The function of the pin (input / output) must be defined before using the function PIN.MODE as below :


To define the pin 5 as input :



To define the pin 4 as input with a pullup:



To define the pin 2 as output



Although pin numbers can be from 0 to 16, gpio pins 6 to 11 should not be used because they are connected to flash memory chips on most modules. Trying to use these pins as IOs will likely cause the program to crash.


Digital pins 0 to 5 and 12 to 15 can be INPUT, OUTPUT, or INPUT, PULLUP .

Pin 16 can be INPUT, OUTPUT.  At startup, all available pins are configured as INPUT.

Pins may also serve other functions, like Serial, I2C, SPI.

These functions are normally activated by the corresponding library.



This diagram shows pin mapping for the popular ESP-12F module.

(*) pins not available.


The value from a pîn can read as below :

A = PIN(5) read from pin GPIO5


The pin value can be set as below

PIN(2)= 0 set 0 on the pin GPIO2


The pin value (0 or 1) can also be easily toggled by subtracting it from 1 (because 1-0=1 and 1-1=0), eg:

PIN(2)= 1 - PIN(2) toggles the value of GPIO2 pin


As many modules use the NodeMCU pin numbering, please use the table below to find the corresponding reference:

NodeMCU and Wemos Pin Reference

Standard GPIO Reference
























In order to use the Wemos / NodeMcu references, it could be useful to add this code to create the pin constants at the beginning of the program :




Then refer to the pin constants as below :

a = PIN(D1)

PIN(D3) = 1


The pins GPIO1 (TXD0) and GPIO3 (RXD0) can be used as normal GPIO pins simply declaring them as input or output using the command PIN.MODE .


However, they can be restored at their normal function using the same command with the keyword SPECIAL :


PIN.MODE 1, INPUT  ' set pin 1 (TX) as input
PIN.MODE 3, OUTPUT ' set pin 3 (RX) as output


PIN.MODE 1, SPECIAL ' restore the pin 1 as (TX)

PIN.MODE 3, SPECIAL ' restore the pin 3 as (RX)


The INTERRUPT command permit to trigger an event when the signal on an input pin changes.

The interrupt is triggered BOTH when the signal goes from LOW to HIGH and HIGH to LOW.




pin.mode 12, input   ' set pin 12 as input
interrupt 12, change_input  ' set interrrupt on pin 12


if pin(12) = 0 then return   ' if the pin is low, returns back
print "The pin changed to HIGH"


Analog input

ESP8266 has a single ADC channel available to users. It can be used to read voltage at ADC pin.

To read the voltage applied at the pin, the function ADC can be used as below :


print ADC


The voltage range is  0 ... 1.0V and the corresponding range returned by the function is 0 … 1024.

Some modules (like the NodeMCU) have a voltage divider that modify this range.

In particular, the NodeMCU have a full scale range of 3.3V.

Hardware interfaces:

The ESP8266 contains several H/W interfaces that can be controlled by Annex WI-Fi Basic using specific commands and functions.


This functionality permits to control the output duty cycle of any pin, acting like an analog output.

The pin can be any available pin and the range of the value can be from 0 to 1023.

To use it, there is no need to configure the pin, the command PWM can be used directly as below:


PWM(12) = 512


To disable PWM :

PWM(12) = 0


The default PWM Frequency is 1000 Hz but can be changed using the command

OPTION.PWMFREQ freq where freq can be any value from 1 Hz to 40000 Hz



The ESP doesn't have hardware PWM, so the implementation is by software.

With one PWM output at 40KHz, the CPU is already rather loaded. The more PWM outputs used, and the higher their frequency, the closer you get to the CPU limits, and the less CPU cycles are available for sketch execution.



It is possible to generate a tone on any pin using the command PIN.TONE.

The syntax is PIN.TONE pin, freq [, duration]


The pin can be any valid GPIO, the frequency can be between 1 and 5000Hz, the optional parameter duration define the duration of the tone in msec; if not defined the tone will last forever and can be removed using the same command with frequency equal to 0.


Example :

PIN.TONE 14, 1000, 200    ‘ tone of 1000Hz on pin 14 for 200 msec

PIN.TONE 14, 100   ‘ tone of 100Hz non stop

PIN.TONE 14, 0   ‘ clear the tone



This functionality exposes the ability to control RC (hobby) servo motors. It support up to 4 servos on any available pin.

While many RC servo motors will accept the 3.3V IO data pin from a ESP8266, most will not be able to run off 3.3v and will require another power source that matches their specifications. Make sure to connect the grounds between the ESP8266 and the servo motor power supply.

Before using it, the servo channel (from 1 to 4) and the pin must be defined.

This can be done using the command SERVO.SETUP id, pin  as below :

SERVO.SETUP 1, 12    ' attach the servo #1 to pin GPIO12

SERVO.SETUP 2, 13    ' attach the servo #2 to pin GPIO13


After the definition, the servo can be controlled with the command SERVO value as below:

SERVO 1, 90  ' set the servo 1 at 90°

SERVO 2, 45  ' set the servo 2 at 45°

The value must be within the range from 0 to 180


To detach the servo from the pin, use the command SERVO.SETUP id, OFF  as below :





This functionality exposes two counters that permit to count pulses from any input pin.

Each counter can return the frequency of the signal using a timeframe of one second.

Additionally, each counter can also return the time occurred between consecutive pulses (period); this is useful as this will permit to determine the frequency of low frequency signals simply taking its reciprocal 

(f = 1 / period).

These counters are not based on H/W but are managed using processor interrupts so the input frequency should be limited to around 10 Khz.

It is possible to define when the pulse is counted (on Rising Edge, on Falling Edge, on Change).

The “on Change” is particularly interesting when associated with low frequency measurement as it will permit to double the number of pulses.

Before using the counters, the input pin must be set as INPUT using the command PIN.MODE.

To start to use the counters, the following command is available:

COUNTER.SETUP cnt, pin [,mode]


‘cnt’ defines which counter (1 or 2)

‘pin’ defines the input pin (can be any valid pin except GPIO16)

‘mode’ can be 1 (rising edge), 2 (falling edge) or 3 (change). If not specified, the mode change is enabled.



PIN.MODE 12,INPUT   ‘defines the pin GPIO12 as INPUT

COUNTER.SETUP 1, 12, 1  ‘ Counter 1 using pin GPIO12, count on Rising Edge


The pulses counted can be read using the function COUNTER.COUNT(cnt).

The frequency can be read using the function COUNTER.FREQ(cnt).

The period between 2 consecutive pulses can be read using the function COUNTER.PERIOD(cnt).



print COUNTER.COUNT(1)  ‘print the pulses counted from the counter 1

print COUNTER.FREQ(1) ‘print the frequency from the counter 1

print COUNTER.PERIOD(1) ‘print the period from the counter 1


FInally the counters can be reset with the command COUNTER.RESET cnt



COUNTER.RESET 1  ‘ reset the counter 1


PID controllers

A proportional–integral–derivative controller (PID controller. or three-term controller) is a control loop feedback mechanism widely used in industrial control systems and a variety of other applications requiring continuously modulated control. (ref wikipedia)

A PID controller continuously calculates an error value e(t) as the difference between a desired setpoint (SP) and a measured process variable (PV) and applies a correction based on proportional, integral, and derivative terms (denoted P, I, and D respectively), hence the name.

In practical terms it automatically applies accurate and responsive correction to a control function.

An everyday example is the cruise control on a car, where ascending a hill would lower speed if only constant engine power is applied. The controller's PID algorithm restores the measured speed to the desired speed with minimal delay and overshoot, by increasing the power output of the engine.

Annex implements 4 PID controllers that can be used simultaneously for any application.


The commands are :

PIDx.INIT Kp, Ki, Kd


PIDx.LIMITS min, max




The main function is:



PIDx can bePID1, PID2, PID3 or PID4.


The first step is to initialise the PID controller.

This can be done with the command PIDx.INIT Kp, Ki, Kd :


PID1.INIT 50, 80, 1 'initialise the controller with Kp = 50, Ki = 80 and Kd = 1


Optionally the output limits can be set using the command PIDx.LIMITS min, max.

If not defined the output is limited between 0 and 255


PID1.LIMITS 0, 1023 ' limits the output between 0 and 1023


Then the sampling period can be defined using the command PIDx.PERIOD msec

If not defined the period is set at 100 msec


PIDx.PERIOD 50 ' define the period at 50 msec


Finally the main function  output = PIDx.COMPUTE(input, setpoint)




This function must be called regularly in a loop; the best is to call it using a timer.


The command PIDx.SETMODE mode can be used to put the loop in manual with PIDx.SETMODE 0.

In this case the PID loop will be stopped and the output value will be frozen.

To restore the auto mode (default), the command is PIDx.SETMODE 1.


At any moment the PID parameters can be changed using the command PIDx.PARAMS Kp, Ki, Kd :


PID1.PARAMS 30, 80, 10 ' modify the PID parameters with Kp = 30, Ki = 80 and Kd = 10


The following example shows how control the speed of a 3-wire 12V PC fan.

The PID utilise the counter to determine the fans speed controlling it using the PWM.

A little circuit is required to drive the positive side of the FAN.






CODE: pid1.bas

' PID Test program

' cicciocb 2019

' this example controls the speed of a 3-wire PC fan

' using the internal counter as input and the PWM as output


PID1.INIT 1, 5, 0   'init the PID paramters

PID1.LIMITS 0, 1023  'the PWM goes up to 1023


pin.mode 12, input, pullup   'GPIO12 is the tach input. Pullup is ON

counter.setup 1, 12, 3  ' count changes so the output is doubled

cnt_p = 0 ' previous value of the counter

target = 50 'the default target speed (hz)


timer0 100, do_pid 'the PID is updated each 100msec

onHtmlReload create_web_page

gosub create_web_page






a$ = a$ + "SPEED (Hz) " + textbox$(target)

html a$




' The frequency is computed at each cycle counting the pulses occurred

' As the cycle is executed each 100msec, the frequency computed

' is 1/10 of the real one 

cnt = counter.count(1)

freq = cnt - cnt_p ' the frequency

cnt_p = cnt


'the frequency is doubled and divided by 10

'so the real target is target *2 /10

out = pid1.compute(freq, target *2 /10) 'compute the PID

print "pulses ";freq, "freq "; freq *10/2, "pwm out ";out

pwm(13) = out





The I²C bus allows the module to connect to I²C devices.


I²C uses only two bidirectional open-drain lines, Serial Data Line (SDA) and Serial Clock Line (SCL), pulled up with resistors (typically 4.7K to 10K).


The I²C has a 7 bit address space permitting, theoretically, to connect up to 126 I/O devices.


The maximal number of nodes is limited by the address space and also by the total bus capacitance of 400 pF, which restricts practical communication distances to a few meters. The relatively high impedance and low noise immunity requires a common ground potential, which again restricts practical use to communication within the same PC board or small system of boards.


The current implementation is master mode @ 100Khz by default.


The SDA and SCL pins can be freely defined using the command I2C.SETUP sda_pin, scl_pin.

For example, to define pins 4(SDA) and 5(SCL) the command is :

I2C.SETUP 4, 5


It is important to provide the correct pullup resistor on these lines; values from 10K to 100K should be appropriate.


The commands available are :


The functions available are :



There are also other advanced functions / commands to simplify exchanges with the i2c bus.

The advanced commands available are :



The advanced functions available are :



As all the devices can have a "not well" determined address, please find here a little i2c scanner program which returns the address of all the devices found connected to the bus

'I2C Address Scanner

'print in the console the address of the devices found

I2C.SETUP 4, 5  ' set I2C port on pins 4 and 5


for i = 0 to 120

  i2c.begin i

  if i2c.end = 0 then

     print "found "; i , hex$(i)

     pause 10

  end if

next i





PCF8574 Module

This is an example of connection of a module with PCF8574 bought on Ebay at less than 2€ 



This drawing shows how this module must be connected to the ESP8266.

It provides 8 digital inputs or outputs.


This is an example of code that "drives" this module:

I2C.SETUP 4, 5  ' set I2C port on pins 4 and 5

device_address = 32  'set to module i2c address

'Write from 0 to 255 on the module

'Each pin will blink at different frequency

For i = 0 to 255

PCF8574_write i

Next i


'Read all the inputs

'The result is printed into the serial console

' put all the inputs at pullup state

PCF8574_write 255


r = 0

For i = 0 to 1000

  PCF8574_read r

  Print r

Next i



sub PCF8574_write(x)

  i2c.begin device_address

  i2c.write x


end sub


sub PCF8574_read(x)

  i2c.begin device_address

  i2c.reqfrom device_address, 1

  x =


end sub

ADS1115 Module

This is another example of a connection of a module with ADS1115 bought on Ebay at less than 2€.

This is a 16 Bit ADC 4 channel Module with Programmable Gain Amplifier.



Because the module already contains two 10K I2C pullups, no external resistors are required



As this device is quite simple to interface, it can be directly driven using a “driver” written in basic.

' ADS1115 Driver for Annex

' datasheet

' ADS1115 Registers

ADS1115_ADDRESS = &h48

ADS1115_CONV_REG = 0 : ADS1115_CONF_REG = 1

ADS1115_HI_T_REG = 2 : ADS1115_LO_T_REG = 3


dim BUFF_IN(2) ' buffer used for read/write to module

i2c.setup 4,5 ' set I2C bus


' Set the ADS1115 with :

'    AINp = AIN0 and AINn = AIN1

'    FSR = ±4.096 V

'    16 SPS

ADS1115_setup 0, 1, 1


' scale in volt

scale = 4.096 / 32768


v = 0

for i = 0 to 100000

 ADS1115_read v  ' read from the module

 print v * scale

next i






' AINp is the input positive

' AINn is the input negative

'0 : AINp = AIN0 and AINn = AIN1

'1 : AINp = AIN0 and AINn = AIN3

'2 : AINp = AIN1 and AINn = AIN3

'3 : AINp = AIN2 and AINn = AIN3

'4 : AINp = AIN0 and AINn = GND

'5 : AINp = AIN1 and AINn = GND

'6 : AINp = AIN2 and AINn = GND

'7 : AINp = AIN3 and AINn = GND



'0 : FSR = ±6.144 V

'1 : FSR = ±4.096 V

'2 : FSR = ±2.048 V

'3 : FSR = ±1.024 V

'4 : FSR = ±0.512 V

'5 : FSR = ±0.256 V

'6 : FSR = ±0.256 V

'7 : FSR = ±0.256 V



'0 : 8 SPS

'1 : 16 SPS

'2 : 32 SPS

'3 : 64 SPS

'4 : 128 SPS

'5 : 250 SPS

'6 : 475 SPS

'7 : 860 SPS

sub ADS1115_setup(inp_mux, gain, rate)

 local conf

 conf = (inp_mux << 12) or (gain << 9) or (rate << 5) or 3 ' + disable comp

 'use the IO Buffer 0 for writing

 iobuff.dim(0,2) =  (conf and &hff00) >> 8 , conf and &hff

 i2c.write_iobuff(0), ADS1115_ADDRESS, ADS1115_CONF_REG

end sub


sub ADS1115_read(ret)

 'use the IO Buffer 0 for reading

 i2c.read_iobuff(0), ADS1115_ADDRESS, ADS1115_CONV_REG, 2

 if iobuff.len(0) = 0 then

   print "No communication"

   ret = 0


   ret =, 0) << 8 +, 1)

 end if

 if ret > 32768 then ret = ret - 65536

end sub

MCP23017 Module

This is another example for connecting an I2C module, an MCP20S17 bought on Ebay at less than 2€.

This module provides 16 GPIO pins that can be used as digital inputs or outputs.



Because the module already contains two 10K I2C pullups, no external resistors are required





As this device is quite simple to interface, it can be directly driven using a “driver” written in basic.

' MCP23017 Driver for Annex

' datasheet

I2C.SETUP 4, 5  ' set I2C port on pins 4 and 5

device_address = 32  'set to module i2c address


'MCP23017 internal registers

IODIRA   = 0  : IODIRB   = 1 : IPOLA   = 2  : IPOLB   = 3


INTCONA  = 8  : INTCONB  = 9 : IOCONA  = 10 : IOCONB  = 11

GPPUA    = 12 : GPPUB   = 13 : INTFA   = 14 : INTFB   = 15

INTCAPA  = 16 : INTCAPB = 17 : GPIOA   = 18 : GPIOB   = 19

OLATA    = 20 : OLATB   = 21


i2C.WriteRegByte device_address, IOCONA, &h08 ' init MCP23S17 with bit HAEN

i2C.WriteRegByte device_address, IODIRA, &hFF ' all PORT A pins as input

i2C.WriteRegByte device_address, GPPUA,  &hff ' set PORT A pullup on all pins

i2C.WriteRegByte device_address, IODIRB, &h00 ' all PORT B pins as output


r = 0

for z = 0 to 255

  I2C.WriteRegByte device_address, GPIOB, z  ' pulse all GPIOB pins