Serial Communication

Basic Operation

Serial communication uses RX and TX pins to receive and transmit data.

As there is no common clock signal, both devices must agree on a number of parameters. If necessary, these parameters can be given to the microcontroller's (StringTypeLink["Serial", paclet:ref/device/Serial]) specification.

Basic serial specifications.

Load the package.

Needs["MicrocontrollerKit`"]

Set the baud rate.

MicrocontrollerEmbedCode[(StateSpaceModelFull[1, 1, , ]),<|"Target"->"ArduinoUno","Inputs"->0->"Serial","Outputs"->1->"Serial","Serial"->"BaudRate"->57600|>,"/dev/cu.usbmodem14101"]

There is only one RX and one TX pin on the Uno, so specification can just be "Serial".

The input and output pins are unique and need not be explicitly given.

MicrocontrollerEmbedCode[(StateSpaceModelFull[1, 1, , ]),<|"Target"->"ArduinoUno","Inputs"->"Serial","Outputs"->"Serial","Serial"->"BaudRate"->57600|>,"/dev/cu.usbmodem14101"]

In addition, there are other specifications that configure the actual data that is being transferred.

Serial data specifications.

The "DelimiterByte" is relevant only if there are more than one input or output channels.

Set the delimiter byte as an empty space.

ℳ=MicrocontrollerEmbedCode[(StateSpaceModelFull[0.5`, 2, 1, , ]),<|"Target"->"ArduinoUno","Inputs"->"Serial","Outputs"->{"Serial","Serial"},"Serial"->"DelimiterByte"->" "|>,"/dev/cu.usbmodem14101"]

The parameters in the deployed code can be retrieved from the (PackageLink[MicrocontrollerCodeData, paclet:MicrocontrollerKit/ref/MicrocontrollerCodeData, MicrocontrollerKit Package Symbol]) object.

The values of the serial properties.

Dataset[ℳ["Serial"]]

The "BaudRateError" gives the percentage error in the baud rate. Properties like "TransmissionSpeedMode" are microcontroller specific. All the properties, except for "BaudRateError" can be set in the (StringTypeLink["Serial", paclet:ref/device/Serial]) option.

Specific property values can also be extracted.

The baud rate value.

ℳ["Serial"]["BaudRate"]

Virtual COM Port

On some microcontrollers the serial functionality can be set up over USB. In these cases, the RX and TX pins are not used but rather the USB pins D- and D+.

The communication happens over a virtual port and the parameters are set using "SerialOverUSB" . Other than that, the workflow is similar to the regular case.

Set the start byte to 8.

ℳ=MicrocontrollerEmbedCode[(StateSpaceModelFull[1, 0.5`, ,{},{Automatic}, ]), <|"Target"->"ArduinoMicro", "Inputs"->"A0"->"Analog", "Outputs"->"SerialOverUSB","SerialOverUSB"->"StartByte"->8|>,  "/dev/cu.usbmodem14101"]

Retrieve the value of the start byte.

ℳ["SerialOverUSB"]["StartByte"]

Device Framework

While on some boards such as the Arduino Micro the serial functionality is implemented in software, other boards such as the Arduino Uno have a USB-to-serial converter. Both kinds of boards can communicate with a personal computer through the USB port using the serial interface. Through this serial interface the Wolfram Device Framework can communicate with these boards.

First, the microcontroller needs to be set up to send or receive data.

Set up the microcontroller to send and receive numerical data.

ℳ = MicrocontrollerEmbedCode[(NonlinearStateSpaceModelFull[Sin[r], \[Null], 0.75`, {r}Automatic, ]), 
  <|"Target"->"ArduinoUno","Inputs"->"Serial","Outputs"->"Serial"|>, "/dev/cu.usbmodem14101"]

The microcontroller is now a serial device. Open a serial connection to it using the device framework.

Open a connection.

dev =DeviceOpen["Serial","/dev/cu.usbmodem14101"]

Start a task to send and receive data.

u=y=c={};
task=SessionSubmit@ScheduledTask[

If[DeviceExecute[dev,"SerialReadyQ"],
AppendTo[y,DeviceReadBuffer[dev,"ReadTerminator"->ℳ["Serial"]["EndByte"]]];DeviceExecute[dev,"ReadFlush"];
AppendTo[c,RandomReal[]];
AppendTo[u,RandomReal[{0,2π}]];
DeviceWrite[dev,ℳ["Serial"]["StartByte"]];
DeviceWrite[dev, ToString@u[[-1]]];
DeviceWrite[dev,ℳ["Serial"]["EndByte"]]
],

0.75];

Plot the data.

ListPlot[MapThread[Style[{#1,#2},Hue@#3]&,{Most@u,ToExpression[FromCharacterCode[Rest@#]]&/@Rest[y],Most@c}]]

Stop the task and close the connection to the device.

TaskRemove[task];
DeviceClose[dev]