Project updated to V1.0 Release Candidate 2 (December 31st, 2022)
In this Meadow project we're going to learn how to build the very popular retro drawing toy Etch-A-Sketch using a couple of rotary encoders and a TFT SPI display. We'll see how easy is to write the logic using the powerful driver platform Meadow.Foundation and its GraphicsLibrary to do all the drawing.
Everything you need to build this project is included in the Wilderness Labs Meadow F7 w/Hack Kit Pro. We'll see how easy is to program these peripherals using Meadow.Foundation.
Meadow.Foundationa platform for quickly and easily building connected things using.NET on Meadow. Created by Wilderness Labs, it's completely open source and maintained by the Wilderness Labs community.
If you're new working with Meadow, I suggest you go to the Getting Started w/ Meadow by Controlling the Onboard RGB LEDproject to properly set up your development environment.
Step 1 - Assemble the circuitWire up your EdgeASketch circuit like the Fritzing diagram below:
Note about interrupts on Meadow F7
If you look at the diagram closely, you can see that we're wiring the top rotary encoder to Analog pins A1, A2 and A3. This is possible because you can actually configure these pins to be digital input ports to handle interrupts. Check this Meadow pinout diagram:
Notice the pins marked with an Interrupt Group range from group 00 to group 15. This is important to have in mind for when configuring digital input ports, you have to make sure that you're using only one pin per Interrupt Group, otherwise you will run into problems trying to get events. For example, you wont get interrupt events when configuring pins D08 and D09 since both belong to Interrupt Group 06.
Step 2 - Create a Meadow Application projectCreate a new Meadow Application project in Visual Studio 2019 for Windows or macOS and name it EdgeASketch.
Step 3 - Add the required NuGet packagesFor this project, search and install the following NuGet packages:
Step 4 - Write the code for EdgeASketchCopy the following code below:
// public class MeadowApp : App<F7FeatherV1> <- If you have a Meadow F7v1.*
public class MeadowApp : App<F7FeatherV2>
{
int x, y;
MicroGraphics graphics;
RotaryEncoderWithButton rotaryX;
RotaryEncoderWithButton rotaryY;
public override Task Initialize()
{
var onboardLed = new RgbPwmLed(
device: Device,
redPwmPin: Device.Pins.OnboardLedRed,
greenPwmPin: Device.Pins.OnboardLedGreen,
bluePwmPin: Device.Pins.OnboardLedBlue);
onboardLed.SetColor(Color.Red);
var config = new SpiClockConfiguration(
speed: new Frequency(48000, Frequency.UnitType.Kilohertz),
mode: SpiClockConfiguration.Mode.Mode3);
var spiBus = Device.CreateSpiBus(
clock: Device.Pins.SCK,
copi: Device.Pins.MOSI,
cipo: Device.Pins.MISO,
config: config);
var st7789 = new St7789(
device: Device,
spiBus: spiBus,
chipSelectPin: null,
dcPin: Device.Pins.D01,
resetPin: Device.Pins.D00,
width: 240, height: 240);
graphics = new MicroGraphics(st7789);
graphics.Clear(true);
graphics.DrawRectangle(0, 0, 240, 240, Color.White, true);
graphics.DrawPixel(x, y, Color.Red);
graphics.Show();
x = graphics.Width / 2;
y = graphics.Height / 2;
rotaryX = new RotaryEncoderWithButton(
device: Device,
aPhasePin: Device.Pins.A01,
bPhasePin: Device.Pins.A02,
buttonPin: Device.Pins.A03);
rotaryX.Rotated += RotaryXRotated;
rotaryY = new RotaryEncoderWithButton(
Device,
Device.Pins.D03,
Device.Pins.D04,
Device.Pins.D05);
rotaryY.Rotated += RotaryYRotated;
rotaryY.Clicked += RotaryYClicked;
onboardLed.SetColor(Color.Green);
return base.Initialize();
}
void RotaryXRotated(object sender, RotaryChangeResult e)
{
if (e.New == RotationDirection.Clockwise)
x++;
else
x--;
x = Math.Clamp(x, 1, graphics.Width - 1);
graphics.DrawPixel(x, y + 1, Color.Red);
graphics.DrawPixel(x, y, Color.Red);
graphics.DrawPixel(x, y - 1, Color.Red);
}
void RotaryYRotated(object sender, RotaryChangeResult e)
{
if (e.New == RotationDirection.Clockwise)
y++;
else
y--;
y = Math.Clamp(y, 1, graphics.Height - 1);
graphics.DrawPixel(x + 1, y, Color.Red);
graphics.DrawPixel(x, y, Color.Red);
graphics.DrawPixel(x - 1, y, Color.Red);
}
void RotaryYClicked(object sender, EventArgs e)
{
x = graphics.Width / 2;
y = graphics.Height / 2;
graphics.DrawRectangle(0, 0, 240, 240, Color.White, true);
graphics.DrawPixel(x, y, Color.Red);
}
public override async Task Run()
{
while (true)
{
graphics.Show();
await Task.Delay(500);
}
}
}
Meadow Constructor
In the MeadowApp's Constructor
, we first initialize the ST7789
SPI display along with the MicroGraphics Library, We immediately draw a white filled rectangle that covers the entire screen, and draw a Red pixel in the middle of the display with the previously initialized x and y integers. We also initialize the two Rotary Encoders
, one to control the draw on the X axis and the other to draw on the Y axis. Both rotaries have the Rotated
event registered.
RotatyXRotated and RotatyYRotated event handlers
In the event handlers, you can check to which direction the rotary encoders were turned by accessing the e.Direction
property and comparing with the enum RotationDirection
to see if its Clockwise or CounterClockwise. If its Clockwise, we increment either the X or Y coordinates (depending which Rotaty was turned), and we would decrement if its turned the other way.
Notice we're drawing at three pixels at a time in both directions, we do this to make the line stroke a bit thicker, since the resolution of the display is so high, the drawing line is too thing, making it difficult to see what you're doing.
RotaryYClicked
Since we're using rotary encoders with buttons, you can handle Click event handlers, like you would do working with PushButtons. The RotaryYClicked
event handler will clear the display and re-initialize the x and y coordinates back to the middle of the display.
Click the Run button in Visual Studio. It should look like to the following GIF:
This project is only the tip of the iceberg in terms of the extensive exciting things you can do with Meadow.Foundation.
- It comes with a huge peripheral driver library with drivers for the most common sensors and peripherals.
- The peripheral drivers encapsulate the core logic and expose a simple, clean, modern API.
- This project is backed by a growing community that is constantly working on building cool connected things and are always excited to help new-comers and discuss new projects.
Comments