Wednesday, August 17, 2016

Programming Arduino in Visual Studio Code

I have really been enjoying using Visual Studio Code lately.  I just finished using it for a Golang backend and in place of the Intel XDK editor for a Cordova frontend (the XDK is great for building and launching Cordova apps, but I'm not a big fan of its editor).

I wouldn't say that I'm going to use it for everything (emacs is still my top choice for C++, shell scripting, LaTeX, and quick-and-dirty org-mode tables), but Visual Studio Code is pretty darn nice.  Here are a few quick reasons why I like it:

  • No wasted screen real estate.  No buttons for things that are in a menu.  No toolbars that you can screw up and never find again, like in Eclipse.  It's lean and lightweight.
  • Awesome extensions.  Really.  I installed the Go extension by lukehoban, and it felt like I was working in the preferred IDE for Go.  I installed ESLint, TSLint, and CSSLint, and they just worked perfectly.
  • Git integration.  I have never liked the git integration in any IDE I've ever used.  Visual Studio Code seems to understand the 80/20 rule... for easy git operations, it works great.  For hard things, it knows that I'm just going to use the command line.  I've actually used it as often as not in recent projects.  It just works.
  • Sane keyboard shortcuts.  I don't use a mouse if I can avoid it.  I think it goes back to when I started using Windows 3.0 instead of DOS, and constantly found my mouse performing poorly, and needing me to disassemble the bottom and clean lint off of the ball and rollers.  I learned the Windows keyboard shortcuts.  And Microsoft rarely changed them (the office ribbon being a notable exception).  When I work in emacs, the muscle memory in my fingers knows exactly how to navigate.  The same is true for well-designed windows apps.  When a program breaks the rules (like IntelliJ not respecting that Shift-F10 is supposed to open a context menu), I get so annoyed that I'll rant in the middle of a blog post!
  • Easy configuration.  Configuration files are JSON, and they have autocomplete features to help me do what I need to do.  It's not as powerful as emacs, but I haven't changed my .emacs file in years, because it seems like every time I want to change anything, I have to re-learn elisp and spend an hour digging around on the web.
So now that I've established myself as being on the Visual Studio Code bandwagon, let me show one reason why it's so great.  You can make extensions for just about any language or environment, and people do.  In my opinion, the Arduino IDE is just about the worst development tool ever (it rivals writing code in Notepad).  But in just a few easy steps, you can switch to Visual Studio Code, and never look back.

First, you'll want to install the Arduino extension (currently version 0.0.4) by moozzyk.  This gives syntax highlighting, and other simple stuff that you'd expect.

Second, you will need to set up a tasks.json file.  This will let you compile sketches, and deploy sketches to a plugged-in Arduino.  Below is my tasks.json.  It's specific to Windows (though easy to extend to OSX and Linux), and generic enough that you can put it in a .vscode folder in your main Arduino sketchbook folder, and then it will let you build and install any sketch in any subfolder:


// tasks.json for building and running Arduino sketches from
// Visual Studio Code
//
// Note: this configuration uses whatever serial port was most recently used
// by the Arduino IDE
{
    "version": "0.1.0",
    "windows": {
 "command": "c:\\galileo\\arduino_debug.exe"
    },
    "isShellCommand": true,
    "showOutput": "always",
    "suppressTaskName": true,
    "tasks": [
 {
     "taskName": "Compile",
     "args": [
  "--verify",
  "-v",
  "${file}"
     ],
     "isBuildCommand": true,
     "showOutput": "always",
     "problemMatcher": {
  "owner": "external",
  "fileLocation": [
      "relative",
      "${fileDirname}"
  ],
  "pattern": {
      "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
      "file": 1,
      "line": 2,
      "column": 3,
      "severity": 4,
      "message": 5
  }
     }
 },
 {
     "taskName": "Run",
     "args": [
  "--upload",
  "-v",
  "${file}"
     ],
     "isTestCommand": true,
     "showOutput": "always"
 }
    ]
}

With this file in place, you can use ctrl-shift-b to run the Compile task.  You can reach the Run task by using ctrl-shift-p and then typing "task test", which will choose "Tasks: Run Test Task".

So then, at this point, you only need the Arduino IDE for two things: changing the board type/serial port, and running a serial debugger.  Short of hard-coding information in your tasks.json file whenever the board info changes, I don't know of an easy workaround for the first problem.  But for the second, it turns out that PuTTY is a fine alternative to the Arduino serial monitor.  I've been using it for a decade, and never noticed that with one click, you can switch from ssh to serial connections:


That's it!  Just click on the "Serial" radio, enter your COM port, and you have everything you need.

For the sake of completeness, here's the sketch I used.  Intel graciously donated some Galileo V2 boards and Grove IoT kits, and my son used them to display temperature readings on an LCD:




// Sketch for Galileo Gen 2 with Grove kit, for displaying temperature in
// Farenheit on LCD
//
// Temperature Sensor is connected to A0
// LCD Screen is connected to I2C #2

#include <Wire.h>
#include "rgb_lcd.h"

rgb_lcd lcd;

// background color for the LCD
const int colorR = 0;
const int colorG = 255;
const int colorB = 0;

// Pin for the temperature sensor
const int pinTemp = A0;

// Define the B-value of the thermistor in the Grove kit, so we can convert
// to Celsius
const int B = 3975;

void setup() {
    // set up the LCD's number of columns and rows, then its color
    lcd.begin(16, 2);
    lcd.setRGB(colorR, colorG, colorB);
}

void loop() {
    // Position cursor at 0,0
    lcd.setCursor(0, 0);

    // Read raw value of temperature sensor
    int val = analogRead(pinTemp);

    // Convert to Farenheit
    float resistance = (float)(1023-val)*10000/val;
    float temperature = 1/(log(resistance/10000)/B+1/298.15)-273.15;
    temperature = temperature * 9.0 / 5.0 + 32;

    // Print temperature to LCD
    lcd.print(temperature);

    // Repeat every second
    delay(1000);

}

Have you tried Visual Studio Code yet?  Should I post more of my experiences?  Leave a comment to share your thoughts.

No comments:

Post a Comment