This is only a preview of the June 2014 issue of Silicon Chip. You can view 37 of the 104 pages in the full issue, including the advertisments. For full access, purchase the issue for $10.00 or subscribe for access to the latest issues. Items relevant to "The Majestic Loudspeaker System":
Items relevant to "2-Way Passive Loudspeaker Crossover Network":
Items relevant to "Touch-Screen Digital Audio Recorder, Pt.1":
Items relevant to "The Micromite: An Easily Programmed Microcontroller, Pt.2":
Items relevant to "40V Switchmode/Linear Bench Power Supply, Pt.3":
Purchase a printed copy of this issue for $10.00. |
Using the
By GEOFF GRAHAM
Micromite, Pt.2
Interfacing & controlling external devices
Now that you know how the Micromite works, we’ll dive right
in with some useful programming tips and show how to control
external devices. In particular, we’ll show how to use it for
infrared (IR) remote control, to measure temperature, control a
servo, interface to an LCD and keypad and much more.
L
AST MONTH, we introduced the Micromite – a
low-cost 28-pin microcontroller running a Microsoftcompatible BASIC interpreter called MMBasic. MMBasic
is easy to use and gives your Micromite-based project the
ability to measure, react to and control all sorts of external
parameters and devices.
In particular, MMBasic includes a number of powerful
commands that allow you to measure voltages, respond
to an infrared remote control, display data on an LCD,
measure distance and much more. This month, we’re going to show you how to use these commands and more.
To make it easier for a program to interact with external
devices, the Micromite includes drivers for a number of
common peripheral devices. In some cases, it’s possible to
achieve the same outcome by manipulating the Micromite’s
I/O pins in BASIC but these drivers have the convenience
of packaging the requirement into one or two easy-to-use
commands.
If you want to go beyond these commands and access
various specialised features of an external device, you
can always develop your own driver to directly drive the
I/O pins.
IR remote control decoder
Adding an infrared remote control to your project
requires very little effort thanks to the IR command in
MMBasic. When enabled, this function runs in the background and interrupts the running program whenever a
key is pressed on the IR remote. It will work with any
Sony-compatible remote, including controls using 15-bit
or 20-bit messages (most cheap universal remote controls
can generate Sony commands).
To detect the IR signal, you need an IR receiver connected to the Micromite’s IR pin (pin 16) – see Fig.1. The
receiver will sense the IR light, demodulate the signal and
present it as a TTL voltage level signal to this pin. Set-up
64 Silicon Chip
of the I/O pin (pin 16) is automatically carried out by the
IR command.
Sony-compatible remote controls use a 40kHz modulation frequency but receivers for that frequency can be
hard to find. Generally, 38kHz receivers will work fine
but maximum sensitivity will be achieved with a 40kHz
device such as the Vishay TSOP4840. Examples of 38kHz
receivers that work include the Vishay TSOP4838, Jaycar
ZD1952 and Altronics Z1611A.
To set-up the decoder you use the command
IR dev, key, interrupt
where dev is a variable that will be updated with the device
code and key is the variable to be updated with the key
code. Interrupt is the interrupt label to call when a new
key press has been detected (interrupts are described in
detail later in this article).
The IR decoding is done in the background and the
program will continue after this command without interruption.
The following example shows how to use the IR decoder:
IR DevCode, KeyCode, IR_Int ' start the IR decoder
DO
< body of the program >
LOOP
IR_Int:
' a key press has been detected
PRINT "Received device = " DevCode " key = " KeyCode
IRETURN
Sony remote controls can address many different devices
(DVDs, TVs etc) so the program would normally examine
the device code first to determine if the signal was intended
for the program. If it was, it then takes action based on the
key pressed. There are many different devices and key
codes so the best method of determining what codes your
siliconchip.com.au
The Vishay TSOP4838 is a typical infrared
receiver that will work with the Micromite.
By using this and any Sony compatible
remote control, you can add infrared remote
control to your Micromite based project.
+5V
+3.3V
IR RECEIVER
100Ω
MICROMITE
remote generates is to use the above program.
16
100nF
IR remote control transmitter
The IR SEND command allows you to transmit a 12-bit
Sony-compatible infrared remote control signal. This could
be used to control a Sony product that uses 12-bit codes
or communicate with another Micromite.
Fig.2 shows what’s required. A transistor (Q1) is used to
drive the infrared LED because the output of the Micromite
is limited to about 10mA, which would not provide a very
bright infrared signal. This circuit provides about 50mA
to the LED which is much better.
To send a signal, you use the command
Fig.1: this circuit will add an infrared remote control
decoder to your Micromite project. The receiver can
be a Vishay TSOP4838, Jaycar ZD1952 or Altronics
Z1611A and the remote control can be any Sony com
patible infrared remote control, including controls
using 15 or 20-bit messages.
+5V
+3.3V
IR SEND pin, dev, key
where pin is the I/O pin used, dev is the device code to
send and key is the key code. Any I/O pin on the Micromite
can be used and you do not have to set it up beforehand
(the IR SEND command will automatically do that).
Note that the modulation frequency used is 38kHz and
this matches the common IR receivers (described above)
for maximum sensitivity when communicating between
two Micromites.
Measuring temperature
The DS18B20() function in MMBasic will get the temperature from a DS18B20 temperature sensor. This device
can be purchased on eBay for about $5 in a variety of
packages, including a waterproof probe version.
The DS18B20 can be powered separately from a 3-5V
supply (see data sheet) or it can operate on “parasite power”
from the Micromite’s data line as shown in Fig.3. Multiple
sensors can be used but note that a separate I/O pin and
pull-up resistor is required is required for each one.
To get the current temperature, you just use the DS18B20()
function in an expression. For example:
PRINT "Temperature: " DS18B20(pin)
where pin is the I/O pin to which the sensor is connected.
You do not have to configure the I/O pin; that’s handled
by MMBasic.
The returned value is in °C with a resolution of 0.25°C
and is accurate to ±0.5°C.
The time required for the overall measurement is 200ms
and the running program will pause for this period while
the measurement is being made. This also means that
interrupts will be disabled for this period. If you don’t
want this to happen, you can separately trigger the measurement then return later to retrieve the reading. That’s
done with the DS18B20 START command as described in
the Micromite User Manual (available for download from
the SILICON CHIP website).
Real time clock interface
Using the RTC GETTIME command, it’s easy to get the
current time from a PCF8563 real time clock. This intesiliconchip.com.au
56Ω
IRLED
A
λ
MICROMITE
K
I/O PIN
1k
B
IR
LED
K
A
C
BC338
BC338
B
E
E
C
Fig.2: this is all you need to generate Sony compatible
12-bit remote control signals. This could be used to
control a Sony product or communicate with another
Micromite.
+3V – +5V
MA
1 8 B 2 X IM
0
4.7k
GND
ANY
MICROMITE
I/O PIN
DQ
VDD
Fig.3: measuring temperature is easy using the DS
18B20 temperature sensor. It can operate on parasitic
power from the Micromite with VDD grounded as
shown here or it can be powered separately by a 3-5V
supply directly connected to the VDD terminal.
The DS18B20 temperature sensor comes in many forms.
This waterproof probe version comes from Australian
Robotics (photo: Australian Robotics).
June 2014 65
+3.3V
4.7k
4.7k
18
5
17
6
MICROMITE
3V
LITHIUM
BUTTON
CELL
8
2
PCF8563
RTC
3
4
1
32.768kHz
CRYSTAL
32pF
Fig.4: adding a PCF8563 real time clock means that
your Micromite-based project will always know the
correct time. Because the PCF8563 draws very little
current it can be permanently connected to a 3V
cell as shown here. The 32pF adjustable capacitor is
used to trim the crystal frequency for very accurate
timekeeping but can be left out completely.
The LCD command will work with 1, 2 or 4-line LCD
modules that use the KS0066, HD44780 or SPLC780
controller chip. This is a typical example supplied by
NexusCyber Electronics.
the clock inside the Micromite. Normally, this command
will be placed at the beginning of the program so that the
time is set at power-up.
Left to its own devices, the clock in the Micromite can
drift by as much as two or three seconds in an hour. If an
accurate time is required over a long period, the PCF8563
can be polled at regular intervals using the SETTICK command, eg:
RTC GETTIME
SETTICK 12 * 3600000, SetTime, 4
< normal program >
This is a typical pre-assembled real time clock module
using the PCF8563 chip. Photo by www.wvshare.com
SetTime:
RTC GETTIME
IRETURN
' set the time at startup
' interrupt every 12 hours
' interrupt called every 12 hours
' reset the time
LCD readout
grated circuit is popular and cheap and will keep accurate
time to about ±50ppm, even with the power removed (it’s
battery backed).
The PCF8563 can be purchased for around $5 on eBay
and complete modules using the PCF8563 along with a
battery can be found for as little as $10.
This is an I2C device and it should be connected to the
2
I C I/O pins of the Micromite. Also, because the PCF8563
draws very little current (even when communicating via
I2C), it can be permanently connected to the lithium cell
(typical cell life is 15 years).
Fig.4 shows the circuit details. The 32pF adjustable
capacitor is used to trim the crystal frequency for very
accurate timekeeping. However, that can be tedious as it
will involve checking the time for drift over several days
or even weeks. If you don’t want to do that, you can substitute a 10pF capacitor or leave it out completely and the
timekeeping will still be quite good.
Before you can use the PCF8563, its time must first be
set. That’s done with the RTC SETTIME command which
uses the format RTC SETTIME year, month, day, hour,
minute, second. Note that the year is just the last two
digits (ie, 14 for 2014) and the hour is in 24-hour format.
For example, the following will set the PCF8563 to 4PM
on the 10th November, 2014:
RTC SETTIME 14, 11, 10, 16, 0, 0
To retrieve the time, you use the RTC GETTIME command which will read the time from the PCF8563 and set
66 Silicon Chip
The LCD command will display text on a standard LCD
module with just a few lines of BASIC. It will work with
LCD modules that use the KS0066, HD44780 or SPLC780
controller chip and have 1, 2 or 4-line displays. Suitable
modules include Altronics Z7001, Jaycar QP5512 and
Futurlec LCD16X2. eBay is another good source and prices
typically range from $10 to $50.
A keypad is a low-tech method of entering data into a
Micromite-based system and it’s easy to connect a 4x3
keypad like this to your project. Photo by Vetco.
siliconchip.com.au
+3.3V
+5V
RS
4
EN
MICROMITE
D7
D6
D5
D4
6
2
Vdd
RS
LCD MODULE
CONTRAST
3
VR1
10k
EN
D7 D6 D5 D4 D3 D2 D1 D0 GND
1
14 13 12 11 10 9 8 7
R/W
5
+3.3V
Fig.6: a keypad is a simple & convenient
method of entering data into a Micromite
based system. The Micromite supports either
a 4x3 or a 4x4 keypad and the monitoring
and decoding of key presses is done in the
background while your program keeps
running in the foreground.
R1
R2
MICROMITE
To set-up the display, you use the LCD INIT command
as follows:
LCD INIT d4, d5, d6, d7, rs, en
where d4, d5, d6 & d7 are the I/O pins that connect to
inputs D4, D5, D6 & D7 on the LCD module (inputs D0-D3
and R/W on the module should be connected to ground);
rs is the pin connected to the register select input on the
module (sometimes called CMD or DAT); and en is the pin
connected to the enable or chip select input on the module.
Any I/O pins on the Micromite can be used and you do
not have to set them up beforehand (the LCD command
automatically does that for you). Fig.5 shows a typical
set up.
To display characters on the module, you use the LCD
command, as follows:
LCD line, pos, data$
Where line is the line on the display (1-4), pos is the
position on the line where the data is to be written (the
first position on the line is 1) and data$ is a string containing the data to write to the LCD display. The characters
in data$ will overwrite whatever was on that section of
the LCD line.
The following shows a typical usage:
LCD INIT 2, 3, 4, 5, 23, 24
LCD 1, 2, "Temperature"
LCD 2, 6, STR$(DS18B20(15))
Note that this example also uses the DS18B20 function
to get the temperature (described above) and that the sensor is connected to pin 15.
Keypad interface
A keypad provides a simple method of entering data into
siliconchip.com.au
Fig.5: adding a 1, 2 or 4-line LCD to a
Micromite is easy. Any I/O pins on the
Micromite can be used and you do not
have to set them up beforehand – the
LCD command automatically does that
for you.
R3
R4
C1
C2
C3
1
2
3
A
4
5
6
B
7
8
9
C
*
0
#
D
C4
a Micromite-based system. The Micromite supports either
a 4x3 or a 4x4 keypad and key presses are monitored and
decoded in the background.
An example of a 4x3 keypad is the Altronics S5381,
while the Altronics S5383 is a 4x4 keypad.
When a key press is detected, an interrupt is issued
and during this interrupt routine, the program can take
whatever action is required (interrupts are described later).
To enable the keypad feature you use the command:
KEYPAD var, int, r1, r2, r3, r4, c1, c2, c3, c4
where var is a variable that will be updated with the key
code; int is the label of the interrupt to call when a new
key press has been detected; r1, r2, r3 & r4 are the pin
numbers used for the four row connections to the keypad
(see Fig.6); and c1, c2, c3 & c4 are the column connections.
Note that c4 is used only with 4x4 keypads and should
be omitted if you are using a 4x3 keypad.
Fig.6 shows the circuit. Any I/O pins on the Micromite
can be used and you do not have to set them up beforehand;
the KEYPAD command will automatically do that for you.
The detection and decoding of key presses is done in the
background and the program will continue after this command without interruption. When a key press is detected,
the value of the variable var will be set to the number representing the key (these are listed in the Micromite User
Manual). Then the interrupt subroutine will be called, eg:
Keypad KeyCode, KP_Int, 1, 2, 3, 4, 8, 9, 10 ' 4x3 keyboard
DO
< body of the program >
LOOP
KP_Int:
' a key press has been detected
PRINT "Key press = " KeyCode
IRETURN
June 2014 67
Table 1: CPU Speed vs Current
CPU Speed
Current Draw
48MHz
25mA
40MHz (default)
21mA
30MHz
16mA
20MHz
12mA
10MHz
7mA
5MHz
4mA
given or the STOP option is used (which will terminate
the output).
As another example, the following will swing two servos
connected to outputs PWM 1A and PWM 1B back and
forth alternatively every five seconds:
DO
SERVO 1, 0.8, 2.2
PAUSE 5000
SERVO 1, 2.2, 0.8
PAUSE 5000
LOOP
Controlling a servo
Measuring distance
A servo is basically a motor with integrated gears and a
control system that allows its shaft position to be precisely
controlled. The Micromite can simultaneously control up
to five servos.
Standard servos allow the shaft to be positioned at various angles, usually between -90° and +90°. Continuous
rotation servos also allow the shaft rotation to be set to
various speeds.
The position of the servo is controlled by a signal pulse
which is repeated every 20ms. Generally, a pulse width
of 0.8ms will position the rotor at -90°, a pulse width of
2.2ms will position it at +90° and a pulse width of 1.5ms
will centre the rotor. However, note that these numbers
can vary between manufacturers.
Most servos require a high current 5V power source and
have two power leads, red for +V and black for ground.
The third wire is the control signal which should be connected to a Micromite SERVO I/O pin. Depending on their
size, servos can be quite powerful but the control signal
used remains the same.
The Micromite has two servo controllers, the first capable of controlling up to three servos and the second two
servos. To drive a servo, you use this command for the
servos connected to controller 1:
By using an HC-SR04 ultrasonic sensor and the DISTANCE() function, you can measure the distance to a target. The HC-SR04 device can be found on eBay for about
$5 and it will measure distances from about 30mm out to
3m. It works by transmitting an ultrasonic sound pulse
and the Micromite then measures the time it takes for the
echo to be returned.
The DISTANCE function is used as follows:
SERVO 1, 1A, 1B, 1C
Similarly, this is the command for the servos connected
to controller 2:
SERVO 2, 2A, 2B
The labels 1A, 1B, 1C, 2A etc are the desired pulse
widths in milliseconds for each output of the channel. The
output pins are designated as PWM 1A, PWM 1B, PWM 2A
etc (the PWM and SERVO commands are closely related
and use the same I/O pins). These I/O pin functions were
shown in Fig.1 in last month’s article which introduced
the Micromite.
If you want to control less than the maximum number
of servos, you can simply leave the unused output off the
list and use that pin as a general purpose I/O.
The pulse width can be specified with a high resolution
(about 0.005ms). For example, the following will position
the rotor of the servo connected to channel 1A to a position near its centre:
SERVO 1, 1.525
Following the SERVO command, the Micromite will
continue to generate a stream of pulses with this duty
cycle in the background until another servo command is
68 Silicon Chip
d = DISTANCE(trig, echo)
where trig is the I/O pin connected to the sensor’s trigger
input and echo is the pin connected to the sensor’s echo
output. Note that the HC-SR04 ultrasonic sensor is a 5V
device and so the echo pin should be a 5V-capable pin.
As with previous functions, the Micromite’s I/O pins
are automatically configured by the distance function. The
value returned is the distance in centimetres to the target
or -1 if no target is detected.
If you want to use multiple sensors, they can share the
same trig output from the Micromite but you must use
different I/O pins for the echo input. You can also use
3-pin devices and in that case only one pin number need
be specified.
Saved variables
Because the Micromite does not have a normal storage
system (such as an SD card) it needs a facility to save
information when the power is switched off. That’s done
with the VAR SAVE command which will take a number
of variables on its command line and will save their values
in non-volatile flash memory. The space reserved for saved
variables is 1.5KB.
These variables can be restored later with the VAR
RESTORE command which will add the saved variables
to the variable table of the running program. Normally,
this command is placed near the start of a program so
that the variables are ready for use when the Micromite
is powered up.
This facility is intended for saving data such as calibration data, user selected options and other items which
change infrequently. It should not be used for frequent
saves as this could wear out the flash memory.
The flash in the PIC32MX150/250 series of chips has
a high endurance of over 20,000 writes and erases. With
normal use, this will never be reached but it could be exceeded by a program that repeatedly saves variables. For
example, a program that saved a set of variables once a second would wear out the flash memory in six hours, while
a program that saved the same data once a day would run
siliconchip.com.au
for over 50 years and still not wear out the flash memory.
CPU speed control
MMBasic can control the Micromite’s clock speed via
the CPU command. At start-up, the chip will run at 40MHz
but the speed can be changed under program control
from 5MHz to 48MHz. The current drawn by the chip is
proportional to the clock speed so this command can be
used to balance performance against current consumption.
Table 1 (measured on a PIC32MX150F128B-I/SP) illustrates this.
When the clock speed is changed all the serial ports
(including the console) will be unaffected although there
may be a small glitch during any change. The internal
clocks and timers will also be unaffected. By contrast, the
PWM, SPI and I2C functions will have their speeds changed
proportionally so if this is not desired, they should be shut
down before the change and restarted again afterwards.
The Micromite can control
up to five servos like
this unit. Photo courtesy
Wikimedia Commons.
The HC-SR04 distance
measuring sensor will
enable your Micromite
project to measure the
distance to an object.
It’s useful for robotics,
tank level monitoring
and many other
applications. Photo by
Robotsoft Systems.
CPU sleep
For battery-powered operation, it’s handy to be able to
power the chip down completely and start it up again on
some event. With the Micromite, you can use the CPU
SLEEP command which will put the processor to sleep
with a current drain of about 80µA.
While it’s asleep, the chip monitors the WAKEUP pin
which is automatically set up as a digital input by the CPU
SLEEP command. The CPU will then be woken up when
the WAKEUP pin changes state (ie, goes from high to low
or low to high). The program will then continue with the
command following the CPU SLEEP command.
The wake-up signal could be a button press, an incoming signal or some other external interrupt.
The infrared remote control function uses the same I/O
pin as the wake-up signal and it’s possible to combine the
two so that an incoming IR signal will wake the Micromite
which will then decode that signal. In this way, you can
have a Micromite running on battery power that will wake
up on an IR signal, do something based on that signal, then
go back to a low-power sleep mode.
The following is an example:
IR DevCode, KeyCode, IR_Int ' start the IR decoder
DO
CPU SLEEP
' now sleep until a signal
LOOP
IR_Int:
' a key press has been detected
< do some work based on the key press >
IRETURN
' return to sleep again
Watchdog timer
The main use for the Micromite is as an embedded
controller. It can be programmed in MMBasic and when
the program is debugged and ready for “prime time” the
AUTORUN configuration setting can be turned on. The
chip will then automatically run its program when power
is applied and act as a custom integrated circuit performing
some specific task. The end user need not know anything
about what is running inside the chip.
However, it’s possible that a fault in the program could
cause MMBasic to generate an error and return to the command prompt. This would be of little use in an embedded
siliconchip.com.au
situation as the Micromite would not have anything connected to the console.
Another possibility is that the BASIC program could
get itself stuck in an endless loop for some reason. In both
cases, the visible effect would be the same . . . the program
would stop running until the power was cycled.
To guard against this, the watchdog timer can be used.
This is a timer in MMBasic that counts down to zero and
when it reaches zero the processor is automatically rebooted (the same as when power was first applied), even
if MMBasic was sitting at the command prompt.
In practice, the WATCHDOG command should be placed
in strategic locations in the program so that it keeps resetting the timer and thus prevents the counter from reaching
zero. Then, if a fault occurs, the program will stop running
and the timer will not be reset. As a result, it will now
count down zero and the program will be restarted (assuming the AUTORUN option has been set).
PIN security
Sometimes, it’s important to keep the data and the program in an embedded controller secret. This can be done
in the Micromite by using the OPTION PIN command.
This command will set a PIN number (which is stored in
flash memory) and whenever the Micromite returns to the
console (for whatever reason) the user will be prompted
to enter the PIN.
Without the correct PIN, the user cannot get to the command prompt. The only options are to enter the correct
PIN or reboot the Micromite. However, if it’s rebooted, the
user will still need the correct PIN to access the command
prompt. Because an intruder cannot reach the command
prompt, they cannot list or copy a program, nor can they
June 2014 69
change the program or change any aspect of MMBasic or
the Micromite.
Once set, the PIN can only be removed by providing
the correct PIN in the first place. If the number is lost, the
only method of recovery is to reset MMBasic as described
later (which will erase the program).
Note that there are complicated (and expensive) methods
of accessing the data on the chip even if a PIN has been
set (eg, by removing the plastic packaging and physically
accessing the silicon die).
The serial console
Using the OPTION BAUDRATE command, the baud
rate of the console can be changed to any speed up to
230,400bps. Changing the console baud rate to a higher
speed makes the full screen editor much faster when it
comes to redrawing the screen. So, if you have a reliable
connection to the Micromite, it’s worth changing the speed
to at least 115,200bps.
When running as an embedded controller the serial
console may no longer be required for programming. This
means that it can then be used as a third serial port, with
OPTION BAUDRATE used to set the required speed. If
you do this, it might be worth using the OPTION BREAK
command to disable the break key to prevent an unintended CTRL-C in the console receive data from halting
the running program.
Once changed, the console baud rate will be permanently remembered unless another OPTION BAUDRATE
command is used to change it. Note that when using this
command it’s possible to accidentally set the baud rate to
an invalid speed. If that happens, the only way out is to
reset MMBasic as described later.
You will need a voltage divider if you want to measure
voltages greater than 3.3V. For small voltages, you may
need an amplifier to increase the input voltage to make
an accurate measurement.
One small point here is that when the Micromite measures voltage, it uses pin 28 (analog power) as its reference
and assumes that this pin is at exactly 3.3V. If you use a
different supply voltage, you will need to scale the reading in your BASIC program to compensate. For example:
Volts = PIN(pin) / 3.3 * Vdd
where Vdd is the supply voltage.
Many devices generate an output voltage that represents
a physical quantity. Examples include accelerometers,
strain gauges, pressure sensors and humidity sensors. You
can use this same technique to measure the voltage output
from these sensors and scale the reading to a meaningful
number.
Counting inputs
The pins marked as COUNT (ie, pins 15-18) can be configured as counting inputs to measure frequency or period,
or to just count pulses on the input. For example, the following will print the frequency of the signal on pin 15:
> SETPIN 15, 3
> PRINT PIN(15)
110374
>
The SETPIN command configures pin 9 as a digital input
and the PIN() function will return the value of that pin
(the number 1 if the pin is high). The IF command will
then execute the command after the THEN statement if
the input was high. If the input pin was low, the program
would just continue with the next line.
In this case, the frequency is 110.374kHz.
The frequency response ranges up to 200kHz maximum
and the measurement is returned in Hz with a resolution
of 1Hz. The value is updated once a second (ie, the gating
period is 1s).
For accurate measurement of signals less than 10Hz,
it’s generally better to measure the period of the signal.
When set to this mode, the Micromite will measure the
number of milliseconds between sequential rising edges
of the input waveform. The value is updated on the low to
high transition so if your signal has a period of (say) 100
seconds you must wait for that amount of time in order
for the PIN() function to return an updated value.
The COUNT pins can also count the number of pulses
on their input. When a pin is configured as a counter (eg,
SETPIN 15,CIN), the counter will be reset to zero and the
Micromite will then count every low to high voltage transition. The counter can be reset to zero again by executing
the SETPIN command a second time (even though the
input was already configured as a counter).
The response to input pulses is very fast and the Micr
omite can count pulses as narrow as 20ns (although the
maximum frequency of the pulse stream is still limited
to 200kHz).
Analog inputs
Digital outputs
Digital inputs
A digital input is the simplest type of input pin configuration. If the input voltage is higher than 2.5V, the logic level
will be high (numeric value of 1), while anything below
0.65V will be low (numeric value of 0). The digital inputs
all use Schmitt trigger logic, so anything in between these
levels will retain the previous logic level.
In your BASIC program, you would set the input as a
digital input and use the PIN() function to get its level.
For example:
SETPIN 23, DIN
IF PIN(23) = 1 THEN PRINT "High"
Pins marked as ANALOG can be configured to measure the voltage on the pin. The input range is from 0V to
3.3V and the PIN() function will return the voltage. For
example:
> SETPIN 23, AIN
> PRINT PIN(23)
2.345
>
70 Silicon Chip
All I/O pins can be configured as standard digital outputs. This means that when an output pin is set to logic
low it will be pulled to 0V and when set high it will be
pulled to 3.3V. In MMBasic, this is done with the PIN
command. For example PIN(15) = 0 will set pin 15 low,
while PIN(15) = 1 will set it high.
When operating in this mode, a pin is capable of sourcing 10mA which is sufficient to drive a LED or other logic
siliconchip.com.au
circuits running at 3.3V. Pins marked as 5V have a couple
of additional properties that make it easy to connect to 5V
circuitry. First, as inputs, they can be directly connected
to a circuit that generates up to 5V without the need for
voltage dropping resistors. These pins can also be set up
to be open collector outputs.
The term ‘open collector output’ means that the output
driver will pull the output low (to zero volts) when the
output is set to a logic low but will go to a high impedance
state when set to logic high. If you then connect a pull-up
resistor to 5V on the output, the logic high level will be
5V (instead of 3.3V using the standard output mode). The
maximum pull-up voltage in this mode is 5.5V.
Pulse width modulation
The PWM (Pulse Width Modulation) command allows
the Micromite to generate square waves with a programcontrolled duty cycle. By varying the duty cycle, you can
generate a program-controlled output voltage and this
could in turn be used to control external devices that
require an analog input (power supplies, motor controllers, etc).
Five PWM outputs are available in two groups and the
frequency of each group can be independently set from
20Hz to 500kHz (see Pt.1 last month). The duty cycle for
each output can also be independently set from 0-100%
with 0.1% resolution when the frequency is below 25kHz.
Above 25kHz, the resolution is 1% or better up to 250kHz.
When the Micromite is powered up or the PWM OFF
command is used the PWM outputs will be set to high
impedance (they are neither off nor on). So, if you want
the PWM output to be low by default (zero power in most
applications), you should use a resistor to pull the output
to ground when it is set to high impedance. Alternatively,
if you want the default to be high (full power), you should
connect the resistor to 3.3V.
Interrupts
Interrupts are a handy way of dealing with an event that
can occur at an unpredictable time. An example is when
the user presses a button. You could insert code after each
statement to check if a button has been pressed but an
interrupt makes for a cleaner and more readable program.
When an interrupt occurs, MMBasic executes a special
section of code and then returns to the main program when
it has finished. The main program will be unaffected by
this interrupt and will then carry on as normal.
I/O pins designated as INT (see Fig.1 in Pt.1 last month)
can be configured to generate an interrupt using the SETPIN
command. Many interrupts (including the tick interrupt,
IR interrupt, etc) can be active at any one time. Interrupts
can be set to occur on a rising or falling digital input signal
(or both) and will cause an immediate branch to a specified
line number, label or user defined subroutine. The target
can be the same or different for each interrupt.
If two or more interrupts occur at the same time, they
are processed in order of pin numbers (ie, an interrupt on
pin 2 will have the highest priority). All other interrupts
are disabled during the processing of an interrupt until the
interrupt routine returns with an IRETURN.
During an interrupt (and at all other times), the state
of the pin that caused the interrupt can be determined
using the PIN() function. For most programs, MMBasic
siliconchip.com.au
will respond to an interrupt in under 50μs. To prevent
slowing the main program too much, an interrupt should
be short and exit as soon as possible. You must also remember to disable an interrupt when you have finished
with it – background interrupts can cause bugs which are
difficult to find.
Timing
MMBasic maintains an internal clock which will provide
the current date and time using the DATE$ and TIME$
functions. You can also set the date/time by assigning the
new date and time to these functions. This makes it easy to
time events and control external circuitry that needs timing.
On power-up, the calendar starts from midnight on
the 1st January 2000 but by using the RTC command (see
above) you can correct the time maintained by a PCF8563
real time clock (RTC) chip.
Another timing function is the PAUSE command which
will freeze the execution of the program for a specified
number of milliseconds. So, to create a 12ms wide pulse,
you could use the following:
SETPIN 4, DOUT
PIN(4) = 1
PAUSE 12
PIN(4) = 0
You can also create a pulse using the PULSE command.
This can generate very narrow pulses (eg, 20μs) or long
pulses lasting up to several days. Long pulses are run in the
background and the program will continue uninterrupted.
Another useful feature is the TIMER function which acts
like a stopwatch. You can set it to any value (usually zero)
and it will count upwards every millisecond.
A timing function is also provided by the SETTICK
command. This command will generate an interrupt at
regular intervals (specified in milliseconds). Think of it
as the regular ‘tick’ of a watch.
As an example, the following code fragment will print
the current time and the voltage on pin 2 every second.
This process will run independently of the main program
which could be doing something completely unrelated:
SETPIN 2, AIN
SETTICK 1000, DOINT
DO
' main processing loop
LOOP
DOINT:
PRINT TIME$, PIN(2)
IRETURN
The second line sets up the ‘tick’ interrupt, the first
parameter of SETTICK is the period of the interrupt
(1000ms) and the second is the label of the interrupt code.
Every second (ie, every 1000ms), the main processing loop
will be interrupted and the program at the label DOINT
will be executed.
Up to four ‘tick’ interrupts can be set up. This type of
interrupt has the lowest priority.
Serial communications
Two serial ports are available for asynchronous serial
communications. These are labelled COM1: and COM2:
June 2014 71
+3.3V
K
MICROMITE
PIN 22
A
1N4148
OR SIMILAR
22k
PIN 21
RS-232 DEVICE
TRANSMIT DATA
RS-232 DEVICE
RECEIVE DATA
SIGNAL GROUND
Fig.7: many devices use RS-232, including modems,
hardwired serial ports on a PC and test equipment.
Here’s a low-cost method of connecting such devices to
the Micromite.
and after being opened they have an associated file number.
You you can use any commands that operate with a file
number to read and write to/from a serial port. A serial
port is also closed using the CLOSE command.
The following is an example:
OPEN "COM1:4800" AS #5
PRINT #5, "Hello"
dat$ = INPUT$(20, #5)
CLOSE #5
This opens COM1: with a speed of 4800 baud and then
transmits the string “Hello”. It then gets up to 20 characters
from the port and closes it. This isn’t a very useful example but it does show how simple it is to use a serial port.
By the way, the syntax was defined by Bill Gates in
the 1970s – MMBasic tries to keep as close to Microsoft
BASIC as possible.
The baud rate can be up to 230,400 on COM1 and 19,200
on COM2. There are other options that can be applied
including nine data bits, two stop bits and data enable
for RS-484 compatibility. These options are explained in
greater detail in the Micromite User Manual.
The signal polarity is standard for devices running at
TTL voltages (see section below for RS-232 voltages). Idle
is voltage high, the start bit is voltage low, data uses a high
voltage for logic 1 and the stop bit is voltage high.
These signal levels allow you to directly connect to
devices like GPS modules (which generally use TTL voltage levels).
Low-cost RS-232 interface
The RS-232 signalling system is used by modems,
hardwired serial ports on a PC, test equipment etc. It is
the same as the serial TTL system used on the Micromite
with two exceptions:
(1) The voltage levels for RS-232 are +12V and -12V,
whereas TTL serial uses +3.3V and 0V.
(2) The signalling is inverted (ie, the idle voltage is -12V,
the start bit is +12V etc).
Cheap RS-232-to-TTL converters can be purchased on
the internet. However, if cable lengths are kept short, you
can directly connect the Micromite to RS-232 provided
you add a resistor and a diode as shown in Fig.7.
First, the signalling polarity needs to be inverted. On
the Micromite, COM1: can be specified to invert both the
72 Silicon Chip
transmit and receive signals (the INV option), so that’s
an easy fix.
For the receive data (ie, the ±12V signal from the remote RS-232 device), the signal voltage can be limited
using a 22kΩ series resistor and a diode that clamps the
maximum positive signal level to the +3.3V rail (there is
no internal clamp diode as it is a 5V tolerant input). The
Micromite’s input impedance is very high so the resistor
will not cause a voltage drop. However, it does mean that
when the signal swings to the maximum +12V, it will be
safely clipped by the diode. Similarly, when it swings to
-12V it will be clipped by an internal protection diode on
pin 22 of the Micromite.
The transmit signal (ie, from pin 21) can be directly connected to the input of the RS-232 device. The Micromite
will only swing the signal from 0V to +3.3V but most RS232 inputs have a threshold of about +1V so the Micromite’s
transmit data will still be interpreted as a valid signal.
These measures break the rules for RS-232 signalling
but it should work fine if you only want to use it over a
short distance (a metre or two). Once it’s connected, all
you need do is open COM1: with the invert option, eg:
OPEN “COM1: 4800, INV” AS #1
I2C communications
The Inter Integrated Circuit (I2C) bus was developed
by Philips (now NXP) to transfer data between ICs. Many
devices can now communicate using I2C and it’s especially
useful for communicating between Micromites.
Two signals are used for communications: (1) the data
line (called SDA) and (2) the clock line (called SCL). Both
should be pulled up to +3.3V or +5V (depending on the
device) by resistors (typically 4.7kΩ). Both the Micromite
and the other device signal each other by pulling these
lines low.
Within MMBasic, there are commands to open the connection, write data, read data and close the connection.
Normally, the Micromite would operate in master mode so
that it controls the communications but it can also work
in slave mode. Full details on the relevant commands are
in the Micromite User Manual.
Fig.8 shows an example of I2C being used for communications between two Micromites, in this case to offload
the keypad and LCD functions from the master device.
Taken together, these functions use up to 14 I/O pins so
it’s convenient to assign responsibility for handling them
to a slave Micromite as shown. After all, a Micromite chip
doesn’t cost very much.
Using just a few lines of code, the master Micromite
can query the slave Micromite to determine if a key on
the keypad has been pressed. It can also send some data to
the slave to be displayed on the LCD. Fig.9 shows the code
that needs to be running on the slave, while Fig.10 is all
that you need on the master to update the display and get
the last key pressed on the keypad (just six lines in total).
1-Wire & SPI communications
To round out the communications facilities, MMBasic
also includes support for 1-Wire and SPI communications.
The 1-Wire protocol was developed by Dallas Semiconductor to communicate with chips using a single signalling line. It’s commonly used for communicating with the
siliconchip.com.au
+3.3V
+3.3V
+3.3V
1
2
3
A
4
5
6
B
7
8
9
C
R1
R2
R3
R4
+5V
RS
4
EN
6
*
2x
10k
MICROMITE
#1
(MASTER)
0
#
D
C4
C3
C2
C1
18
17
2
18
2
17
I C DATA
I C CLOCK
MICROMITE
#2
(SLAVE)
D7
D6
D5
2
Vdd
RS
EN
16 x 2
LCD MODULE
CONTRAST
D7 D6 D5 D4 D3 D2 D1 D0 GND
1
14 13 12 11 10 9 8 7
3
VR1
10k
R/W
5
D4
Fig.8: this diagram illustrates how to connect two Micromites together so that the LCD and keypad interfaces can be
offloaded to the second (slave) Micromite using I2C communications. Together these functions use up to 14 I/O pins so
this is a handy and low cost method of freeing up I/O pins on the master Micromite.
DS18B20 temperature sensor but MMBasic has an inbuilt
function for dealing with that device that’s much more
convenient to use. Other 1-Wire devices include memory
chips and security devices.
SPI has been around a long time and many devices use
that protocol including memory chips, accelerometers,
environment sensors and a host of others.
Rather than go into the detail here, you can download
the Micromite User Manual which provides a detailed
explanation of the commands and functions which support these protocols.
Defined subroutines & functions
MMBasic allows you to define your own subroutines and
functions in your programs. These are modern programming techniques that are useful in organising programs so
that they are easy to modify and read. They will be new
to many readers so we will take a little time to explain
how they work.
A defined subroutine or function is simply a block of
programming code that is self-contained and can be ‘called’
from anywhere within your program. It is the same as if
you have added your own command or function to the
language.
For example, assume that you would like to have the
command FLASH added to MMBasic and its job would
be to flash a LED on pin 2. You could define a subroutine
like this:
Sub FLASH
SETPIN 2, DOUT
Pin(2) = 1
Pause 100
Pin(2) = 0
End Sub
With this subroutine in place, you now just use the
command FLASH to flash the LED, eg:
IF A < B THEN FLASH
Defined subroutines can have ‘arguments’ (sometimes
called parameter lists). In the definition of the subroutine
they look like this:
siliconchip.com.au
Sub MYSUB (arg1, arg2$, arg3)
<statements>
<statements>
End Sub
When you call the subroutine you can assign values to
the arguments, eg:
MYSUB 23, "Cat", 55
In this case, variable arg1 will have the value “23”, arg2$
the value “Cat”, and so on. The arguments act like ordinary
variables but they exist only within the subroutine and will
vanish when the subroutine ends. You can have variables
with the same name in the main program and they will
be different from arguments defined for the subroutine (at
the risk of making debugging harder).
Local variables
Inside a subroutine, you will need to use variables for
various tasks. In reusable code, you don’t want the name
you chose for any such variable to clash with a variable of
the same name in the main program. This can be ensured
by defining a variable as LOCAL.
For example, this is our FLASH subroutine again but
this time we have extended it to take an argument (nbr)
that specifies how many times to flash the LED:
Sub FLASH ( nbr )
Local count
SETPIN 2, DOUT
For count = 1 To nbr
Pin(2) = 1
Pause 100
Pin(2) = 0
Pause 150
Next count
End Sub
The counting variable (count) is declared as local which
means that (like the argument list) it only exists within the
subroutine and will vanish when the subroutine exits. You
can have a variable called count in your main program and
it will be separate from the variable count in your subrouJune 2014 73
LCD INIT 2, 3, 4, 5, 6, 7
KEYPAD pad, PadI, 9, 8, 14, 15, 16, 24, 25, 26
I2C SLAVE OPEN &H26, 0, 0, WriteD, ReadD
' slave’s address is 26 (hex)
DO
WATCHDOG 1000
LOOP
' the program loops forever
' this will recover from errors
ReadD:
I2C SLAVE READ 18, msg$, recvd
LCD ASC(msg$), ASC(MID$(msg$, 2, 1), MID$(msg$, 3)
IRETURN
' received a message
' get the message
' display it
' return from the interrupt
WriteD:
I2C SLAVE WRITE &H26, pad
IRETURN
' request from the master
' send the last key press
' return from the interrupt
PadI:
IRETURN
' key down on the keypad
' we do not do anything
Fig.9: this is the program running on the slave Micromite which is handling an LCD display module and a 4x4 keypad.
The program waits for data, in which case it will send it to the LCD display. It also waits for a request from the master
and in that case it will send the last key pressed on the keypad. The watchdog timer is set running so that if an error
occurs the Micromite will automatically restart itself.
tine. If you do not declare the variable as local, it will be
created ‘globally’ in your program and be visible in the
main program and subroutines, just like a normal variable.
You can define multiple items with the one LOCAL
command and if an item is an array, the LOCAL command will also dimension the array (ie, you do not need
the DIM command).
Defined functions
Defined functions are similar to defined subroutines, the
main difference being that the function is used to return a
value in an expression. For example, if you wanted a function to select the maximum of two values you could define:
Function Max(a, b)
If a > b
Max = a
Else
Max = b
EndIf
End Function
You could then use it in an expression, as follows:
SetPin 1, 1 : SetPin 2, 1
Print "The highest voltage is" Max(Pin(1), Pin(2))
The rules for the argument list in a function are similar
to subroutines. The only difference is that brackets are
required around the argument list when you are calling
a function (they are optional when calling a subroutine).
To return a value from the function, you assign a value
to the function’s name within the function. If the function’s
name is terminated with a ‘$’ the function will return a
string, otherwise it will return a number. Within the function, the function’s name acts like a standard variable.
As another example, let’s assume that you need a function to format time in AM/PM format. The code is as
follows:
74 Silicon Chip
Function MyTime$(hours, minutes)
Local h
h = hours
If hours > 12 Then h = h – 12
MyTime$ = Str$(h) + ":" + Str$(minutes)
If hours <= 12 Then
MyTime$ = MyTime$ + "AM"
Else
MyTime$ = MyTime$ + "PM"
EndIf
End Function
As you can see, the function name is used as an ordinary local variable inside the subroutine. It’s only when
the function returns that the value assigned to MyTime$
is made available to the expression that called it. This
example also illustrates that you can use local variables
within functions just like subroutines.
Passing arguments by reference
If you use an ordinary variable (ie, not an expression)
as the value when calling a subroutine or a function, the
argument within the subroutine/function will point back
to the variable used in the call. In addition, any changes
to the argument in your routine will also be made to the
supplied variable. This is called passing arguments by
reference. For example, you might define a subroutine to
swap two values, as follows:
Sub Swap a, b
Local t
t=a
a=b
b=t
End Sub
In your calling program, you would use variables for
both arguments as follows:
siliconchip.com.au
s$ = chr$(1) + chr$(1) + "Hello Micromite"
I2C OPEN 100, 1000
I2C WRITE &H26, 0, 18, s$
I2C READ &H26, 0, 1, pad
IF MM.I2C THEN ERROR "Slave did not respond"
I2C CLOSE
Fig.10: this is all that is needed to send data to the LCD
connected to the slave and get the last key pressed on
they keypad. First an 18-character string is built up –
the first character is the line on the LCD to place the
text and the second is the column position. The rest
of the string is the data to display. After that has been
sent, the program gets one byte from the slave which is
stored in the variable ‘pad’. This is the value of the last
key pressed on the keypad.
Swap nbr1, nbr2
The result will be that the values of nbr1 and nbr2 will
be swapped.
Unless you need to return a value via the argument, you
should not use an argument as a general-purpose variable
inside a subroutine or function. This is because another
user of your routine may unwittingly use a variable in
their call and that variable will be ‘magically’ changed by
your routine. It’s much safer to assign the argument to a
local variable and manipulate that instead.
PIN and then forget the number. In this case, MMBasic
can be reset to its original configuration using either of
two methods:
(1) reprogram the chip with the Micromite firmware using
a PIC32 programmer; or
(2) short pins 11 & 12 together while applying power.
Following this, you then need to wait a couple of seconds
and remove the power and the short.
Either method will result in the program memory and
saved variables being completely erased and all options
(security PIN, console baud rate, etc) will be reset to their
initial defaults.
Coming next month
Next month, we will describe the SILICON CHIP ASCII
Video Terminal. This is a stand-alone serial terminal that
you can attach to a Micromite to create and edit your
program or you can just use it to display data.
The ASCII Video Terminal can drive a VGA or composite monitor and will accept a standard PS2 keyboard for
input, so it is the perfect companion for the Micromite. It
connects to the Micromite via a serial interface and can
SC
also connect to your PC via USB.
Proposed Format for KitStop ¼ Page Ad
Silicon Chip Magazine June 2014
Resetting MMBasic
It’s possible to get MMBasic into a state where Ctrl-C on
the console will not be recognised, eg, if you set a security
Where To Get The Micromite
A pre-programmed Micromite chip is available for $15 plus
p&p from the SILICON CHIP Online Shop (includes the 47μF
capacitor). MMBasic and a User Manual are also available on
the SILICON CHIP website (free of charge).
Remote Control Made Really Easy
The KSRC2 UHF set controls
appliances, lighting, scoreboards
& models over 40metres. Its
two independent receiver relay
outputs are rated to 500Watts
Fully
Assembled
Special S.C Project Offer!!!
$22.30 inc. GST
Plus $7.50 P & P
Digital Panel Meters at Analogue Prices
KSDVM-30 ULTRA-COMPACT
4.5-30VDC Digital Panel Meter
Features: Bright 0.36” Red LED Digits,
$6.70
Snap-Fit Housing, Range optimized for
inc. GST
solar, automotive and trucking applications. Plus $4.50 P & P
MXA026
Fully
Assembled
Stop-Watch
& Clock
Six, daylight-visible 60mm Digits
Timing Down to 100th sec.
Battery Back-up circuit
Really easy to use and install.
Special Low Price $93.70 inc. GST
plus $11.50 post and Pack
www.kitstop.com.au
P.O. Box 5422 Clayton Vic.3168
Tel:0432 502 755
siliconchip.com.au
June 2014 75
|