Micro:bit - Morse Transmitter
Written by Harry Fairhead   
Monday, 01 March 2021
Article Index
Micro:bit - Morse Transmitter
Polling v Events
A Morse Transmitter

The micro:bit has a built-in radio that can be used to create a very simple Morse code transmitter. This is an extract from the newly published second edition of my book on programming the micro:bit in C, now covering both the original version and V2.

Micro:bit IoT In C Second Edition

By Harry Fairhead

microbite2360

Buy from Amazon.

Contents

  1. The Micro:bit Family
  2. Getting Started With C
  3. First Steps With The GPIO
  4. Fast Memory-Mapped GPIO
  5. Pulse Width Modulation, Servos and More
  6. I2C Bus
  7. I2C Measuring Temperature And Humidity
  8. Creating A Custom Protocol
  9. DS18B20 1-Wire Temperature Sensor
  10. SPI Bus
  11. A‑to‑D With The SPI Bus
  12. Serial Connections
  13. Getting On WiFi
  14. The LED Display
  15. Radio Sounds
    Extract: Morse Transmitter  ***NEW!
  16. Appendix I The Mbed Online Compiler
  17. Appendix II Yotta And Offline Development

 <ASIN:1871962676>

<ASIN:B08XPRMK97>

The micro:bit has a radio which works as a Bluetooth Low Energy (BLE) connection. It can also be used in a raw point-to-point mode. The Bluetooth aspects of the radio are fairly well documented and mostly high level. What is more interesting to the C/C++ programmer is the raw radio used to send small amounts of data.

The V2 also has a built in loudspeaker which provides some other opportunities for using the radio. If you add an external speaker to the V1 then it too can be used in the same way.

Developing With Radio

Developing programs that work with a radio or any other form of communications is a doubly difficult task. The problem is that you have to have two programs – one that sends and one that receives. Even if you structure your program so that the same program works in both modes, the actual task for the transmitter and the receiver is always different. Put simply, you have just written two new programs and you download one to the receiver and one to the transmitter – if it doesn’t work which has the problem?

This is where normal debugging procedures start to get complicated by the fact that you can only debug one at a time and you have to do so on the assumption that the other end of the link is working. If you can’t find a bug at the end you are working at, you have to switch your attention to the other end of the link and assume that the end you have just left is working. This isn’t particularly efficient and it can be very frustrating.

The best way to work, but it isn’t always possible, is to write the simplest program you can that works at both ends of the connection. Verify that this does indeed work. Then proceed by making small changes at one end of the link only. This, of course, isn’t always possible as a change in the transmitter often needs a change in the receiver, but it is surprising how often changes are simply elaborations on what is already working. If you do need to change things at both ends of the connection then making small changes is your best method of keeping things manageable.

Principles Of Radio

The micro:bit radio link works in the same band as WiFi, i.e. 2.4GHz, but it’s a narrow band, 1MHz, transmission which limits the data rate to 1Mbps. You can send blocks of data up to 1024 bytes, but the default limit is 32 bytes which is actually more than enough for many purposes. At full transmitting strength, you can get a 20m range. Also notice that frequency hopping isn’t used and this can mean that the micro:bit will interfere with WiFi on the same band.

First we need to look at how to setup the radio. You can create a radio object:

MicroBitRadio radio=MicroBitRadio();

or you can simply use the radio object created by the MicroBit object:

MicroBit uBit;
uBit.radio

The radio can be enabled and disabled using the enable and disable methods.

You can use:

int setFrequencyBand(int band)

to set the radio band used to transmit and receive data. The band parameter sets the frequency in the range 0 to 99MHz starting from 2.4GHz. For example:

setFrequencyBand(42);

sets the frequency to 2.442GHz. You can set the transmission power using:

int setTransmitPower(int power)

where power varies from 0 to 7 with 7 being the highest power. Why would you want to lower the transmitting power? Lower power means less battery drain and less chance of interfering with other micro:bits working nearby.

You can use the setFrequencyBand function to make sure a particular group of micro:bits form a communicating group but you can also use:

int setGroup(uint8_t group)

to form groups of communicating micro:bits on the same frequency band. Once you have set the group only other micro:bits on same group and, of course, same frequency band, will receive transmissions.

Once you have the radio configured the low level way of sending and receiving data is to use the send and recv functions which work with a frame buffer:

FrameBuffer recv()
int send( FrameBuffer * buffer)

The FrameBuffer struct is:

struct FrameBuffer
{
  uint8_t    length; // The length of the remaining bytes 
  uint8_t     version; // Protocol version code.
  uint8_t     group;   // ID of the group 
  uint8_t     protocol;  // Inner protocol id
  uint8_t     payload[MICROBIT_RADIO_MAX_PACKET_SIZE];
// User data FrameBuffer *next; // pointer to next buffer int rssi;
// Received signal strength of this frame. };

The only difficult fields to deal with are protocol which should be set to either:

MICROBIT_RADIO_PROTOCOL_DATAGRAM  
MICROBIT_RADIO_PROTOCOL_EVENTBUS

or something new you have invented and, at the time of writing, version is set to 1.

There seems to be little reason to use the FrameBuffer directly as the radio’s datagram object provides a set of functions that work with simpler data types. The send method can be use to send a simpler types of data:

int send(ManagedString data)
int send(uint8_t * buffer, int len)

In most cases, sending a ManagedString is what you want, but an array of unsigned integers is also useful. Notice that you are limited to 32bytes in each case. There is also a lower-level function that works with a managed type:

int send( PacketBuffer data)

The PacketBuffer records the data, length and an RSSI - Received Signal Strength Indicator. It is an estimated measure of power level that an RF client device is receiving:

PacketBuffer(uint8_t *data, int length, int rssi = 0);

In most cases you won’t need it.

For receiving data there are two versions of the recv function:

int recv( uint8_t * buf, int len)

and

PacketBuffer recv()

The PacketBuffer version of the function is more useful than you might expect because the ManagedString object has a constructor which converts the PacketBuffer, allowing you to write things like:

ManagedString s = uBit.radio.datagram.recv();

and the data payload of the PacketBuffer will be converted into the ManagedString.

<ASIN:B08WTBNJ5Q>

<ASIN:B08NLX7773>



Last Updated ( Wednesday, 03 March 2021 )